Closed Bug 1562891 Opened 6 years ago Closed 6 years ago

AddressSanitizer: heap-use-after-free /src/obj-firefox/dist/include/js/RootingAPI.h:339:56 in operator bool

Categories

(Core :: DOM: File, defect)

defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla69
Tracking Status
firefox-esr60 --- unaffected
firefox-esr68 --- unaffected
firefox67 --- unaffected
firefox68 --- unaffected
firefox69 + fixed

People

(Reporter: jkratzer, Assigned: baku)

References

(Blocks 2 open bugs, Regression)

Details

(5 keywords, Whiteboard: [post-critsmash-triage])

Attachments

(4 files)

Found while fuzzing mozilla-central rev a15e5a44b7ed. I'm currently trying to find a reproducible testcase and will update if one becomes available.

This appears to be a recent regression. This crash has occurred several hundred times beginning earlier this morning.

==21604==ERROR: AddressSanitizer: heap-use-after-free on address 0x6030003b0788 at pc 0x7fd0fcfe8af5 bp 0x7ffc4e010dc0 sp 0x7ffc4e010db8
READ of size 8 at 0x6030003b0788 thread T0 (file:// Content)
    #0 0x7fd0fcfe8af4 in operator bool /src/obj-firefox/dist/include/js/RootingAPI.h:339:56
    #1 0x7fd0fcfe8af4 in TraceCallbackFunc::Trace(JS::Heap<JSObject*>*, char const*, void*) const /src/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp:48
    #2 0x7fd0fcf8b034 in mozilla::CycleCollectedJSRuntime::TraverseNativeRoots(nsCycleCollectionNoteRootCallback&) /src/xpcom/base/CycleCollectedJSRuntime.cpp:772:15
    #3 0x7fd0fcf8d60f in mozilla::CycleCollectedJSRuntime::TraverseRoots(nsCycleCollectionNoteRootCallback&) /src/xpcom/base/CycleCollectedJSRuntime.cpp:1115:3
    #4 0x7fd0fcfe3130 in nsCycleCollector::BeginCollection(ccType, nsICycleCollectorListener*) /src/xpcom/base/nsCycleCollector.cpp:3611:19
    #5 0x7fd0fcfe1f75 in nsCycleCollector::Collect(ccType, js::SliceBudget&, nsICycleCollectorListener*, bool) /src/xpcom/base/nsCycleCollector.cpp:3413:9
    #6 0x7fd0fcfe6f8c in nsCycleCollector_collect(nsICycleCollectorListener*) /src/xpcom/base/nsCycleCollector.cpp:3949:21
    #7 0x7fd101b4a91b in nsJSContext::CycleCollectNow(nsICycleCollectorListener*) /src/dom/base/nsJSEnvironment.cpp:1423:3
    #8 0x7fd10454bae8 in mozilla::dom::FuzzingFunctions_Binding::cycleCollect(JSContext*, unsigned int, JS::Value*) /src/obj-firefox/dom/bindings/FuzzingFunctionsBinding.cpp:66:3
    #9 0x7fd10c56e337 in CallJSNative /src/js/src/vm/Interpreter.cpp:448:13
    #10 0x7fd10c56e337 in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) /src/js/src/vm/Interpreter.cpp:540
    #11 0x7fd10c54e94e in CallFromStack /src/js/src/vm/Interpreter.cpp:599:10
    #12 0x7fd10c54e94e in Interpret(JSContext*, js::RunState&) /src/js/src/vm/Interpreter.cpp:3088
    #13 0x7fd10c538218 in js::RunScript(JSContext*, js::RunState&) /src/js/src/vm/Interpreter.cpp:425:10
    #14 0x7fd10c56ee3f in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) /src/js/src/vm/Interpreter.cpp:568:13
    #15 0x7fd10c571062 in js::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, js::AnyInvokeArgs const&, JS::MutableHandle<JS::Value>) /src/js/src/vm/Interpreter.cpp:611:8
    #16 0x7fd10d1ff138 in JS::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, JS::HandleValueArray const&, JS::MutableHandle<JS::Value>) /src/js/src/jsapi.cpp:2661:10
    #17 0x7fd104456700 in mozilla::dom::Function::Call(JSContext*, JS::Handle<JS::Value>, nsTArray<JS::Value> const&, JS::MutableHandle<JS::Value>, mozilla::ErrorResult&) /src/obj-firefox/dom/bindings/FunctionBinding.cpp:41:8
    #18 0x7fd1019a5e59 in void mozilla::dom::Function::Call<nsCOMPtr<nsIGlobalObject> >(nsCOMPtr<nsIGlobalObject> const&, nsTArray<JS::Value> const&, JS::MutableHandle<JS::Value>, mozilla::ErrorResult&, char const*, mozilla::dom::CallbackObject::ExceptionHandling, JS::Realm*) /src/obj-firefox/dist/include/mozilla/dom/FunctionBinding.h:73:12
    #19 0x7fd1019a57ea in mozilla::dom::CallbackTimeoutHandler::Call(char const*) /src/dom/base/TimeoutHandler.cpp:163:29
    #20 0x7fd1014810a7 in nsGlobalWindowInner::RunTimeoutHandler(mozilla::dom::Timeout*, nsIScriptContext*) /src/dom/base/nsGlobalWindowInner.cpp:5904:38
    #21 0x7fd10199e1ad in mozilla::dom::TimeoutManager::RunTimeout(mozilla::TimeStamp const&, mozilla::TimeStamp const&, bool) /src/dom/base/TimeoutManager.cpp:971:44
    #22 0x7fd10199cc82 in mozilla::dom::TimeoutExecutor::MaybeExecute() /src/dom/base/TimeoutExecutor.cpp:179:11
    #23 0x7fd1019a1b45 in mozilla::dom::TimeoutExecutor::Run() /src/dom/base/TimeoutExecutor.cpp:234:5
    #24 0x7fd0fd23c582 in mozilla::ThrottledEventQueue::Inner::ExecuteRunnable() /src/xpcom/threads/ThrottledEventQueue.cpp:252:22
    #25 0x7fd0fd235537 in mozilla::ThrottledEventQueue::Inner::Executor::Run() /src/xpcom/threads/ThrottledEventQueue.cpp:80:15
    #26 0x7fd0fd1d5475 in mozilla::SchedulerGroup::Runnable::Run() /src/xpcom/threads/SchedulerGroup.cpp:295:32
    #27 0x7fd0fd2163bc in nsThread::ProcessNextEvent(bool, bool*) /src/xpcom/threads/nsThread.cpp:1225:14
    #28 0x7fd0fd21e244 in NS_ProcessNextEvent(nsIThread*, bool) /src/xpcom/threads/nsThreadUtils.cpp:486:10
    #29 0x7fd0fe62827f in mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate*) /src/ipc/glue/MessagePump.cpp:88:21
    #30 0x7fd0fe4fe3de in RunInternal /src/ipc/chromium/src/base/message_loop.cc:315:10
    #31 0x7fd0fe4fe3de in RunHandler /src/ipc/chromium/src/base/message_loop.cc:308
    #32 0x7fd0fe4fe3de in MessageLoop::Run() /src/ipc/chromium/src/base/message_loop.cc:290
    #33 0x7fd107c236c3 in nsBaseAppShell::Run() /src/widget/nsBaseAppShell.cpp:137:27
    #34 0x7fd10c29014e in XRE_RunAppShell() /src/toolkit/xre/nsEmbedFunctions.cpp:919:20
    #35 0x7fd0fe4fe3de in RunInternal /src/ipc/chromium/src/base/message_loop.cc:315:10
    #36 0x7fd0fe4fe3de in RunHandler /src/ipc/chromium/src/base/message_loop.cc:308
    #37 0x7fd0fe4fe3de in MessageLoop::Run() /src/ipc/chromium/src/base/message_loop.cc:290
    #38 0x7fd10c28ec91 in XRE_InitChildProcess(int, char**, XREChildData const*) /src/toolkit/xre/nsEmbedFunctions.cpp:754:34
    #39 0x5613ab835ee3 in content_process_main /src/browser/app/../../ipc/contentproc/plugin-container.cpp:56:28
    #40 0x5613ab835ee3 in main /src/browser/app/nsBrowserApp.cpp:267
    #41 0x7fd121f5ab96 in __libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310
    #42 0x5613ab75741c in _start (/home/worker/builds/m-c-20190702093917-fuzzing-asan-opt/firefox+0x4541c)

0x6030003b0788 is located 24 bytes inside of 32-byte region [0x6030003b0770,0x6030003b0790)
freed by thread T0 (file:// Content) here:
    #0 0x5613ab802ab2 in __interceptor_free /builds/worker/workspace/moz-toolchain/src/llvm/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:124:3
    #1 0x7fd0fcfd7cb1 in SnowWhiteKiller::~SnowWhiteKiller() /src/xpcom/base/nsCycleCollector.cpp:2416:7
    #2 0x7fd0fcfd6363 in nsCycleCollector::FreeSnowWhite(bool) /src/xpcom/base/nsCycleCollector.cpp:2609:3
    #3 0x7fd0fcfe2cc5 in nsCycleCollector::BeginCollection(ccType, nsICycleCollectorListener*) /src/xpcom/base/nsCycleCollector.cpp:3584:3
    #4 0x7fd0fcfe1f75 in nsCycleCollector::Collect(ccType, js::SliceBudget&, nsICycleCollectorListener*, bool) /src/xpcom/base/nsCycleCollector.cpp:3413:9
    #5 0x7fd0fcfe6f8c in nsCycleCollector_collect(nsICycleCollectorListener*) /src/xpcom/base/nsCycleCollector.cpp:3949:21
    #6 0x7fd101b4a91b in nsJSContext::CycleCollectNow(nsICycleCollectorListener*) /src/dom/base/nsJSEnvironment.cpp:1423:3
    #7 0x7fd10454bae8 in mozilla::dom::FuzzingFunctions_Binding::cycleCollect(JSContext*, unsigned int, JS::Value*) /src/obj-firefox/dom/bindings/FuzzingFunctionsBinding.cpp:66:3
    #8 0x7fd10c56e337 in CallJSNative /src/js/src/vm/Interpreter.cpp:448:13
    #9 0x7fd10c56e337 in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) /src/js/src/vm/Interpreter.cpp:540
    #10 0x7fd10c54e94e in CallFromStack /src/js/src/vm/Interpreter.cpp:599:10
    #11 0x7fd10c54e94e in Interpret(JSContext*, js::RunState&) /src/js/src/vm/Interpreter.cpp:3088
    #12 0x7fd10c538218 in js::RunScript(JSContext*, js::RunState&) /src/js/src/vm/Interpreter.cpp:425:10
    #13 0x7fd10c56ee3f in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) /src/js/src/vm/Interpreter.cpp:568:13
    #14 0x7fd10c571062 in js::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, js::AnyInvokeArgs const&, JS::MutableHandle<JS::Value>) /src/js/src/vm/Interpreter.cpp:611:8
    #15 0x7fd10d1ff138 in JS::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, JS::HandleValueArray const&, JS::MutableHandle<JS::Value>) /src/js/src/jsapi.cpp:2661:10
    #16 0x7fd104456700 in mozilla::dom::Function::Call(JSContext*, JS::Handle<JS::Value>, nsTArray<JS::Value> const&, JS::MutableHandle<JS::Value>, mozilla::ErrorResult&) /src/obj-firefox/dom/bindings/FunctionBinding.cpp:41:8
    #17 0x7fd1019a5e59 in void mozilla::dom::Function::Call<nsCOMPtr<nsIGlobalObject> >(nsCOMPtr<nsIGlobalObject> const&, nsTArray<JS::Value> const&, JS::MutableHandle<JS::Value>, mozilla::ErrorResult&, char const*, mozilla::dom::CallbackObject::ExceptionHandling, JS::Realm*) /src/obj-firefox/dist/include/mozilla/dom/FunctionBinding.h:73:12
    #18 0x7fd1019a57ea in mozilla::dom::CallbackTimeoutHandler::Call(char const*) /src/dom/base/TimeoutHandler.cpp:163:29
    #19 0x7fd1014810a7 in nsGlobalWindowInner::RunTimeoutHandler(mozilla::dom::Timeout*, nsIScriptContext*) /src/dom/base/nsGlobalWindowInner.cpp:5904:38
    #20 0x7fd10199e1ad in mozilla::dom::TimeoutManager::RunTimeout(mozilla::TimeStamp const&, mozilla::TimeStamp const&, bool) /src/dom/base/TimeoutManager.cpp:971:44
    #21 0x7fd10199cc82 in mozilla::dom::TimeoutExecutor::MaybeExecute() /src/dom/base/TimeoutExecutor.cpp:179:11

previously allocated by thread T0 (file:// Content) here:
    #0 0x5613ab802e33 in __interceptor_malloc /builds/worker/workspace/moz-toolchain/src/llvm/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:146:3
    #1 0x5613ab837b9d in moz_xmalloc /src/memory/mozalloc/mozalloc.cpp:52:15
    #2 0x7fd10560fdb4 in operator new /src/obj-firefox/dist/include/mozilla/cxxalloc.h:33:10
    #3 0x7fd10560fdb4 in mozilla::dom::Blob::Stream(JSContext*, JS::MutableHandle<JSObject*>, mozilla::ErrorResult&) /src/dom/file/Blob.cpp:353
    #4 0x7fd101ed4147 in mozilla::dom::Blob_Binding::stream(JSContext*, JS::Handle<JSObject*>, mozilla::dom::Blob*, JSJitMethodCallArgs const&) /src/obj-firefox/dom/bindings/BlobBinding.cpp:745:24
    #5 0x7fd104c4b152 in bool mozilla::dom::binding_detail::GenericMethod<mozilla::dom::binding_detail::NormalThisPolicy, mozilla::dom::binding_detail::ThrowExceptions>(JSContext*, unsigned int, JS::Value*) /src/dom/bindings/BindingUtils.cpp:3171:13
    #6 0x7fd10c56e337 in CallJSNative /src/js/src/vm/Interpreter.cpp:448:13
    #7 0x7fd10c56e337 in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) /src/js/src/vm/Interpreter.cpp:540
    #8 0x7fd10c54e94e in CallFromStack /src/js/src/vm/Interpreter.cpp:599:10
    #9 0x7fd10c54e94e in Interpret(JSContext*, js::RunState&) /src/js/src/vm/Interpreter.cpp:3088
    #10 0x7fd10c538218 in js::RunScript(JSContext*, js::RunState&) /src/js/src/vm/Interpreter.cpp:425:10
    #11 0x7fd10c56ee3f in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) /src/js/src/vm/Interpreter.cpp:568:13
    #12 0x7fd10c571062 in js::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, js::AnyInvokeArgs const&, JS::MutableHandle<JS::Value>) /src/js/src/vm/Interpreter.cpp:611:8
    #13 0x7fd10d1ff138 in JS::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, JS::HandleValueArray const&, JS::MutableHandle<JS::Value>) /src/js/src/jsapi.cpp:2661:10
    #14 0x7fd1045b29d6 in mozilla::dom::BlobCallback::Call(JSContext*, JS::Handle<JS::Value>, mozilla::dom::Blob*, mozilla::ErrorResult&) /src/obj-firefox/dom/bindings/HTMLCanvasElementBinding.cpp:88:8
    #15 0x7fd104e0f1a2 in Call /src/obj-firefox/dist/include/mozilla/dom/HTMLCanvasElementBinding.h:180:12
    #16 0x7fd104e0f1a2 in mozilla::dom::CanvasRenderingContextHelper::ToBlob(JSContext*, nsIGlobalObject*, mozilla::dom::BlobCallback&, nsTSubstring<char16_t> const&, JS::Handle<JS::Value>, bool, mozilla::ErrorResult&)::EncodeCallback::ReceiveBlob(already_AddRefed<mozilla::dom::Blob>) /src/dom/canvas/CanvasRenderingContextHelper.cpp:42
    #17 0x7fd1018515f7 in mozilla::dom::EncodingCompleteEvent::Run() /src/dom/base/ImageEncoder.cpp:108:22
    #18 0x7fd0fd2163bc in nsThread::ProcessNextEvent(bool, bool*) /src/xpcom/threads/nsThread.cpp:1225:14
    #19 0x7fd0fd21e244 in NS_ProcessNextEvent(nsIThread*, bool) /src/xpcom/threads/nsThreadUtils.cpp:486:10
    #20 0x7fd1076f0703 in SpinEventLoopUntil<mozilla::ProcessFailureBehavior::ReportToCaller, (lambda at /builds/worker/workspace/build/src/dom/xhr/XMLHttpRequestMainThread.cpp:2909:31)> /src/obj-firefox/dist/include/nsThreadUtils.h:348:25
    #21 0x7fd1076f0703 in mozilla::dom::XMLHttpRequestMainThread::SendInternal(mozilla::dom::BodyExtractorBase const*, bool) /src/dom/xhr/XMLHttpRequestMainThread.cpp:2909
    #22 0x7fd1076edf7d in mozilla::dom::XMLHttpRequestMainThread::Send(JSContext*, mozilla::dom::Nullable<mozilla::dom::DocumentOrBlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString> const&, mozilla::ErrorResult&) /src/dom/xhr/XMLHttpRequestMainThread.cpp:2683:11
    #23 0x7fd103e1350d in mozilla::dom::XMLHttpRequest_Binding::send(JSContext*, JS::Handle<JSObject*>, mozilla::dom::XMLHttpRequest*, JSJitMethodCallArgs const&) /src/obj-firefox/dom/bindings/XMLHttpRequestBinding.cpp:1346:24
    #24 0x7fd104c4b152 in bool mozilla::dom::binding_detail::GenericMethod<mozilla::dom::binding_detail::NormalThisPolicy, mozilla::dom::binding_detail::ThrowExceptions>(JSContext*, unsigned int, JS::Value*) /src/dom/bindings/BindingUtils.cpp:3171:13

SUMMARY: AddressSanitizer: heap-use-after-free /src/obj-firefox/dist/include/js/RootingAPI.h:339:56 in operator bool
Shadow bytes around the buggy address:
  0x0c068006e0a0: fd fd fd fa fa fa fd fd fd fa fa fa fd fd fd fa
  0x0c068006e0b0: fa fa fd fd fd fa fa fa fd fd fd fd fa fa fd fd
  0x0c068006e0c0: fd fa fa fa fd fd fd fa fa fa fd fd fd fa fa fa
  0x0c068006e0d0: fd fd fd fd fa fa 00 00 05 fa fa fa fd fd fd fa
  0x0c068006e0e0: fa fa fd fd fd fa fa fa fd fd fd fd fa fa fd fd
=>0x0c068006e0f0: fd[fd]fa fa fd fd fd fa fa fa fd fd fd fa fa fa
  0x0c068006e100: fd fd fd fd fa fa fd fd fd fd fa fa 00 00 00 00
  0x0c068006e110: fa fa fd fd fd fa fa fa fd fd fd fa fa fa fd fd
  0x0c068006e120: fd fa fa fa fd fd fd fa fa fa fd fd fd fd fa fa
  0x0c068006e130: fd fd fd fd fa fa fd fd fd fa fa fa fd fd fd fa
  0x0c068006e140: fa fa fd fd fd fa fa fa fd fd fd fd fa fa fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==21604==ABORTING

Nice find. It sounds like a regression from bug 1557781. It looks like blobs aren't rooting their callback properly. Maybe a subclass overrides the Trace method but fails to call the parent trace?

Flags: needinfo?(amarchesini)
Keywords: regression, sec-high
Regressed by: 1557781
Group: core-security → dom-core-security

Actually, this looks more like Blob::Stream() failed to call DropJSObjects() when it was freed.

Assignee: nobody → amarchesini
Flags: needinfo?(amarchesini)
Attached file testcase.html

Attaching the testcase to land as a crashtest. Testcase must be accessed first via index.html.

Attached file index.html
Flags: in-testsuite?

Comment on attachment 9075423 [details]
Bug 1562891 - BodyStream should flag itself as close correctly, r?smaug

Security Approval Request

  • How easily could an exploit be constructed based on the patch?: This is a UAF. It cannot be exploited. At least, not easily.
  • Do comments in the patch, the check-in comment, or tests included in the patch paint a bulls-eye on the security problem?: No
  • Which older supported branches are affected by this flaw?:
  • If not all supported branches, which bug introduced the flaw?: Bug 1557781
  • Do you have backports for the affected branches?: No
  • If not, how different, hard to create, and risky will they be?: No needs to backport the patch.
  • How likely is this patch to cause regressions; how much testing does it need?: Low. The state check is simply wrong. We need to set the new state only when we are doing the real cleanup of BodyStream.
Attachment #9075423 - Flags: sec-approval?
Keywords: checkin-needed

Comment on attachment 9075423 [details]
Bug 1562891 - BodyStream should flag itself as close correctly, r?smaug

This is trunk-only so it doesn't need sec-approval.

Attachment #9075423 - Flags: sec-approval?

This was pushed to autoland:
https://hg.mozilla.org/integration/autoland/rev/02fa74d45af5412d2d6cf4581fd9f0c437c6c0e0

That said, can we still land the testcase here? :)

Flags: needinfo?(amarchesini)
Keywords: checkin-needed

It's not so easy to create a test that releases the BodyStream OOM. Jonco, do you know how to write a that where ReadableStream is guaranteed to be released OOM?

Flags: needinfo?(amarchesini) → needinfo?(jcoppeard)
Group: dom-core-security → core-security-release
Status: NEW → RESOLVED
Closed: 6 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla69

Can't we use the testcase from comment 4?

Flags: needinfo?(jcoppeard)

I can land it as crashtest but FuzzingFunctions.garbageCollect() is defined only in FUZZING builds.

Flags: needinfo?(jkratzer)

(In reply to Andrea Marchesini [:baku] from comment #13)

I can land it as crashtest but FuzzingFunctions.garbageCollect() is defined only in FUZZING builds.

There's SpecialPowers.forceGC(). I see that in a few crash tests.

Flags: needinfo?(jkratzer)

Test reviewed.

Keywords: checkin-needed
Flags: in-testsuite? → in-testsuite+
Keywords: checkin-needed
Flags: qe-verify-
Whiteboard: [post-critsmash-triage]
Group: core-security-release
Has Regression Range: --- → yes
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: