Content-process null dereference in the popover opening path via re-entrant `removeAttribute("popover")` during autofocus handling
Categories
(Core :: DOM: Core & HTML, defect)
Tracking
()
| Tracking | Status | |
|---|---|---|
| firefox151 | --- | fixed |
People
(Reporter: liberty_rapid, Assigned: ltenenbaum)
References
Details
(4 keywords, Whiteboard: [client-bounty-form], [wptsync upstream])
Crash Data
Attachments
(2 files)
Description
I discovered this issue by running a minimized HTML testcase against an official Linux x86_64 Firefox Nightly AddressSanitizer (ASan) build, following Mozilla's ASan documentation and using fuzzfetch to obtain the build artifact. The testcase reliably triggers a null-pointer dereference in a content process when a popover is opened, its autofocus descendant receives focus, and the focus handler removes the popover attribute re-entrantly during showPopover().
Environment
- Product: Firefox Nightly (ASan CI build)
- Version:
151.0a1 - Build ID:
20260324002715 - Source revision:
acbfb05622cd827a7418d36628f75857628a81ce - Platform: Linux x86_64
- OS: Ubuntu 24.04.4 LTS
Reproduction
-
Download an official Linux ASan Nightly build. For example:
python -m fuzzfetch --asan --build acbfb05622cd827a7418d36628f75857628a81ce -n firefox-asan -
Save the following testcase as
testcase.html:<!doctype html> <meta charset="utf-8"> <body> <script> "use strict"; addEventListener("load", () => { const popover = document.createElement("div"); popover.setAttribute("popover", "auto"); const input = document.createElement("input"); input.setAttribute("autofocus", ""); popover.append(input); document.body.append(popover); input.addEventListener( "focus", () => { popover.removeAttribute("popover"); }, { once: true } ); popover.showPopover(); }); </script> </body> -
Run Firefox with a fresh profile and symbolized ASan output enabled:
export ASAN_SYMBOLIZER_PATH=/path/to/firefox-asan/llvm-symbolizer export ASAN_OPTIONS='symbolize=1:abort_on_error=1:disable_coredump=0:fast_unwind_on_malloc=0' export MOZ_CRASHREPORTER_DISABLE=1 export MOZ_DISABLE_CONTENT_SANDBOX=1 /path/to/firefox-asan/firefox \ --headless \ --no-remote \ --profile /tmp/fx-asan-profile \ file:///absolute/path/to/testcase.html -
Observe that the content process aborts with an ASan-reported SIGSEGV / null dereference.
Observed Result
The crash is reproducible and symbolized. A representative excerpt is:
AddressSanitizer:DEADLYSIGNAL
ERROR: AddressSanitizer: SEGV on unknown address 0x000000000020
The signal is caused by a READ memory access.
#0 ... in GetToggleEventTask ... PopoverData.h:90
#1 ... in nsGenericHTMLElement::QueuePopoverEventTask(...) ... nsGenericHTMLElement.cpp:3479
#2 ... in nsGenericHTMLElement::ShowPopoverInternal(...) ... nsGenericHTMLElement.cpp:3755
The read from 0x20 is consistent with dereferencing a null PopoverData*.
Expected Result
Firefox should safely handle this re-entrant state change and either abort the popover operation or revalidate the element state before continuing. Web content should not be able to trigger a null-pointer dereference in the content process by removing the popover attribute during autofocus handling.
Root Cause Analysis
The issue is caused by a re-entrancy gap in the popover opening path.
nsGenericHTMLElement::ShowPopoverInternal() queues the popover toggle task only after it runs popover focusing steps:
dom/html/nsGenericHTMLElement.cpp:3742-3755
Specifically:
FocusPopover()is called at3743QueuePopoverEventTask(PopoverVisibilityState::Hidden, aSource)is called at3755
FocusPopover() chooses the autofocus target and synchronously focuses it:
dom/html/nsGenericHTMLElement.cpp:3848-3864
In this testcase, the focused element's focus handler executes:
popover.removeAttribute("popover");
That mutation reaches nsGenericHTMLElement::AfterSetAttr(), which schedules AfterSetPopoverAttr() through nsContentUtils::AddScriptRunner(...):
dom/html/nsGenericHTMLElement.cpp:736-753
Mozilla's own AddScriptRunner() contract explicitly notes that if it is currently safe to run script, the runnable executes synchronously before returning:
dom/base/nsContentUtils.h:2328-2337dom/base/nsContentUtils.cpp:7266-7280
AfterSetPopoverAttr() then observes that the popover attribute transitioned to the missing state. If the popover is open, it hides it, re-reads the current attribute state, and when the state is None it clears the backing PopoverData:
- state transition logic:
dom/html/nsGenericHTMLElement.cpp:698-723 - hide call:
704-706 - re-read after script effects:
707-710 ClearPopoverData():713-715
ClearPopoverData() is implemented here:
dom/base/Element.cpp:5739-5743
After this re-entrant cleanup completes, execution returns to the original ShowPopoverInternal() call frame, which still assumes PopoverData exists and calls QueuePopoverEventTask().
QueuePopoverEventTask() does:
auto* data = GetPopoverData();
MOZ_ASSERT(data, "Should have popover data");
if (auto* queuedToggleEventTask = data->GetToggleEventTask()) {
dom/html/nsGenericHTMLElement.cpp:3474-3486
In the optimized ASan build, the assertion does not prevent continued execution, so data->GetToggleEventTask() dereferences a null pointer and crashes.
Impact
This is a reliable content-process null-pointer dereference reachable from web content via popover, autofocus, and a focus event handler. I have not investigated exploitability beyond the reliable crash / abort primitive.
Updated•16 days ago
|
Updated•16 days ago
|
Comment 1•15 days ago
|
||
The bug has a crash signature, thus the bug will be considered confirmed.
Updated•15 days ago
|
Updated•14 days ago
|
| Assignee | ||
Comment 2•13 days ago
|
||
Updated•13 days ago
|
Backed out for causing wc failures at popover-focus-blur-crash.html
Backout link
Push with failures
Failure log(s)
Failure line: TEST-UNEXPECTED-PASS | /html/semantics/popovers/popover-focus-blur-crash.html | expected CRASH
also this
Failure line: TEST-UNEXPECTED-OK | /html/semantics/popovers/popover-events.html | expected CRASH
| Assignee | ||
Comment 7•9 days ago
|
||
Should just be a matter of updating the test expectations because of the recent wptsync…
Comment 10•8 days ago
|
||
| bugherder | ||
Description
•