aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2023-01-19 10:56:50 +0100
committerFabian Kosmale <fabian.kosmale@qt.io>2023-01-24 11:25:42 +0100
commit2135f6b2aa816b57b43a0863d4d284c715433ee8 (patch)
tree470f774e76cf3d917d47d2dda63f12fb123c6a69
parentd0f1aed1c62f23e2f80afd2981201eda58f5be19 (diff)
QJSEngine: Fix potential JS stack overflow cauased by spread operator
createSpreadArguments could in theory allocate a (nearly) unbounded number of QV4::Values. Avoid this by checking whether we approach jsStackTop. This fixes CVE-2022-43591. Change-Id: I01aecb979da47b7261688c9f185dc33a50a579a5 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> (cherry picked from commit 6511aa4344c1d47ede8546540fe70bdff8523545)
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp5
-rw-r--r--tests/auto/qml/qjsengine/tst_qjsengine.cpp12
2 files changed, 17 insertions, 0 deletions
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index f4dfc7850a..f07f7e38a1 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -1561,6 +1561,11 @@ static CallArgs createSpreadArguments(Scope &scope, Value *argv, int argc)
if (done->booleanValue())
break;
++argCount;
+ constexpr auto safetyMargin = 100; // leave some space on the stack for actual work with the elements
+ if (qint64(scope.engine->jsStackLimit - scope.engine->jsStackTop) < safetyMargin) {
+ scope.engine->throwRangeError(QLatin1String("Too many elements in array to use it with the spread operator"));
+ return { nullptr, 0 };
+ }
v = scope.alloc<Scope::Uninitialized>();
}
}
diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
index 6e15486d23..8c2f9ae645 100644
--- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp
+++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp
@@ -264,6 +264,8 @@ private slots:
void forOfAndGc();
void staticInNestedClasses();
+ void spreadNoOverflow();
+
public:
Q_INVOKABLE QJSValue throwingCppMethod1();
Q_INVOKABLE void throwingCppMethod2();
@@ -5620,6 +5622,16 @@ void tst_QJSEngine::staticInNestedClasses()
QCOMPARE(engine.evaluate(program).toString(), u"a"_s);
}
+void tst_QJSEngine::spreadNoOverflow()
+{
+ QJSEngine engine;
+
+ const QString program = QString::fromLatin1("var a = [] ;a.length = 555840;Math.max(...a)");
+ const QJSValue result = engine.evaluate(program);
+ QVERIFY(result.isError());
+ QCOMPARE(result.errorType(), QJSValue::RangeError);
+}
+
QTEST_MAIN(tst_QJSEngine)
#include "tst_qjsengine.moc"