From b3d816093a91e748e75d5a3a4dbc8be584682206 Mon Sep 17 00:00:00 2001 From: Charalampos Stratakis Date: Wed, 22 Mar 2017 14:14:51 +0100 Subject: [PATCH] Protect key list during fork() --- Include/pythread.h | 2 ++ Modules/posixmodule.c | 33 +++++++++++++++++++++++++++++++++ Python/thread.c | 18 ++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/Include/pythread.h b/Include/pythread.h index dfd6157..f3e6259 100644 --- a/Include/pythread.h +++ b/Include/pythread.h @@ -30,6 +30,8 @@ PyAPI_FUNC(void) PyThread_delete_key(int); PyAPI_FUNC(int) PyThread_set_key_value(int, void *); PyAPI_FUNC(void *) PyThread_get_key_value(int); PyAPI_FUNC(void) PyThread_delete_key_value(int key); +PyAPI_FUNC(int) _PyThread_AcquireKeyLock(void); +PyAPI_FUNC(void) _PyThread_ReleaseKeyLock(void); /* Cleanup after a fork */ PyAPI_FUNC(void) PyThread_ReInitTLS(void); diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index e73805f..039a08d 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -3836,7 +3836,18 @@ posix_fork1(PyObject *self, PyObject *noargs) pid_t pid; int result = 0; _PyImport_AcquireLock(); +#ifdef WITH_THREAD + if (_PyThread_AcquireKeyLock() == 0) { + _PyImport_ReleaseLock(); + PyErr_SetString(PyExc_RuntimeError, + "could not acquire thread key lock"); + return NULL; + } +#endif pid = fork1(); +#ifdef WITH_THREAD + _PyThread_ReleaseKeyLock(); +#endif if (pid == 0) { /* child: this clobbers and resets the import lock. */ PyOS_AfterFork(); @@ -3869,7 +3880,18 @@ posix_fork(PyObject *self, PyObject *noargs) pid_t pid; int result = 0; _PyImport_AcquireLock(); +#ifdef WITH_THREAD + if (_PyThread_AcquireKeyLock() == 0) { + _PyImport_ReleaseLock(); + PyErr_SetString(PyExc_RuntimeError, + "could not acquire thread key lock"); + return NULL; + } +#endif pid = fork(); +#ifdef WITH_THREAD + _PyThread_ReleaseKeyLock(); +#endif if (pid == 0) { /* child: this clobbers and resets the import lock. */ PyOS_AfterFork(); @@ -3995,7 +4017,18 @@ posix_forkpty(PyObject *self, PyObject *noargs) pid_t pid; _PyImport_AcquireLock(); +#ifdef WITH_THREAD + if (_PyThread_AcquireKeyLock() == 0) { + _PyImport_ReleaseLock(); + PyErr_SetString(PyExc_RuntimeError, + "could not acquire thread key lock"); + return NULL; + } +#endif pid = forkpty(&master_fd, NULL, NULL, NULL); +#ifdef WITH_THREAD + _PyThread_ReleaseKeyLock(); +#endif if (pid == 0) { /* child: this clobbers and resets the import lock. */ PyOS_AfterFork(); diff --git a/Python/thread.c b/Python/thread.c index 3b69f96..876a342 100644 --- a/Python/thread.c +++ b/Python/thread.c @@ -387,6 +387,24 @@ PyThread_delete_key_value(int key) PyThread_release_lock(keymutex); } +int +_PyThread_AcquireKeyLock(void) +{ + if (keymutex == NULL) { + keymutex = PyThread_allocate_lock(); + } + if (keymutex == NULL) { + return 0; + } + return PyThread_acquire_lock(keymutex, 1); +} + +void +_PyThread_ReleaseKeyLock(void) +{ + PyThread_release_lock(keymutex); +} + /* Forget everything not associated with the current thread id. * This function is called from PyOS_AfterFork(). It is necessary * because other thread ids which were in use at the time of the fork -- 2.9.3