Closed Bug 1399091 Opened 7 years ago Closed 7 years ago

heap-use-after-free in nsRange::~nsRange

Categories

(Core :: DOM: Selection, defect)

57 Branch
defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla58
Tracking Status
firefox-esr52 --- unaffected
firefox55 --- unaffected
firefox56 --- unaffected
firefox57 + fixed
firefox58 + fixed

People

(Reporter: nils, Assigned: catalinb)

References

Details

(5 keywords)

Attachments

(5 files, 5 obsolete files)

Attached file ASAN output
The following testcase crashes the latest ASAN build of Firefox (BuildID=20170910080726). It requires the attached div.html in the same directory and the fuzzPriv extension installed.

<script>
function start() {
	setInterval('fuzzPriv.GC();fuzzPriv.CC()',4);
	o0=open('div.html','popup74','height=2');
	o0.onload=fun1;
	setTimeout(fun0, 40);
}
function fun0() {
	o3=this;
	fuzzPriv.trustedKeyEvent(document.documentElement,'press',true,false,false,false,0,65);
	o42=document.createRange();
	o43=o3.getSelection();
	o52=o43.getRangeAt(0);
	o153=o0.getSelection();
	o158=document.createElement('input');
	setTimeout(fun2, 4);
}
function fun1(e) {
	o93=e.target;
	o105=o93.getElementsByTagName('*')[3];
	o52.setEndBefore(o105);
	o42.setEndBefore(o105);
	o153.addRange(o42);
	o42.insertNode(o158);
	o153.addRange(o52);
}
function fun2() {
	o0.close();
	window.setTimeout("location.reload();",10);
}
</script>
<body onload="start()"></body>

ASAN output:
=================================================================
==14613==ERROR: AddressSanitizer: heap-use-after-free on address 0x6030002d1578 at pc 0x7faa7aa53394 bp 0x7fff3ff72c10 sp 0x7fff3ff72c08
WRITE of size 8 at 0x6030002d1578 thread T0 (file:// Content)
    #0 0x7faa7aa53393 in remove /builds/worker/workspace/build/src/obj-firefox/dist/include/mozilla/LinkedList.h:246:18
    #1 0x7faa7aa53393 in ~LinkedListElement /builds/worker/workspace/build/src/obj-firefox/dist/include/mozilla/LinkedList.h:198
    #2 0x7faa7aa53393 in nsRange::~nsRange() /builds/worker/workspace/build/src/dom/base/nsRange.cpp:259
    #3 0x7faa7aa533bd in nsRange::~nsRange() /builds/worker/workspace/build/src/dom/base/nsRange.cpp:254:1
    #4 0x7faa77c21047 in SnowWhiteKiller::~SnowWhiteKiller() /builds/worker/workspace/build/src/xpcom/base/nsCycleCollector.cpp:2695:25
    #5 0x7faa77c2870b in FreeSnowWhite /builds/worker/workspace/build/src/xpcom/base/nsCycleCollector.cpp:2883:3
    #6 0x7faa77c2870b in nsCycleCollector::BeginCollection(ccType, nsICycleCollectorListener*) /builds/worker/workspace/build/src/xpcom/base/nsCycleCollector.cpp:3899
    #7 0x7faa77c27c23 in nsCycleCollector::Collect(ccType, js::SliceBudget&, nsICycleCollectorListener*, bool) /builds/worker/workspace/build/src/xpcom/base/nsCycleCollector.cpp:3720:9
    #8 0x7faa77c2ba70 in nsCycleCollector_collect(nsICycleCollectorListener*) /builds/worker/workspace/build/src/xpcom/base/nsCycleCollector.cpp:4289:21
    #9 0x7faa7a9fe66d in nsJSContext::CycleCollectNow(nsICycleCollectorListener*) /builds/worker/workspace/build/src/dom/base/nsJSEnvironment.cpp:1480:3
    #10 0x7faa7a53e28b in nsDOMWindowUtils::CycleCollect(nsICycleCollectorListener*) /builds/worker/workspace/build/src/dom/base/nsDOMWindowUtils.cpp:1434:3
    #11 0x7faa77db1c91 in NS_InvokeByIndex /builds/worker/workspace/build/src/xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_x86_64_unix.S:129
    #12 0x7faa7956e7a0 in Invoke /builds/worker/workspace/build/src/js/xpconnect/src/XPCWrappedNative.cpp:1996:12
    #13 0x7faa7956e7a0 in Call /builds/worker/workspace/build/src/js/xpconnect/src/XPCWrappedNative.cpp:1315
    #14 0x7faa7956e7a0 in XPCWrappedNative::CallMethod(XPCCallContext&, XPCWrappedNative::CallMode) /builds/worker/workspace/build/src/js/xpconnect/src/XPCWrappedNative.cpp:1282
    #15 0x7faa7957576f in XPC_WN_CallMethod(JSContext*, unsigned int, JS::Value*) /builds/worker/workspace/build/src/js/xpconnect/src/XPCWrappedNativeJSOps.cpp:928:12
    #16 0x7faa82a70a54 in CallJSNative /builds/worker/workspace/build/src/js/src/jscntxtinlines.h:293:15
    #17 0x7faa82a70a54 in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:495
    #18 0x7faa82a5a2c9 in CallFromStack /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:546:12
    #19 0x7faa82a5a2c9 in Interpret(JSContext*, js::RunState&) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:3084
    #20 0x7faa82a4182b in js::RunScript(JSContext*, js::RunState&) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:435:12
    #21 0x7faa82a70bec in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:513:15
    #22 0x7faa82a71542 in js::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, js::AnyInvokeArgs const&, JS::MutableHandle<JS::Value>) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:559:10
    #23 0x7faa834c2ad3 in JS_CallFunctionValue(JSContext*, JS::Handle<JSObject*>, JS::Handle<JS::Value>, JS::HandleValueArray const&, JS::MutableHandle<JS::Value>) /builds/worker/workspace/build/src/js/src/jsapi.cpp:2906:12
    #24 0x7faa7948c7cb in xpc::FunctionForwarder(JSContext*, unsigned int, JS::Value*) /builds/worker/workspace/build/src/js/xpconnect/src/ExportHelpers.cpp:315:18
    #25 0x7faa82a70a54 in CallJSNative /builds/worker/workspace/build/src/js/src/jscntxtinlines.h:293:15
    #26 0x7faa82a70a54 in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:495
    #27 0x7faa82a5a2c9 in CallFromStack /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:546:12
    #28 0x7faa82a5a2c9 in Interpret(JSContext*, js::RunState&) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:3084
    #29 0x7faa82a4182b in js::RunScript(JSContext*, js::RunState&) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:435:12
    #30 0x7faa82a73367 in js::ExecuteKernel(JSContext*, JS::Handle<JSScript*>, JSObject&, JS::Value const&, js::AbstractFramePtr, JS::Value*) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:724:15
    #31 0x7faa82a73bd2 in js::Execute(JSContext*, JS::Handle<JSScript*>, JSObject&, JS::Value*) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:756:12
    #32 0x7faa834d5dc9 in ExecuteScript(JSContext*, JS::AutoObjectVector&, JS::Handle<JSScript*>, JS::Value*) /builds/worker/workspace/build/src/js/src/jsapi.cpp:4667:12
    #33 0x7faa7aa134a9 in nsJSUtils::ExecutionContext::CompileAndExec(JS::CompileOptions&, JS::SourceBufferHolder&, JS::MutableHandle<JSScript*>) /builds/worker/workspace/build/src/dom/base/nsJSUtils.cpp:265:8
    #34 0x7faa7aa13a06 in nsJSUtils::ExecutionContext::CompileAndExec(JS::CompileOptions&, nsTSubstring<char16_t> const&) /builds/worker/workspace/build/src/dom/base/nsJSUtils.cpp:287:10
    #35 0x7faa7a609158 in nsGlobalWindow::RunTimeoutHandler(mozilla::dom::Timeout*, nsIScriptContext*) /builds/worker/workspace/build/src/dom/base/nsGlobalWindow.cpp:13241:19
    #36 0x7faa7a7e1f74 in mozilla::dom::TimeoutManager::RunTimeout(mozilla::TimeStamp const&, mozilla::TimeStamp const&) /builds/worker/workspace/build/src/dom/base/TimeoutManager.cpp:878:42
    #37 0x7faa7a7d6e70 in mozilla::dom::TimeoutExecutor::MaybeExecute() /builds/worker/workspace/build/src/dom/base/TimeoutExecutor.cpp:167:11
    #38 0x7faa7a7d7642 in mozilla::dom::TimeoutExecutor::Run() /builds/worker/workspace/build/src/dom/base/TimeoutExecutor.cpp:224:5
    #39 0x7faa77d9d4dc in mozilla::ThrottledEventQueue::Inner::ExecuteRunnable() /builds/worker/workspace/build/src/xpcom/threads/ThrottledEventQueue.cpp:193:22
    #40 0x7faa77d9cf9f in mozilla::ThrottledEventQueue::Inner::Executor::Run() /builds/worker/workspace/build/src/xpcom/threads/ThrottledEventQueue.cpp:79:15
    #41 0x7faa77d61e10 in mozilla::SchedulerGroup::Runnable::Run() /builds/worker/workspace/build/src/xpcom/threads/SchedulerGroup.cpp:396:25
    #42 0x7faa77d88dcd in nsThread::ProcessNextEvent(bool, bool*) /builds/worker/workspace/build/src/xpcom/threads/nsThread.cpp:1039:14
    #43 0x7faa77d8eaf8 in NS_ProcessNextEvent(nsIThread*, bool) /builds/worker/workspace/build/src/xpcom/threads/nsThreadUtils.cpp:521:10
    #44 0x7faa78b32b21 in mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate*) /builds/worker/workspace/build/src/ipc/glue/MessagePump.cpp:97:21
    #45 0x7faa78a9386b in RunInternal /builds/worker/workspace/build/src/ipc/chromium/src/base/message_loop.cc:326:10
    #46 0x7faa78a9386b in RunHandler /builds/worker/workspace/build/src/ipc/chromium/src/base/message_loop.cc:319
    #47 0x7faa78a9386b in MessageLoop::Run() /builds/worker/workspace/build/src/ipc/chromium/src/base/message_loop.cc:299
    #48 0x7faa7e24ba5f in nsBaseAppShell::Run() /builds/worker/workspace/build/src/widget/nsBaseAppShell.cpp:158:27
    #49 0x7faa8258cb47 in XRE_RunAppShell() /builds/worker/workspace/build/src/toolkit/xre/nsEmbedFunctions.cpp:866:22
    #50 0x7faa78a9386b in RunInternal /builds/worker/workspace/build/src/ipc/chromium/src/base/message_loop.cc:326:10
    #51 0x7faa78a9386b in RunHandler /builds/worker/workspace/build/src/ipc/chromium/src/base/message_loop.cc:319
    #52 0x7faa78a9386b in MessageLoop::Run() /builds/worker/workspace/build/src/ipc/chromium/src/base/message_loop.cc:299
    #53 0x7faa8258c5b0 in XRE_InitChildProcess(int, char**, XREChildData const*) /builds/worker/workspace/build/src/toolkit/xre/nsEmbedFunctions.cpp:691:34
    #54 0x4eb873 in content_process_main /builds/worker/workspace/build/src/browser/app/../../ipc/contentproc/plugin-container.cpp:63:30
    #55 0x4eb873 in main /builds/worker/workspace/build/src/browser/app/nsBrowserApp.cpp:285
    #56 0x7faa953c482f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #57 0x41d1c8 in _start (/fuzzer3/firefox/firefox+0x41d1c8)

0x6030002d1578 is located 8 bytes inside of 24-byte region [0x6030002d1570,0x6030002d1588)
freed by thread T0 (file:// Content) here:
    #0 0x4bb6fb in __interceptor_free /builds/slave/moz-toolchain/src/llvm/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:47:3
    #1 0x7faa7a9dc569 in operator delete /builds/worker/workspace/build/src/obj-firefox/dist/include/mozilla/mozalloc.h:230:12
    #2 0x7faa7a9dc569 in operator() /builds/worker/workspace/build/src/obj-firefox/dist/include/mozilla/UniquePtr.h:528
    #3 0x7faa7a9dc569 in reset /builds/worker/workspace/build/src/obj-firefox/dist/include/mozilla/UniquePtr.h:343
    #4 0x7faa7a9dc569 in ~UniquePtr /builds/worker/workspace/build/src/obj-firefox/dist/include/mozilla/UniquePtr.h:288
    #5 0x7faa7a9dc569 in nsINode::nsSlots::~nsSlots() /builds/worker/workspace/build/src/dom/base/nsINode.cpp:135
    #6 0x7faa7a70832d in mozilla::dom::FragmentOrElement::nsDOMSlots::~nsDOMSlots() /builds/worker/workspace/build/src/dom/base/FragmentOrElement.cpp:761:1
    #7 0x7faa7aa38337 in nsNodeUtils::LastRelease(nsINode*) /builds/worker/workspace/build/src/dom/base/nsNodeUtils.cpp:313:5
    #8 0x7faa7a6c4722 in mozilla::dom::FragmentOrElement::Release() /builds/worker/workspace/build/src/dom/base/FragmentOrElement.cpp:2221:1
    #9 0x7faa7a7236ea in ~nsCOMPtr_base /builds/worker/workspace/build/src/obj-firefox/dist/include/nsCOMPtr.h:313:7
    #10 0x7faa7a7236ea in ContentUnbinder::UnbindSubtree(nsIContent*) /builds/worker/workspace/build/src/dom/base/FragmentOrElement.cpp:1492
    #11 0x7faa7a722ff7 in ContentUnbinder::Run() /builds/worker/workspace/build/src/dom/base/FragmentOrElement.cpp:1502:9
    #12 0x7faa7a70ea85 in UnbindAll /builds/worker/workspace/build/src/dom/base/FragmentOrElement.cpp:1526:11
    #13 0x7faa7a70ea85 in mozilla::dom::FragmentOrElement::ClearContentUnbinder() /builds/worker/workspace/build/src/dom/base/FragmentOrElement.cpp:1560
    #14 0x7faa7a81f2b9 in nsCCUncollectableMarker::Observe(nsISupports*, char const*, char16_t const*) /builds/worker/workspace/build/src/dom/base/nsCCUncollectableMarker.cpp:361:5
    #15 0x7faa77c90b1c in nsObserverList::NotifyObservers(nsISupports*, char const*, char16_t const*) /builds/worker/workspace/build/src/xpcom/ds/nsObserverList.cpp:112:19
    #16 0x7faa77c94468 in nsObserverService::NotifyObservers(nsISupports*, char const*, char16_t const*) /builds/worker/workspace/build/src/xpcom/ds/nsObserverService.cpp:296:19
    #17 0x7faa794fbb64 in XPCJSRuntime::BeginCycleCollectionCallback() /builds/worker/workspace/build/src/js/xpconnect/src/XPCJSRuntime.cpp:700:14
    #18 0x7faa77c28191 in nsCycleCollector::BeginCollection(ccType, nsICycleCollectorListener*) /builds/worker/workspace/build/src/xpcom/base/nsCycleCollector.cpp:3863:19
    #19 0x7faa77c27c23 in nsCycleCollector::Collect(ccType, js::SliceBudget&, nsICycleCollectorListener*, bool) /builds/worker/workspace/build/src/xpcom/base/nsCycleCollector.cpp:3720:9
    #20 0x7faa77c2ba70 in nsCycleCollector_collect(nsICycleCollectorListener*) /builds/worker/workspace/build/src/xpcom/base/nsCycleCollector.cpp:4289:21
    #21 0x7faa7a9fe66d in nsJSContext::CycleCollectNow(nsICycleCollectorListener*) /builds/worker/workspace/build/src/dom/base/nsJSEnvironment.cpp:1480:3
    #22 0x7faa7a53e28b in nsDOMWindowUtils::CycleCollect(nsICycleCollectorListener*) /builds/worker/workspace/build/src/dom/base/nsDOMWindowUtils.cpp:1434:3
    #23 0x7faa77db1c91 in NS_InvokeByIndex /builds/worker/workspace/build/src/xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_x86_64_unix.S:129
    #24 0x7faa7956e7a0 in Invoke /builds/worker/workspace/build/src/js/xpconnect/src/XPCWrappedNative.cpp:1996:12
    #25 0x7faa7956e7a0 in Call /builds/worker/workspace/build/src/js/xpconnect/src/XPCWrappedNative.cpp:1315
    #26 0x7faa7956e7a0 in XPCWrappedNative::CallMethod(XPCCallContext&, XPCWrappedNative::CallMode) /builds/worker/workspace/build/src/js/xpconnect/src/XPCWrappedNative.cpp:1282
    #27 0x7faa7957576f in XPC_WN_CallMethod(JSContext*, unsigned int, JS::Value*) /builds/worker/workspace/build/src/js/xpconnect/src/XPCWrappedNativeJSOps.cpp:928:12
    #28 0x7faa82a70a54 in CallJSNative /builds/worker/workspace/build/src/js/src/jscntxtinlines.h:293:15
    #29 0x7faa82a70a54 in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:495
    #30 0x7faa82a5a2c9 in CallFromStack /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:546:12
    #31 0x7faa82a5a2c9 in Interpret(JSContext*, js::RunState&) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:3084
    #32 0x7faa82a4182b in js::RunScript(JSContext*, js::RunState&) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:435:12
    #33 0x7faa82a70bec in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:513:15
    #34 0x7faa82a71542 in js::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, js::AnyInvokeArgs const&, JS::MutableHandle<JS::Value>) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:559:10
    #35 0x7faa834c2ad3 in JS_CallFunctionValue(JSContext*, JS::Handle<JSObject*>, JS::Handle<JS::Value>, JS::HandleValueArray const&, JS::MutableHandle<JS::Value>) /builds/worker/workspace/build/src/js/src/jsapi.cpp:2906:12
    #36 0x7faa7948c7cb in xpc::FunctionForwarder(JSContext*, unsigned int, JS::Value*) /builds/worker/workspace/build/src/js/xpconnect/src/ExportHelpers.cpp:315:18
    #37 0x7faa82a70a54 in CallJSNative /builds/worker/workspace/build/src/js/src/jscntxtinlines.h:293:15
    #38 0x7faa82a70a54 in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:495
    #39 0x7faa82a5a2c9 in CallFromStack /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:546:12
    #40 0x7faa82a5a2c9 in Interpret(JSContext*, js::RunState&) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:3084
    #41 0x7faa82a4182b in js::RunScript(JSContext*, js::RunState&) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:435:12

previously allocated by thread T0 (file:// Content) here:
    #0 0x4bba4c in malloc /builds/slave/moz-toolchain/src/llvm/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:64:3
    #1 0x4ecf6d in moz_xmalloc /builds/worker/workspace/build/src/memory/mozalloc/mozalloc.cpp:84:17
    #2 0x7faa7aa5722f in operator new /builds/worker/workspace/build/src/obj-firefox/dist/include/mozilla/mozalloc.h:206:12
    #3 0x7faa7aa5722f in MakeUnique<mozilla::LinkedList<nsRange>> /builds/worker/workspace/build/src/obj-firefox/dist/include/mozilla/UniquePtr.h:680
    #4 0x7faa7aa5722f in nsRange::RegisterCommonAncestor(nsINode*) /builds/worker/workspace/build/src/dom/base/nsRange.cpp:423
    #5 0x7faa7aa55587 in nsRange::DoSetRange(nsRange::RangeBoundaryBase<nsINode*, nsIContent*> const&, nsRange::RangeBoundaryBase<nsINode*, nsIContent*> const&, nsINode*, bool) /builds/worker/workspace/build/src/dom/base/nsRange.cpp:999:9
    #6 0x7faa7aa6471c in DoSetRange /builds/worker/workspace/build/src/dom/base/nsRange.h:661:5
    #7 0x7faa7aa6471c in nsRange::SetEnd(nsINode*, unsigned int) /builds/worker/workspace/build/src/dom/base/nsRange.cpp:1479
    #8 0x7faa7aa65768 in nsRange::SetEndBefore(nsINode&, mozilla::ErrorResult&) /builds/worker/workspace/build/src/dom/base/nsRange.cpp:1598:9
    #9 0x7faa7aa654a8 in nsRange::SetEndBeforeJS(nsINode&, mozilla::ErrorResult&) /builds/worker/workspace/build/src/dom/base/nsRange.cpp:1580:3
    #10 0x7faa7b3d2e05 in mozilla::dom::RangeBinding::setEndBefore(JSContext*, JS::Handle<JSObject*>, nsRange*, JSJitMethodCallArgs const&) /builds/worker/workspace/build/src/obj-firefox/dom/bindings/RangeBinding.cpp:647:9
    #11 0x7faa7c40da50 in mozilla::dom::GenericBindingMethod(JSContext*, unsigned int, JS::Value*) /builds/worker/workspace/build/src/dom/bindings/BindingUtils.cpp:3050:13
    #12 0x7faa82a70a54 in CallJSNative /builds/worker/workspace/build/src/js/src/jscntxtinlines.h:293:15
    #13 0x7faa82a70a54 in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:495
    #14 0x7faa82a5a2c9 in CallFromStack /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:546:12
    #15 0x7faa82a5a2c9 in Interpret(JSContext*, js::RunState&) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:3084
    #16 0x7faa82a4182b in js::RunScript(JSContext*, js::RunState&) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:435:12
    #17 0x7faa82a70bec in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:513:15
    #18 0x7faa82a71542 in js::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, js::AnyInvokeArgs const&, JS::MutableHandle<JS::Value>) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:559:10
    #19 0x7faa83777dfe in js::ForwardingProxyHandler::call(JSContext*, JS::Handle<JSObject*>, JS::CallArgs const&) const /builds/worker/workspace/build/src/js/src/proxy/Wrapper.cpp:175:12
    #20 0x7faa8373aa39 in js::CrossCompartmentWrapper::call(JSContext*, JS::Handle<JSObject*>, JS::CallArgs const&) const /builds/worker/workspace/build/src/js/src/proxy/CrossCompartmentWrapper.cpp:359:23
    #21 0x7faa83757e53 in js::Proxy::call(JSContext*, JS::Handle<JSObject*>, JS::CallArgs const&) /builds/worker/workspace/build/src/js/src/proxy/Proxy.cpp:497:21
    #22 0x7faa8375a817 in js::proxy_Call(JSContext*, unsigned int, JS::Value*) /builds/worker/workspace/build/src/js/src/proxy/Proxy.cpp:757:12
    #23 0x7faa82a70e9c in CallJSNative /builds/worker/workspace/build/src/js/src/jscntxtinlines.h:293:15
    #24 0x7faa82a70e9c in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:477
    #25 0x7faa82a71542 in js::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, js::AnyInvokeArgs const&, JS::MutableHandle<JS::Value>) /builds/worker/workspace/build/src/js/src/vm/Interpreter.cpp:559:10
    #26 0x7faa834c495b in JS::Call(JSContext*, JS::Handle<JS::Value>, JS::Handle<JS::Value>, JS::HandleValueArray const&, JS::MutableHandle<JS::Value>) /builds/worker/workspace/build/src/js/src/jsapi.cpp:2965:12
    #27 0x7faa7be44be5 in mozilla::dom::EventHandlerNonNull::Call(JSContext*, JS::Handle<JS::Value>, mozilla::dom::Event&, JS::MutableHandle<JS::Value>, mozilla::ErrorResult&) /builds/worker/workspace/build/src/obj-firefox/dom/bindings/EventHandlerBinding.cpp:260:37
    #28 0x7faa7c8157d5 in Call<nsISupports *> /builds/worker/workspace/build/src/obj-firefox/dist/include/mozilla/dom/EventHandlerBinding.h:362:12
    #29 0x7faa7c8157d5 in mozilla::JSEventHandler::HandleEvent(nsIDOMEvent*) /builds/worker/workspace/build/src/dom/events/JSEventHandler.cpp:215
    #30 0x7faa7c7deda9 in mozilla::EventListenerManager::HandleEventSubType(mozilla::EventListenerManager::Listener*, nsIDOMEvent*, mozilla::dom::EventTarget*) /builds/worker/workspace/build/src/dom/events/EventListenerManager.cpp:1112:51
    #31 0x7faa7c7e0e70 in mozilla::EventListenerManager::HandleEventInternal(nsPresContext*, mozilla::WidgetEvent*, nsIDOMEvent**, mozilla::dom::EventTarget*, nsEventStatus*) /builds/worker/workspace/build/src/dom/events/EventListenerManager.cpp:1283:20
    #32 0x7faa7c7c0c61 in mozilla::EventTargetChainItem::HandleEventTargetChain(nsTArray<mozilla::EventTargetChainItem>&, mozilla::EventChainPostVisitor&, mozilla::EventDispatchingCallback*, mozilla::ELMCreationDetector&) /builds/worker/workspace/build/src/dom/events/EventDispatcher.cpp:462:16
    #33 0x7faa7c7c4132 in mozilla::EventDispatcher::Dispatch(nsISupports*, nsPresContext*, mozilla::WidgetEvent*, nsIDOMEvent*, nsEventStatus*, mozilla::EventDispatchingCallback*, nsTArray<mozilla::dom::EventTarget*>*) /builds/worker/workspace/build/src/dom/events/EventDispatcher.cpp:822:9
    #34 0x7faa7ea9508e in nsDocumentViewer::LoadComplete(nsresult) /builds/worker/workspace/build/src/layout/base/nsDocumentViewer.cpp:1081:7
    #35 0x7faa81a397e1 in nsDocShell::EndPageLoad(nsIWebProgress*, nsIChannel*, nsresult) /builds/worker/workspace/build/src/docshell/base/nsDocShell.cpp:7741:21
    #36 0x7faa81a35804 in nsDocShell::OnStateChange(nsIWebProgress*, nsIRequest*, unsigned int, nsresult) /builds/worker/workspace/build/src/docshell/base/nsDocShell.cpp:7539:7

SUMMARY: AddressSanitizer: heap-use-after-free /builds/worker/workspace/build/src/obj-firefox/dist/include/mozilla/LinkedList.h:246:18 in remove
Shadow bytes around the buggy address:
  0x0c0680052250: fd fa fa fa fd fd fd fa fa fa fd fd fd fa fa fa
  0x0c0680052260: fd fd fd fa fa fa fd fd fd fa fa fa fd fd fd fa
  0x0c0680052270: fa fa fd fd fd fa fa fa fd fd fd fa fa fa fd fd
  0x0c0680052280: fd fa fa fa fd fd fd fa fa fa fd fd fd fa fa fa
  0x0c0680052290: fd fd fd fa fa fa fd fd fd fd fa fa fd fd fd fa
=>0x0c06800522a0: fa fa fd fd fd fa fa fa fd fd fd fa fa fa fd[fd]
  0x0c06800522b0: fd fa fa fa fd fd fd fd fa fa fd fd fd fd fa fa
  0x0c06800522c0: fd fd fd fa fa fa fd fd fd fa fa fa fd fd fd fa
  0x0c06800522d0: fa fa fd fd fd fa fa fa fd fd fd fa fa fa fd fd
  0x0c06800522e0: fd fa fa fa fd fd fd fa fa fa fd fd fd fd fa fa
  0x0c06800522f0: fd fd fd fa fa fa fd fd fd fd fa fa fd fd 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
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  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
==14613==ABORTING
Attached file div.html
Group: core-security → dom-core-security
Catalin, please take a look here. Mats can probably help if you aren't getting anywhere.
Flags: needinfo?(catalin.badea392)
I think the problem is that we don't remove the range from its current selection before adding it to a new one.
Assignee: nobody → catalin.badea392
Flags: needinfo?(catalin.badea392)
Attached file test.html
Simpler version that triggers an assert in nsRange::SetSelection.

http://searchfox.org/mozilla-central/rev/2c9a5993ac40ec1db8450e3e0a85702fa291b9e2/dom/base/nsRange.cpp#1055
Comment on attachment 8908687 [details] [diff] [review]
Avoid adding the same range to multiple selections.

I think the invariant in the assertion here is valid.
Having both a non-null aSelection and mSelection is a sign that
something did go wrong earlier.  We could take this patch as
a kind of wallpaper (with an assertion added back before
the RemoveRange call), but I'd prefer fixing the underlying
bug first.

When the assertion fails in nsRange::SetSelection, we have:
(rr) p this->mSelection->HasSameRoot(*this->GetStartContainer())
$1 = false

That isn't a valid state.  It appears we get into this state
by first adding a valid Range to a Selection, then call
nsRange::SetEnd with a node from a different document.
We should reject such calls IMO (probably silently, since
that's what we do in Selection::Collapse in the same situation).

So I think we need to add an additional test in all places
we call IsValidBoundary() in nsRange code, with something
like this:
if (IsInSelection() && !mSelection->HasSameRoot(aNode)) {
  return NS_OK; // aNode is not a valid boundary node for this Range
}

(or modify IsValidBoundary() itself to do this check)
Attachment #8908687 - Flags: review?(mats) → review-
(In reply to Mats Palmgren (:mats) from comment #8)
> Comment on attachment 8908687 [details] [diff] [review]
> Avoid adding the same range to multiple selections.
> 
> I think the invariant in the assertion here is valid.
> Having both a non-null aSelection and mSelection is a sign that
> something did go wrong earlier.  We could take this patch as
> a kind of wallpaper (with an assertion added back before
> the RemoveRange call), but I'd prefer fixing the underlying
> bug first.
It's much safer to enforce not being part of multiple selections
here. By fixing the callers to pass the assertions we might
miss some cases and end up having to fix this again.

> 
> When the assertion fails in nsRange::SetSelection, we have:
> (rr) p this->mSelection->HasSameRoot(*this->GetStartContainer())
> $1 = false
> 
> That isn't a valid state.  It appears we get into this state
> by first adding a valid Range to a Selection, then call
> nsRange::SetEnd with a node from a different document.
> We should reject such calls IMO (probably silently, since
> that's what we do in Selection::Collapse in the same situation).
I also think we should reject positioning on a node from a different
document when part of a selection. FWIW, Chrome does allow it.

> 
> So I think we need to add an additional test in all places
> we call IsValidBoundary() in nsRange code, with something
> like this:
> if (IsInSelection() && !mSelection->HasSameRoot(aNode)) {
>   return NS_OK; // aNode is not a valid boundary node for this Range
> }
> 
> (or modify IsValidBoundary() itself to do this check)
I'll add the check to IsValidBoundary.
I think we should also take the catch-all fix from the previous patch.
Attachment #8909329 - Flags: review?(mats)
Comment on attachment 8908687 [details] [diff] [review]
Avoid adding the same range to multiple selections.

Resubmitting this for review. This is safer than expecting the debug assert to reveal all potential bugs.
Attachment #8908687 - Flags: review- → review?(mats)
Comment on attachment 8908687 [details] [diff] [review]
Avoid adding the same range to multiple selections.

(In reply to Cătălin Badea (:catalinb) from comment #10)
> I think we should also take the catch-all fix from the previous patch.

I agree, but I think we should treat this as safety fallback, because
if the assertion fails then we very likely have a bug further up
the call chain that we want to fix.  We don't want to silently accept
calls that fails that invariant.

>-  // At least one of aSelection and mSelection must be null
>-  // aSelection will be null when we are removing from a selection
>-  // and a range can't be in more than one selection at a time,
>-  // thus mSelection must be null too.

Please keep this comment, and keep the MOZ_ASSERT right after it.

>+  // Remove this range from the current selection before adding it to another.
>+  if (aSelection && mSelection) {
>+    mSelection->RemoveRange(this);
>+  }

Please change the comment to say it's a wallpaper, e.g.:
// This is a wallpaper in case our caller failed to ensure the above invariant.

r=mats with those changes
Attachment #8908687 - Flags: review?(mats) → review+
Comment on attachment 8909329 [details] [diff] [review]
Prevent dom ranges from positioning on elements from a different document when part of a selection.

r=mats, with a few nits:

>-  static nsINode* ComputeRootNode(nsINode* aNode)
>-  {
>-    return ComputeRootNode(aNode, false);
>-  }
...
>-  static nsINode* ComputeRootNode(nsINode* aNode,
>-                                  bool aMaySpanAnonymousSubtrees);

Please keep these two methods as is.  The reason is that
we don't want to expose the aMaySpanAnonymousSubtrees
param in the public API (since it's a thing we want to
get rid of eventually and thus don't want to enable
new consumers to depend on it).

Please add the following comment above the second declaration:
// This signature is intentionally non-public to avoid adding
// new code that depends on the "MaySpanAnonymousSubtrees" concept,
// which we want to remove eventually.

>+  inline nsINode* ComputeNewRootNode(nsINode* aNode) const
>+  {
>+    return ComputeRootNode(aNode, mMaySpanAnonymousSubtrees);
>+  }

Please move this method up a bit so that it's after the other
ComputeNewRootNode declaration, and move the non-public
ComputeRootNode after those two.

Also, it would be nice if you could document what the two-param
ComputeNewRootNode method does (at least).  In particular, point
out that for ranges that are in a Selection, it rejects nodes
that are not in the same document as that Selection.
And that it's this method that should be called from methods
that are entry points for JS methods since we want that check
there.

(The ComputeRootNode/ComputeNewRootNode naming seems slightly
confusing to me, although I don't have any better suggestions.)
Attachment #8909329 - Flags: review?(mats) → review+
This is a regression from bug 1395701 so I don't expect 52 is affected.

Do the new sanity checks on selection basically implement http://w3c.github.io/selection-api/#widl-Selection-addRange-void-Range-range step 1, or some other sanity-check?
Blocks: 1395701
Ah, those sanity checks (which we already do) won't help, because we're repositioning the range to be in a new document.

We should probably file some spec issues here, once we land the fix.  Cătălin, thank you for picking this up!

Should probably add some crashtests too.
Attachment #8908687 - Attachment is obsolete: true
Attachment #8909329 - Attachment is obsolete: true
Attachment #8910259 - Attachment is obsolete: true
Attachment #8910258 - Attachment is obsolete: true
Comment on attachment 8910277 [details] [diff] [review]
Avoid adding the same range to multiple selections.

[Security approval request comment]
How easily could an exploit be constructed based on the patch?
It's not obvious this fixes a crash without knowledge of the ownership relation between Selection and nsRange. Also, it needs specific gc.

Do comments in the patch, the check-in comment, or tests included in the patch paint a bulls-eye on the security problem?
This should be landed with a different bug number, otherwise the commit message is fine.

Which older supported branches are affected by this flaw?
If not all supported branches, which bug introduced the flaw?
Comment #14 suggests this was introduced in 57 by bug 1395701.
I will need to check this.

Do you have backports for the affected branches? If not, how different, hard to create, and risky will they be?

How likely is this patch to cause regressions; how much testing does it need?
Unlikely to cause regressions.
Attachment #8910277 - Flags: sec-approval?
Comment on attachment 8910267 [details] [diff] [review]
Prevent dom ranges from positioning on elements from a different document when part of a selection.

Do you think we should land this patch in an open bug?
The reasons would be that it changes web api behaviour and the other patch also prevents the UAF.
Attachment #8910267 - Flags: feedback?(mats)
(In reply to Cătălin Badea (:catalinb) from comment #21)
> Do you think we should land this patch in an open bug?

Sure, I think that's a good idea to avoid drawing attention to this change.
Comment on attachment 8910267 [details] [diff] [review]
Prevent dom ranges from positioning on elements from a different document when part of a selection.

>+  // *silently* reject root nodes different then that of the current selection

It should be "different than that" there I think (a instead of e).
Attachment #8910267 - Flags: feedback?(mats) → feedback+
(In reply to Cătălin Badea (:catalinb) from comment #20)

> Which older supported branches are affected by this flaw?
> If not all supported branches, which bug introduced the flaw?
> Comment #14 suggests this was introduced in 57 by bug 1395701.
> I will need to check this.


I'll need to know the answer before this can get sec-approval to land. We need to know how far back the bug goes.
Flags: needinfo?(catalin.badea392)
For what it's worth, I'm pretty sure this is a regression from bug 1395701.  See bug 1400179 comment 6 for an analysis of what used to happen before that patch in this situation, and it should not have led to UAF.
(In reply to Al Billings [:abillings] from comment #24)
> (In reply to Cătălin Badea (:catalinb) from comment #20)
> 
> > Which older supported branches are affected by this flaw?
> > If not all supported branches, which bug introduced the flaw?
> > Comment #14 suggests this was introduced in 57 by bug 1395701.
> > I will need to check this.
> 
> 
> I'll need to know the answer before this can get sec-approval to land. We
> need to know how far back the bug goes.

I couldn't reproduce the asan crash before bug 1395701, which confirms bz's analysis.
Flags: needinfo?(catalin.badea392)
Flags: needinfo?(abillings)
:abillings, could you please give the security approval now?
You don't need sec-approval for trunk-only issues, as I understand.  So this could have landed without sec-approval to start with.

That said, I don't know what the status is of this bug at this point, since 57 is branching today so it might now not be trunk-only anymore.  :(
The branch date for 57 was yesterday. It needs sec-approval and an uplift request for Beta now.
Comment on attachment 8910277 [details] [diff] [review]
Avoid adding the same range to multiple selections.

sec-approval+ for trunk.
Please also nominate a patch for Beta (57) to land after trunk is green.
Flags: needinfo?(abillings)
Attachment #8910277 - Flags: sec-approval? → sec-approval+
Keywords: checkin-needed
Comment on attachment 8910267 [details] [diff] [review]
Prevent dom ranges from positioning on elements from a different document when part of a selection.

Per comment 21, this patch is going into a different bug.
Attachment #8910267 - Attachment is obsolete: true
Comment on attachment 8910277 [details] [diff] [review]
Avoid adding the same range to multiple selections.

Approval Request Comment
[Feature/Bug causing the regression]:
dom ranges
[User impact if declined]:
Crash/potential exploit
[Is this code covered by automated tests?]:
No. I will add the test case as a crashtest once this gets uplifted.
[Has the fix been verified in Nightly?]:
Yes.
[Needs manual test from QE? If yes, steps to reproduce]:
No.
[List of other uplifts needed for the feature/fix]:
No.
[Is the change risky?]:
[Why is the change risky/not risky?]:
Not risky, it's a very simple change.
[String changes made/needed]:
None.
Attachment #8910277 - Flags: approval-mozilla-beta?
https://hg.mozilla.org/mozilla-central/rev/c3b24ef42810
Status: NEW → RESOLVED
Closed: 7 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla58
Comment on attachment 8910277 [details] [diff] [review]
Avoid adding the same range to multiple selections.

Fix a sec-high, taking it
Attachment #8910277 - Flags: approval-mozilla-beta? → approval-mozilla-beta+
Group: dom-core-security → core-security-release
Flags: sec-bounty?
Flags: sec-bounty? → sec-bounty+
Keywords: regression
Group: core-security-release

(In reply to Cătălin Badea (:catalinb) from comment #34)

Comment on attachment 8910277 [details] [diff] [review]
Avoid adding the same range to multiple selections.

Approval Request Comment
[Feature/Bug causing the regression]:
dom ranges
[User impact if declined]:
Crash/potential exploit
[Is this code covered by automated tests?]:
No. I will add the test case as a crashtest once this gets uplifted.

It seems this never happened.

[Is the change risky?]:
[Why is the change risky/not risky?]:
Not risky, it's a very simple change.
[String changes made/needed]:
None.

Flags: in-testsuite?

With :catalinb's test-case attached to this ticket I couldn't reproduce hitting https://searchfox.org/mozilla-central/rev/d58860eb739af613774c942c3bb61754123e449b/dom/base/nsRange.cpp#965,975, so I wonder whether this fallback is still necessary.

You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: