CRUX-ARM : Home

Home :: Documentation :: Download :: Development :: Community :: Ports :: Packages :: Bugs :: Links :: About :: Donors
python: updated to 2.7.14
authorVictor Martinez <pitillo@ono.com>
Sat, 10 Mar 2018 14:07:56 +0000 (15:07 +0100)
committerVictor Martinez <pitillo@ono.com>
Sat, 10 Mar 2018 14:07:56 +0000 (15:07 +0100)
python/.md5sum
python/CVE-2018-1000030.patch [new file with mode: 0644]
python/Pkgfile

index 827b1afbb602d54d519c36188bbcbecf5ce39af8..2522becf539e2a4ffea8ae8e54d97b926691f37e 100644 (file)
@@ -1,2 +1,3 @@
+ff653e9e002ca0e3d4a828988e52edd3  CVE-2018-1000030.patch
 1f6db41ad91d9eb0a6f0c769b8613c5b  Python-2.7.14.tar.xz
 387d5f6d00d2be01ecb87216cac0f88c  pyconfig.h
diff --git a/python/CVE-2018-1000030.patch b/python/CVE-2018-1000030.patch
new file mode 100644 (file)
index 0000000..efec476
--- /dev/null
@@ -0,0 +1,258 @@
+--- a/Lib/test/test_file2k.py  2018-02-16 17:49:45.180147747 -0500
++++ b/Lib/test/test_file2k.py  2018-02-16 17:51:06.870149602 -0500
+@@ -652,6 +652,33 @@ class FileThreadingTests(unittest.TestCa
+             self.f.writelines('')
+         self._test_close_open_io(io_func)
++    def test_iteration_torture(self):
++        # bpo-31530
++        with open(self.filename, "wb") as fp:
++            for i in xrange(2**20):
++                fp.write(b"0"*50 + b"\n")
++        with open(self.filename, "rb") as f:
++            def it():
++                for l in f:
++                    pass
++            self._run_workers(it, 10)
++
++    def test_iteration_seek(self):
++        # bpo-31530: Crash when concurrently seek and iterate over a file.
++        with open(self.filename, "wb") as fp:
++            for i in xrange(10000):
++                fp.write(b"0"*50 + b"\n")
++        with open(self.filename, "rb") as f:
++            it = iter([1] + [0]*10)  # one thread reads, others seek
++            def iterate():
++                if next(it):
++                    for l in f:
++                        pass
++                else:
++                    for i in xrange(100):
++                        f.seek(i*100, 0)
++            self._run_workers(iterate, 10)
++
+ @unittest.skipUnless(os.name == 'posix', 'test requires a posix system.')
+ class TestFileSignalEINTR(unittest.TestCase):
+--- a/Objects/fileobject.c     2018-02-16 17:49:45.304147750 -0500
++++ b/Objects/fileobject.c     2018-02-16 17:51:06.872149603 -0500
+@@ -430,7 +430,7 @@ close_the_file(PyFileObject *f)
+             if (f->ob_refcnt > 0) {
+                 PyErr_SetString(PyExc_IOError,
+                     "close() called during concurrent "
+-                    "operation on the same file object.");
++                    "operation on the same file object");
+             } else {
+                 /* This should not happen unless someone is
+                  * carelessly playing with the PyFileObject
+@@ -438,7 +438,7 @@ close_the_file(PyFileObject *f)
+                  * pointer. */
+                 PyErr_SetString(PyExc_SystemError,
+                     "PyFileObject locking error in "
+-                    "destructor (refcnt <= 0 at close).");
++                    "destructor (refcnt <= 0 at close)");
+             }
+             return NULL;
+         }
+@@ -604,7 +604,12 @@ err_iterbuffered(void)
+     return NULL;
+ }
+-static void drop_readahead(PyFileObject *);
++static void
++drop_file_readahead(PyFileObject *f)
++{
++    PyMem_FREE(f->f_buf);
++    f->f_buf = NULL;
++}
+ /* Methods */
+@@ -627,7 +632,7 @@ file_dealloc(PyFileObject *f)
+     Py_XDECREF(f->f_mode);
+     Py_XDECREF(f->f_encoding);
+     Py_XDECREF(f->f_errors);
+-    drop_readahead(f);
++    drop_file_readahead(f);
+     Py_TYPE(f)->tp_free((PyObject *)f);
+ }
+@@ -762,7 +767,7 @@ file_seek(PyFileObject *f, PyObject *arg
+     if (f->f_fp == NULL)
+         return err_closed();
+-    drop_readahead(f);
++    drop_file_readahead(f);
+     whence = 0;
+     if (!PyArg_ParseTuple(args, "O|i:seek", &offobj, &whence))
+         return NULL;
+@@ -2221,12 +2226,16 @@ static PyGetSetDef file_getsetlist[] = {
+     {0},
+ };
++typedef struct {
++    char *buf, *bufptr, *bufend;
++} readaheadbuffer;
++
+ static void
+-drop_readahead(PyFileObject *f)
++drop_readaheadbuffer(readaheadbuffer *rab)
+ {
+-    if (f->f_buf != NULL) {
+-        PyMem_Free(f->f_buf);
+-        f->f_buf = NULL;
++    if (rab->buf != NULL) {
++        PyMem_FREE(rab->buf);
++        rab->buf = NULL;
+     }
+ }
+@@ -2234,35 +2243,34 @@ drop_readahead(PyFileObject *f)
+    (unless at EOF) and no more than bufsize.  Returns negative value on
+    error, will set MemoryError if bufsize bytes cannot be allocated. */
+ static int
+-readahead(PyFileObject *f, Py_ssize_t bufsize)
++readahead(PyFileObject *f, readaheadbuffer *rab, Py_ssize_t bufsize)
+ {
+     Py_ssize_t chunksize;
+-    if (f->f_buf != NULL) {
+-        if( (f->f_bufend - f->f_bufptr) >= 1)
++    if (rab->buf != NULL) {
++        if ((rab->bufend - rab->bufptr) >= 1)
+             return 0;
+         else
+-            drop_readahead(f);
++            drop_readaheadbuffer(rab);
+     }
+-    if ((f->f_buf = (char *)PyMem_Malloc(bufsize)) == NULL) {
++    if ((rab->buf = PyMem_MALLOC(bufsize)) == NULL) {
+         PyErr_NoMemory();
+         return -1;
+     }
+     FILE_BEGIN_ALLOW_THREADS(f)
+     errno = 0;
+-    chunksize = Py_UniversalNewlineFread(
+-        f->f_buf, bufsize, f->f_fp, (PyObject *)f);
++    chunksize = Py_UniversalNewlineFread(rab->buf, bufsize, f->f_fp, (PyObject *)f);
+     FILE_END_ALLOW_THREADS(f)
+     if (chunksize == 0) {
+         if (ferror(f->f_fp)) {
+             PyErr_SetFromErrno(PyExc_IOError);
+             clearerr(f->f_fp);
+-            drop_readahead(f);
++            drop_readaheadbuffer(rab);
+             return -1;
+         }
+     }
+-    f->f_bufptr = f->f_buf;
+-    f->f_bufend = f->f_buf + chunksize;
++    rab->bufptr = rab->buf;
++    rab->bufend = rab->buf + chunksize;
+     return 0;
+ }
+@@ -2272,45 +2280,43 @@ readahead(PyFileObject *f, Py_ssize_t bu
+    logarithmic buffer growth to about 50 even when reading a 1gb line. */
+ static PyStringObject *
+-readahead_get_line_skip(PyFileObject *f, Py_ssize_t skip, Py_ssize_t bufsize)
++readahead_get_line_skip(PyFileObject *f, readaheadbuffer *rab, Py_ssize_t skip, Py_ssize_t bufsize)
+ {
+     PyStringObject* s;
+     char *bufptr;
+     char *buf;
+     Py_ssize_t len;
+-    if (f->f_buf == NULL)
+-        if (readahead(f, bufsize) < 0)
++    if (rab->buf == NULL)
++        if (readahead(f, rab, bufsize) < 0)
+             return NULL;
+-    len = f->f_bufend - f->f_bufptr;
++    len = rab->bufend - rab->bufptr;
+     if (len == 0)
+-        return (PyStringObject *)
+-            PyString_FromStringAndSize(NULL, skip);
+-    bufptr = (char *)memchr(f->f_bufptr, '\n', len);
++        return (PyStringObject *)PyString_FromStringAndSize(NULL, skip);
++    bufptr = (char *)memchr(rab->bufptr, '\n', len);
+     if (bufptr != NULL) {
+         bufptr++;                               /* Count the '\n' */
+-        len = bufptr - f->f_bufptr;
+-        s = (PyStringObject *)
+-            PyString_FromStringAndSize(NULL, skip + len);
++        len = bufptr - rab->bufptr;
++        s = (PyStringObject *)PyString_FromStringAndSize(NULL, skip + len);
+         if (s == NULL)
+             return NULL;
+-        memcpy(PyString_AS_STRING(s) + skip, f->f_bufptr, len);
+-        f->f_bufptr = bufptr;
+-        if (bufptr == f->f_bufend)
+-            drop_readahead(f);
++        memcpy(PyString_AS_STRING(s) + skip, rab->bufptr, len);
++        rab->bufptr = bufptr;
++        if (bufptr == rab->bufend)
++            drop_readaheadbuffer(rab);
+     } else {
+-        bufptr = f->f_bufptr;
+-        buf = f->f_buf;
+-        f->f_buf = NULL;                /* Force new readahead buffer */
++        bufptr = rab->bufptr;
++        buf = rab->buf;
++        rab->buf = NULL;                /* Force new readahead buffer */
+         assert(len <= PY_SSIZE_T_MAX - skip);
+-        s = readahead_get_line_skip(f, skip + len, bufsize + (bufsize>>2));
++        s = readahead_get_line_skip(f, rab, skip + len, bufsize + (bufsize>>2));
+         if (s == NULL) {
+-            PyMem_Free(buf);
++            PyMem_FREE(buf);
+             return NULL;
+         }
+         memcpy(PyString_AS_STRING(s) + skip, bufptr, len);
+-        PyMem_Free(buf);
++        PyMem_FREE(buf);
+     }
+     return s;
+ }
+@@ -2328,7 +2334,30 @@ file_iternext(PyFileObject *f)
+     if (!f->readable)
+         return err_mode("reading");
+-    l = readahead_get_line_skip(f, 0, READAHEAD_BUFSIZE);
++    {
++        /*
++          Multiple threads can enter this method while the GIL is released
++          during file read and wreak havoc on the file object's readahead
++          buffer. To avoid dealing with cross-thread coordination issues, we
++          cache the file buffer state locally and only set it back on the file
++          object when we're done.
++        */
++        readaheadbuffer rab = {f->f_buf, f->f_bufptr, f->f_bufend};
++        f->f_buf = NULL;
++        l = readahead_get_line_skip(f, &rab, 0, READAHEAD_BUFSIZE);
++        /*
++          Make sure the file's internal read buffer is cleared out. This will
++          only do anything if some other thread interleaved with us during
++          readahead. We want to drop any changeling buffer, so we don't leak
++          memory. We may lose data, but that's what you get for reading the same
++          file object in multiple threads.
++        */
++        drop_file_readahead(f);
++        f->f_buf = rab.buf;
++        f->f_bufptr = rab.bufptr;
++        f->f_bufend = rab.bufend;
++    }
++
+     if (l == NULL || PyString_GET_SIZE(l) == 0) {
+         Py_XDECREF(l);
+         return NULL;
+@@ -2692,7 +2721,7 @@ int PyObject_AsFileDescriptor(PyObject *
+     }
+     else {
+         PyErr_SetString(PyExc_TypeError,
+-                        "argument must be an int, or have a fileno() method.");
++                        "argument must be an int, or have a fileno() method");
+         return -1;
+     }
index 4575ac7a70b83d4c954dd5044db173432cc21043..b6871369f8eea57e69d18a94b8167df2dc5a6801 100644 (file)
@@ -8,6 +8,7 @@ name=python
 version=2.7.14
 release=1
 source=(http://www.python.org/ftp/$name/$version/Python-$version.tar.xz \
+        CVE-2018-1000030.patch
         pyconfig.h)
 
 build () {
@@ -16,6 +17,11 @@ build () {
   export CFLAGS="-O2 -pipe -mfloat-abi=hard"
   export CXXFLAGS="$CFLAGS"
 
+  # fix for CVE-2018-1000030
+  # see https://bugs.python.org/issue31530
+  patch -p1 -i $SRC/CVE-2018-1000030.patch
+
   # set OPT to the python default without -O3
   # our CFLAGS are used as well
   OPT="-Wall -Wstrict-prototypes -fwrapv" \