summaryrefslogtreecommitdiff
path: root/apt-pkg
diff options
context:
space:
mode:
authorJulian Andres Klode <julian.klode@canonical.com>2020-12-09 17:30:57 +0100
committerJulian Andres Klode <julian.klode@canonical.com>2020-12-09 17:30:57 +0100
commitd4bdd5faef84ef90966dd9dc9bbfc6243864747f (patch)
tree2b85bacae381c674077235d5dfde96e9cf55a1ed /apt-pkg
parentf9a621d335622a8909177f6d347e32e3876fde3f (diff)
parentdf81895bce764dd02fbb4d67b92d28a730b5281f (diff)
Merge branch 'pu/cve-2020-27350'
Diffstat (limited to 'apt-pkg')
-rw-r--r--apt-pkg/contrib/arfile.cc14
-rw-r--r--apt-pkg/contrib/extracttar.cc21
-rw-r--r--apt-pkg/deb/debfile.cc15
3 files changed, 48 insertions, 2 deletions
diff --git a/apt-pkg/contrib/arfile.cc b/apt-pkg/contrib/arfile.cc
index 5cb43c690..6d4a1f158 100644
--- a/apt-pkg/contrib/arfile.cc
+++ b/apt-pkg/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-pkg/contrib/extracttar.cc b/apt-pkg/contrib/extracttar.cc
index 1616c9f12..dc2437528 100644
--- a/apt-pkg/contrib/extracttar.cc
+++ b/apt-pkg/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 /*{{{*/
// ---------------------------------------------------------------------
/* */
@@ -166,6 +176,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.
@@ -218,6 +233,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 +254,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-pkg/deb/debfile.cc b/apt-pkg/deb/debfile.cc
index f8d752e7f..bef0cd0d8 100644
--- a/apt-pkg/deb/debfile.cc
+++ b/apt-pkg/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;