diff options
Diffstat (limited to 'apt-inst')
-rw-r--r-- | apt-inst/contrib/arfile.cc | 14 | ||||
-rw-r--r-- | apt-inst/contrib/extracttar.cc | 21 | ||||
-rw-r--r-- | apt-inst/deb/debfile.cc | 15 |
3 files changed, 48 insertions, 2 deletions
diff --git a/apt-inst/contrib/arfile.cc b/apt-inst/contrib/arfile.cc index 5cb43c690..6d4a1f158 100644 --- a/apt-inst/contrib/arfile.cc +++ b/apt-inst/contrib/arfile.cc @@ -94,7 +94,12 @@ bool ARArchive::LoadHeaders() delete Memb; return _error->Error(_("Invalid archive member header")); } - + + if (Left < 0 || Memb->Size > static_cast<unsigned long long>(Left)) + { + delete Memb; + return _error->Error(_("Invalid archive member header")); + } // Check for an extra long name string if (memcmp(Head.Name,"#1/",3) == 0) { @@ -106,6 +111,13 @@ bool ARArchive::LoadHeaders() delete Memb; return _error->Error(_("Invalid archive member header")); } + + if (Len > Memb->Size) + { + delete Memb; + return _error->Error(_("Invalid archive member header")); + } + if (File.Read(S,Len) == false) { delete Memb; diff --git a/apt-inst/contrib/extracttar.cc b/apt-inst/contrib/extracttar.cc index 19ac1c8b1..cbee4d12a 100644 --- a/apt-inst/contrib/extracttar.cc +++ b/apt-inst/contrib/extracttar.cc @@ -55,7 +55,17 @@ 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; + +// A file size limit that we allow extracting. Currently, that's 128 GB. +// We also should leave some wiggle room for code adding files to it, and +// possibly conversion for signed, so this should not be larger than like 2**62. +static const unsigned long long APT_FILESIZE_LIMIT = 1llu << 37; + // ExtractTar::ExtractTar - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -170,6 +180,11 @@ bool ExtractTar::Go(pkgDirStream &Stream) StrToNum(Tar->Minor,Itm.Minor,sizeof(Tar->Minor),8) == false) return _error->Error(_("Corrupted archive")); + // Security check. Prevents overflows below the code when rounding up in skip/copy code, + // and provides modest protection against decompression bombs. + if (Itm.Size > APT_FILESIZE_LIMIT) + return _error->Error("Tar member too large: %llu > %llu bytes", Itm.Size, APT_FILESIZE_LIMIT); + // Grab the filename and link target: use last long name if one was // set, otherwise use the header value as-is, but remember that it may // fill the entire 100-byte block and needs to be zero-terminated. @@ -222,6 +237,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) @@ -241,6 +258,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) diff --git a/apt-inst/deb/debfile.cc b/apt-inst/deb/debfile.cc index f8d752e7f..bef0cd0d8 100644 --- a/apt-inst/deb/debfile.cc +++ b/apt-inst/deb/debfile.cc @@ -184,11 +184,23 @@ bool debDebFile::ControlExtract::DoItem(Item &Itm,int &Fd) // --------------------------------------------------------------------- /* This sets up to extract the control block member file into a memory block of just the right size. All other files go into the bit bucket. */ + +// Upper size limit for control files. Two reasons for having a limit here: +// +// 1. We read those files into memory and want to avoid being killed by OOM +// +// 2. We allocate (Itm.Size+2)-large arrays, so this can overflow if Itm.Size +// becomes 2**64-2 or larger. This is obviously +// +// 64 MiB seems like a terribly large size that everyone should be happy with. +static const unsigned long long DEB_CONTROL_SIZE_LIMIT = 64 * 1024 * 1024; bool debDebFile::MemControlExtract::DoItem(Item &Itm,int &Fd) { // At the control file, allocate buffer memory. if (Member == Itm.Name) { + if (Itm.Size > DEB_CONTROL_SIZE_LIMIT) + return _error->Error("Control file too large: %llu > %llu bytes", Itm.Size, DEB_CONTROL_SIZE_LIMIT); delete [] Control; Control = new char[Itm.Size+2]; IsControl = true; @@ -237,6 +249,9 @@ bool debDebFile::MemControlExtract::Read(debDebFile &Deb) record. */ bool debDebFile::MemControlExtract::TakeControl(const void *Data,unsigned long long Size) { + if (Size > DEB_CONTROL_SIZE_LIMIT) + return _error->Error("Control file too large: %llu > %llu bytes", Size, DEB_CONTROL_SIZE_LIMIT); + delete [] Control; Control = new char[Size+2]; Length = Size; |