diff options
author | Fabian Kosmale <fabian.kosmale@qt.io> | 2023-01-19 10:56:50 +0100 |
---|---|---|
committer | Fabian Kosmale <fabian.kosmale@qt.io> | 2023-01-24 11:25:42 +0100 |
commit | 2135f6b2aa816b57b43a0863d4d284c715433ee8 (patch) | |
tree | 470f774e76cf3d917d47d2dda63f12fb123c6a69 | |
parent | d0f1aed1c62f23e2f80afd2981201eda58f5be19 (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.cpp | 5 | ||||
-rw-r--r-- | tests/auto/qml/qjsengine/tst_qjsengine.cpp | 12 |
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" |