diff options
| author | Julian Andres Klode <jak@debian.org> | 2015-06-11 16:15:34 +0200 |
|---|---|---|
| committer | Julian Andres Klode <jak@debian.org> | 2015-06-11 16:15:34 +0200 |
| commit | 3ae6e69473c785b6c56cfb27c31a7c9375416f06 (patch) | |
| tree | ca40a4883e0a6ee3add162078781c4b714d6208f /python | |
| parent | a6e3d4d872b852de308f19a15215180cb4116765 (diff) | |
| download | python-apt-3ae6e69473c785b6c56cfb27c31a7c9375416f06.tar.gz | |
python/tarfile.cc: LFS: Handle too large file
Handle both file sizes larger than SIZE_MAX and allocation
failures when reading the data of a tarmember.
If using the go() function with a callback, pass None as the data
parameter for files that are too large. For extractdata, raise
a MemoryError if the file too extract is too large.
Also check for an existing error first in extractdata, before
raising a new one.
Test the whole thing on 32-bit platforms with a sample deb that
contains a zeroed file that is 5GB large (compressed using xz
at level 1 to a few kb).
Diffstat (limited to 'python')
| -rw-r--r-- | python/tarfile.cc | 38 |
1 files changed, 31 insertions, 7 deletions
diff --git a/python/tarfile.cc b/python/tarfile.cc index adc8e819..0aeae662 100644 --- a/python/tarfile.cc +++ b/python/tarfile.cc @@ -43,7 +43,8 @@ public: PyObject *py_data; // The requested member or NULL. const char *member; - // Set to true if an error occured in the Python callback. + // Set to true if an error occured in the Python callback, or a file + // was too large to read in extractdata. bool error; // Place where the copy of the data is stored. char *copy; @@ -76,9 +77,13 @@ bool PyDirStream::DoItem(Item &Itm, int &Fd) { if (!member || strcmp(Itm.Name, member) == 0) { // Allocate a new buffer if the old one is too small. + if (Itm.Size > SIZE_MAX) + goto to_large; if (copy == NULL || copy_size < Itm.Size) { delete[] copy; - copy = new char[Itm.Size]; + copy = new (std::nothrow) char[Itm.Size]; + if (copy == NULL) + goto to_large; copy_size = Itm.Size; } Fd = -2; @@ -86,6 +91,19 @@ bool PyDirStream::DoItem(Item &Itm, int &Fd) Fd = -1; } return true; +to_large: + delete[] copy; + copy = NULL; + copy_size = 0; + /* If we are looking for a specific member, abort reading now */ + if (member) { + error = true; + PyErr_Format(PyExc_MemoryError, + "The member %s was too large to read into memory", + Itm.Name); + return false; + } + return true; } #if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 14) @@ -96,7 +114,8 @@ bool PyDirStream::Process(Item &Itm,const unsigned char *Data, unsigned long Size,unsigned long Pos) #endif { - memcpy(copy + Pos, Data,Size); + if (copy != NULL) + memcpy(copy + Pos, Data,Size); return true; } @@ -107,7 +126,12 @@ bool PyDirStream::FinishedFile(Item &Itm,int Fd) return true; Py_XDECREF(py_data); - py_data = PyBytes_FromStringAndSize(copy, Itm.Size); + if (copy == NULL) { + Py_INCREF(Py_None); + py_data = Py_None; + } else { + py_data = PyBytes_FromStringAndSize(copy, Itm.Size); + } if (!callback) return true; @@ -424,12 +448,12 @@ static PyObject *tarfile_extractdata(PyObject *self, PyObject *args) // Go through the stream. GetCpp<ExtractTar*>(self)->Go(stream); + if (stream.error) + return 0; + if (!stream.py_data) return PyErr_Format(PyExc_LookupError, "There is no member named '%s'", member.path); - if (stream.error) { - return 0; - } return Py_INCREF(stream.py_data), stream.py_data; } |
