aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2023-09-21 09:50:27 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2023-10-06 20:04:21 +0000
commitb47065e311994440cf2b9804690fac26ebdb17f4 (patch)
tree33fec10942e732bb37ee6e39569a1fa4aedf1d72
parent0eac64695c427882112b70a89bdf7da98d7fd945 (diff)
QML diskcache: Verify cache file size
We can't rely on the checksum verification, as we still assume that we can read all bytes in the range claimed by the unit's header. If for some reason the cache file has been truncated, that will lead to crashes due to out-of-bound reads. As we already store the unit's size in the header, use it for an initial verification before doing any further work. Initial test case was provided by Harald Sitter <sitter@kde.org>. Pick-to: 6.5 6.2 5.15 Fixes: QTBUG-117130 Change-Id: Idd20191ed0e0ef9c37985c4c64124578f0607ad3 Reviewed-by: Semih Yavuz <semih.yavuz@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> (cherry picked from commit 7a3db863f4edda12a8dda36b807ef64e98f2046f) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/qml/jsruntime/qv4compilationunitmapper_unix.cpp10
-rw-r--r--src/qml/jsruntime/qv4compilationunitmapper_win.cpp17
-rw-r--r--tests/auto/qml/qmlcachegen/data/truncateTest.qml764
-rw-r--r--tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp19
4 files changed, 810 insertions, 0 deletions
diff --git a/src/qml/jsruntime/qv4compilationunitmapper_unix.cpp b/src/qml/jsruntime/qv4compilationunitmapper_unix.cpp
index d7364f8706..7b8178fe84 100644
--- a/src/qml/jsruntime/qv4compilationunitmapper_unix.cpp
+++ b/src/qml/jsruntime/qv4compilationunitmapper_unix.cpp
@@ -43,6 +43,16 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co
// Data structure and qt version matched, so now we can access the rest of the file safely.
length = static_cast<size_t>(lseek(fd, 0, SEEK_END));
+ /* Error out early on file corruption. We assume we can read header.unitSize bytes
+ later (even before verifying the checksum), potentially causing out-of-bound
+ reads
+ Also, no need to wait until checksum verification if we know beforehand
+ that the cached unit is bogus
+ */
+ if (length != header.unitSize) {
+ *errorString = QStringLiteral("Potential file corruption, file too small");
+ return nullptr;
+ }
void *ptr = mmap(nullptr, length, PROT_READ, MAP_SHARED, fd, /*offset*/0);
if (ptr == MAP_FAILED) {
diff --git a/src/qml/jsruntime/qv4compilationunitmapper_win.cpp b/src/qml/jsruntime/qv4compilationunitmapper_win.cpp
index 2ea54ce286..9ac4085453 100644
--- a/src/qml/jsruntime/qv4compilationunitmapper_win.cpp
+++ b/src/qml/jsruntime/qv4compilationunitmapper_win.cpp
@@ -50,6 +50,23 @@ CompiledData::Unit *CompilationUnitMapper::open(const QString &cacheFileName, co
// Data structure and qt version matched, so now we can access the rest of the file safely.
+ /* Error out early on file corruption. We assume we can read header.unitSize bytes
+ later (even before verifying the checksum), potentially causing out-of-bound
+ reads
+ Also, no need to wait until checksum verification if we know beforehand
+ that the cached unit is bogus
+ */
+ LARGE_INTEGER fileSize;
+ if (!GetFileSizeEx(handle, &fileSize)) {
+ *errorString = QStringLiteral("Could not determine file size");
+ return nullptr;
+ }
+ if (header.unitSize != fileSize.QuadPart) {
+ *errorString = QStringLiteral("Potential file corruption, file too small");
+ return nullptr;
+ }
+
+
HANDLE fileMappingHandle = CreateFileMapping(handle, 0, PAGE_READONLY, 0, 0, 0);
if (!fileMappingHandle) {
*errorString = qt_error_string(GetLastError());
diff --git a/tests/auto/qml/qmlcachegen/data/truncateTest.qml b/tests/auto/qml/qmlcachegen/data/truncateTest.qml
new file mode 100644
index 0000000000..fee768cf77
--- /dev/null
+++ b/tests/auto/qml/qmlcachegen/data/truncateTest.qml
@@ -0,0 +1,764 @@
+import QtQuick 2.15
+import QtQuick.Layouts 2.15
+
+Item {
+ width: 400
+ height: 400
+
+ component Button : Item {
+ property string text
+ property Item background
+ }
+
+ ColumnLayout {
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+ Button {
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: "red"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+
+ }
+}
diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
index 60d4a5df32..52979539a2 100644
--- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
+++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp
@@ -63,6 +63,8 @@ private slots:
void inlineComponent();
void posthocRequired();
+ void gracefullyHandleTruncatedCacheFile();
+
void scriptStringCachegenInteraction();
void saveableUnitPointer();
};
@@ -839,6 +841,23 @@ void tst_qmlcachegen::posthocRequired()
qPrintable(component.errorString()));
}
+void tst_qmlcachegen::gracefullyHandleTruncatedCacheFile()
+{
+#if defined(QTEST_CROSS_COMPILED)
+ QSKIP("Cannot call qmlcachegen on cross-compiled target.");
+#endif
+
+ bool ok = generateCache(testFile("truncateTest.qml"));
+ QVERIFY(ok);
+ const QString qmlcFile = testFile("truncateTest.qmlc");
+ QVERIFY(QFile::exists(qmlcFile));
+ QFile::resize(qmlcFile, QFileInfo(qmlcFile).size() / 2);
+ QQmlEngine engine;
+ CleanlyLoadingComponent component(&engine, testFileUrl("truncateTest.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+}
+
void tst_qmlcachegen::scriptStringCachegenInteraction()
{
#if defined(QTEST_CROSS_COMPILED)