diff options
author | Franck Dude <enstone83@gmail.com> | 2019-12-14 23:41:30 +0100 |
---|---|---|
committer | Franck Dude <enstone83@gmail.com> | 2020-03-19 10:43:46 +0100 |
commit | ed93680f34e92ad0383aa4e610bb65689118ca93 (patch) | |
tree | af3a3c9aa07a370d5923559538c8da6eceef4bf9 /tests | |
parent | 2437f81b0022f9524ca467e28c889d8683c464cf (diff) | |
download | qtwebsockets-ed93680f34e92ad0383aa4e610bb65689118ca93.tar.gz |
Add a public api to set max frame and message size (CVE-2018-21035)
This change allows the user to set a lower allowed frame/message size
for reception. The purpose is to avoid an attacker to exhaust the
virtual memory of the peer.
Fixes CVE-2018-21035
[ChangeLog] Added public API to set the maximum frame size and message size
Task-number: QTBUG-70693
Change-Id: I5dc5918badc99166afdcc8d9c6106247a9f8666f
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp | 90 | ||||
-rw-r--r-- | tests/auto/websockets/websocketframe/tst_websocketframe.cpp | 2 |
2 files changed, 89 insertions, 3 deletions
diff --git a/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp b/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp index 71e1262..aca3f40 100644 --- a/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp +++ b/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp @@ -39,7 +39,9 @@ class EchoServer : public QObject { Q_OBJECT public: - explicit EchoServer(QObject *parent = nullptr); + explicit EchoServer(QObject *parent = nullptr, + quint64 maxAllowedIncomingMessageSize = QWebSocket::maxIncomingMessageSize(), + quint64 maxAllowedIncomingFrameSize = QWebSocket::maxIncomingFrameSize()); ~EchoServer(); QHostAddress hostAddress() const { return m_pWebSocketServer->serverAddress(); } @@ -57,13 +59,17 @@ private Q_SLOTS: private: QWebSocketServer *m_pWebSocketServer; + quint64 m_maxAllowedIncomingMessageSize; + quint64 m_maxAllowedIncomingFrameSize; QList<QWebSocket *> m_clients; }; -EchoServer::EchoServer(QObject *parent) : +EchoServer::EchoServer(QObject *parent, quint64 maxAllowedIncomingMessageSize, quint64 maxAllowedIncomingFrameSize) : QObject(parent), m_pWebSocketServer(new QWebSocketServer(QStringLiteral("Echo Server"), QWebSocketServer::NonSecureMode, this)), + m_maxAllowedIncomingMessageSize(maxAllowedIncomingMessageSize), + m_maxAllowedIncomingFrameSize(maxAllowedIncomingFrameSize), m_clients() { if (m_pWebSocketServer->listen(QHostAddress(QStringLiteral("127.0.0.1")))) { @@ -82,6 +88,9 @@ void EchoServer::onNewConnection() { QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection(); + pSocket->setMaxAllowedIncomingFrameSize(m_maxAllowedIncomingFrameSize); + pSocket->setMaxAllowedIncomingMessageSize(m_maxAllowedIncomingMessageSize); + Q_EMIT newConnection(pSocket->requestUrl()); Q_EMIT newConnection(pSocket->request()); @@ -144,6 +153,9 @@ private Q_SLOTS: void tst_setProxy(); #endif void overlongCloseReason(); + void incomingMessageTooLong(); + void incomingFrameTooLong(); + void testingFrameAndMessageSizeApi(); }; tst_QWebSocket::tst_QWebSocket() @@ -795,6 +807,80 @@ void tst_QWebSocket::overlongCloseReason() QCOMPARE(socket.closeReason(), reason.leftRef(123)); QTRY_COMPARE(socketDisconnectedSpy.count(), 1); } + +void tst_QWebSocket::incomingMessageTooLong() +{ +//QTBUG-70693 + quint64 maxAllowedIncomingMessageSize = 1024; + quint64 maxAllowedIncomingFrameSize = QWebSocket::maxIncomingFrameSize(); + + EchoServer echoServer(nullptr, maxAllowedIncomingMessageSize, maxAllowedIncomingFrameSize); + + QWebSocket socket; + + QSignalSpy socketConnectedSpy(&socket, &QWebSocket::connected); + QSignalSpy serverConnectedSpy(&echoServer, QOverload<QUrl>::of(&EchoServer::newConnection)); + QSignalSpy socketDisconnectedSpy(&socket, &QWebSocket::disconnected); + + QUrl url = QUrl(QStringLiteral("ws://") + echoServer.hostAddress().toString() + + QStringLiteral(":") + QString::number(echoServer.port())); + socket.open(url); + QTRY_COMPARE(socketConnectedSpy.count(), 1); + QTRY_COMPARE(serverConnectedSpy.count(), 1); + + QString payload(maxAllowedIncomingMessageSize+1, 'a'); + QCOMPARE(socket.sendTextMessage(payload), payload.size()); + + QTRY_COMPARE(socketDisconnectedSpy.count(), 1); + QCOMPARE(socket.closeCode(), QWebSocketProtocol::CloseCodeTooMuchData); +} + +void tst_QWebSocket::incomingFrameTooLong() +{ +//QTBUG-70693 + quint64 maxAllowedIncomingMessageSize = QWebSocket::maxIncomingMessageSize(); + quint64 maxAllowedIncomingFrameSize = 1024; + + EchoServer echoServer(nullptr, maxAllowedIncomingMessageSize, maxAllowedIncomingFrameSize); + + QWebSocket socket; + socket.setOutgoingFrameSize(maxAllowedIncomingFrameSize+1); + + QSignalSpy socketConnectedSpy(&socket, &QWebSocket::connected); + QSignalSpy serverConnectedSpy(&echoServer, QOverload<QUrl>::of(&EchoServer::newConnection)); + QSignalSpy socketDisconnectedSpy(&socket, &QWebSocket::disconnected); + + QUrl url = QUrl(QStringLiteral("ws://") + echoServer.hostAddress().toString() + + QStringLiteral(":") + QString::number(echoServer.port())); + socket.open(url); + QTRY_COMPARE(socketConnectedSpy.count(), 1); + QTRY_COMPARE(serverConnectedSpy.count(), 1); + + QString payload(maxAllowedIncomingFrameSize+1, 'a'); + QCOMPARE(socket.sendTextMessage(payload), payload.size()); + + QTRY_COMPARE(socketDisconnectedSpy.count(), 1); + QCOMPARE(socket.closeCode(), QWebSocketProtocol::CloseCodeTooMuchData); +} + +void tst_QWebSocket::testingFrameAndMessageSizeApi() +{ +//requested by André Hartmann, QTBUG-70693 + QWebSocket socket; + + const quint64 outgoingFrameSize = 5; + socket.setOutgoingFrameSize(outgoingFrameSize); + QTRY_COMPARE(outgoingFrameSize, socket.outgoingFrameSize()); + + const quint64 maxAllowedIncomingFrameSize = 9; + socket.setMaxAllowedIncomingFrameSize(maxAllowedIncomingFrameSize); + QTRY_COMPARE(maxAllowedIncomingFrameSize, socket.maxAllowedIncomingFrameSize()); + + const quint64 maxAllowedIncomingMessageSize = 889; + socket.setMaxAllowedIncomingMessageSize(maxAllowedIncomingMessageSize); + QTRY_COMPARE(maxAllowedIncomingMessageSize, socket.maxAllowedIncomingMessageSize()); +} + #endif // QT_NO_NETWORKPROXY QTEST_MAIN(tst_QWebSocket) diff --git a/tests/auto/websockets/websocketframe/tst_websocketframe.cpp b/tests/auto/websockets/websocketframe/tst_websocketframe.cpp index bbf0e5f..7046657 100644 --- a/tests/auto/websockets/websocketframe/tst_websocketframe.cpp +++ b/tests/auto/websockets/websocketframe/tst_websocketframe.cpp @@ -541,7 +541,7 @@ void tst_WebSocketFrame::tst_malformedFrames_data() //too much data { const char bigpayloadIndicator = char(127); - const quint64 payloadSize = MAX_FRAME_SIZE_IN_BYTES + 1; + const quint64 payloadSize = QWebSocketFrame::maxFrameSize() + 1; uchar swapped[8] = {0}; qToBigEndian<quint64>(payloadSize, swapped); QTest::newRow("Frame too big") |