summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorJulian Andres Klode <jak@debian.org>2015-06-11 16:15:34 +0200
committerJulian Andres Klode <jak@debian.org>2015-06-11 16:15:34 +0200
commit3ae6e69473c785b6c56cfb27c31a7c9375416f06 (patch)
treeca40a4883e0a6ee3add162078781c4b714d6208f /python
parenta6e3d4d872b852de308f19a15215180cb4116765 (diff)
downloadpython-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.cc38
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;
}