Access Violation on IsPatternMatching -> JS_GetProperty -> JS_ForwardGetPropertyTo
Categories
(Core :: JavaScript Engine, defect, P2)
Tracking
()
People
(Reporter: sourc7, Assigned: bthrall)
References
(Blocks 2 open bugs)
Details
(Keywords: csectype-oom, reporter-external, sec-moderate, Whiteboard: [reporter-external] [client-bounty-form] [verif?] [adv-main117+] [adv-esr115.2+])
Attachments
(9 files)
735.62 KB,
text/html
|
Details | |
8.36 KB,
text/plain
|
Details | |
3.37 KB,
text/plain
|
Details | |
3.57 KB,
text/plain
|
Details | |
48 bytes,
text/x-phabricator-request
|
RyanVM
:
approval-mozilla-esr115+
|
Details | Review |
48 bytes,
text/x-phabricator-request
|
RyanVM
:
approval-mozilla-esr115+
|
Details | Review |
48 bytes,
text/x-phabricator-request
|
RyanVM
:
approval-mozilla-esr115+
|
Details | Review |
48 bytes,
text/x-phabricator-request
|
Details | Review | |
430 bytes,
text/plain
|
Details |
After allocate memory to exhaust the process virtual memory and execute invalid JS function inside try {} catch() {} and input pattern. On Firefox 32-bit it able to crash on JS_GetProperty on address 0x000083d8, more interestingly on Firefox 64-bit it able to crash on dynamic (changing) address including 0x00050512fab2b080, 0x000514975972b080, 0x000526aa3e72b080, and more..
Currently the testcase.html is fine-tuned to make it very reliably to reproduce on Firefox 114.0.1 (32-bit) on Windows 11, I tested this very reliably crash on JS_GetProperty on both my machine Intel i9-13900k and AMD Ryzen 7 5700G, it still able to crash on Firefox Nightly 116.0a1 (2023-06-16) (32-bit), but reduced success rate and have to adjust fillMemory code to make it very reliably on Nightly. For now I decided to submit this report and adjust that later.
Tested on:
- Firefox 114.0.1 (32-bit)
- Firefox 114.0.1 (64-bit)
- Firefox Nightly 116.0a1 (2023-06-16) (32-bit)
- Firefox Nightly 116.0a1 (2023-06-16) (64-bit)
Steps to reproduce:
- Open Firefox 114.0.1 (32-bit)
- Visit attached testcase.html
- Wait ~20 seconds
- Firefox tab crashed
- Analyze the minidump using WinDbg
- Firefox crash on JS_GetProperty -> JS_ForwardGetPropertyTo
Reporter | ||
Comment 1•2 years ago
|
||
Reporter | ||
Comment 2•2 years ago
|
||
Reporter | ||
Comment 3•2 years ago
|
||
Updated•2 years ago
|
Updated•2 years ago
|
Updated•2 years ago
|
Comment 4•2 years ago
|
||
Looking at the attached stacks, nsContentUtils::IsPatternMatching() is here:
ReportPatternCompileFailure(aPattern, aDocument, &error, cx);
I'm guessing that is on this line, because that's the only call to JS_GetProperty
in the file:
if (!JS_GetProperty(cx, exnObj, "message", &messageVal)) {
I'm not sure how we're getting into IsPatternMatching, though.
Comment 5•2 years ago
|
||
Because of the testcase setting inputElement.pattern, so when then later value is updated using setRangeText, that triggers HasPatternMismatch() call, I believe through https://searchfox.org/mozilla-central/rev/4e8f62a231e71dc53eb50b6d74afca21d6b254e9/dom/html/HTMLInputElement.cpp#6800,6814
Comment 6•2 years ago
|
||
Isn't this more a JS engine issue. I don't immediately see anything unusual on the DOM side.
Comment 8•2 years ago
|
||
(In reply to Olli Pettay [:smaug][bugs@pettay.fi] from comment #6)
Isn't this more a JS engine issue. I don't immediately see anything unusual on the DOM side.
If this is unrelated to the DOM, would there be a way to convert the failing test case into one which does not rely on the DOM?
Reporter | ||
Comment 9•2 years ago
|
||
Ok great! I got the root cause of memory allocation failure that cause the access violation, I'll post the detail soon.
Reporter | ||
Comment 10•2 years ago
|
||
The testcase.html is set inputElement.pattern
that invokensContentUtils::IsPatternMatching
to do JS::CheckRegExpSyntax
-> js::FrontendContext::convertToRuntimeError
-> js::ErrorToException
-> js::CopyErrorReport
On CopyErrorHelper
it do calloc
to allocate the uint8_t* cursor
using cx->pod_calloc<uint8_t>(mallocSize);
then when calloc
failure, the cursor
is set to null
then as if (!cursor) {
the function will return nullptr;
When the calloc
is failure at first try, it look like the js::CopyErrorReport
is also call to JSRuntime::onOutOfMemory
to try do GC, but it still return the nullptr
for the uint8_t* cursor
. Then js::ErrorToException
check if (!report) {
it will call return
After the fc.convertToRuntimeErrorAndClear();
function is called, then the JS::CheckRegExpSyntax
will return true;
cause nsContentUtils::IsPatternMatching
to pass the return Nothing()
so it go inside if (!error.isUndefined()) {
to call ReportPatternCompileFailure(aPattern, aDocument, &error, cx);
, the function call JS_GetProperty(cx, exnObj, "message", &messageVal)
-> JS_ForwardGetPropertyTo
-> check
-> checkImpl
-> check
-> compartment
-> shape
-> headerPtr
then crash at get
Comment 11•2 years ago
|
||
Thanks for the report!
This indeed sounds like a JS engine issue then, and now I know who to forward it to.
Bryan it sounds like JS::CheckRegExpSyntax
does not behave as described in its declaration, by discarding the error and returning true.
I suspect the problem comes from either not setting or clearing the FrontendContext OutOfMemory flag ahead of returning into JS::CheckRegExpSyntax
.
Updated•2 years ago
|
Updated•2 years ago
|
Assignee | ||
Comment 12•2 years ago
|
||
I'll take a look!
Updated•2 years ago
|
Reporter | ||
Comment 13•2 years ago
|
||
(In reply to Irvan Kurniawan (:sourc7) from comment #0)
it still able to crash on Firefox Nightly 116.0a1 (2023-06-16) (32-bit), but reduced success rate and have to adjust fillMemory code to make it very reliably on Nightly.
Ok, after testing for a while, the attached testcase.html is also very reliable on Firefox Nightly 117.0a1 (2023-07-13) (32-bit), when testing 20 times on ffpuppet launcher I can get 20 times success, 0 failure on Intel i9-13900k and AMD Ryzen 7 5700G.
When attach the process with WinDbg, I able to capture the access-violation crash, on crash stack index [0xb]
the xul!ReportPatternCompileFailure
code if (!JS_GetProperty(cx, exnObj, "message", &messageVal)) {
the exnObj
variable exnObj->ptr->header_->value_
value already set to 0x83d8
, then on stack [0x0]
the xul!js::gc::HeaderWord::get
code uintptr_t value = value_;
the this
local name is set to 0x83d8
which is the crash address.
Assignee | ||
Comment 14•2 years ago
|
||
It looks like the problem is that fc.convertToRuntimeErrorAndClear();
allocates memory, so it can trigger OOM.
This can cause JS::CheckRegExpSyntax()
to return true when it should return false in the following scenario:
JS::CheckRegExpSyntax()
is called with a string that has invalid syntaxirregexp::CheckPatternSyntax()
returns false and sets SyntaxError on the FrontendContextJS::CheckRegExpSyntax()
follows the failure path and calls fc.convertToRuntimeErrorAndClear()convertToRuntimeErrorAndClear()
triggers OOM and sets a pending OOM exception on the JSContextJS::CheckRegExpSyntax()
extracts the OOM exception, thinking it is the SyntaxError, and returns true
I should have a patch to correctly check for OOM in convertToRuntimeErrorAndClear()
soon.
Thanks for the detailed analysis, :sourc7, it was really helpful in diagnosing the problem!
Assignee | ||
Comment 15•2 years ago
|
||
It is simpler to think about ErrorToException returning true when the error is
correctly converted, which is why it returns false on recursion even though you
could argue that nothing went wrong in that case.
Assignee | ||
Comment 16•2 years ago
|
||
Depends on D184160
Assignee | ||
Comment 17•2 years ago
|
||
In that case, the error stored in cx is an OOM rather than the expected
SyntaxError. CheckRegExpSyntax should return false in that case.
Depends on D184161
Assignee | ||
Comment 18•2 years ago
|
||
Depends on D184162
Assignee | ||
Comment 19•2 years ago
|
||
Landing patches D184160, D184161, and D184162 without sec-approval because this is marked sec-moderate.
Patch D184254 contains tests and will be landed at a later time, according to security procedure.
Comment 20•2 years ago
|
||
![]() |
||
Comment 21•2 years ago
|
||
https://hg.mozilla.org/mozilla-central/rev/599e241178d6
https://hg.mozilla.org/mozilla-central/rev/880d3a8b52ba
https://hg.mozilla.org/mozilla-central/rev/ea812280de66
Updated•2 years ago
|
Comment 22•2 years ago
|
||
Comment on attachment 9345111 [details]
Bug 1839007 - Add CheckRegExpSyntax jit-test r=arai
Revision D184254 was moved to bug 1845132. Setting attachment 9345111 [details] to obsolete.
Updated•2 years ago
|
Comment 23•2 years ago
|
||
We're going to leave the severity at moderate because so far the read access violation is only for a fixed offset (slightly varying with the base allocation pointer in 64 bits, but that doesn't appear to be under your control). If there's a way to get more control over the read address we'd consider raising the severity.
Updated•2 years ago
|
Assignee | ||
Comment 24•2 years ago
|
||
Comment on attachment 9344931 [details]
Bug 1839007 - Return bool from ErrorToException r=arai
ESR Uplift Approval Request
- If this is not a sec:{high,crit} bug, please state case for ESR consideration: This is a small change that improves content tab stability in low-memory situations and there is a low risk of applying it.
- User impact if declined: There is a chance of crashing the content tab in low-memory situations when the JavaScript executes an invalid regular expression.
- Fix Landed on Version: 117
- Risk to taking this patch: Low
- Why is the change risky/not risky? (and alternatives if risky): The change only effects the code path in the case of an invalid regular expression, so only websites with broken regular expressions could potentially see any change in behavior. The change is also isolated to a small number of files and applies cleanly to the esr115 release commit.
Assignee | ||
Updated•2 years ago
|
Updated•2 years ago
|
Updated•2 years ago
|
Comment 25•2 years ago
|
||
Managed to reproduce the crash on Firefox Firefox 114.0.1 (32-bit) and on Firefox Nightly 116.0a1 (2023-06-16) (32-bit) on Windows 11 and Windows 10.
The crash is still reproducible on the latest Firefox Nightly 118.0a1 (2023-08-04) x32 on both Windows 11/10.
Bryan, could you please take a look at this to see if it's also reproducible on your side?
Thanks.
Assignee | ||
Comment 26•2 years ago
|
||
Unfortunately, the testcase for this bug eats up all the memory available to the tab, so the tab will crash even if the bug is fixed. I'm sorry for not making that clear earlier!
Does Firefox have different behavior if a tab crashes because of OOM vs. other crashes? That might be one way to verify the bug is fixed.
I'm also looking at verifying that the code behaves as I expect on current mozilla-central using a debugger.
Comment 27•2 years ago
|
||
I didn't see any different behavior between the two builds, they even crashed at approximative the same time.
Could you please mark this bug as verified after verifying that the code behaves as I expect on current mozilla-central using a debugger?
Thanks.
Comment 28•1 years ago
|
||
Comment on attachment 9344931 [details]
Bug 1839007 - Return bool from ErrorToException r=arai
Approved for 115.2esr.
Updated•1 years ago
|
Updated•1 years ago
|
Comment 29•1 years ago
|
||
uplift |
Updated•1 years ago
|
Assignee | ||
Comment 30•1 years ago
|
||
I couldn't get the attached testcase to reproduce the same memory failure as it originally did, but I was able to use a debugger to do so and verify that mozilla-central, including the patches for this bug, handles the OOM correctly now.
Specifically, when an OOM happens while converting the FrontendContext error to a JSContext error, JS::CheckRegExpSyntax()
returns false, which is the documented behavior.
Comment 31•1 years ago
|
||
Removing qa-verify+ since we couldn't verify this issue on our end.
Comment 32•1 years ago
|
||
Updated•1 years ago
|
Updated•1 years ago
|
Updated•1 years ago
|
Updated•1 year ago
|
Comment 33•1 year ago
|
||
Comment 34•1 year ago
|
||
Updated•1 year ago
|
Updated•1 year ago
|
Updated•8 months ago
|
Description
•