From e5098123c12880d922923d1117f7b82995c6b5a0 Mon Sep 17 00:00:00 2001 From: aavit Date: Wed, 19 Oct 2011 14:02:24 +0200 Subject: Fixes: the png_handle_cHRM crash bug in bundled libpng 1.5.4 The PNG Development Group explains that libpng 1.5.4 (only) introduced a divide-by-zero bug in png_handle_cHRM(), which could lead to crashes (denial of service) for certain malformed PNGs. Ref. http://www.libpng.org/pub/png/libpng.html This commit contains the patch recommended by the PNG Development Group, ref. http://www.kb.cert.org/vuls/id/477046 Task-number: QTBUG-22168 (cherry picked from commit 55c2ea18c522bd8700f43884124e02b460cdb5e2) --- src/3rdparty/libpng/pngrutil.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/3rdparty/libpng/pngrutil.c b/src/3rdparty/libpng/pngrutil.c index 07e46e2..daf3c5e 100644 --- a/src/3rdparty/libpng/pngrutil.c +++ b/src/3rdparty/libpng/pngrutil.c @@ -1037,12 +1037,14 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) */ png_uint_32 w = y_red + y_green + y_blue; - png_ptr->rgb_to_gray_red_coeff = (png_uint_16)(((png_uint_32)y_red * - 32768)/w); - png_ptr->rgb_to_gray_green_coeff = (png_uint_16)(((png_uint_32)y_green - * 32768)/w); - png_ptr->rgb_to_gray_blue_coeff = (png_uint_16)(((png_uint_32)y_blue * - 32768)/w); + if (w != 0) { + png_ptr->rgb_to_gray_red_coeff = (png_uint_16)(((png_uint_32)y_red * + 32768)/w); + png_ptr->rgb_to_gray_green_coeff = (png_uint_16)(((png_uint_32)y_green + * 32768)/w); + png_ptr->rgb_to_gray_blue_coeff = (png_uint_16)(((png_uint_32)y_blue * + 32768)/w); + } } } #endif -- cgit v0.12 From 0375fff2b077ddd20a97c1b1c8d34f22553abe0c Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Fri, 21 Oct 2011 09:59:54 +0200 Subject: Fix performance regression on Mac OS X when creating/destroying QMutex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit cf17b743d2fe84ab259b7232ab07b58a1872e18e, which changed QMutex to use a Mach semaphore_t on Mac OS X. We now use pthread_mutex_t on Mac OS X as well. Contention performance is mostly unchanged, but the new constructionQMutex() benchmark added in this commit shows that creating/destroying a semaphore_t is about 20 times slower than pthread_mutex_t. Reviewed-by: Olivier Goffart Reviewed-by: João Abecasis --- src/corelib/thread/qmutex_p.h | 8 +--- src/corelib/thread/qmutex_unix.cpp | 50 +++------------------- .../corelib/thread/qmutex/tst_qmutex.cpp | 19 ++++++++ 3 files changed, 26 insertions(+), 51 deletions(-) diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h index a9923c4..d2ffd28 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/src/corelib/thread/qmutex_p.h @@ -58,10 +58,6 @@ #include #include -#if defined(Q_OS_MAC) -# include -#endif - #if defined(Q_OS_SYMBIAN) # include #endif @@ -83,9 +79,7 @@ public: Qt::HANDLE owner; uint count; -#if defined(Q_OS_MAC) - semaphore_t mach_semaphore; -#elif defined(Q_OS_UNIX) && !defined(Q_OS_LINUX) && !defined(Q_OS_SYMBIAN) +#if defined(Q_OS_UNIX) && !defined(Q_OS_LINUX) && !defined(Q_OS_SYMBIAN) volatile bool wakeup; pthread_mutex_t mutex; pthread_cond_t cond; diff --git a/src/corelib/thread/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp index 2a9d23c..790fad3 100644 --- a/src/corelib/thread/qmutex_unix.cpp +++ b/src/corelib/thread/qmutex_unix.cpp @@ -65,7 +65,7 @@ QT_BEGIN_NAMESPACE -#if !defined(Q_OS_MAC) && !defined(Q_OS_LINUX) +#if !defined(Q_OS_LINUX) static void report_error(int code, const char *where, const char *what) { if (code != 0) @@ -77,11 +77,7 @@ static void report_error(int code, const char *where, const char *what) QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) : QMutexData(mode), maximumSpinTime(MaximumSpinTimeThreshold), averageWaitTime(0), owner(0), count(0) { -#if defined(Q_OS_MAC) - kern_return_t r = semaphore_create(mach_task_self(), &mach_semaphore, SYNC_POLICY_FIFO, 0); - if (r != KERN_SUCCESS) - qWarning("QMutex: failed to create semaphore, error %d", r); -#elif !defined(Q_OS_LINUX) +#if !defined(Q_OS_LINUX) wakeup = false; report_error(pthread_mutex_init(&mutex, NULL), "QMutex", "mutex init"); report_error(pthread_cond_init(&cond, NULL), "QMutex", "cv init"); @@ -90,47 +86,13 @@ QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) QMutexPrivate::~QMutexPrivate() { -#if defined(Q_OS_MAC) - kern_return_t r = semaphore_destroy(mach_task_self(), mach_semaphore); - if (r != KERN_SUCCESS) - qWarning("QMutex: failed to destroy semaphore, error %d", r); -#elif !defined(Q_OS_LINUX) +#if !defined(Q_OS_LINUX) report_error(pthread_cond_destroy(&cond), "QMutex", "cv destroy"); report_error(pthread_mutex_destroy(&mutex), "QMutex", "mutex destroy"); #endif } -#if defined(Q_OS_MAC) - -bool QMutexPrivate::wait(int timeout) -{ - if (contenders.fetchAndAddAcquire(1) == 0) { - // lock acquired without waiting - return true; - } - kern_return_t r; - if (timeout < 0) { - do { - r = semaphore_wait(mach_semaphore); - } while (r == KERN_ABORTED); - if (r != KERN_SUCCESS) - qWarning("QMutex: infinite wait failed, error %d", r); - } else { - mach_timespec_t ts; - ts.tv_nsec = ((timeout % 1000) * 1000) * 1000; - ts.tv_sec = (timeout / 1000); - r = semaphore_timedwait(mach_semaphore, ts); - } - contenders.deref(); - return r == KERN_SUCCESS; -} - -void QMutexPrivate::wakeUp() -{ - semaphore_signal(mach_semaphore); -} - -#elif defined(Q_OS_LINUX) +#if defined(Q_OS_LINUX) static inline int _q_futex(volatile int *addr, int op, int val, const struct timespec *timeout, int *addr2, int val2) { @@ -174,7 +136,7 @@ void QMutexPrivate::wakeUp() (void) _q_futex(&contenders._q_value, FUTEX_WAKE, 1, 0, 0, 0); } -#else // !Q_OS_MAC && !Q_OS_LINUX +#else // !Q_OS_LINUX bool QMutexPrivate::wait(int timeout) { @@ -221,7 +183,7 @@ void QMutexPrivate::wakeUp() report_error(pthread_mutex_unlock(&mutex), "QMutex::unlock", "mutex unlock"); } -#endif // !Q_OS_MAC && !Q_OS_LINUX +#endif // !Q_OS_LINUX QT_END_NAMESPACE diff --git a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp index 05a1575..eca38b6 100644 --- a/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp +++ b/tests/benchmarks/corelib/thread/qmutex/tst_qmutex.cpp @@ -128,7 +128,9 @@ private slots: void noThread_data(); void noThread(); + void constructionNative(); void uncontendedNative(); + void constructionQMutex(); void uncontendedQMutex(); void uncontendedQMutexLocker(); @@ -205,6 +207,15 @@ void tst_QMutex::noThread() QCOMPARE(int(count), N); } +void tst_QMutex::constructionNative() +{ + QBENCHMARK { + NativeMutexType mutex; + NativeMutexInitialize(&mutex); + NativeMutexDestroy(&mutex); + } +} + void tst_QMutex::uncontendedNative() { NativeMutexType mutex; @@ -216,6 +227,14 @@ void tst_QMutex::uncontendedNative() NativeMutexDestroy(&mutex); } +void tst_QMutex::constructionQMutex() +{ + QBENCHMARK { + QMutex mutex; + Q_UNUSED(mutex); + } +} + void tst_QMutex::uncontendedQMutex() { QMutex mutex; -- cgit v0.12 From 19bd31fc84cc4916aef4835429fc4a55e85d0c28 Mon Sep 17 00:00:00 2001 From: Richard Moore Date: Wed, 19 Oct 2011 11:40:57 +0200 Subject: Add the ability to enable various SSL bug workarounds. There are lots of buggy SSL servers around and to connect to them you need to disable various features. This commit adds the ability to disable the SSL ticket extension, the ability to disable the insertion of empty fragments, and the ability to disable compression. Task-number: QTBUG-21906 Change-Id: I3e1d0347a46e9030b889bbf15b2aad19b8513b73 Merge-request: 68 Reviewed-by: Peter Hartmann (cherry picked from commit 78d02e93aca5325fc5be9bfd275862795207abaa) (commit was cherry-picked from Qt 5 to 4.8 after agreeing with the author because the merge request was filed against Qt 5.) --- src/network/ssl/qssl.cpp | 30 +++++++++++ src/network/ssl/qssl.h | 11 ++++ src/network/ssl/qsslconfiguration.cpp | 29 +++++++++- src/network/ssl/qsslconfiguration.h | 4 ++ src/network/ssl/qsslconfiguration_p.h | 2 + src/network/ssl/qsslsocket.cpp | 2 + src/network/ssl/qsslsocket_openssl.cpp | 33 +++++++++--- tests/manual/qssloptions/main.cpp | 92 ++++++++++++++++++++++++++++++++ tests/manual/qssloptions/qssloptions.pro | 12 +++++ 9 files changed, 206 insertions(+), 9 deletions(-) create mode 100644 tests/manual/qssloptions/main.cpp create mode 100644 tests/manual/qssloptions/qssloptions.pro diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp index 586c894..08a05ff 100644 --- a/src/network/ssl/qssl.cpp +++ b/src/network/ssl/qssl.cpp @@ -120,4 +120,34 @@ QT_BEGIN_NAMESPACE the correct setting for your protocol. */ +/*! + \enum QSsl::SslOption + + Describes the options that can be used to control the details of + SSL behaviour. These options are generally used to turn features off + to work around buggy servers. + + \value SslOptionDisableEmptyFragments Disables the insertion of empty + fragments into the data when using block ciphers. When enabled, this + prevents some attacks (such as the BEAST attack), however it is + incompatible with some servers. + \value SslOptionDisableTickets Disables the SSL session ticket + extension. This can cause slower connection setup, however some servers + are not compatible with the extension. + \value SslOptionDisableCompression Disables the SSL compression + extension. When enabled, this allows the data being passed over SSL to + be compressed, however some servers are not compatible with this + extension. + \value SslOptionDisableServerNameIndication Disables the SSL server + name indication extension. When enabled, this tells the server the virtual + host being accessed allowing it to respond with the correct certificate. + + By default, SslOptionDisableEmptyFragments is turned on since this causes + problems with a large number of servers, but the other options are disabled. + + Note: Availability of above options depends on the version of the SSL + backend in use. +*/ + + QT_END_NAMESPACE diff --git a/src/network/ssl/qssl.h b/src/network/ssl/qssl.h index 2ecd1c3..453d4da 100644 --- a/src/network/ssl/qssl.h +++ b/src/network/ssl/qssl.h @@ -44,6 +44,7 @@ #define QSSL_H #include +#include QT_BEGIN_HEADER @@ -81,8 +82,18 @@ namespace QSsl { SecureProtocols, UnknownProtocol = -1 }; + + enum SslOption { + SslOptionDisableEmptyFragments = 0x01, + SslOptionDisableSessionTickets = 0x02, + SslOptionDisableCompression = 0x04, + SslOptionDisableServerNameIndication = 0x08 + }; + Q_DECLARE_FLAGS(SslOptions, SslOption) } +Q_DECLARE_OPERATORS_FOR_FLAGS(QSsl::SslOptions) + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp index 69d3b66..e24076e 100644 --- a/src/network/ssl/qsslconfiguration.cpp +++ b/src/network/ssl/qsslconfiguration.cpp @@ -167,7 +167,8 @@ bool QSslConfiguration::operator==(const QSslConfiguration &other) const d->caCertificates == other.d->caCertificates && d->protocol == other.d->protocol && d->peerVerifyMode == other.d->peerVerifyMode && - d->peerVerifyDepth == other.d->peerVerifyDepth; + d->peerVerifyDepth == other.d->peerVerifyDepth && + d->sslOptions == other.d->sslOptions; } /*! @@ -199,7 +200,8 @@ bool QSslConfiguration::isNull() const d->localCertificate.isNull() && d->privateKey.isNull() && d->peerCertificate.isNull() && - d->peerCertificateChain.count() == 0); + d->peerCertificateChain.count() == 0 && + d->sslOptions == 0); } /*! @@ -507,6 +509,29 @@ void QSslConfiguration::setCaCertificates(const QList &certific } /*! + Enables or disables an SSL compatibility option. + + \sa testSSlOption() +*/ +void QSslConfiguration::setSslOption(QSsl::SslOption option, bool on) +{ + if (on) + d->sslOptions |= option; + else + d->sslOptions &= ~option; +} + +/*! + Returns true if the specified SSL compatibility option is enabled. + + \sa testSSlOption() +*/ +bool QSslConfiguration::testSslOption(QSsl::SslOption option) const +{ + return d->sslOptions & option; +} + +/*! Returns the default SSL configuration to be used in new SSL connections. diff --git a/src/network/ssl/qsslconfiguration.h b/src/network/ssl/qsslconfiguration.h index 258b454..ff8c8fc 100644 --- a/src/network/ssl/qsslconfiguration.h +++ b/src/network/ssl/qsslconfiguration.h @@ -59,6 +59,7 @@ #include #include +#include QT_BEGIN_HEADER @@ -118,6 +119,9 @@ public: QList caCertificates() const; void setCaCertificates(const QList &certificates); + void setSslOption(QSsl::SslOption option, bool on); + bool testSslOption(QSsl::SslOption option) const; + static QSslConfiguration defaultConfiguration(); static void setDefaultConfiguration(const QSslConfiguration &configuration); diff --git a/src/network/ssl/qsslconfiguration_p.h b/src/network/ssl/qsslconfiguration_p.h index af80e4c..b83edb9 100644 --- a/src/network/ssl/qsslconfiguration_p.h +++ b/src/network/ssl/qsslconfiguration_p.h @@ -98,6 +98,8 @@ public: QSslSocket::PeerVerifyMode peerVerifyMode; int peerVerifyDepth; + QSsl::SslOptions sslOptions; + // in qsslsocket.cpp: static QSslConfiguration defaultConfiguration(); static void setDefaultConfiguration(const QSslConfiguration &configuration); diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index df61fb6..3ac8f18 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -896,6 +896,7 @@ void QSslSocket::setSslConfiguration(const QSslConfiguration &configuration) d->configuration.peerVerifyDepth = configuration.peerVerifyDepth(); d->configuration.peerVerifyMode = configuration.peerVerifyMode(); d->configuration.protocol = configuration.protocol(); + d->configuration.sslOptions = configuration.d->sslOptions; d->allowRootCertOnDemandLoading = false; } @@ -2027,6 +2028,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri ptr->protocol = global->protocol; ptr->peerVerifyMode = global->peerVerifyMode; ptr->peerVerifyDepth = global->peerVerifyDepth; + ptr->sslOptions = global->sslOptions; } /*! diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 8e53974..3942209 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -285,12 +285,29 @@ init_context: return false; } - // Enable all bug workarounds. - if (configuration.protocol == QSsl::TlsV1SslV3 || configuration.protocol == QSsl::SecureProtocols) { - q_SSL_CTX_set_options(ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2); - } else { - q_SSL_CTX_set_options(ctx, SSL_OP_ALL); - } + // Enable bug workarounds. + long options; + if (configuration.protocol == QSsl::TlsV1SslV3 || configuration.protocol == QSsl::SecureProtocols) + options = SSL_OP_ALL|SSL_OP_NO_SSLv2; + else + options = SSL_OP_ALL; + + // This option is disabled by default, so we need to be able to clear it + if (configuration.sslOptions & QSsl::SslOptionDisableEmptyFragments) + options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; + else + options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; + +#ifdef SSL_OP_NO_TICKET + if (configuration.sslOptions & QSsl::SslOptionDisableSessionTickets) + options |= SSL_OP_NO_TICKET; +#endif +#ifdef SSL_OP_NO_COMPRESSION + if (configuration.sslOptions & QSsl::SslOptionDisableCompression) + options |= SSL_OP_NO_COMPRESSION; +#endif + + q_SSL_CTX_set_options(ctx, options); // Initialize ciphers QByteArray cipherString; @@ -419,7 +436,9 @@ init_context: tlsHostName = hostName; QByteArray ace = QUrl::toAce(tlsHostName); // only send the SNI header if the URL is valid and not an IP - if (!ace.isEmpty() && !QHostAddress().setAddress(tlsHostName)) { + if (!ace.isEmpty() + && !QHostAddress().setAddress(tlsHostName) + && !(configuration.sslOptions & QSsl::SslOptionDisableServerNameIndication)) { #if OPENSSL_VERSION_NUMBER >= 0x10000000L if (!q_SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, ace.data())) #else diff --git a/tests/manual/qssloptions/main.cpp b/tests/manual/qssloptions/main.cpp new file mode 100644 index 0000000..6f2f361 --- /dev/null +++ b/tests/manual/qssloptions/main.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + if (argc < 3) { + QTextStream out(stdout); + out << "Usage: " << argv[0] << " host port [options]" << endl; + out << "The options can be one or more of the following:" << endl; + out << "enable_empty_fragments" << endl; + out << "disable_session_tickets" << endl; + out << "disable_compression" << endl; + out << "disable_sni" << endl; + return 1; + } + + QString host = QString::fromLocal8Bit(argv[1]); + int port = QString::fromLocal8Bit(argv[2]).toInt(); + + QSslConfiguration config = QSslConfiguration::defaultConfiguration(); + + for (int i=3; i < argc; i++) { + QString option = QString::fromLocal8Bit(argv[i]); + + if (option == QLatin1String("enable_empty_fragments")) + config.setSslOption(QSsl::SslOptionDisableEmptyFragments, false); + else if (option == QLatin1String("disable_session_tickets")) + config.setSslOption(QSsl::SslOptionDisableSessionTickets, true); + else if (option == QLatin1String("disable_compression")) + config.setSslOption(QSsl::SslOptionDisableCompression, true); + else if (option == QLatin1String("disable_sni")) + config.setSslOption(QSsl::SslOptionDisableServerNameIndication, true); + } + + QSslConfiguration::setDefaultConfiguration(config); + + QSslSocket socket; + //socket.setSslConfiguration(config); + socket.connectToHostEncrypted(host, port); + + if ( !socket.waitForEncrypted() ) { + qDebug() << socket.errorString(); + return 1; + } + + return 0; +} diff --git a/tests/manual/qssloptions/qssloptions.pro b/tests/manual/qssloptions/qssloptions.pro new file mode 100644 index 0000000..c1c8446 --- /dev/null +++ b/tests/manual/qssloptions/qssloptions.pro @@ -0,0 +1,12 @@ +load(qttest_p4) +TEMPLATE = app +TARGET = tst_qssloptions +DEPENDPATH += . +INCLUDEPATH += . + +QT -= gui +QT += network + +#CONFIG += release + +SOURCES += main.cpp -- cgit v0.12