From 3562df8732f66848342874526d0ce12392d7d62e Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Fri, 27 Nov 2020 19:29:49 +0100 Subject: Keep reference to SSL verify_call in Connection object (#956) * Keep reference to SSL verify_call in Connection object If a set_verify is used on a context before and after a Connection the reference in the SSL* object still points to the old _verify_helper object. Since this object has no longer any references to it, the callback can result in a segfault. This commit fixes the issues by ensuring that as long as the Connection object/SSL* object lives a reference to the callback function is held. * Add Unit test for set_verify_callback deference --- tests/test_ssl.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'tests/test_ssl.py') diff --git a/tests/test_ssl.py b/tests/test_ssl.py index aed2367..8fdcae2 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -6,6 +6,7 @@ Unit tests for :mod:`OpenSSL.SSL`. """ import datetime +import gc import sys import uuid @@ -1389,6 +1390,51 @@ class TestContext(object): assert "silly verify failure" == str(exc.value) + def test_set_verify_callback_reference(self): + """ + If the verify callback passed to `Context.set_verify` is set multiple + times, the pointers to the old call functions should not be dangling + and trigger a segfault. + """ + serverContext = Context(TLSv1_2_METHOD) + serverContext.use_privatekey( + load_privatekey(FILETYPE_PEM, root_key_pem) + ) + serverContext.use_certificate( + load_certificate(FILETYPE_PEM, root_cert_pem) + ) + + clientContext = Context(TLSv1_2_METHOD) + + clients = [] + + for i in range(5): + + def verify_callback(*args): + return True + + serverSocket, clientSocket = socket_pair() + client = Connection(clientContext, clientSocket) + + clients.append((serverSocket, client)) + + clientContext.set_verify(VERIFY_PEER, verify_callback) + + gc.collect() + + # Make them talk to each other. + for serverSocket, client in clients: + server = Connection(serverContext, serverSocket) + server.set_accept_state() + client.set_connect_state() + + for _ in range(5): + for s in [client, server]: + try: + s.do_handshake() + except WantReadError: + pass + @pytest.mark.parametrize("mode", [SSL.VERIFY_PEER, SSL.VERIFY_NONE]) def test_set_verify_default_callback(self, mode): """ -- cgit v1.2.1