New submission from Tim Boddy <timothywbo...@gmail.com>:
I noticed a memory leak /usr/lib/python3.5/site-packages/OpenSSL/crypto.py in the definition of the class X509StoreContext. The problem is that the __init__ function calls self._init() then later the function verify_certificate calls _init() again. In spite of the disclaimer int __init__ about "no adverse effect", the adverse effect here is that if one does two calls to X509_STORE_CTX_init on the same X509_STORE_CTX without any intervening calls to X509_STORE_CTX_cleanup on that same X509_STORE_CTX it will leak one X509_VERIFY_PARAM and one X509_VERIFY_PARAM_ID. Here is most of the relevant class: class X509StoreContext(object): """ An X.509 store context. An X.509 store context is used to carry out the actual verification process of a certificate in a described context. For describing such a context, see :class:`X509Store`. :ivar _store_ctx: The underlying X509_STORE_CTX structure used by this instance. It is dynamically allocated and automatically garbage collected. :ivar _store: See the ``store`` ``__init__`` parameter. :ivar _cert: See the ``certificate`` ``__init__`` parameter. :param X509Store store: The certificates which will be trusted for the purposes of any verifications. :param X509 certificate: The certificate to be verified. """ def __init__(self, store, certificate): store_ctx = _lib.X509_STORE_CTX_new() self._store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free) self._store = store self._cert = certificate # Make the store context available for use after instantiating this # class by initializing it now. Per testing, subsequent calls to # :meth:`_init` have no adverse affect. self._init() def _init(self): """ Set up the store context for a subsequent verification operation. """ Set up the store context for a subsequent verification operation. """ ret = _lib.X509_STORE_CTX_init( self._store_ctx, self._store._store, self._cert._x509, _ffi.NULL ) if ret <= 0: _raise_current_error() def _cleanup(self): """ Internally cleans up the store context. The store context can then be reused with a new call to :meth:`_init`. """ _lib.X509_STORE_CTX_cleanup(self._store_ctx) def _exception_from_context(self): """ Convert an OpenSSL native context error failure into a Python exception. When a call to native OpenSSL X509_verify_cert fails, additional information about the failure can be obtained from the store context. """ errors = [ _lib.X509_STORE_CTX_get_error(self._store_ctx), _lib.X509_STORE_CTX_get_error_depth(self._store_ctx), _native(_ffi.string(_lib.X509_verify_cert_error_string( _lib.X509_STORE_CTX_get_error(self._store_ctx)))), ] # A context error should always be associated with a certificate, so we # expect this call to never return :class:`None`. _x509 = _lib.X509_STORE_CTX_get_current_cert(self._store_ctx) _cert = _lib.X509_dup(_x509) pycert = X509.__new__(X509) pycert._x509 = _ffi.gc(_cert, _lib.X509_free) return X509StoreContextError(errors, pycert) def set_store(self, store): """ Set the context's X.509 store. .. versionadded:: 0.15 :param X509Store store: The store description which will be used for the purposes of any *future* verifications. """ self._store = store def verify_certificate(self): """ Verify a certificate in a context. .. versionadded:: 0.15 :raises X509StoreContextError: If an error occurred when validating a certificate in the context. Sets ``certificate`` attribute to indicate which certificate caused the error. """ # Always re-initialize the store context in case # :meth:`verify_certificate` is called multiple times. self._init() ret = _lib.X509_verify_cert(self._store_ctx) self._cleanup() if ret <= 0: raise self._exception_from_context() ---------- messages: 318927 nosy: timboddy priority: normal severity: normal status: open title: Memory leak in X509StoreContext class. type: resource usage versions: Python 3.5 _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue33795> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com