From 783d574b932288b61f915b28d5b7b9c5a979f58e Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 6 Mar 2020 13:38:17 -0800 Subject: CBOR support: prevent overflowing QByteArray's max allocation QByteArray doesn't like it. Apply the same protection to QString, which we know uses the same backend but uses elements twice as big. That means it can contain slightly more than half as many elements, but exact half will suffice for our needs. Change-Id: Iaa63461109844e978376fffd15f9d4c7a9137856 Reviewed-by: Edward Welbourne --- .../serialization/qcborvalue/tst_qcborvalue.cpp | 52 +++++++++++++++++----- 1 file changed, 42 insertions(+), 10 deletions(-) (limited to 'tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp') diff --git a/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp b/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp index 49bb9cc144..488771d059 100644 --- a/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp +++ b/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 Intel Corporation. +** Copyright (C) 2020 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -40,6 +40,8 @@ #include #include +#include + Q_DECLARE_METATYPE(QCborKnownTags) Q_DECLARE_METATYPE(QCborValue) Q_DECLARE_METATYPE(QCborValue::EncodingOptions) @@ -102,6 +104,8 @@ private slots: void fromCborStreamReaderIODevice(); void validation_data(); void validation(); + void hugeDeviceValidation_data(); + void hugeDeviceValidation(); void recursionLimit_data(); void recursionLimit(); void toDiagnosticNotation_data(); @@ -1689,10 +1693,17 @@ void tst_QCborValue::fromCborStreamReaderIODevice() fromCbor_common(doCheck); } +#include "../cborlargedatavalidation.cpp" + void tst_QCborValue::validation_data() { + // Add QCborStreamReader-specific limitations due to use of QByteArray and + // QString, which are allocated by QArrayData::allocate(). + const qsizetype MaxInvalid = std::numeric_limits::max(); + const qsizetype MinInvalid = MaxByteArraySize + 1; addValidationColumns(); - addValidationData(); + addValidationData(MinInvalid); + addValidationLargeData(MinInvalid, MaxInvalid); // These tests say we have arrays and maps with very large item counts. // They are meant to ensure we don't pre-allocate a lot of memory @@ -1700,28 +1711,49 @@ void tst_QCborValue::validation_data() // elements in the stream is only 2, so we should get an unexpected EOF // error. QCborValue internally uses 16 bytes per element, so we get to // 2 GB at 2^27 elements. - QTest::addRow("very-large-array-no-overflow") << raw("\x9a\x07\xff\xff\xff" "\0\0"); - QTest::addRow("very-large-array-overflow1") << raw("\x9a\x40\0\0\0" "\0\0"); + QTest::addRow("very-large-array-no-overflow") << raw("\x9a\x07\xff\xff\xff" "\0\0") << 0 << CborErrorUnexpectedEOF; + QTest::addRow("very-large-array-overflow1") << raw("\x9a\x40\0\0\0" "\0\0") << 0 << CborErrorUnexpectedEOF; // this makes sure we don't accidentally clip to 32-bit: sending 2^32+2 elements - QTest::addRow("very-large-array-overflow2") << raw("\x9b\0\0\0\1""\0\0\0\2" "\0\0"); + QTest::addRow("very-large-array-overflow2") << raw("\x9b\0\0\0\1""\0\0\0\2" "\0\0") << 0 << CborErrorDataTooLarge; } void tst_QCborValue::validation() { QFETCH(QByteArray, data); + QFETCH(CborError, expectedError); + QCborError error = { QCborError::Code(expectedError) }; - QCborParserError error; - QCborValue decoded = QCborValue::fromCbor(data, &error); - QVERIFY(error.error != QCborError{}); + QCborParserError parserError; + QCborValue decoded = QCborValue::fromCbor(data, &parserError); + QCOMPARE(parserError.error, error); if (data.startsWith('\x81')) { // decode without the array prefix - decoded = QCborValue::fromCbor(data.mid(1), &error); - QVERIFY(error.error != QCborError{}); + char *ptr = const_cast(data.constData()); + QByteArray mid = QByteArray::fromRawData(ptr + 1, data.size() - 1); + decoded = QCborValue::fromCbor(mid, &parserError); + QCOMPARE(parserError.error, error); } } +void tst_QCborValue::hugeDeviceValidation_data() +{ + addValidationHugeDevice(MaxByteArraySize + 1, MaxStringSize + 1); +} + +void tst_QCborValue::hugeDeviceValidation() +{ + QFETCH(QSharedPointer, device); + QFETCH(CborError, expectedError); + QCborError error = { QCborError::Code(expectedError) }; + + device->open(QIODevice::ReadOnly | QIODevice::Unbuffered); + QCborStreamReader reader(device.data()); + QCborValue decoded = QCborValue::fromCbor(reader); + QCOMPARE(reader.lastError(), error); +} + void tst_QCborValue::recursionLimit_data() { constexpr int RecursionAttempts = 4096; -- cgit v1.2.3 From bff56f953adc8ce743aa774d6ad09725d8b9bc45 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 20 Mar 2020 17:55:31 -0300 Subject: tst_QCborValue: Prepare for 64-bit QVectors in Qt 6 Change-Id: Ief61acdfbe4d4b5ba1f0fffd15fe1e921aab0a72 Reviewed-by: Lars Knoll --- .../serialization/qcborvalue/tst_qcborvalue.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp') diff --git a/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp b/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp index 488771d059..6d8161c1f9 100644 --- a/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp +++ b/tests/auto/corelib/serialization/qcborvalue/tst_qcborvalue.cpp @@ -1709,13 +1709,21 @@ void tst_QCborValue::validation_data() // They are meant to ensure we don't pre-allocate a lot of memory // unnecessarily and possibly crash the application. The actual number of // elements in the stream is only 2, so we should get an unexpected EOF - // error. QCborValue internally uses 16 bytes per element, so we get to - // 2 GB at 2^27 elements. - QTest::addRow("very-large-array-no-overflow") << raw("\x9a\x07\xff\xff\xff" "\0\0") << 0 << CborErrorUnexpectedEOF; - QTest::addRow("very-large-array-overflow1") << raw("\x9a\x40\0\0\0" "\0\0") << 0 << CborErrorUnexpectedEOF; - - // this makes sure we don't accidentally clip to 32-bit: sending 2^32+2 elements - QTest::addRow("very-large-array-overflow2") << raw("\x9b\0\0\0\1""\0\0\0\2" "\0\0") << 0 << CborErrorDataTooLarge; + // error. QCborValue internally uses 16 bytes per element, so we get to 2 + // GB at 2^27 elements (32-bit) or, theoretically, 2^63 bytes at 2^59 + // elements (64-bit). + if (sizeof(QVector::size_type) == sizeof(int)) { + // 32-bit sizes (Qt 5 and 32-bit platforms) + QTest::addRow("very-large-array-no-overflow") << raw("\x9a\x07\xff\xff\xff" "\0\0") << 0 << CborErrorUnexpectedEOF; + QTest::addRow("very-large-array-overflow1") << raw("\x9a\x40\0\0\0" "\0\0") << 0 << CborErrorUnexpectedEOF; + + // this makes sure we don't accidentally clip to 32-bit: sending 2^32+2 elements + QTest::addRow("very-large-array-overflow2") << raw("\x9b\0\0\0\1""\0\0\0\2" "\0\0") << 0 << CborErrorDataTooLarge; + } else { + // 64-bit Qt 6 + QTest::addRow("very-large-array-no-overflow") << raw("\x9b\x07\xff\xff\xff" "\xff\xff\xff\xff" "\0\0"); + QTest::addRow("very-large-array-overflow") << raw("\x9b\x40\0\0\0" "\0\0\0\0" "\0\0"); + } } void tst_QCborValue::validation() -- cgit v1.2.3