summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorØystein Heskestad <oystein.heskestad@qt.io>2021-03-03 12:23:18 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-03-07 07:56:21 +0000
commit03332d8a000816cc5736a9d65404a3d247b79bed (patch)
tree96eb0673333bb59c4647265d2f613c18a29c9a89
parent218b7c8a5bbc540324d45bad752f328799f97b95 (diff)
Make qdecompresshelper archive bomb check only trigger for large files
This is to avoid false positives. By default files are large if uncompressed size > 10 MB. Only configurable internally. Also add auto tests. Task-number: QTBUG-91392 Change-Id: I32258cb7c957f2a23a05157ba4ed5c0af2ba585e Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> (cherry picked from commit be73ca7eb1cebcc15064666e647bc337b5c2baa2) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/network/access/qdecompresshelper.cpp8
-rw-r--r--src/network/access/qdecompresshelper_p.h2
-rw-r--r--tests/auto/network/access/qdecompresshelper/10K.gzbin0 -> 55 bytes
-rw-r--r--tests/auto/network/access/qdecompresshelper/tst_qdecompresshelper.cpp40
4 files changed, 50 insertions, 0 deletions
diff --git a/src/network/access/qdecompresshelper.cpp b/src/network/access/qdecompresshelper.cpp
index 2e44a58cf4..d0e75ef0dc 100644
--- a/src/network/access/qdecompresshelper.cpp
+++ b/src/network/access/qdecompresshelper.cpp
@@ -405,6 +405,11 @@ void QDecompressHelper::setArchiveBombDetectionEnabled(bool enable)
countHelper->setArchiveBombDetectionEnabled(enable);
}
+void QDecompressHelper::setMinimumArchiveBombSize(qint64 threshold)
+{
+ minimumArchiveBombSize = threshold;
+}
+
bool QDecompressHelper::isPotentialArchiveBomb() const
{
if (!archiveBombDetectionEnabled)
@@ -413,6 +418,9 @@ bool QDecompressHelper::isPotentialArchiveBomb() const
if (totalCompressedBytes == 0)
return false;
+ if (totalUncompressedBytes <= minimumArchiveBombSize)
+ return false;
+
// Some protection against malicious or corrupted compressed files that expand far more than
// is reasonable.
double ratio = double(totalUncompressedBytes) / double(totalCompressedBytes);
diff --git a/src/network/access/qdecompresshelper_p.h b/src/network/access/qdecompresshelper_p.h
index 4e66581022..6a77775790 100644
--- a/src/network/access/qdecompresshelper_p.h
+++ b/src/network/access/qdecompresshelper_p.h
@@ -92,6 +92,7 @@ public:
void clear();
void setArchiveBombDetectionEnabled(bool enable);
+ void setMinimumArchiveBombSize(qint64 threshold);
static bool isSupportedEncoding(const QByteArray &encoding);
static QByteArrayList acceptedEncoding();
@@ -119,6 +120,7 @@ private:
// Used for calculating the ratio
bool archiveBombDetectionEnabled = true;
+ qint64 minimumArchiveBombSize = 10 * 1024 * 1024;
qint64 totalUncompressedBytes = 0;
qint64 totalCompressedBytes = 0;
diff --git a/tests/auto/network/access/qdecompresshelper/10K.gz b/tests/auto/network/access/qdecompresshelper/10K.gz
new file mode 100644
index 0000000000..c5c4959763
--- /dev/null
+++ b/tests/auto/network/access/qdecompresshelper/10K.gz
Binary files differ
diff --git a/tests/auto/network/access/qdecompresshelper/tst_qdecompresshelper.cpp b/tests/auto/network/access/qdecompresshelper/tst_qdecompresshelper.cpp
index c31ab294cc..cfeff188f4 100644
--- a/tests/auto/network/access/qdecompresshelper/tst_qdecompresshelper.cpp
+++ b/tests/auto/network/access/qdecompresshelper/tst_qdecompresshelper.cpp
@@ -64,6 +64,9 @@ private Q_SLOTS:
void decompressBigData_data();
void decompressBigData();
+ void archiveBomb_data();
+ void archiveBomb();
+
#if QT_POINTER_SIZE >= 8
void bigZlib();
#endif
@@ -392,6 +395,43 @@ void tst_QDecompressHelper::decompressBigData()
QTEST(totalSize, "size");
}
+void tst_QDecompressHelper::archiveBomb_data()
+{
+ QTest::addColumn<QByteArray>("encoding");
+ QTest::addColumn<QString>("path");
+ QTest::addColumn<bool>("shouldFail");
+
+ QTest::newRow("gzip-10K") << QByteArray("gzip") << (srcDir + "/10K.gz") << false;
+ QTest::newRow("gzip-4G") << QByteArray("gzip") << QString(":/4G.gz") << true;
+}
+
+void tst_QDecompressHelper::archiveBomb()
+{
+ QFETCH(bool, shouldFail);
+ QFETCH(QString, path);
+ QFile file(path);
+ QVERIFY(file.open(QIODevice::ReadOnly));
+
+ QDecompressHelper helper;
+ QFETCH(QByteArray, encoding);
+ helper.setEncoding(encoding);
+ QVERIFY(helper.isValid());
+
+ constexpr qint64 SafeSizeLimit = 10 * 1024 * 1024;
+ constexpr qint64 RatioLimit = 40;
+ qint64 bytesToRead = std::min(SafeSizeLimit / RatioLimit, file.bytesAvailable());
+ QByteArray output(1 + bytesToRead * RatioLimit, Qt::Uninitialized);
+ helper.feed(file.read(bytesToRead));
+ qsizetype bytesRead = helper.read(output.data(), output.size());
+ QVERIFY(bytesRead <= output.size());
+ QVERIFY(helper.isValid());
+
+ if (shouldFail)
+ QCOMPARE(bytesRead, -1);
+ else
+ QVERIFY(bytesRead > 0);
+}
+
#if QT_POINTER_SIZE >= 8
void tst_QDecompressHelper::bigZlib()
{