[Python-checkins] bpo-13097: ctypes: limit callback to 1024 arguments (GH-19914)

Sean Gillespie webhook-mailer at python.org
Wed May 27 11:22:12 EDT 2020


https://github.com/python/cpython/commit/29a1384c040d39659e7d01f1fd7b6eb71ef2634e
commit: 29a1384c040d39659e7d01f1fd7b6eb71ef2634e
branch: master
author: Sean Gillespie <sean at swgillespie.me>
committer: GitHub <noreply at github.com>
date: 2020-05-27T17:22:07+02:00
summary:

bpo-13097: ctypes: limit callback to 1024 arguments (GH-19914)

ctypes now raises an ArgumentError when a callback
is invoked with more than 1024 arguments.

The ctypes module allocates arguments on the stack in
ctypes_callproc() using alloca(), which is problematic
when large numbers of arguments are passed. Instead
of a stack overflow, this commit raises an ArgumentError
if more than 1024 parameters are passed.

files:
A Misc/NEWS.d/next/Library/2020-05-06-02-01-25.bpo-13097.Wh5xSK.rst
M Lib/ctypes/test/test_callbacks.py
M Modules/_ctypes/callproc.c

diff --git a/Lib/ctypes/test/test_callbacks.py b/Lib/ctypes/test/test_callbacks.py
index f622093df61da..937a06d981b00 100644
--- a/Lib/ctypes/test/test_callbacks.py
+++ b/Lib/ctypes/test/test_callbacks.py
@@ -287,6 +287,21 @@ def callback(check, s):
         self.assertEqual(s.second, check.second)
         self.assertEqual(s.third, check.third)
 
+    def test_callback_too_many_args(self):
+        def func(*args):
+            return len(args)
+
+        CTYPES_MAX_ARGCOUNT = 1024
+        proto = CFUNCTYPE(c_int, *(c_int,) * CTYPES_MAX_ARGCOUNT)
+        cb = proto(func)
+        args1 = (1,) * CTYPES_MAX_ARGCOUNT
+        self.assertEqual(cb(*args1), CTYPES_MAX_ARGCOUNT)
+
+        args2 = (1,) * (CTYPES_MAX_ARGCOUNT + 1)
+        with self.assertRaises(ArgumentError):
+            cb(*args2)
+
+
 ################################################################
 
 if __name__ == '__main__':
diff --git a/Misc/NEWS.d/next/Library/2020-05-06-02-01-25.bpo-13097.Wh5xSK.rst b/Misc/NEWS.d/next/Library/2020-05-06-02-01-25.bpo-13097.Wh5xSK.rst
new file mode 100644
index 0000000000000..a7f5f58828917
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-05-06-02-01-25.bpo-13097.Wh5xSK.rst
@@ -0,0 +1 @@
+``ctypes`` now raises an ``ArgumentError`` when a callback is invoked with more than 1024 arguments.
\ No newline at end of file
diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c
index 5c1ecabd8164d..9bc28c260717d 100644
--- a/Modules/_ctypes/callproc.c
+++ b/Modules/_ctypes/callproc.c
@@ -1072,6 +1072,14 @@ GetComError(HRESULT errcode, GUID *riid, IUnknown *pIunk)
 #define IS_PASS_BY_REF(x) (x > 8 || !POW2(x))
 #endif
 
+/*
+ * bpo-13097: Max number of arguments _ctypes_callproc will accept.
+ *
+ * This limit is enforced for the `alloca()` call in `_ctypes_callproc`,
+ * to avoid allocating a massive buffer on the stack.
+ */
+#define CTYPES_MAX_ARGCOUNT 1024
+
 /*
  * Requirements, must be ensured by the caller:
  * - argtuple is tuple of arguments
@@ -1107,6 +1115,13 @@ PyObject *_ctypes_callproc(PPROC pProc,
         ++argcount;
 #endif
 
+    if (argcount > CTYPES_MAX_ARGCOUNT)
+    {
+        PyErr_Format(PyExc_ArgError, "too many arguments (%zi), maximum is %i",
+                     argcount, CTYPES_MAX_ARGCOUNT);
+        return NULL;
+    }
+
     args = (struct argument *)alloca(sizeof(struct argument) * argcount);
     if (!args) {
         PyErr_NoMemory();



More information about the Python-checkins mailing list