From 37346b2b9bd740803f120057d64c6a30f2e74152 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Sat, 23 Aug 2008 20:27:43 +0000 Subject: #3643 add a few more checks to _testcapi to prevent segfaults Author: Victor Stinner Reviewer: Benjamin Peterson --- Misc/NEWS | 6 ++++++ Modules/_testcapimodule.c | 24 ++++++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS index 07fc1f3..2ae121a 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -25,6 +25,12 @@ Library - Fixed two format strings in the _collections module. +Extension Modules +----------------- + +- Issue #3643: Added a few more checks to _testcapi to prevent segfaults by + exploitation of poor argument checking. + What's New in Python 2.6 beta 3? ================================ diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 2ed81aa..f3a9f5c 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -600,6 +600,10 @@ raise_exception(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "Oi:raise_exception", &exc, &num_args)) return NULL; + if (!PyExceptionClass_Check(exc)) { + PyErr_Format(PyExc_TypeError, "an exception class is required"); + return NULL; + } exc_args = PyTuple_New(num_args); if (exc_args == NULL) @@ -628,14 +632,17 @@ raise_exception(PyObject *self, PyObject *args) */ static PyThread_type_lock thread_done = NULL; -static void +static int _make_call(void *callable) { PyObject *rc; + int success; PyGILState_STATE s = PyGILState_Ensure(); rc = PyObject_CallFunction((PyObject *)callable, ""); + success = (rc != NULL); Py_XDECREF(rc); PyGILState_Release(s); + return success; } /* Same thing, but releases `thread_done` when it returns. This variant @@ -652,10 +659,17 @@ static PyObject * test_thread_state(PyObject *self, PyObject *args) { PyObject *fn; + int success = 1; if (!PyArg_ParseTuple(args, "O:test_thread_state", &fn)) return NULL; + if (!PyCallable_Check(fn)) { + PyErr_Format(PyExc_TypeError, "'%s' object is not callable", + fn->ob_type->tp_name); + return NULL; + } + /* Ensure Python is set up for threading */ PyEval_InitThreads(); thread_done = PyThread_allocate_lock(); @@ -666,10 +680,10 @@ test_thread_state(PyObject *self, PyObject *args) /* Start a new thread with our callback. */ PyThread_start_new_thread(_make_call_from_thread, fn); /* Make the callback with the thread lock held by this thread */ - _make_call(fn); + success &= _make_call(fn); /* Do it all again, but this time with the thread-lock released */ Py_BEGIN_ALLOW_THREADS - _make_call(fn); + success &= _make_call(fn); PyThread_acquire_lock(thread_done, 1); /* wait for thread to finish */ Py_END_ALLOW_THREADS @@ -679,7 +693,7 @@ test_thread_state(PyObject *self, PyObject *args) */ Py_BEGIN_ALLOW_THREADS PyThread_start_new_thread(_make_call_from_thread, fn); - _make_call(fn); + success &= _make_call(fn); PyThread_acquire_lock(thread_done, 1); /* wait for thread to finish */ Py_END_ALLOW_THREADS @@ -687,6 +701,8 @@ test_thread_state(PyObject *self, PyObject *args) PyThread_release_lock(thread_done); PyThread_free_lock(thread_done); + if (!success) + return NULL; Py_RETURN_NONE; } #endif -- cgit v0.12