Closed Bug 1792041 Opened 3 years ago Closed 3 years ago

UndefinedBehaviorSanitizer: /xpcom/io/Base64.cpp:327:13: runtime error: index 127 out of bounds for type 'const uint8_t[127]' (aka 'const unsigned char[127]')

Categories

(Core :: XPCOM, defect)

x86_64
Linux
defect

Tracking

()

RESOLVED FIXED
107 Branch
Tracking Status
firefox-esr102 106+ fixed
firefox105 --- wontfix
firefox106 + fixed
firefox107 + fixed

People

(Reporter: jkratzer, Assigned: jstutte)

References

(Blocks 1 open bug)

Details

(Keywords: csectype-bounds, sec-moderate, testcase, Whiteboard: [bugmon:confirm][post-critsmash-triage][adv-main106+r][adv-esr102.4+r])

Attachments

(2 files)

Testcase found while fuzzing mozilla-central rev c9041757a18a (built with: --enable-debug --enable-fuzzing).

Testcase can be reproduced using the following commands:

$ pip install fuzzfetch grizzly-framework
$ python -m fuzzfetch --build c9041757a18a --debug --fuzzing -n firefox
$ python -m grizzly.replay ./firefox/firefox testcase.zip
UndefinedBehaviorSanitizer: /xpcom/io/Base64.cpp:327:13: runtime error: index 127 out of bounds for type 'const uint8_t[127]' (aka 'const unsigned char[127]')

    /xpcom/io/Base64.cpp:327:13: runtime error: index 127 out of bounds for type 'const uint8_t[127]' (aka 'const unsigned char[127]')
        #0 0x7fe97e67f448 in (anonymous namespace)::Base64URLCharToValue(char, unsigned char*) /xpcom/io/Base64.cpp:327:13
        #1 0x7fe97e67ef85 in bool mozilla::Decode4to3<char, unsigned char, bool (*)(char, unsigned char*)>(char const*, unsigned char*, bool (*)(char, unsigned char*)) /xpcom/io/Base64.cpp:450:8
        #2 0x7fe97e67eae9 in mozilla::Base64URLDecode(nsTSubstring<char> const&, mozilla::Base64URLDecodePaddingPolicy, FallibleTArray<unsigned char>&) /xpcom/io/Base64.cpp:681:10
        #3 0x7fe985be1112 in mozilla::dom::PushManager::NormalizeAppServerKey(mozilla::dom::OwningArrayBufferViewOrArrayBufferOrString const&, nsTArray<unsigned char>&) /dom/push/PushManager.cpp:513:19
        #4 0x7fe985be033f in mozilla::dom::PushManager::PerformSubscriptionActionFromWorker(mozilla::dom::PushManager::SubscriptionAction, mozilla::dom::PushSubscriptionOptionsInit const&, mozilla::ErrorResult&) /dom/push/PushManager.cpp:492:19
        #5 0x7fe982873be7 in mozilla::dom::PushManager_Binding::subscribe(JSContext*, JS::Handle<JSObject*>, void*, JSJitMethodCallArgs const&) /builds/worker/workspace/obj-build/dom/bindings/PushManagerBinding.cpp:516:60
        #6 0x7fe982873919 in mozilla::dom::PushManager_Binding::subscribe_promiseWrapper(JSContext*, JS::Handle<JSObject*>, void*, JSJitMethodCallArgs const&) /builds/worker/workspace/obj-build/dom/bindings/PushManagerBinding.cpp:537:13
        #7 0x7fe983a29381 in bool mozilla::dom::binding_detail::GenericMethod<mozilla::dom::binding_detail::NormalThisPolicy, mozilla::dom::binding_detail::ConvertExceptionsToPromises>(JSContext*, unsigned int, JS::Value*) /dom/bindings/BindingUtils.cpp:3287:13
        #8 0x7fe98e1e7cb3 in CallJSNative /js/src/vm/Interpreter.cpp:458:13
        #9 0x7fe98e1e7cb3 in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct, js::CallReason) /js/src/vm/Interpreter.cpp:546:12
        #10 0x7fe98e1d6639 in InternalCall /js/src/vm/Interpreter.cpp:613:10
        #11 0x7fe98e1d6639 in CallFromStack /js/src/vm/Interpreter.cpp:618:10
        #12 0x7fe98e1d6639 in Interpret(JSContext*, js::RunState&) /js/src/vm/Interpreter.cpp:3374:16
        #13 0x7fe98e1bbc3e in js::RunScript(JSContext*, js::RunState&) /js/src/vm/Interpreter.cpp:430:13
        #14 0x7fe98e1eb935 in js::ExecuteKernel(JSContext*, JS::Handle<JSScript*>, JS::Handle<JSObject*>, js::AbstractFramePtr, JS::MutableHandle<JS::Value>) /js/src/vm/Interpreter.cpp:824:13
        #15 0x7fe98c87209c in bool EvaluateSourceBuffer<mozilla::Utf8Unit>(JSContext*, js::ScopeKind, JS::Handle<JSObject*>, JS::ReadOnlyCompileOptions const&, JS::SourceText<mozilla::Utf8Unit>&, JS::MutableHandle<JS::Value>) /js/src/vm/CompilationAndEvaluation.cpp:526:10
        #16 0x7fe98c871c86 in JS::Evaluate(JSContext*, JS::ReadOnlyCompileOptions const&, JS::SourceText<mozilla::Utf8Unit>&, JS::MutableHandle<JS::Value>) /js/src/vm/CompilationAndEvaluation.cpp:534:10
        #17 0x7fe98688e2a7 in bool mozilla::dom::workerinternals::loader::EvaluateSourceBuffer<mozilla::Utf8Unit>(JSContext*, JS::CompileOptions const&, JS::SourceText<mozilla::Utf8Unit>&) /dom/workers/ScriptLoader.cpp:383:10
        #18 0x7fe98688a4ff in mozilla::dom::workerinternals::loader::WorkerScriptLoader::EvaluateScript(JSContext*, JS::loader::ScriptLoadRequest*) /dom/workers/ScriptLoader.cpp:1003:13
        #19 0x7fe986889d54 in mozilla::dom::workerinternals::loader::WorkerScriptLoader::ProcessPendingRequests(JSContext*) /dom/workers/ScriptLoader.cpp:643:10
        #20 0x7fe98688f344 in mozilla::dom::workerinternals::loader::ScriptExecutorRunnable::WorkerRun(JSContext*, mozilla::dom::WorkerPrivate*) /dom/workers/ScriptLoader.cpp:1137:24
        #21 0x7fe9868e704e in mozilla::dom::WorkerRunnable::Run() /dom/workers/WorkerRunnable.cpp:377:12
        #22 0x7fe97e79a1ee in nsThread::ProcessNextEvent(bool, bool*) /xpcom/threads/nsThread.cpp:1199:16
        #23 0x7fe97e7a3e44 in NS_ProcessNextEvent(nsIThread*, bool) /xpcom/threads/nsThreadUtils.cpp:465:10
        #24 0x7fe9868d7145 in mozilla::dom::WorkerPrivate::RunCurrentSyncLoop() /dom/workers/WorkerPrivate.cpp:4200:7
        #25 0x7fe9845d010c in mozilla::dom::AutoSyncLoopHolder::Run() /builds/worker/workspace/obj-build/dist/include/mozilla/dom/WorkerPrivate.h:1504:27
        #26 0x7fe98688ffee in mozilla::dom::workerinternals::(anonymous namespace)::LoadAllScripts(mozilla::dom::WorkerPrivate*, mozilla::UniquePtr<mozilla::dom::SerializedStackHolder, mozilla::DefaultDelete<mozilla::dom::SerializedStackHolder> >, nsTArray<nsTString<char16_t> > const&, bool, mozilla::dom::WorkerScriptType, mozilla::ErrorResult&, mozilla::Encoding const*) /dom/workers/ScriptLoader.cpp:264:14
        #27 0x7fe98688fc52 in mozilla::dom::workerinternals::LoadMainScript(mozilla::dom::WorkerPrivate*, mozilla::UniquePtr<mozilla::dom::SerializedStackHolder, mozilla::DefaultDelete<mozilla::dom::SerializedStackHolder> >, nsTSubstring<char16_t> const&, mozilla::dom::WorkerScriptType, mozilla::ErrorResult&, mozilla::Encoding const*) /dom/workers/ScriptLoader.cpp:1250:3
        #28 0x7fe9868f9726 in mozilla::dom::(anonymous namespace)::CompileScriptRunnable::WorkerRun(JSContext*, mozilla::dom::WorkerPrivate*) /dom/workers/WorkerPrivate.cpp:380:5
        #29 0x7fe9868e704e in mozilla::dom::WorkerRunnable::Run() /dom/workers/WorkerRunnable.cpp:377:12
        #30 0x7fe97e79a1ee in nsThread::ProcessNextEvent(bool, bool*) /xpcom/threads/nsThread.cpp:1199:16
        #31 0x7fe97e7a3e44 in NS_ProcessNextEvent(nsIThread*, bool) /xpcom/threads/nsThreadUtils.cpp:465:10
        #32 0x7fe9868cf1ec in mozilla::dom::WorkerPrivate::DoRunLoop(JSContext*) /dom/workers/WorkerPrivate.cpp:3204:7
        #33 0x7fe9868a5e1e in mozilla::dom::workerinternals::(anonymous namespace)::WorkerThreadPrimaryRunnable::Run() /dom/workers/RuntimeService.cpp:2042:42
        #34 0x7fe97e79a1ee in nsThread::ProcessNextEvent(bool, bool*) /xpcom/threads/nsThread.cpp:1199:16
        #35 0x7fe97e7a3e44 in NS_ProcessNextEvent(nsIThread*, bool) /xpcom/threads/nsThreadUtils.cpp:465:10
        #36 0x7fe97ff3e135 in mozilla::ipc::MessagePumpForNonMainThreads::Run(base::MessagePump::Delegate*) /ipc/glue/MessagePump.cpp:300:20
        #37 0x7fe97fdbb5f1 in RunInternal /ipc/chromium/src/base/message_loop.cc:381:10
        #38 0x7fe97fdbb5f1 in RunHandler /ipc/chromium/src/base/message_loop.cc:374:3
        #39 0x7fe97fdbb5f1 in MessageLoop::Run() /ipc/chromium/src/base/message_loop.cc:356:3
        #40 0x7fe97e791338 in nsThread::ThreadFunc(void*) /xpcom/threads/nsThread.cpp:384:10
        #41 0x7fe9a61d8b7e in _pt_root /nsprpub/pr/src/pthreads/ptthread.c:201:5
        #42 0x7fe9a6959b42 in start_thread nptl/./nptl/pthread_create.c:442:8
        #43 0x7fe9a69eb9ff  misc/../sysdeps/unix/sysv/linux/x86_64/clone3.S:81
    
    SUMMARY: UndefinedBehaviorSanitizer: out-of-bounds-index /xpcom/io/Base64.cpp:327:13 in
Attached file Testcase

Bugmon Analysis
Unable to reproduce bug 1792041 using build mozilla-central 20220922095647-c9041757a18a. Without a baseline, bugmon is unable to analyze this bug.
Removing bugmon keyword as no further action possible. Please review the bug and re-add the keyword for further analysis.

Keywords: bugmon

Seems like this has something to do with workers.

Flags: needinfo?(jmarshall)
Flags: needinfo?(echuang)

Marking as s-s until we can determine if this represents a security issue or not.

Group: core-security
Group: core-security → dom-core-security

You can find a pernosco session for this bug here.

(In reply to Jason Kratzer [:jkratzer] from comment #5)

You can find a pernosco session for this bug here.

Thanks! That looks a bit weird. We have the static kBase64URLDecodeTable and it seems ubsan does not like kBase64URLDecodeTable[127]. sizeof(kBase64URLDecodeTable) results to 127 in gdb, so this would tell us that kBase64URLDecodeTable lacks an element. Indeed if I look at *aValue = kBase64URLDecodeTable[index & 0x7f]; I assume that the array is supposed to be 128 bytes long instead, not 127.

It is unclear to me though what the missing element should be numerically.

In any case it seems to me that we are in XPCOM land here.

Component: DOM: Push Notifications → XPCOM

And yes, it is a buffer overrun, but I am not sure how exploitable that might be given the probable alignment to 4 or even 8 byte boundaries. We might just read random data, which is bad enough.

I'll mark it as sec-moderate, as it looks like we're reading just past the end of a fixed location in memory.

Talking with :mt we found that 127 (DEL) can be just mapped to 255.

Flags: needinfo?(jmarshall)
Flags: needinfo?(echuang)

And we might want to ensure that https://searchfox.org/mozilla-central/source/xpcom/tests/gtest/TestBase64.cpp has complete coverage for all characters.

Assignee: nobody → jstutte
Status: NEW → ASSIGNED
Attachment #9296420 - Attachment description: Bug 1792041 - Add a value for DEL to kBase64URLDecodeTable. r?#xpcom-reviewers → Bug 1792041 - Add a value for DEL to kBase64URLDecodeTable and have static asserts for lookupo tables' length. r?#xpcom-reviewers
Attachment #9296420 - Attachment description: Bug 1792041 - Add a value for DEL to kBase64URLDecodeTable and have static asserts for lookupo tables' length. r?#xpcom-reviewers → Bug 1792041 - Add a value for DEL to kBase64URLDecodeTable and have static asserts for lookup tables' length. r?#xpcom-reviewers

Add a value for DEL to kBase64URLDecodeTable and have static asserts for lookup tables' length. r=xpcom-reviewers,nika
https://hg.mozilla.org/integration/autoland/rev/fba6ffac04a6
https://hg.mozilla.org/mozilla-central/rev/fba6ffac04a6

Group: dom-core-security → core-security-release
Status: ASSIGNED → RESOLVED
Closed: 3 years ago
Resolution: --- → FIXED
Target Milestone: --- → 107 Branch

The patch landed in nightly and beta is affected.
:jstutte, is this bug important enough to require an uplift?

  • If yes, please nominate the patch for beta approval.
  • If no, please set status-firefox106 to wontfix.

For more information, please visit auto_nag documentation.

Flags: needinfo?(jstutte)

Comment on attachment 9296420 [details]
Bug 1792041 - Add a value for DEL to kBase64URLDecodeTable and have static asserts for lookup tables' length. r?#xpcom-reviewers

Beta/Release Uplift Approval Request

  • User impact if declined: Unknown, we just have a fuzzer test case. We can read just 1 byte beyond a static buffer.
  • Is this code covered by automated tests?: Yes
  • Has the fix been verified in Nightly?: Yes
  • Needs manual test from QE?: No
  • If yes, steps to reproduce:
  • List of other uplifts needed: None
  • Risk to taking this patch: Low
  • Why is the change risky/not risky? (and alternatives if risky): We just added a value to the buffer and added some static asserts for testing. There is only one small logic change in Base64URLCharToValue where we used to wrap around for values >128 by bit-masking, now we will return a failure/invalid value for those. For correct requests this should have no impact.
  • String changes made/needed:
  • Is Android affected?: Yes
Flags: needinfo?(jstutte)
Attachment #9296420 - Flags: approval-mozilla-beta?

Comment on attachment 9296420 [details]
Bug 1792041 - Add a value for DEL to kBase64URLDecodeTable and have static asserts for lookup tables' length. r?#xpcom-reviewers

Approved for 106.0b8, thanks.

Attachment #9296420 - Flags: approval-mozilla-beta? → approval-mozilla-beta+

Comment on attachment 9296420 [details]
Bug 1792041 - Add a value for DEL to kBase64URLDecodeTable and have static asserts for lookup tables' length. r?#xpcom-reviewers

Approved for 102.4esr.

Attachment #9296420 - Flags: approval-mozilla-esr102+
Flags: qe-verify-
Whiteboard: [bugmon:confirm] → [bugmon:confirm][post-critsmash-triage]
Whiteboard: [bugmon:confirm][post-critsmash-triage] → [bugmon:confirm][post-critsmash-triage][adv-main106+r]
Whiteboard: [bugmon:confirm][post-critsmash-triage][adv-main106+r] → [bugmon:confirm][post-critsmash-triage][adv-main106+r][adv-esr102.4+r]
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: