diff options
author | Alex Gaynor <alex.gaynor@gmail.com> | 2016-11-13 15:55:22 -0500 |
---|---|---|
committer | Paul Kehrer <paul.l.kehrer@gmail.com> | 2016-11-13 12:55:22 -0800 |
commit | d862933de5c344fcdf99ab2f43f3bf8da65f3e41 (patch) | |
tree | 16d73c47a45f939336fe5e41bf45293097a5a222 /src/_cffi_src | |
parent | 562b9a905596f3e58b27be584a9532aa3a4dc833 (diff) | |
download | cryptography-d862933de5c344fcdf99ab2f43f3bf8da65f3e41.tar.gz cryptography-d862933de5c344fcdf99ab2f43f3bf8da65f3e41.tar.bz2 cryptography-d862933de5c344fcdf99ab2f43f3bf8da65f3e41.zip |
C locking callback (#3226)
* Remove Python OpenSSL locking callback and replace it with one in C
The Python OpenSSL locking callback is unsafe; if GC is triggered
during the callback's invocation, it can result in the callback being
invoked reentrantly, which can lead to deadlocks. This patch replaces
it with one in C that gets built at compile time via cffi along with
the rest of the OpenSSL binding.
* fixes for some issues
* unused
* revert these changes
* these two for good measure
* missing param
* sigh, syntax
* delete tests that assumed an ability to mess with locks
* style fixes
* licensing stuff
* utf8
* Unicode. Huh. What it isn't good for, absolutely nothing.
Diffstat (limited to 'src/_cffi_src')
-rw-r--r-- | src/_cffi_src/openssl/callbacks.py | 73 |
1 files changed, 72 insertions, 1 deletions
diff --git a/src/_cffi_src/openssl/callbacks.py b/src/_cffi_src/openssl/callbacks.py index 5ae89b18..4a6b4d37 100644 --- a/src/_cffi_src/openssl/callbacks.py +++ b/src/_cffi_src/openssl/callbacks.py @@ -12,6 +12,9 @@ INCLUDES = """ #include <openssl/ssl.h> #include <openssl/x509.h> #include <openssl/x509_vfy.h> +#include <openssl/crypto.h> + +#include <pythread.h> """ TYPES = """ @@ -37,6 +40,7 @@ extern "Python" int Cryptography_rand_status(void); """ FUNCTIONS = """ +int _setup_ssl_threads(void); """ MACROS = """ @@ -50,4 +54,71 @@ if cffi.__version_info__ < (1, 4, 0) or sys.version_info >= (3, 5): # backwards compatibility for old cffi version on PyPy # and Python >=3.5 (https://github.com/pyca/cryptography/issues/2970) TYPES = "static const long Cryptography_STATIC_CALLBACKS;" - CUSTOMIZATIONS = "static const long Cryptography_STATIC_CALLBACKS = 0;" + CUSTOMIZATIONS = """static const long Cryptography_STATIC_CALLBACKS = 0; +""" + +CUSTOMIZATIONS += """ +/* This code is derived from the locking code found in the Python _ssl module's + locking callback for OpenSSL. + + Copyright 2001-2016 Python Software Foundation; All Rights Reserved. +*/ + +static unsigned int _ssl_locks_count = 0; +static PyThread_type_lock *_ssl_locks = NULL; + +static void _ssl_thread_locking_function(int mode, int n, const char *file, + int line) { + /* this function is needed to perform locking on shared data + structures. (Note that OpenSSL uses a number of global data + structures that will be implicitly shared whenever multiple + threads use OpenSSL.) Multi-threaded applications will + crash at random if it is not set. + + locking_function() must be able to handle up to + CRYPTO_num_locks() different mutex locks. It sets the n-th + lock if mode & CRYPTO_LOCK, and releases it otherwise. + + file and line are the file number of the function setting the + lock. They can be useful for debugging. + */ + + if ((_ssl_locks == NULL) || + (n < 0) || ((unsigned)n >= _ssl_locks_count)) { + return; + } + + if (mode & CRYPTO_LOCK) { + PyThread_acquire_lock(_ssl_locks[n], 1); + } else { + PyThread_release_lock(_ssl_locks[n]); + } +} + +int _setup_ssl_threads(void) { + unsigned int i; + + if (_ssl_locks == NULL) { + _ssl_locks_count = CRYPTO_num_locks(); + _ssl_locks = PyMem_New(PyThread_type_lock, _ssl_locks_count); + if (_ssl_locks == NULL) { + PyErr_NoMemory(); + return 0; + } + memset(_ssl_locks, 0, sizeof(PyThread_type_lock) * _ssl_locks_count); + for (i = 0; i < _ssl_locks_count; i++) { + _ssl_locks[i] = PyThread_allocate_lock(); + if (_ssl_locks[i] == NULL) { + unsigned int j; + for (j = 0; j < i; j++) { + PyThread_free_lock(_ssl_locks[j]); + } + PyMem_Free(_ssl_locks); + return 0; + } + } + CRYPTO_set_locking_callback(_ssl_thread_locking_function); + } + return 1; +} +""" |