Python 3.8.7 security fix

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Python 3.8.7 security fix

Theo Buehler-3
sprintf strikes again.

https://nvd.nist.gov/vuln/detail/CVE-2021-3177#vulnCurrentDescriptionTitle

This was made public last night UTC and looks pretty bad, but there seem
to be no releases for in-tree Pythons available as of now. I'm not
familiar with how Python deals with security issues...

This page links to commits against the various releases:
https://python-security.readthedocs.io/vuln/ctypes-buffer-overflow-pycarg_repr.html
I expect the 3.9 patches to apply as easily as the present one. I can do
that if I'm told to do it.

A simple test is from https://bugs.python.org/issue42938

>>> from ctypes import *
>>> c_double.from_param(1e300)
Trace/BPT trap (core dumped)

This is fixed with this patch.  I tried running python's test suite, but
there are lots of issues with threading and async io...

Index: Makefile
===================================================================
RCS file: /cvs/ports/lang/python/3.8/Makefile,v
retrieving revision 1.11
diff -u -p -r1.11 Makefile
--- Makefile 4 Jan 2021 14:04:42 -0000 1.11
+++ Makefile 16 Feb 2021 09:41:01 -0000
@@ -9,6 +9,7 @@ VERSION = 3.8
 PATCHLEVEL = .7
 SHARED_LIBS = python3.8 0.0
 VERSION_SPEC = >=3.8,<3.9
+REVISION = 0
 
 CONFIGURE_ARGS += --with-ensurepip=no
 CONFIGURE_ARGS += --enable-loadable-sqlite-extensions
Index: files/CHANGES.OpenBSD
===================================================================
RCS file: /cvs/ports/lang/python/3.8/files/CHANGES.OpenBSD,v
retrieving revision 1.1
diff -u -p -r1.1 CHANGES.OpenBSD
--- files/CHANGES.OpenBSD 7 Nov 2019 16:14:09 -0000 1.1
+++ files/CHANGES.OpenBSD 16 Feb 2021 09:40:51 -0000
@@ -14,5 +14,7 @@ http://bugs.python.org/issue25191
 4.  Disable libuuid, otherwise Python prefers it over the libc uuid
 functions.
 
+5.  Applied a patch for CVE-2021-3177
+
 These changes are available in the OpenBSD CVS repository
 <http://www.openbsd.org/anoncvs.html> in ports/lang/python/3.8.
Index: patches/patch-2021-01-18-09-27-31_bpo-42938_4Zn4Mp_rst
===================================================================
RCS file: patches/patch-2021-01-18-09-27-31_bpo-42938_4Zn4Mp_rst
diff -N patches/patch-2021-01-18-09-27-31_bpo-42938_4Zn4Mp_rst
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-2021-01-18-09-27-31_bpo-42938_4Zn4Mp_rst 16 Feb 2021 09:43:37 -0000
@@ -0,0 +1,11 @@
+$OpenBSD$
+
+CVE-2021-3177
+https://github.com/python/cpython/pull/24239
+
+Index: 2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst
+--- 2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst.orig
++++ 2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst
+@@ -0,0 +1,2 @@
++Avoid static buffers when computing the repr of :class:`ctypes.c_double` and
++:class:`ctypes.c_longdouble` values.
Index: patches/patch-Lib_ctypes_test_test_parameters_py
===================================================================
RCS file: patches/patch-Lib_ctypes_test_test_parameters_py
diff -N patches/patch-Lib_ctypes_test_test_parameters_py
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-Lib_ctypes_test_test_parameters_py 16 Feb 2021 09:44:20 -0000
@@ -0,0 +1,58 @@
+$OpenBSD$
+
+CVE-2021-3177
+https://github.com/python/cpython/pull/24239
+
+Index: Lib/ctypes/test/test_parameters.py
+--- Lib/ctypes/test/test_parameters.py.orig
++++ Lib/ctypes/test/test_parameters.py
+@@ -201,6 +201,49 @@ class SimpleTypesTestCase(unittest.TestCase):
+         with self.assertRaises(ZeroDivisionError):
+             WorseStruct().__setstate__({}, b'foo')
+
++    def test_parameter_repr(self):
++        from ctypes import (
++            c_bool,
++            c_char,
++            c_wchar,
++            c_byte,
++            c_ubyte,
++            c_short,
++            c_ushort,
++            c_int,
++            c_uint,
++            c_long,
++            c_ulong,
++            c_longlong,
++            c_ulonglong,
++            c_float,
++            c_double,
++            c_longdouble,
++            c_char_p,
++            c_wchar_p,
++            c_void_p,
++        )
++        self.assertRegex(repr(c_bool.from_param(True)), r"^<cparam '\?' at 0x[A-Fa-f0-9]+>$")
++        self.assertEqual(repr(c_char.from_param(97)), "<cparam 'c' ('a')>")
++        self.assertRegex(repr(c_wchar.from_param('a')), r"^<cparam 'u' at 0x[A-Fa-f0-9]+>$")
++        self.assertEqual(repr(c_byte.from_param(98)), "<cparam 'b' (98)>")
++        self.assertEqual(repr(c_ubyte.from_param(98)), "<cparam 'B' (98)>")
++        self.assertEqual(repr(c_short.from_param(511)), "<cparam 'h' (511)>")
++        self.assertEqual(repr(c_ushort.from_param(511)), "<cparam 'H' (511)>")
++        self.assertRegex(repr(c_int.from_param(20000)), r"^<cparam '[li]' \(20000\)>$")
++        self.assertRegex(repr(c_uint.from_param(20000)), r"^<cparam '[LI]' \(20000\)>$")
++        self.assertRegex(repr(c_long.from_param(20000)), r"^<cparam '[li]' \(20000\)>$")
++        self.assertRegex(repr(c_ulong.from_param(20000)), r"^<cparam '[LI]' \(20000\)>$")
++        self.assertRegex(repr(c_longlong.from_param(20000)), r"^<cparam '[liq]' \(20000\)>$")
++        self.assertRegex(repr(c_ulonglong.from_param(20000)), r"^<cparam '[LIQ]' \(20000\)>$")
++        self.assertEqual(repr(c_float.from_param(1.5)), "<cparam 'f' (1.5)>")
++        self.assertEqual(repr(c_double.from_param(1.5)), "<cparam 'd' (1.5)>")
++        self.assertEqual(repr(c_double.from_param(1e300)), "<cparam 'd' (1e+300)>")
++        self.assertRegex(repr(c_longdouble.from_param(1.5)), r"^<cparam ('d' \(1.5\)|'g' at 0x[A-Fa-f0-9]+)>$")
++        self.assertRegex(repr(c_char_p.from_param(b'hihi')), "^<cparam 'z' \(0x[A-Fa-f0-9]+\)>$")
++        self.assertRegex(repr(c_wchar_p.from_param('hihi')), "^<cparam 'Z' \(0x[A-Fa-f0-9]+\)>$")
++        self.assertRegex(repr(c_void_p.from_param(0x12)), r"^<cparam 'P' \(0x0*12\)>$")
++
+ ################################################################
+
+ if __name__ == '__main__':
Index: patches/patch-Modules__ctypes_callproc_c
===================================================================
RCS file: patches/patch-Modules__ctypes_callproc_c
diff -N patches/patch-Modules__ctypes_callproc_c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-Modules__ctypes_callproc_c 16 Feb 2021 09:43:58 -0000
@@ -0,0 +1,109 @@
+$OpenBSD$
+
+CVE-2021-3177
+https://github.com/python/cpython/pull/24239
+
+Index: Modules/_ctypes/callproc.c
+--- Modules/_ctypes/callproc.c.orig
++++ Modules/_ctypes/callproc.c
+@@ -484,58 +484,47 @@ is_literal_char(unsigned char c)
+ static PyObject *
+ PyCArg_repr(PyCArgObject *self)
+ {
+-    char buffer[256];
+     switch(self->tag) {
+     case 'b':
+     case 'B':
+-        sprintf(buffer, "<cparam '%c' (%d)>",
++        return PyUnicode_FromFormat("<cparam '%c' (%d)>",
+             self->tag, self->value.b);
+-        break;
+     case 'h':
+     case 'H':
+-        sprintf(buffer, "<cparam '%c' (%d)>",
++        return PyUnicode_FromFormat("<cparam '%c' (%d)>",
+             self->tag, self->value.h);
+-        break;
+     case 'i':
+     case 'I':
+-        sprintf(buffer, "<cparam '%c' (%d)>",
++        return PyUnicode_FromFormat("<cparam '%c' (%d)>",
+             self->tag, self->value.i);
+-        break;
+     case 'l':
+     case 'L':
+-        sprintf(buffer, "<cparam '%c' (%ld)>",
++        return PyUnicode_FromFormat("<cparam '%c' (%ld)>",
+             self->tag, self->value.l);
+-        break;
+
+     case 'q':
+     case 'Q':
+-        sprintf(buffer,
+-#ifdef MS_WIN32
+-            "<cparam '%c' (%I64d)>",
+-#else
+-            "<cparam '%c' (%lld)>",
+-#endif
++        return PyUnicode_FromFormat("<cparam '%c' (%lld)>",
+             self->tag, self->value.q);
+-        break;
+     case 'd':
+-        sprintf(buffer, "<cparam '%c' (%f)>",
+-            self->tag, self->value.d);
+-        break;
+-    case 'f':
+-        sprintf(buffer, "<cparam '%c' (%f)>",
+-            self->tag, self->value.f);
+-        break;
+-
++    case 'f': {
++        PyObject *f = PyFloat_FromDouble((self->tag == 'f') ? self->value.f : self->value.d);
++        if (f == NULL) {
++            return NULL;
++        }
++        PyObject *result = PyUnicode_FromFormat("<cparam '%c' (%R)>", self->tag, f);
++        Py_DECREF(f);
++        return result;
++    }
+     case 'c':
+         if (is_literal_char((unsigned char)self->value.c)) {
+-            sprintf(buffer, "<cparam '%c' ('%c')>",
++            return PyUnicode_FromFormat("<cparam '%c' ('%c')>",
+                 self->tag, self->value.c);
+         }
+         else {
+-            sprintf(buffer, "<cparam '%c' ('\\x%02x')>",
++            return PyUnicode_FromFormat("<cparam '%c' ('\\x%02x')>",
+                 self->tag, (unsigned char)self->value.c);
+         }
+-        break;
+
+ /* Hm, are these 'z' and 'Z' codes useful at all?
+    Shouldn't they be replaced by the functionality of c_string
+@@ -544,22 +533,20 @@ PyCArg_repr(PyCArgObject *self)
+     case 'z':
+     case 'Z':
+     case 'P':
+-        sprintf(buffer, "<cparam '%c' (%p)>",
++        return PyUnicode_FromFormat("<cparam '%c' (%p)>",
+             self->tag, self->value.p);
+         break;
+
+     default:
+         if (is_literal_char((unsigned char)self->tag)) {
+-            sprintf(buffer, "<cparam '%c' at %p>",
++            return PyUnicode_FromFormat("<cparam '%c' at %p>",
+                 (unsigned char)self->tag, (void *)self);
+         }
+         else {
+-            sprintf(buffer, "<cparam 0x%02x at %p>",
++            return PyUnicode_FromFormat("<cparam 0x%02x at %p>",
+                 (unsigned char)self->tag, (void *)self);
+         }
+-        break;
+     }
+-    return PyUnicode_FromString(buffer);
+ }
+
+ static PyMemberDef PyCArgType_members[] = {
Index: patches/patch-Modules__hashopenssl_c
===================================================================
RCS file: /cvs/ports/lang/python/3.8/patches/patch-Modules__hashopenssl_c,v
retrieving revision 1.1
diff -u -p -r1.1 patch-Modules__hashopenssl_c
--- patches/patch-Modules__hashopenssl_c 7 Nov 2019 16:14:09 -0000 1.1
+++ patches/patch-Modules__hashopenssl_c 16 Feb 2021 09:43:51 -0000
@@ -3,9 +3,9 @@ $OpenBSD: patch-Modules__hashopenssl_c,v
 Index: Modules/_hashopenssl.c
 --- Modules/_hashopenssl.c.orig
 +++ Modules/_hashopenssl.c
-@@ -26,7 +26,8 @@
- #include <openssl/objects.h>
- #include "openssl/err.h"
+@@ -30,7 +30,8 @@
+ #  error "OPENSSL_THREADS is not defined, Python requires thread-safe OpenSSL"
+ #endif
 
 -#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
 +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
Index: patches/patch-Modules__ssl_c
===================================================================
RCS file: /cvs/ports/lang/python/3.8/patches/patch-Modules__ssl_c,v
retrieving revision 1.1
diff -u -p -r1.1 patch-Modules__ssl_c
--- patches/patch-Modules__ssl_c 7 Nov 2019 16:14:09 -0000 1.1
+++ patches/patch-Modules__ssl_c 16 Feb 2021 09:41:55 -0000
@@ -6,7 +6,7 @@ exactly what python's lock protects
 Index: Modules/_ssl.c
 --- Modules/_ssl.c.orig
 +++ Modules/_ssl.c
-@@ -135,7 +135,8 @@ static void _PySSLFixErrno(void) {
+@@ -139,7 +139,8 @@ static void _PySSLFixErrno(void) {
  /* Include generated data (error codes) */
  #include "_ssl_data.h"
 
@@ -16,7 +16,7 @@ Index: Modules/_ssl.c
  #  define OPENSSL_VERSION_1_1 1
  #  define PY_OPENSSL_1_1_API 1
  #endif
-@@ -200,6 +201,9 @@ static void _PySSLFixErrno(void) {
+@@ -213,6 +214,9 @@ static void _PySSLFixErrno(void) {
 
  #if defined(OPENSSL_VERSION_1_1) && !defined(OPENSSL_NO_SSL2)
  #define OPENSSL_NO_SSL2
Index: patches/patch-configure_ac
===================================================================
RCS file: /cvs/ports/lang/python/3.8/patches/patch-configure_ac,v
retrieving revision 1.1
diff -u -p -r1.1 patch-configure_ac
--- patches/patch-configure_ac 7 Nov 2019 16:14:09 -0000 1.1
+++ patches/patch-configure_ac 16 Feb 2021 09:41:55 -0000
@@ -15,7 +15,7 @@ Index: configure.ac
 
  # The later defininition of _XOPEN_SOURCE disables certain features
  # on Linux, so we need _GNU_SOURCE to re-enable them (makedev, tm_zone).
-@@ -2775,18 +2775,7 @@ AC_CHECK_LIB(dl, dlopen) # Dynamic linking for SunOS/S
+@@ -2788,18 +2788,7 @@ AC_CHECK_LIB(dl, dlopen) # Dynamic linking for SunOS/S
  AC_CHECK_LIB(dld, shl_load) # Dynamic linking for HP-UX
 
  # checks for uuid.h location

Reply | Threaded
Open this post in threaded view
|

Python 3.9.1 security fix

Theo Buehler-3
On Tue, Feb 16, 2021 at 11:49:31AM +0100, Theo Buehler wrote:

> sprintf strikes again.
>
> https://nvd.nist.gov/vuln/detail/CVE-2021-3177#vulnCurrentDescriptionTitle
>
> This was made public last night UTC and looks pretty bad, but there seem
> to be no releases for in-tree Pythons available as of now. I'm not
> familiar with how Python deals with security issues...
>
> This page links to commits against the various releases:
> https://python-security.readthedocs.io/vuln/ctypes-buffer-overflow-pycarg_repr.html
> I expect the 3.9 patches to apply as easily as the present one. I can do
> that if I'm told to do it.
>
> A simple test is from https://bugs.python.org/issue42938
>
> >>> from ctypes import *
> >>> c_double.from_param(1e300)
> Trace/BPT trap (core dumped)
>
> This is fixed with this patch.  I tried running python's test suite, but
> there are lots of issues with threading and async io...

Here's the corresponding diff for Python 3.9.1

Index: Makefile
===================================================================
RCS file: /cvs/ports/lang/python/3.9/Makefile,v
retrieving revision 1.2
diff -u -p -r1.2 Makefile
--- Makefile 28 Dec 2020 22:28:14 -0000 1.2
+++ Makefile 16 Feb 2021 11:55:24 -0000
@@ -9,6 +9,7 @@ VERSION = 3.9
 PATCHLEVEL = .1
 SHARED_LIBS = python3.9 0.0
 VERSION_SPEC = >=3.9,<3.10
+REVISION = 0
 #PSUBDIR = python/3.9.0
 
 CONFIGURE_ARGS += --with-ensurepip=no
Index: files/CHANGES.OpenBSD
===================================================================
RCS file: /cvs/ports/lang/python/3.9/files/CHANGES.OpenBSD,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 CHANGES.OpenBSD
--- files/CHANGES.OpenBSD 5 Oct 2020 20:48:10 -0000 1.1.1.1
+++ files/CHANGES.OpenBSD 16 Feb 2021 11:55:59 -0000
@@ -14,5 +14,7 @@ http://bugs.python.org/issue25191
 4.  Disable libuuid, otherwise Python prefers it over the libc uuid
 functions.
 
+5.  Applied a patch for CVE-2021-3177.
+
 These changes are available in the OpenBSD CVS repository
 <http://www.openbsd.org/anoncvs.html> in ports/lang/python/3.9.
Index: patches/patch-2021-01-18-09-27-31_bpo-42938_4Zn4Mp_rst
===================================================================
RCS file: patches/patch-2021-01-18-09-27-31_bpo-42938_4Zn4Mp_rst
diff -N patches/patch-2021-01-18-09-27-31_bpo-42938_4Zn4Mp_rst
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-2021-01-18-09-27-31_bpo-42938_4Zn4Mp_rst 16 Feb 2021 11:58:17 -0000
@@ -0,0 +1,11 @@
+$OpenBSD$
+
+CVE-2021-3177
+https://github.com/python/cpython/pull/24247
+
+Index: 2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst
+--- 2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst.orig
++++ 2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst
+@@ -0,0 +1,2 @@
++Avoid static buffers when computing the repr of :class:`ctypes.c_double` and
++:class:`ctypes.c_longdouble` values.
Index: patches/patch-Lib_ctypes_test_test_parameters_py
===================================================================
RCS file: patches/patch-Lib_ctypes_test_test_parameters_py
diff -N patches/patch-Lib_ctypes_test_test_parameters_py
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-Lib_ctypes_test_test_parameters_py 16 Feb 2021 11:58:21 -0000
@@ -0,0 +1,58 @@
+$OpenBSD$
+
+CVE-2021-3177
+https://github.com/python/cpython/pull/24247
+
+Index: Lib/ctypes/test/test_parameters.py
+--- Lib/ctypes/test/test_parameters.py.orig
++++ Lib/ctypes/test/test_parameters.py
+@@ -201,6 +201,49 @@ class SimpleTypesTestCase(unittest.TestCase):
+         with self.assertRaises(ZeroDivisionError):
+             WorseStruct().__setstate__({}, b'foo')
+
++    def test_parameter_repr(self):
++        from ctypes import (
++            c_bool,
++            c_char,
++            c_wchar,
++            c_byte,
++            c_ubyte,
++            c_short,
++            c_ushort,
++            c_int,
++            c_uint,
++            c_long,
++            c_ulong,
++            c_longlong,
++            c_ulonglong,
++            c_float,
++            c_double,
++            c_longdouble,
++            c_char_p,
++            c_wchar_p,
++            c_void_p,
++        )
++        self.assertRegex(repr(c_bool.from_param(True)), r"^<cparam '\?' at 0x[A-Fa-f0-9]+>$")
++        self.assertEqual(repr(c_char.from_param(97)), "<cparam 'c' ('a')>")
++        self.assertRegex(repr(c_wchar.from_param('a')), r"^<cparam 'u' at 0x[A-Fa-f0-9]+>$")
++        self.assertEqual(repr(c_byte.from_param(98)), "<cparam 'b' (98)>")
++        self.assertEqual(repr(c_ubyte.from_param(98)), "<cparam 'B' (98)>")
++        self.assertEqual(repr(c_short.from_param(511)), "<cparam 'h' (511)>")
++        self.assertEqual(repr(c_ushort.from_param(511)), "<cparam 'H' (511)>")
++        self.assertRegex(repr(c_int.from_param(20000)), r"^<cparam '[li]' \(20000\)>$")
++        self.assertRegex(repr(c_uint.from_param(20000)), r"^<cparam '[LI]' \(20000\)>$")
++        self.assertRegex(repr(c_long.from_param(20000)), r"^<cparam '[li]' \(20000\)>$")
++        self.assertRegex(repr(c_ulong.from_param(20000)), r"^<cparam '[LI]' \(20000\)>$")
++        self.assertRegex(repr(c_longlong.from_param(20000)), r"^<cparam '[liq]' \(20000\)>$")
++        self.assertRegex(repr(c_ulonglong.from_param(20000)), r"^<cparam '[LIQ]' \(20000\)>$")
++        self.assertEqual(repr(c_float.from_param(1.5)), "<cparam 'f' (1.5)>")
++        self.assertEqual(repr(c_double.from_param(1.5)), "<cparam 'd' (1.5)>")
++        self.assertEqual(repr(c_double.from_param(1e300)), "<cparam 'd' (1e+300)>")
++        self.assertRegex(repr(c_longdouble.from_param(1.5)), r"^<cparam ('d' \(1.5\)|'g' at 0x[A-Fa-f0-9]+)>$")
++        self.assertRegex(repr(c_char_p.from_param(b'hihi')), "^<cparam 'z' \(0x[A-Fa-f0-9]+\)>$")
++        self.assertRegex(repr(c_wchar_p.from_param('hihi')), "^<cparam 'Z' \(0x[A-Fa-f0-9]+\)>$")
++        self.assertRegex(repr(c_void_p.from_param(0x12)), r"^<cparam 'P' \(0x0*12\)>$")
++
+ ################################################################
+
+ if __name__ == '__main__':
Index: patches/patch-Modules__ctypes_callproc_c
===================================================================
RCS file: patches/patch-Modules__ctypes_callproc_c
diff -N patches/patch-Modules__ctypes_callproc_c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-Modules__ctypes_callproc_c 16 Feb 2021 11:58:23 -0000
@@ -0,0 +1,109 @@
+$OpenBSD$
+
+CVE-2021-3177
+https://github.com/python/cpython/pull/24247
+
+Index: Modules/_ctypes/callproc.c
+--- Modules/_ctypes/callproc.c.orig
++++ Modules/_ctypes/callproc.c
+@@ -489,58 +489,47 @@ is_literal_char(unsigned char c)
+ static PyObject *
+ PyCArg_repr(PyCArgObject *self)
+ {
+-    char buffer[256];
+     switch(self->tag) {
+     case 'b':
+     case 'B':
+-        sprintf(buffer, "<cparam '%c' (%d)>",
++        return PyUnicode_FromFormat("<cparam '%c' (%d)>",
+             self->tag, self->value.b);
+-        break;
+     case 'h':
+     case 'H':
+-        sprintf(buffer, "<cparam '%c' (%d)>",
++        return PyUnicode_FromFormat("<cparam '%c' (%d)>",
+             self->tag, self->value.h);
+-        break;
+     case 'i':
+     case 'I':
+-        sprintf(buffer, "<cparam '%c' (%d)>",
++        return PyUnicode_FromFormat("<cparam '%c' (%d)>",
+             self->tag, self->value.i);
+-        break;
+     case 'l':
+     case 'L':
+-        sprintf(buffer, "<cparam '%c' (%ld)>",
++        return PyUnicode_FromFormat("<cparam '%c' (%ld)>",
+             self->tag, self->value.l);
+-        break;
+
+     case 'q':
+     case 'Q':
+-        sprintf(buffer,
+-#ifdef MS_WIN32
+-            "<cparam '%c' (%I64d)>",
+-#else
+-            "<cparam '%c' (%lld)>",
+-#endif
++        return PyUnicode_FromFormat("<cparam '%c' (%lld)>",
+             self->tag, self->value.q);
+-        break;
+     case 'd':
+-        sprintf(buffer, "<cparam '%c' (%f)>",
+-            self->tag, self->value.d);
+-        break;
+-    case 'f':
+-        sprintf(buffer, "<cparam '%c' (%f)>",
+-            self->tag, self->value.f);
+-        break;
+-
++    case 'f': {
++        PyObject *f = PyFloat_FromDouble((self->tag == 'f') ? self->value.f : self->value.d);
++        if (f == NULL) {
++            return NULL;
++        }
++        PyObject *result = PyUnicode_FromFormat("<cparam '%c' (%R)>", self->tag, f);
++        Py_DECREF(f);
++        return result;
++    }
+     case 'c':
+         if (is_literal_char((unsigned char)self->value.c)) {
+-            sprintf(buffer, "<cparam '%c' ('%c')>",
++            return PyUnicode_FromFormat("<cparam '%c' ('%c')>",
+                 self->tag, self->value.c);
+         }
+         else {
+-            sprintf(buffer, "<cparam '%c' ('\\x%02x')>",
++            return PyUnicode_FromFormat("<cparam '%c' ('\\x%02x')>",
+                 self->tag, (unsigned char)self->value.c);
+         }
+-        break;
+
+ /* Hm, are these 'z' and 'Z' codes useful at all?
+    Shouldn't they be replaced by the functionality of c_string
+@@ -549,22 +538,20 @@ PyCArg_repr(PyCArgObject *self)
+     case 'z':
+     case 'Z':
+     case 'P':
+-        sprintf(buffer, "<cparam '%c' (%p)>",
++        return PyUnicode_FromFormat("<cparam '%c' (%p)>",
+             self->tag, self->value.p);
+         break;
+
+     default:
+         if (is_literal_char((unsigned char)self->tag)) {
+-            sprintf(buffer, "<cparam '%c' at %p>",
++            return PyUnicode_FromFormat("<cparam '%c' at %p>",
+                 (unsigned char)self->tag, (void *)self);
+         }
+         else {
+-            sprintf(buffer, "<cparam 0x%02x at %p>",
++            return PyUnicode_FromFormat("<cparam 0x%02x at %p>",
+                 (unsigned char)self->tag, (void *)self);
+         }
+-        break;
+     }
+-    return PyUnicode_FromString(buffer);
+ }
+
+ static PyMemberDef PyCArgType_members[] = {

Reply | Threaded
Open this post in threaded view
|

[stable] Update to Python 3.7.10

Theo Buehler-3
This includes a fix for the high severity issue (bpo-42938) and a few
others.

 * bpo-42967: Fix web cache poisoning vulnerability by defaulting the
   query args separator to &, and allowing the user to choose a custom
   separator.

 * bpo-42938: Avoid static buffers when computing the repr of
   ctypes.c_double and ctypes.c_longdouble values.

 * bpo-42103: Prevented potential DoS attack via CPU and RAM exhaustion
   when processing malformed Apple Property List files in binary format.

 * bpo-42051: The plistlib module no longer accepts entity declarations
   in XML plist files to avoid XML vulnerabilities. This should not
   affect users as entity declarations are not used in regular plist
   files.

 * bpo-40791: Add volatile to the accumulator variable in
   hmac.compare_digest, making constant-time-defeating optimizations
   less likely.

Full change log here:
https://docs.python.org/release/3.7.10/whatsnew/changelog.html#changelog
From looking at the diff, it's exhaustive.

Index: Makefile
===================================================================
RCS file: /cvs/ports/lang/python/3.7/Attic/Makefile,v
retrieving revision 1.19.2.1
diff -u -p -r1.19.2.1 Makefile
--- Makefile 13 Oct 2020 12:42:22 -0000 1.19.2.1
+++ Makefile 16 Feb 2021 18:33:40 -0000
@@ -6,12 +6,9 @@
 # Python itself.
 
 VERSION = 3.7
-PATCHLEVEL = .9
+PATCHLEVEL = .10
 SHARED_LIBS = python3.7m 0.0
 VERSION_SPEC = >=3.7,<3.8
-
-REVISION-idle = 0
-REVISION-main = 0
 
 CONFIGURE_ARGS += --with-ensurepip=no
 CONFIGURE_ARGS += --enable-loadable-sqlite-extensions
Index: distinfo
===================================================================
RCS file: /cvs/ports/lang/python/3.7/Attic/distinfo,v
retrieving revision 1.7
diff -u -p -r1.7 distinfo
--- distinfo 24 Aug 2020 15:00:29 -0000 1.7
+++ distinfo 16 Feb 2021 18:33:40 -0000
@@ -1,2 +1,2 @@
-SHA256 (Python-3.7.9.tgz) = ObAYvH2KFl5ZqoJ9muRcRZAXObC7sTch5Plz81IcFmo=
-SIZE (Python-3.7.9.tgz) = 23277790
+SHA256 (Python-3.7.10.tgz) = yWSa2E3DpDTIY332ljEAsuVghpf5ulbYLjgJ5BSOCXU=
+SIZE (Python-3.7.10.tgz) = 23281560
Index: patches/patch-Modules__hashopenssl_c
===================================================================
RCS file: /cvs/ports/lang/python/3.7/patches/Attic/patch-Modules__hashopenssl_c,v
retrieving revision 1.1
diff -u -p -r1.1 patch-Modules__hashopenssl_c
--- patches/patch-Modules__hashopenssl_c 21 Apr 2019 09:33:32 -0000 1.1
+++ patches/patch-Modules__hashopenssl_c 16 Feb 2021 18:33:40 -0000
@@ -3,7 +3,7 @@ $OpenBSD: patch-Modules__hashopenssl_c,v
 Index: Modules/_hashopenssl.c
 --- Modules/_hashopenssl.c.orig
 +++ Modules/_hashopenssl.c
-@@ -38,7 +38,8 @@ module _hashlib
+@@ -42,7 +42,8 @@ module _hashlib
  #define HASH_OBJ_CONSTRUCTOR 0
  #endif
 
Index: patches/patch-Modules__ssl_c
===================================================================
RCS file: /cvs/ports/lang/python/3.7/patches/Attic/patch-Modules__ssl_c,v
retrieving revision 1.1
diff -u -p -r1.1 patch-Modules__ssl_c
--- patches/patch-Modules__ssl_c 21 Apr 2019 09:33:32 -0000 1.1
+++ patches/patch-Modules__ssl_c 16 Feb 2021 18:33:40 -0000
@@ -6,7 +6,7 @@ exactly what python's lock protects
 Index: Modules/_ssl.c
 --- Modules/_ssl.c.orig
 +++ Modules/_ssl.c
-@@ -135,7 +135,8 @@ static void _PySSLFixErrno(void) {
+@@ -139,7 +139,8 @@ static void _PySSLFixErrno(void) {
  /* Include generated data (error codes) */
  #include "_ssl_data.h"
 
@@ -16,7 +16,7 @@ Index: Modules/_ssl.c
  #  define OPENSSL_VERSION_1_1 1
  #  define PY_OPENSSL_1_1_API 1
  #endif
-@@ -196,6 +197,9 @@ static void _PySSLFixErrno(void) {
+@@ -209,6 +210,9 @@ static void _PySSLFixErrno(void) {
 
  #if defined(OPENSSL_VERSION_1_1) && !defined(OPENSSL_NO_SSL2)
  #define OPENSSL_NO_SSL2
Index: patches/patch-configure_ac
===================================================================
RCS file: /cvs/ports/lang/python/3.7/patches/Attic/patch-configure_ac,v
retrieving revision 1.1
diff -u -p -r1.1 patch-configure_ac
--- patches/patch-configure_ac 21 Apr 2019 09:33:32 -0000 1.1
+++ patches/patch-configure_ac 16 Feb 2021 18:33:40 -0000
@@ -15,7 +15,7 @@ Index: configure.ac
 
  # The later defininition of _XOPEN_SOURCE disables certain features
  # on Linux, so we need _GNU_SOURCE to re-enable them (makedev, tm_zone).
-@@ -2789,18 +2789,7 @@ AC_CHECK_LIB(dl, dlopen) # Dynamic linking for SunOS/S
+@@ -2792,18 +2792,7 @@ AC_CHECK_LIB(dl, dlopen) # Dynamic linking for SunOS/S
  AC_CHECK_LIB(dld, shl_load) # Dynamic linking for HP-UX
 
  # checks for uuid.h location
Index: pkg/PLIST-main
===================================================================
RCS file: /cvs/ports/lang/python/3.7/pkg/Attic/PLIST-main,v
retrieving revision 1.15
diff -u -p -r1.15 PLIST-main
--- pkg/PLIST-main 24 Aug 2020 15:00:29 -0000 1.15
+++ pkg/PLIST-main 16 Feb 2021 18:33:40 -0000
@@ -1983,9 +1983,9 @@ lib/python3.7/lib-dynload/
 @so lib/python3.7/lib-dynload/zlib.so
 lib/python3.7/lib2to3/
 lib/python3.7/lib2to3/Grammar.txt
-lib/python3.7/lib2to3/Grammar3.7.9.final.0.pickle
+lib/python3.7/lib2to3/Grammar3.7.10.final.0.pickle
 lib/python3.7/lib2to3/PatternGrammar.txt
-lib/python3.7/lib2to3/PatternGrammar3.7.9.final.0.pickle
+lib/python3.7/lib2to3/PatternGrammar3.7.10.final.0.pickle
 lib/python3.7/lib2to3/__init__.py
 lib/python3.7/lib2to3/__main__.py
 lib/python3.7/lib2to3/__pycache__/

Reply | Threaded
Open this post in threaded view
|

[stable] Backport fix for CVE 2021-3177 to Python 3.8.6

Theo Buehler-3
And here's a backport to 3.8.6 of the fix. Probably worth it as it is
the default version of python.

(I tested both backports on a amd64-stable machine)

Index: Makefile
===================================================================
RCS file: /cvs/ports/lang/python/3.8/Makefile,v
retrieving revision 1.8.2.1
diff -u -p -r1.8.2.1 Makefile
--- Makefile 13 Oct 2020 12:42:22 -0000 1.8.2.1
+++ Makefile 16 Feb 2021 18:54:24 -0000
@@ -9,9 +9,10 @@ VERSION = 3.8
 PATCHLEVEL = .6
 SHARED_LIBS = python3.8 0.0
 VERSION_SPEC = >=3.8,<3.9
+REVISION = 0
 
-REVISION-idle = 0
-REVISION-main = 0
+REVISION-idle = 1
+REVISION-main = 1
 
 CONFIGURE_ARGS += --with-ensurepip=no
 CONFIGURE_ARGS += --enable-loadable-sqlite-extensions
Index: files/CHANGES.OpenBSD
===================================================================
RCS file: /cvs/ports/lang/python/3.8/files/CHANGES.OpenBSD,v
retrieving revision 1.1
diff -u -p -r1.1 CHANGES.OpenBSD
--- files/CHANGES.OpenBSD 7 Nov 2019 16:14:09 -0000 1.1
+++ files/CHANGES.OpenBSD 16 Feb 2021 18:54:24 -0000
@@ -14,5 +14,7 @@ http://bugs.python.org/issue25191
 4.  Disable libuuid, otherwise Python prefers it over the libc uuid
 functions.
 
+5.  Applied a patch for CVE-2021-3177
+
 These changes are available in the OpenBSD CVS repository
 <http://www.openbsd.org/anoncvs.html> in ports/lang/python/3.8.
Index: patches/patch-2021-01-18-09-27-31_bpo-42938_4Zn4Mp_rst
===================================================================
RCS file: patches/patch-2021-01-18-09-27-31_bpo-42938_4Zn4Mp_rst
diff -N patches/patch-2021-01-18-09-27-31_bpo-42938_4Zn4Mp_rst
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-2021-01-18-09-27-31_bpo-42938_4Zn4Mp_rst 16 Feb 2021 18:54:24 -0000
@@ -0,0 +1,11 @@
+$OpenBSD$
+
+CVE-2021-3177
+https://github.com/python/cpython/pull/24239
+
+Index: 2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst
+--- 2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst.orig
++++ 2021-01-18-09-27-31.bpo-42938.4Zn4Mp.rst
+@@ -0,0 +1,2 @@
++Avoid static buffers when computing the repr of :class:`ctypes.c_double` and
++:class:`ctypes.c_longdouble` values.
Index: patches/patch-Lib_ctypes_test_test_parameters_py
===================================================================
RCS file: patches/patch-Lib_ctypes_test_test_parameters_py
diff -N patches/patch-Lib_ctypes_test_test_parameters_py
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-Lib_ctypes_test_test_parameters_py 16 Feb 2021 18:54:24 -0000
@@ -0,0 +1,58 @@
+$OpenBSD$
+
+CVE-2021-3177
+https://github.com/python/cpython/pull/24239
+
+Index: Lib/ctypes/test/test_parameters.py
+--- Lib/ctypes/test/test_parameters.py.orig
++++ Lib/ctypes/test/test_parameters.py
+@@ -201,6 +201,49 @@ class SimpleTypesTestCase(unittest.TestCase):
+         with self.assertRaises(ZeroDivisionError):
+             WorseStruct().__setstate__({}, b'foo')
+
++    def test_parameter_repr(self):
++        from ctypes import (
++            c_bool,
++            c_char,
++            c_wchar,
++            c_byte,
++            c_ubyte,
++            c_short,
++            c_ushort,
++            c_int,
++            c_uint,
++            c_long,
++            c_ulong,
++            c_longlong,
++            c_ulonglong,
++            c_float,
++            c_double,
++            c_longdouble,
++            c_char_p,
++            c_wchar_p,
++            c_void_p,
++        )
++        self.assertRegex(repr(c_bool.from_param(True)), r"^<cparam '\?' at 0x[A-Fa-f0-9]+>$")
++        self.assertEqual(repr(c_char.from_param(97)), "<cparam 'c' ('a')>")
++        self.assertRegex(repr(c_wchar.from_param('a')), r"^<cparam 'u' at 0x[A-Fa-f0-9]+>$")
++        self.assertEqual(repr(c_byte.from_param(98)), "<cparam 'b' (98)>")
++        self.assertEqual(repr(c_ubyte.from_param(98)), "<cparam 'B' (98)>")
++        self.assertEqual(repr(c_short.from_param(511)), "<cparam 'h' (511)>")
++        self.assertEqual(repr(c_ushort.from_param(511)), "<cparam 'H' (511)>")
++        self.assertRegex(repr(c_int.from_param(20000)), r"^<cparam '[li]' \(20000\)>$")
++        self.assertRegex(repr(c_uint.from_param(20000)), r"^<cparam '[LI]' \(20000\)>$")
++        self.assertRegex(repr(c_long.from_param(20000)), r"^<cparam '[li]' \(20000\)>$")
++        self.assertRegex(repr(c_ulong.from_param(20000)), r"^<cparam '[LI]' \(20000\)>$")
++        self.assertRegex(repr(c_longlong.from_param(20000)), r"^<cparam '[liq]' \(20000\)>$")
++        self.assertRegex(repr(c_ulonglong.from_param(20000)), r"^<cparam '[LIQ]' \(20000\)>$")
++        self.assertEqual(repr(c_float.from_param(1.5)), "<cparam 'f' (1.5)>")
++        self.assertEqual(repr(c_double.from_param(1.5)), "<cparam 'd' (1.5)>")
++        self.assertEqual(repr(c_double.from_param(1e300)), "<cparam 'd' (1e+300)>")
++        self.assertRegex(repr(c_longdouble.from_param(1.5)), r"^<cparam ('d' \(1.5\)|'g' at 0x[A-Fa-f0-9]+)>$")
++        self.assertRegex(repr(c_char_p.from_param(b'hihi')), "^<cparam 'z' \(0x[A-Fa-f0-9]+\)>$")
++        self.assertRegex(repr(c_wchar_p.from_param('hihi')), "^<cparam 'Z' \(0x[A-Fa-f0-9]+\)>$")
++        self.assertRegex(repr(c_void_p.from_param(0x12)), r"^<cparam 'P' \(0x0*12\)>$")
++
+ ################################################################
+
+ if __name__ == '__main__':
Index: patches/patch-Modules__ctypes_callproc_c
===================================================================
RCS file: patches/patch-Modules__ctypes_callproc_c
diff -N patches/patch-Modules__ctypes_callproc_c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ patches/patch-Modules__ctypes_callproc_c 16 Feb 2021 18:54:24 -0000
@@ -0,0 +1,109 @@
+$OpenBSD$
+
+CVE-2021-3177
+https://github.com/python/cpython/pull/24239
+
+Index: Modules/_ctypes/callproc.c
+--- Modules/_ctypes/callproc.c.orig
++++ Modules/_ctypes/callproc.c
+@@ -484,58 +484,47 @@ is_literal_char(unsigned char c)
+ static PyObject *
+ PyCArg_repr(PyCArgObject *self)
+ {
+-    char buffer[256];
+     switch(self->tag) {
+     case 'b':
+     case 'B':
+-        sprintf(buffer, "<cparam '%c' (%d)>",
++        return PyUnicode_FromFormat("<cparam '%c' (%d)>",
+             self->tag, self->value.b);
+-        break;
+     case 'h':
+     case 'H':
+-        sprintf(buffer, "<cparam '%c' (%d)>",
++        return PyUnicode_FromFormat("<cparam '%c' (%d)>",
+             self->tag, self->value.h);
+-        break;
+     case 'i':
+     case 'I':
+-        sprintf(buffer, "<cparam '%c' (%d)>",
++        return PyUnicode_FromFormat("<cparam '%c' (%d)>",
+             self->tag, self->value.i);
+-        break;
+     case 'l':
+     case 'L':
+-        sprintf(buffer, "<cparam '%c' (%ld)>",
++        return PyUnicode_FromFormat("<cparam '%c' (%ld)>",
+             self->tag, self->value.l);
+-        break;
+
+     case 'q':
+     case 'Q':
+-        sprintf(buffer,
+-#ifdef MS_WIN32
+-            "<cparam '%c' (%I64d)>",
+-#else
+-            "<cparam '%c' (%lld)>",
+-#endif
++        return PyUnicode_FromFormat("<cparam '%c' (%lld)>",
+             self->tag, self->value.q);
+-        break;
+     case 'd':
+-        sprintf(buffer, "<cparam '%c' (%f)>",
+-            self->tag, self->value.d);
+-        break;
+-    case 'f':
+-        sprintf(buffer, "<cparam '%c' (%f)>",
+-            self->tag, self->value.f);
+-        break;
+-
++    case 'f': {
++        PyObject *f = PyFloat_FromDouble((self->tag == 'f') ? self->value.f : self->value.d);
++        if (f == NULL) {
++            return NULL;
++        }
++        PyObject *result = PyUnicode_FromFormat("<cparam '%c' (%R)>", self->tag, f);
++        Py_DECREF(f);
++        return result;
++    }
+     case 'c':
+         if (is_literal_char((unsigned char)self->value.c)) {
+-            sprintf(buffer, "<cparam '%c' ('%c')>",
++            return PyUnicode_FromFormat("<cparam '%c' ('%c')>",
+                 self->tag, self->value.c);
+         }
+         else {
+-            sprintf(buffer, "<cparam '%c' ('\\x%02x')>",
++            return PyUnicode_FromFormat("<cparam '%c' ('\\x%02x')>",
+                 self->tag, (unsigned char)self->value.c);
+         }
+-        break;
+
+ /* Hm, are these 'z' and 'Z' codes useful at all?
+    Shouldn't they be replaced by the functionality of c_string
+@@ -544,22 +533,20 @@ PyCArg_repr(PyCArgObject *self)
+     case 'z':
+     case 'Z':
+     case 'P':
+-        sprintf(buffer, "<cparam '%c' (%p)>",
++        return PyUnicode_FromFormat("<cparam '%c' (%p)>",
+             self->tag, self->value.p);
+         break;
+
+     default:
+         if (is_literal_char((unsigned char)self->tag)) {
+-            sprintf(buffer, "<cparam '%c' at %p>",
++            return PyUnicode_FromFormat("<cparam '%c' at %p>",
+                 (unsigned char)self->tag, (void *)self);
+         }
+         else {
+-            sprintf(buffer, "<cparam 0x%02x at %p>",
++            return PyUnicode_FromFormat("<cparam 0x%02x at %p>",
+                 (unsigned char)self->tag, (void *)self);
+         }
+-        break;
+     }
+-    return PyUnicode_FromString(buffer);
+ }
+
+ static PyMemberDef PyCArgType_members[] = {
Index: patches/patch-Modules__hashopenssl_c
===================================================================
RCS file: /cvs/ports/lang/python/3.8/patches/patch-Modules__hashopenssl_c,v
retrieving revision 1.1
diff -u -p -r1.1 patch-Modules__hashopenssl_c
--- patches/patch-Modules__hashopenssl_c 7 Nov 2019 16:14:09 -0000 1.1
+++ patches/patch-Modules__hashopenssl_c 16 Feb 2021 18:54:24 -0000
@@ -3,9 +3,9 @@ $OpenBSD: patch-Modules__hashopenssl_c,v
 Index: Modules/_hashopenssl.c
 --- Modules/_hashopenssl.c.orig
 +++ Modules/_hashopenssl.c
-@@ -26,7 +26,8 @@
- #include <openssl/objects.h>
- #include "openssl/err.h"
+@@ -30,7 +30,8 @@
+ #  error "OPENSSL_THREADS is not defined, Python requires thread-safe OpenSSL"
+ #endif
 
 -#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
 +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \
Index: patches/patch-Modules__ssl_c
===================================================================
RCS file: /cvs/ports/lang/python/3.8/patches/patch-Modules__ssl_c,v
retrieving revision 1.1
diff -u -p -r1.1 patch-Modules__ssl_c
--- patches/patch-Modules__ssl_c 7 Nov 2019 16:14:09 -0000 1.1
+++ patches/patch-Modules__ssl_c 16 Feb 2021 18:54:24 -0000
@@ -6,7 +6,7 @@ exactly what python's lock protects
 Index: Modules/_ssl.c
 --- Modules/_ssl.c.orig
 +++ Modules/_ssl.c
-@@ -135,7 +135,8 @@ static void _PySSLFixErrno(void) {
+@@ -139,7 +139,8 @@ static void _PySSLFixErrno(void) {
  /* Include generated data (error codes) */
  #include "_ssl_data.h"
 
@@ -16,7 +16,7 @@ Index: Modules/_ssl.c
  #  define OPENSSL_VERSION_1_1 1
  #  define PY_OPENSSL_1_1_API 1
  #endif
-@@ -200,6 +201,9 @@ static void _PySSLFixErrno(void) {
+@@ -213,6 +214,9 @@ static void _PySSLFixErrno(void) {
 
  #if defined(OPENSSL_VERSION_1_1) && !defined(OPENSSL_NO_SSL2)
  #define OPENSSL_NO_SSL2
Index: patches/patch-configure_ac
===================================================================
RCS file: /cvs/ports/lang/python/3.8/patches/patch-configure_ac,v
retrieving revision 1.1
diff -u -p -r1.1 patch-configure_ac
--- patches/patch-configure_ac 7 Nov 2019 16:14:09 -0000 1.1
+++ patches/patch-configure_ac 16 Feb 2021 18:54:24 -0000
@@ -15,7 +15,7 @@ Index: configure.ac
 
  # The later defininition of _XOPEN_SOURCE disables certain features
  # on Linux, so we need _GNU_SOURCE to re-enable them (makedev, tm_zone).
-@@ -2775,18 +2775,7 @@ AC_CHECK_LIB(dl, dlopen) # Dynamic linking for SunOS/S
+@@ -2788,18 +2788,7 @@ AC_CHECK_LIB(dl, dlopen) # Dynamic linking for SunOS/S
  AC_CHECK_LIB(dld, shl_load) # Dynamic linking for HP-UX
 
  # checks for uuid.h location