summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKonstantin Tokarev <annulen@yandex.ru>2017-09-27 13:23:27 +0300
committerKonstantin Tokarev <annulen@yandex.ru>2017-11-08 16:15:20 +0000
commit1cc2ffbaaa177340bb6f2b0b14ac267a3f24b116 (patch)
treef4c80fc018b1e2bc9eb9f2154b4c36d587495cea
parent3f941dc062674630daa39770ac027658f8fb0302 (diff)
Prevent crash when downloading large blob data
QByteArray::{from,to}Base64 are prone to integer overflow when input data is large, which causes segfaults. We have to set threshold on data size to prevent this from happening. Also, changed data URL construction code to do less intermediate memory reservations. Though biggest offender is QUrl constructor and it has to stay. Original commit: https://github.com/annulen/webkit/commit/535c062962e3e0f425848e6b32ad1c95d25bec4b Change-Id: Ieaf4c914fdff086e15d2358bdb19d378f2a11feb Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
-rw-r--r--Source/WebCore/platform/network/qt/ResourceRequestQt.cpp60
-rw-r--r--Source/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.cpp4
-rw-r--r--Tools/QtTestBrowser/launcherwindow.cpp10
3 files changed, 48 insertions, 26 deletions
diff --git a/Source/WebCore/platform/network/qt/ResourceRequestQt.cpp b/Source/WebCore/platform/network/qt/ResourceRequestQt.cpp
index 83c50062d..2719f1db6 100644
--- a/Source/WebCore/platform/network/qt/ResourceRequestQt.cpp
+++ b/Source/WebCore/platform/network/qt/ResourceRequestQt.cpp
@@ -28,10 +28,9 @@
#include "BlobStorageData.h"
#endif
-#include <qglobal.h>
-
#include <QNetworkRequest>
#include <QUrl>
+#include <wtf/text/Base64.h>
namespace WebCore {
@@ -47,11 +46,11 @@ unsigned initializeMaximumHTTPConnectionCountPerHost()
}
#if ENABLE(BLOB)
-static void appendBlobResolved(QByteArray& data, const QUrl& url, QString* contentType = 0)
+static bool appendBlobResolved(Vector<char>& out, const KURL& url, QString* contentType = 0)
{
RefPtr<BlobStorageData> blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(url);
if (!blobData)
- return;
+ return false;
if (contentType)
*contentType = blobData->contentType();
@@ -60,35 +59,58 @@ static void appendBlobResolved(QByteArray& data, const QUrl& url, QString* conte
const BlobDataItemList::const_iterator itend = blobData->items().end();
for (; it != itend; ++it) {
const BlobDataItem& blobItem = *it;
- if (blobItem.type == BlobDataItem::Data)
- data.append(blobItem.data->data() + static_cast<int>(blobItem.offset), static_cast<int>(blobItem.length));
- else if (blobItem.type == BlobDataItem::Blob)
- appendBlobResolved(data, blobItem.url);
- else if (blobItem.type == BlobDataItem::File) {
+ if (blobItem.type == BlobDataItem::Data) {
+ if (!out.tryAppend(reinterpret_cast<const char*>(blobItem.data->data()) + blobItem.offset, blobItem.length))
+ return false;
+ } else if (blobItem.type == BlobDataItem::File) {
// File types are not allowed here, so just ignore it.
} else
ASSERT_NOT_REACHED();
}
+ return true;
}
-static void resolveBlobUrl(const QUrl& url, QUrl& resolvedUrl)
+static QUrl resolveBlobUrl(const KURL& url)
{
RefPtr<BlobStorageData> blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(url);
if (!blobData)
- return;
+ return QUrl();
- QByteArray data;
+ Vector<char> data;
QString contentType;
- appendBlobResolved(data, url, &contentType);
+ if (!appendBlobResolved(data, url, &contentType)) {
+ qWarning("Failed to convert blob data to base64: cannot allocate memory for continuous blob data");
+ return QUrl();
+ }
+
+ // QByteArray::{from,to}Base64 are prone to integer overflow, this is the maximum size that can be safe
+ size_t maxBase64Size = std::numeric_limits<int>::max() / 3 - 1;
+
+ Vector<char> base64;
+ WTF::base64Encode(data, base64, WTF::Base64URLPolicy);
+ if (base64.isEmpty() || base64.size() > maxBase64Size) {
+ qWarning("Failed to convert blob data to base64: data is too large");
+ return QUrl();
+ }
QString dataUri(QStringLiteral("data:"));
dataUri.append(contentType);
dataUri.append(QStringLiteral(";base64,"));
- dataUri.append(QString::fromLatin1(data.toBase64()));
- resolvedUrl = QUrl(dataUri);
+ dataUri.reserve(dataUri.size() + base64.size());
+ dataUri.append(QLatin1String(base64.data(), base64.size()));
+ return QUrl(dataUri);
}
#endif
+static QUrl toQUrl(const KURL& url)
+{
+#if ENABLE(BLOB)
+ if (url.protocolIs("blob"))
+ return resolveBlobUrl(url);
+#endif
+ return url;
+}
+
static inline QByteArray stringToByteArray(const String& string)
{
if (string.is8Bit())
@@ -99,13 +121,7 @@ static inline QByteArray stringToByteArray(const String& string)
QNetworkRequest ResourceRequest::toNetworkRequest(NetworkingContext *context) const
{
QNetworkRequest request;
- QUrl newurl = url();
-
-#if ENABLE(BLOB)
- if (newurl.scheme() == QLatin1String("blob"))
- resolveBlobUrl(url(), newurl);
-#endif
-
+ QUrl newurl = toQUrl(url());
request.setUrl(newurl);
request.setOriginatingObject(context ? context->originatingObject() : 0);
diff --git a/Source/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.cpp b/Source/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.cpp
index 0b811c8f2..e38c8b6b1 100644
--- a/Source/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.cpp
+++ b/Source/WebKit/qt/WebCoreSupport/FrameLoaderClientQt.cpp
@@ -1300,7 +1300,9 @@ void FrameLoaderClientQt::startDownload(const WebCore::ResourceRequest& request,
if (!m_webFrame)
return;
- m_webFrame->pageAdapter->emitDownloadRequested(request.toNetworkRequest(m_frame->loader()->networkingContext()));
+ QNetworkRequest r = request.toNetworkRequest(m_frame->loader()->networkingContext());
+ if (r.url().isValid())
+ m_webFrame->pageAdapter->emitDownloadRequested(r);
}
PassRefPtr<Frame> FrameLoaderClientQt::createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement, const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight)
diff --git a/Tools/QtTestBrowser/launcherwindow.cpp b/Tools/QtTestBrowser/launcherwindow.cpp
index 0cb0ab2ce..b40a78c8b 100644
--- a/Tools/QtTestBrowser/launcherwindow.cpp
+++ b/Tools/QtTestBrowser/launcherwindow.cpp
@@ -1118,9 +1118,13 @@ void LauncherWindow::downloadRequest(const QNetworkRequest &request)
void LauncherWindow::fileDownloadFinished()
{
- QFileInfo fileInf(m_reply->request().url().toString());
- QString requestFileName = QDir::homePath() + "/" + fileInf.fileName();
- QString fileName = QFileDialog::getSaveFileName(this, "Save as...", requestFileName, "All Files (*)");
+ QString suggestedFileName;
+ if (m_reply->request().url().scheme().toLower() != QLatin1String("data")) {
+ QFileInfo fileInf(m_reply->request().url().toString());
+ suggestedFileName = QDir::homePath() + "/" + fileInf.fileName();
+ } else
+ suggestedFileName = QStringLiteral("data");
+ QString fileName = QFileDialog::getSaveFileName(this, "Save as...", suggestedFileName, "All Files (*)");
if (fileName.isEmpty())
return;