Open Bug 1927354 Opened 1 year ago Updated 1 year ago

Access violation due to memory overflow when using large ArrayBuffer and Web Workers (`MOZ_RELEASE_ASSERT(obj->is<PromiseReactionRecord>());`)

Categories

(Core :: JavaScript Engine, defect, P3)

defect

Tracking

()

People

(Reporter: Laraweron, Unassigned)

References

(Blocks 1 open bug)

Details

(Keywords: csectype-oom, reporter-external, Whiteboard: [client-bounty-form])

Attachments

(4 files)

Attached file poc.html

During testing of the Firefox Nightly build with AddressSanitizer (Asan) enabled, a vulnerability related to the use of the ArrayBuffer object for allocating large amounts of memory (over 2 GB) was discovered. When creating numerous such buffers in a loop, the browser begins to consume all available resources, which can lead to an Out of Memory error. Notably, similar crashes have only been recorded in the Firefox Nightly Asan build, while the stable version of Firefox does not exhibit this issue.

The test involved creating multiple ArrayBuffer buffers with sizes exceeding 2 GB in both the main thread and child processes implemented via Web Workers. As a result of this approach:

The browser begins consuming all available physical and virtual memory.
This leads to a crash with an Out of Memory error or a memory access violation.
In scenarios with Web Workers, the crash occurred simultaneously in the ArrayBuffer process and in child workers, which may indicate incorrect memory management in multithreaded environments.
Based on the test results, the following potential issues were identified:

Race Condition: The crash may be caused by a race condition where multiple workers simultaneously attempt to allocate memory or access it.
Use-After-Free: There is a possibility that the error is caused by an attempt to access already freed memory.
Lack of Optimization in Debug Build: The error may be a result of the characteristics of the debug build of Firefox Nightly with Asan enabled, which can also affect the performance and correctness of memory allocation.
After running the script, open another resource-intensive tab in parallel, such as YouTube or another site with intensive resource usage.
When performing these steps, both tabs often crash simultaneously.

Flags: sec-bounty?
Attached file ff_asan_log.txt

According to the asan log this is crashing on a MOZ_RELEASE_ASSERT() at https://searchfox.org/mozilla-central/rev/552c57cbb4eb9d6ae55a53cff217861f21c3ce6d/js/src/builtin/Promise.cpp#6375

We use these asserts to crash intentionally when we think that's safer than continuing on with the unexpected error we found. But the release-assert would also have crashed in release, if it was hit. Is it just that the ASAN build changes the timing?

I don't know if this is really a worker issue, but they're definitely heavily involved in the testcase and ASAN stack so let's start there.

Group: firefox-core-security → dom-core-security
Component: Security → DOM: Workers
Product: Firefox → Core
Summary: Access violation due to memory overflow when using large ArrayBuffer and Web Workers → Access violation due to memory overflow when using large ArrayBuffer and Web Workers (`MOZ_RELEASE_ASSERT(obj->is<PromiseReactionRecord>());`)

The creation of large ArrayBuffer objects leads to conditions that trigger OOM (Out Of Memory) errors. Restricting these conditions and applying proper optimizations will likely solve the problem, but it is observed specifically in the Firefox Nightly build with AddressSanitizer. When OOM occurs, other functions can also crash (such as neighboring tabs or processes involved in the workload), creating conditions for memory manipulation. By using Web Workers, it is possible to control the process and deliberately induce race conditions to attempt accessing already freed memory segments.

During testing, I received several AddressSanitizer logs that differed from the initial one. When an active YouTube tab was present, a crash also occurred in gfx/angle/checkout/src/libANGLE with an access-violation at an unknown address 0x000000000068.

Using this script provides a 90% probability of provoking an access-violation error in AddressSanitizer, but obtaining a full trace of the error can be challenging.

Attached file asan_log_gfx.txt
Attached file anan_log_full.txt

If the problem here is that the test case is creating a lot of very large ArrayBuffer on multiple threads, that feels like more of a SpiderMonkey issue. I'll move it there and leave some DOM Workers people on the CC list.

Group: dom-core-security → javascript-core-security
Component: DOM: Workers → JavaScript Engine

I'm still not clear on whether this is really a security problem, at least based on the stacks that have been provided so far. Like dveditz said, ff_asan_log.txt is hitting a release assert, which is safe. asan_log_gfx.txt is a null deref (inside a graphics driver), which is also probably safe. anan_log_full.txt is a crash inside ASan's allocator function, inside some Windows system call. Hard to say if that's really a security problem or if that's just the Windows allocator crashing in some safe way in OOM conditions.

(In reply to Andrew McCreight [:mccr8] from comment #7)

I'm still not clear on whether this is really a security problem, at least based on the stacks that have been provided so far. Like dveditz said, ff_asan_log.txt is hitting a release assert, which is safe. asan_log_gfx.txt is a null deref (inside a graphics driver), which is also probably safe. anan_log_full.txt is a crash inside ASan's allocator function, inside some Windows system call. Hard to say if that's really a security problem or if that's just the Windows allocator crashing in some safe way in OOM conditions.

Once I managed to get a warning in the Stable version of Firefox. I reduced the Windows swap file to 16 MB. The browser crashed with various errors, I couldn't track it down again using WinDbg. If this happens again, I'll provide a report. Through a debugger.

(In reply to Raphael from comment #9)

https://crash-stats.mozilla.org/report/index/6990c38a-6784-4275-8767-8f1410241028

A short peek at that crash shows EXCEPTION_STACK_OVERFLOW on an apparently not insanely deep stack. There seems to be a Windows-internal RPC call ongoing that raises an exception, so I wonder if the overflow did happen in that other (system?) process (which would be largely out of our direct control) and we are just getting it thrown here at the call-site. The RPC seems to be a DNS lookup. How typical is this stack for what you are seeing here as a consequence for the above mentioned OOM?

The page file is extremely small (typical of a Windows OOM) so maybe it ran out of memory when trying to allocate more memory for the stack and that turns into STACK_OVERFLOW? I'm not sure how that would look.

I intentionally decreased the swap file to deliberately induce a crash in the Stable version. The crash reports vary, and I haven't been able to catch the error using a debugger due to the infrequent crashes. In the Stable version, unlike the Asan version, the garbage collector performs better. I think this is why it's impossible to achieve a controlled crash; it happens randomly.

https://crash-stats.mozilla.org/report/index/98c3ba8e-520c-40b5-977a-e2d650241028
https://crash-stats.mozilla.org/report/index/ab60e18f-282b-4441-aacf-78f4f0241028
https://crash-stats.mozilla.org/report/index/548ba7e6-eda8-492d-a08e-1c48c0241028

Severity: -- → S3
Priority: -- → P3

The nice thing about random is that it would be extremely hard to turn into an exploit, even if one of the crashes here turn out to be exploitable. The fact that it requires ASAN builds might be because ASAN uses a bunch of memory to keep track of allocations.

Group: javascript-core-security
Keywords: csectype-oom

Unless this can be shown to cause a somewhat reliable exploitable-looking crash, this seems like a denial of service.

Flags: sec-bounty? → sec-bounty-
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: