From fbc230d9c36ba9a56d83217a083e9aaf69e9ca7f Mon Sep 17 00:00:00 2001 From: Mikkel Krautz Date: Sun, 16 Jul 2017 10:48:49 +0200 Subject: [PATCH] src/tests: add TestSSLLocks test for testing our OpenSSL locking implementation. This test tests that our SSLLocks class works correctly. Note: Since OpenSSL 1.1, OpenSSL provides their own locking for Windows and POSIX systems. So if you're playing around with this test, you should only be able to make it crash OpenSSL versions prior to 1.1. --- src/tests/TestSSLLocks/TestSSLLocks.cpp | 106 ++++++++++++++++++++++++ src/tests/TestSSLLocks/TestSSLLocks.pro | 12 +++ src/tests/tests.pro | 3 +- 3 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 src/tests/TestSSLLocks/TestSSLLocks.cpp create mode 100644 src/tests/TestSSLLocks/TestSSLLocks.pro diff --git a/src/tests/TestSSLLocks/TestSSLLocks.cpp b/src/tests/TestSSLLocks/TestSSLLocks.cpp new file mode 100644 index 00000000000..9963c43506a --- /dev/null +++ b/src/tests/TestSSLLocks/TestSSLLocks.cpp @@ -0,0 +1,106 @@ +// Copyright 2005-2017 The Mumble Developers. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file at the root of the +// Mumble source tree or at . + +#include +#include + +#include "SSL.h" +#include "QAtomicIntCompat.h" + +#include + +/// SSLRacer is a thread that runs operations on OpenSSL's +/// RAND infrastructure, in an attempt to crash/segfault +/// the test process. +/// +/// The thread can either query OpenSSL for random bytes, or +/// seed the RAND system. This is controlled by the |seed| +/// parameter to the constructor. +class SSLRacer : public QThread { +public: + bool m_seed; + QAtomicInt *m_running; + + SSLRacer(QAtomicInt *running, bool seed) + : m_seed(seed) + , m_running(running) { + } + + void run() { + unsigned char buf[64]; + while (QAtomicIntLoad(*m_running) == 1) { + for (int i = 0; i < 1024; i++) { + if (m_seed) { + RAND_seed(buf, sizeof(buf)); + } else { + RAND_bytes(buf, sizeof(buf)); + } + } + } + } +}; + +class TestSSLLocks : public QObject { + Q_OBJECT + private slots: + void initTestCase(); + void cleanupTestCase(); + void stress(); +}; + +void TestSSLLocks::initTestCase() { + // For OpenSSL < 1.1, if you comment out this line, + // you'll be running OpenSSL without locking callbacks + // enabled. That'll make this test fail by crashing/segfaulting. + MumbleSSL::initialize(); +} + +void TestSSLLocks::cleanupTestCase() { + MumbleSSL::destroy(); +} + +/// Stress test that our locking callbacks for OpenSSL are set up and +/// working correctly. +/// +/// We do this by spawning a bunch of SSLStresser threads. Some of the +/// threads will try to read random bytes in a tight loop. Other threads +/// will, at the same time, try to add/seed random bytes to the OpenSSL +/// RAND system. +/// +/// The idea is that without proper locking, the data races we're causing +/// should quite quickly cause the process to crash. +void TestSSLLocks::stress() { + std::vector racers; + QAtomicInt running(1); + + // Spawn 24 threads in total. 12 readers, and 12 writers. + // Don't be too careful about cleaning up the threads. We'll either + // pass or crash, so the threads will be cleaned up either way. + int nthreads = 24; + for (int i = 0; i < nthreads; i++) { + bool seeder = i % 2; + SSLRacer *racer = new SSLRacer(&running, seeder); + racers.push_back(racer); + racer->start(); + } + + // Wait 2 seconds for a crash/segfault. + // If we don't crash within 2 seconds, we expect + // that our locking implementation works. + QTest::qSleep(2000); + + // Signal to the racers that they should stop. + running.fetchAndStoreOrdered(0); + + // Wait for all racers to complete. + for (size_t i = 0; i < racers.size(); i++) { + SSLRacer *racer = racers.at(i); + racer->wait(); + delete racer; + } +} + +QTEST_MAIN(TestSSLLocks) +#include "TestSSLLocks.moc" diff --git a/src/tests/TestSSLLocks/TestSSLLocks.pro b/src/tests/TestSSLLocks/TestSSLLocks.pro new file mode 100644 index 00000000000..443c1b25703 --- /dev/null +++ b/src/tests/TestSSLLocks/TestSSLLocks.pro @@ -0,0 +1,12 @@ +# Copyright 2005-2017 The Mumble Developers. All rights reserved. +# Use of this source code is governed by a BSD-style license +# that can be found in the LICENSE file at the root of the +# Mumble source tree or at . + +include(../test.pri) + +QT += network + +TARGET = TestSSLLocks +SOURCES = SSL.cpp SSLLocks.cpp TestSSLLocks.cpp +HEADERS = SSL.h SSLLocks.h diff --git a/src/tests/tests.pro b/src/tests/tests.pro index 2b608453baf..5ba7cf603a4 100644 --- a/src/tests/tests.pro +++ b/src/tests/tests.pro @@ -16,4 +16,5 @@ SUBDIRS += \ TestUnresolvedServerAddress \ TestServerAddress \ TestServerResolver \ - TestSelfSignedCertificate + TestSelfSignedCertificate \ + TestSSLLocks