summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@digia.com>2014-02-27 13:49:49 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-02-28 17:57:13 +0100
commit474bf7b1870c55f53a628aead3eb7a32d80844bb (patch)
treee73c936b371a36ae807b00181a28988b2f9b9266
parent0d0fb04d505d105fb4b2fc71d68f729ce670b12e (diff)
Protect against malicious SPDY messages
Add handling of invalid stream-ids and buffer overflow in header parsing. Change-Id: I712af189d72612639d25890a8861a8f4fe084ce3 Reviewed-by: Peter Hartmann <phartmann@blackberry.com>
-rw-r--r--src/network/access/qspdyprotocolhandler.cpp34
1 files changed, 34 insertions, 0 deletions
diff --git a/src/network/access/qspdyprotocolhandler.cpp b/src/network/access/qspdyprotocolhandler.cpp
index 098b3e9ab0..e87738be46 100644
--- a/src/network/access/qspdyprotocolhandler.cpp
+++ b/src/network/access/qspdyprotocolhandler.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtNetwork module of the Qt Toolkit.
@@ -694,6 +695,10 @@ void QSpdyProtocolHandler::sendPING(quint32 pingID)
bool QSpdyProtocolHandler::uploadData(qint32 streamID)
{
// we only rely on SPDY flow control here and don't care about TCP buffers
+ if (!m_inFlightStreams.contains(streamID)) {
+ sendRST_STREAM(streamID, RST_STREAM_INVALID_STREAM);
+ return false;
+ }
HttpMessagePair messagePair = m_inFlightStreams.value(streamID);
QHttpNetworkRequest request = messagePair.first;
@@ -874,6 +879,10 @@ void QSpdyProtocolHandler::handleSYN_REPLY(char flags, quint32 /*length*/, const
void QSpdyProtocolHandler::parseHttpHeaders(char flags, const QByteArray &frameData)
{
qint32 streamID = getStreamID(frameData.constData());
+ if (!m_inFlightStreams.contains(streamID)) {
+ sendRST_STREAM(streamID, RST_STREAM_INVALID_STREAM);
+ return;
+ }
flags &= 0x3f;
bool flag_fin = flags & 0x01;
@@ -891,16 +900,31 @@ void QSpdyProtocolHandler::parseHttpHeaders(char flags, const QByteArray &frameD
}
qint32 headerCount = fourBytesToInt(uncompressedHeader.constData());
+ if (headerCount * 8 > uncompressedHeader.size()) {
+ qWarning() << Q_FUNC_INFO << "error parsing header from SYN_REPLY message";
+ sendRST_STREAM(streamID, RST_STREAM_PROTOCOL_ERROR);
+ return;
+ }
qint32 readPointer = 4;
for (qint32 a = 0; a < headerCount; ++a) {
qint32 count = fourBytesToInt(uncompressedHeader.constData() + readPointer);
readPointer += 4;
QByteArray name = uncompressedHeader.mid(readPointer, count);
readPointer += count;
+ if (readPointer > uncompressedHeader.size()) {
+ qWarning() << Q_FUNC_INFO << "error parsing header from SYN_REPLY message";
+ sendRST_STREAM(streamID, RST_STREAM_PROTOCOL_ERROR);
+ return;
+ }
count = fourBytesToInt(uncompressedHeader.constData() + readPointer);
readPointer += 4;
QByteArray value = uncompressedHeader.mid(readPointer, count);
readPointer += count;
+ if (readPointer > uncompressedHeader.size()) {
+ qWarning() << Q_FUNC_INFO << "error parsing header from SYN_REPLY message";
+ sendRST_STREAM(streamID, RST_STREAM_PROTOCOL_ERROR);
+ return;
+ }
if (name == ":status") {
httpReply->setStatusCode(value.left(3).toInt());
httpReply->d_func()->reasonPhrase = QString::fromLatin1(value.mid(4));
@@ -1143,6 +1167,11 @@ void QSpdyProtocolHandler::handleWINDOW_UPDATE(char /*flags*/, quint32 /*length*
qint32 streamID = getStreamID(frameData.constData());
qint32 deltaWindowSize = fourBytesToInt(frameData.constData() + 4);
+ if (!m_inFlightStreams.contains(streamID)) {
+ sendRST_STREAM(streamID, RST_STREAM_INVALID_STREAM);
+ return;
+ }
+
QHttpNetworkReply *reply = m_inFlightStreams.value(streamID).second;
Q_ASSERT(reply);
QHttpNetworkReplyPrivate *replyPrivate = reply->d_func();
@@ -1158,6 +1187,11 @@ void QSpdyProtocolHandler::handleDataFrame(const QByteArray &frameHeaders)
Q_ASSERT(frameHeaders.count() >= 8);
qint32 streamID = getStreamID(frameHeaders.constData());
+ if (!m_inFlightStreams.contains(streamID)) {
+ sendRST_STREAM(streamID, RST_STREAM_INVALID_STREAM);
+ return;
+ }
+
unsigned char flags = static_cast<unsigned char>(frameHeaders.at(4));
flags &= 0x3f;
bool flag_fin = flags & 0x01;