diff options
author | Julian Andres Klode <julian.klode@canonical.com> | 2020-12-04 12:37:19 +0100 |
---|---|---|
committer | Julian Andres Klode <julian.klode@canonical.com> | 2020-12-09 17:30:43 +0100 |
commit | 822db13d68658a1a20df2d19c688c18faa331616 (patch) | |
tree | 56d69c08a14cbc1e58b58b07231d9df3dd5cd4c7 /apt-pkg/contrib | |
parent | d10c68d628fe5342d400a999a6d10c5c7c0cef41 (diff) |
tarfile: OOM hardening: Limit size of long names/links to 1 MiB
Tarballs have long names and long link targets structured by a
special tar header with a GNU extension followed by the actual
content (padded to 512 bytes). Essentially, think of a name as
a special kind of file.
The limit of a file size in a header is 12 bytes, aka 10**12
or 1 TB. While this works OK-ish for file content that we stream
to extractors, we need to copy file names into memory, and this
opens us up to an OOM DoS attack.
Limit the file name size to 1 MiB, as libarchive does, to make
things safer.
Diffstat (limited to 'apt-pkg/contrib')
-rw-r--r-- | apt-pkg/contrib/extracttar.cc | 11 |
1 files changed, 10 insertions, 1 deletions
diff --git a/apt-pkg/contrib/extracttar.cc b/apt-pkg/contrib/extracttar.cc index 1616c9f12..f653e227e 100644 --- a/apt-pkg/contrib/extracttar.cc +++ b/apt-pkg/contrib/extracttar.cc @@ -55,7 +55,12 @@ struct ExtractTar::TarHeader char Major[8]; char Minor[8]; }; - + +// We need to read long names (names and link targets) into memory, so let's +// have a limit (shamelessly stolen from libarchive) to avoid people OOMing +// us with large streams. +static const unsigned long long APT_LONGNAME_LIMIT = 1048576llu; + // ExtractTar::ExtractTar - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -218,6 +223,8 @@ bool ExtractTar::Go(pkgDirStream &Stream) { unsigned long long Length = Itm.Size; unsigned char Block[512]; + if (Length > APT_LONGNAME_LIMIT) + return _error->Error("Long name to large: %llu bytes > %llu bytes", Length, APT_LONGNAME_LIMIT); while (Length > 0) { if (InFd.Read(Block,sizeof(Block),true) == false) @@ -237,6 +244,8 @@ bool ExtractTar::Go(pkgDirStream &Stream) { unsigned long long Length = Itm.Size; unsigned char Block[512]; + if (Length > APT_LONGNAME_LIMIT) + return _error->Error("Long name to large: %llu bytes > %llu bytes", Length, APT_LONGNAME_LIMIT); while (Length > 0) { if (InFd.Read(Block,sizeof(Block),true) == false) |