Crash in [@ mozilla::Maybe<T>::emplace<T> | mozilla::dom::SerializeWebAuthnRequestOptions]
Categories
(Core :: DOM: Web Authentication, defect)
Tracking
()
| Tracking | Status | |
|---|---|---|
| firefox-esr140 | --- | unaffected |
| firefox149 | + | affected |
| firefox150 | --- | affected |
| firefox151 | --- | affected |
People
(Reporter: Willmar.Knikker, Unassigned, NeedInfo)
References
(Regression)
Details
(Keywords: regression)
Crash Data
Extra info.
I can reproduce this every time i go to my company's 2fa system, it happens at the stage where i would normally
authenticate with my yubi key.
It also produces the following line in dmesg:
Isolated Web Co[187573]: segfault at 0 ip 00007fffe7edea70 sp 00007fffffff96f0 error 6 in libxul.so[82dda70,7fffe2fe5000+7046000] likely on CPU 6 (core 3, socket 0)
I tried to provide more info by running firefox through gdb, but my lack of expertise has limited me there
if you need any more information or need me to help in any way feel free to ask, as this is my first bug ticket here.
Original crash report:
Crash report: https://crash-stats.mozilla.org/report/index/1e813775-12fc-48e0-938d-34ced0260326
MOZ_CRASH Reason:
MOZ_RELEASE_ASSERT(!isSome())
Top 10 frames:
0 libxul.so MOZ_CrashSequence(void*, long) /usr/src/debug/firefox/firefox-149.0/obj/dist/include/mozilla/Assertions.h:237
0 libxul.so mozilla::Maybe<mozilla::dom::Record<nsTString<char16_t>, mozilla::dom::Authen... /usr/src/debug/firefox/firefox-149.0/obj/dist/include/mozilla/Maybe.h:1069
0 libxul.so mozilla::dom::Optional_base<mozilla::dom::Record<nsTString<char16_t>, mozilla... /usr/src/debug/firefox/firefox-149.0/obj/dist/include/mozilla/dom/BindingDeclarations.h:179
0 libxul.so mozilla::dom::SerializeWebAuthnRequestOptions(JSContext*, nsTString<char16_t>... /usr/src/debug/firefox/firefox-149.0/dom/webauthn/WebAuthnUtil.cpp:565
1 libxul.so mozilla::dom::WebAuthnHandler::GetAssertion(JSContext*, mozilla::dom::PublicK... /usr/src/debug/firefox/firefox-149.0/dom/webauthn/WebAuthnHandler.cpp:633
2 libxul.so mozilla::dom::CredentialsContainer::Get(JSContext*, mozilla::dom::CredentialR... /usr/src/debug/firefox/firefox-149.0/dom/credentialmanagement/CredentialsContainer.cpp:185
3 libxul.so mozilla::dom::CredentialsContainer_Binding::get(JSContext*, JS::Handle<JSObje... /usr/src/debug/firefox/firefox-149.0/obj/dom/bindings/CredentialManagementBinding.cpp:773
3 libxul.so mozilla::dom::CredentialsContainer_Binding::get_promiseWrapper(JSContext*, JS... /usr/src/debug/firefox/firefox-149.0/obj/dom/bindings/CredentialManagementBinding.cpp:789
4 libxul.so mozilla::dom::binding_detail::GenericMethod<mozilla::dom::binding_detail::Nor... /usr/src/debug/firefox/firefox-149.0/dom/bindings/BindingUtils.cpp:3343
5 libxul.so CallJSNative(JSContext*, bool (*)(JSContext*, unsigned int, JS::Value*), js::... /usr/src/debug/firefox/firefox-149.0/js/src/vm/Interpreter.cpp:490
Comment 1•3 days ago
|
||
I've let Claude Code perform an analysis on this crash, and matches our findings: something broke between 148 and 149 related to PRF. Our application does use evalByCredential, and it is very likely that the map has 2 or more entries. This report is AI generated, so it may be wrong. However, I do think it's very helpful:
Found the bug. The issue is on line 598:
for (const auto& entry : prfInputs.mEvalByCredential.Value().Entries()) {
auto* jsonEntry =
prfInputsJSON.mEvalByCredential.Construct().Entries().AppendElement(
fallible);
prfInputsJSON.mEvalByCredential.Construct() is called inside the loop. On the first iteration it creates the Record inside the Maybe. On the second iteration, it calls Construct() again on a Maybe that already has a value, which triggers MOZ_RELEASE_ASSERT(!isSome()) and crashes.
This only crashes when a WebAuthn navigator.credentials.get() call includes a prf extension with an evalByCredential map containing 2 or more entries.
It was introduced by commit 22371ef633e4 (Bug 2008744 - pass JSON serialized WebAuthn requests to WebAuthnCredentialManager).
Root Cause
In dom/webauthn/WebAuthnUtil.cpp:598, the Construct() call on mEvalByCredential is inside the for loop:
if (prfInputs.mEvalByCredential.WasPassed()) {
for (const auto& entry : prfInputs.mEvalByCredential.Value().Entries()) {
auto* jsonEntry =
prfInputsJSON.mEvalByCredential.Construct().Entries().AppendElement(
// ^^^^^^^^^^^
// BUG: Called on every iteration!
fallible);
mEvalByCredential is an Optional<Record<...>>, backed by a Maybe. Construct() calls Maybe::emplace(), which asserts !isSome(). On the first loop iteration this works fine — it creates the Record. On the second iteration, the Maybe already has a value, so emplace() hits MOZ_RELEASE_ASSERT(!isSome()) and crashes.
The crash only manifests when a website calls navigator.credentials.get() with a prf extension whose evalByCredential map has 2 or more entries.
Fix
The Construct() call needs to be moved before the loop:
if (prfInputs.mEvalByCredential.WasPassed()) {
auto& evalByCredentialJSON = prfInputsJSON.mEvalByCredential.Construct();
for (const auto& entry : prfInputs.mEvalByCredential.Value().Entries()) {
auto* jsonEntry =
evalByCredentialJSON.Entries().AppendElement(fallible);
This was introduced in Bug 2008744 (commit 22371ef633e4), which landed between Firefox 148 and 149.
Updated•3 days ago
|
Comment 2•3 days ago
|
||
Set release status flags based on info from the regressing bug 2008744
:jschanck, since you are the author of the regressor, bug 2008744, could you take a look? Also, could you set the severity field?
For more information, please visit BugBot documentation.
Comment 3•2 days ago
|
||
[Tracking Requested - why for this release]: Crash in the wild for users.
Comment 5•2 days ago
|
||
Copying crash signatures from duplicate bugs.
Comment 6•7 hours ago
|
||
We can track but the crash volume is very low. The planned dot release is next week.
Comment 7•1 hour ago
|
||
The bug is marked as tracked for firefox149 (release). However, the bug still isn't assigned.
:ckerschb, could you please find an assignee for this tracked bug? Given that it is a regression and we know the cause, we could also simply backout the regressor. If you disagree with the tracking decision, please talk with the release managers.
For more information, please visit BugBot documentation.
Description
•