Bug 70456 (CVE-2012-0611) - Use after free in positioned generated content under run-in
Summary: Use after free in positioned generated content under run-in
Status: RESOLVED FIXED
Alias: CVE-2012-0611
Product: Security
Classification: Unclassified
Component: Security (show other bugs)
Version: 525.x (Nightly build)
Hardware: All All
: P2 Major
Assignee: WebKit Security Group
URL:
Keywords: InRadar
: 72666 (view as bug list)
Depends on:
Blocks:
 
Reported: 2011-10-19 16:54 PDT by Abhishek Arya
Modified: 2014-02-18 22:36 PST (History)
12 users (show)

See Also:


Attachments
Patch (5.80 KB, patch)
2011-11-16 17:02 PST, Ken Buchanan
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Abhishek Arya 2011-10-19 16:54:24 PDT
credit: Marty + ASAN + ClusterFuzz
http://code.google.com/p/chromium/issues/detail?id=100958

Bot CLUSTER_FUZZ_331 on platform LINUX
Chromium Revision : 106012
Webkit Revision : 97678

Testcase::
<style> .c17 { position: relative; }
.c19::after { display: compact; position: absolute; content: no-close-quote; }
.c19:nth-of-type(-n+6) { display: run-in;</style>
<script>
var nodes = Array();
function boom() {
try { nodes[45] = document.createElement('thead'); } catch(e) {}
try { nodes[45].setAttribute('class', 'c19'); } catch(e) {}
try { document.documentElement.appendChild(nodes[45]); } catch(e) {}
try { nodes[46] = document.createElement('b'); } catch(e) {}
try { nodes[46].setAttribute('class', 'c19'); } catch(e) {}
try { document.documentElement.appendChild(nodes[46]); } catch(e) {}
try { nodes[47] = document.createElement('header'); } catch(e) {}
try { document.documentElement.appendChild(nodes[47]); } catch(e) {}
}
window.onload = boom;
</script>

/mnt/scratch0/chrome/src/out/Release/DumpRenderTree 

ASAN:SIGILL
=================================================================
==16725== ERROR: AddressSanitizer heap-use-after-free on address 0x7f6cbb283ab0 at pc 0x2527275 bp 0x7fff3223adf0 sp 0x7fff3223ace0
READ of size 1 at 0x7f6cbb283ab0 thread T0
    #0 0x2527275 in WebCore::RenderBlock::layoutPositionedObjects(bool) 
    #1 0x251d37d in WebCore::RenderBlock::layoutBlock(bool, int, WebCore::RenderBlock::BlockLayoutPass) 
    #2 0x251afe9 in WebCore::RenderBlock::layout() 
    #3 0x27de57b in WebCore::RenderView::layout() 
    #4 0x2045cab in WebCore::FrameView::layout(bool) 
    #5 0x2050277 in WebCore::FrameView::visibleContentsResized() 
    #6 0x16f7d77 in WebCore::ScrollView::updateScrollbars(WebCore::IntSize const&) 
    #7 0x16fa7e4 in WebCore::ScrollView::setContentsSize(WebCore::IntSize const&) 
    #8 0x2041e3b in WebCore::FrameView::setContentsSize(WebCore::IntSize const&) 
    #9 0x2042291 in WebCore::FrameView::adjustViewSize() 
    #10 0x2045e2f in WebCore::FrameView::layout(bool) 
    #11 0x12d2168 in WebCore::Document::implicitClose() 
    #12 0x1ee65dc in WebCore::FrameLoader::checkCompleted() 
    #13 0x1ee28c8 in WebCore::FrameLoader::finishedParsing() 
    #14 0x12f073e in WebCore::Document::finishedParsing() 
    #15 0x15b9b4e in WebCore::HTMLDocumentParser::prepareToStopParsing() 
    #16 0x1ec4444 in WebCore::DocumentWriter::endIfNotLoadingMainResource() 
    #17 0x1f030f9 in WebCore::FrameLoader::finishedLoading() 
    #18 0x1f28034 in WebCore::MainResourceLoader::didFinishLoading(double) 
    #19 0x338c097 in webkit_glue::WebURLLoaderImpl::Context::OnCompletedRequest(net::URLRequestStatus const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, base::Time const&) 
    #20 0x34c3c03 in (anonymous namespace)::RequestProxy::NotifyCompletedRequest(net::URLRequestStatus const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, base::Time const&) webkit/tools/test_shell/simple_resource_loader_bridge.cc:0
    #21 0x34c405e in base::internal::Invoker4<false, base::internal::InvokerStorage4<void ((anonymous namespace)::RequestProxy::*)(net::URLRequestStatus const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, base::Time const&), (anonymous namespace)::RequestProxy*, net::URLRequestStatus, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, base::Time>, void ((anonymous namespace)::RequestProxy::*)(net::URLRequestStatus const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, base::Time const&)>::DoInvoke(base::internal::InvokerStorageBase*) webkit/tools/test_shell/simple_resource_loader_bridge.cc:0
    #22 0x866067 in MessageLoop::RunTask(MessageLoop::PendingTask const&) 
    #23 0x866819 in MessageLoop::DeferOrRunPendingTask(MessageLoop::PendingTask const&) 
    #24 0x867cd8 in MessageLoop::DoWork() 
    #25 0x8aef0f in (anonymous namespace)::WorkSourceDispatch(_GSource*, int (*)(void*), void*) base/message_pump_glib.cc:0
    #26 0x7f6cc34298c2 in g_main_dispatch /build/buildd/glib2.0-2.24.1/glib/gmain.c:1960
    #27 0x7f6cc342d748 in g_main_context_iterate /build/buildd/glib2.0-2.24.1/glib/gmain.c:2591
    #28 0x7f6cc342d8fc in IA__g_main_context_iteration /build/buildd/glib2.0-2.24.1/glib/gmain.c:2654
    #29 0x8b1361 in base::MessagePumpGtk::RunOnce(_GMainContext*, bool) 
    #30 0x8afa6d in base::MessagePumpGlib::RunWithDispatcher(base::MessagePump::Delegate*, base::MessagePumpDispatcher*) 
    #31 0x864ba9 in MessageLoop::RunInternal() 
    #32 0x863ad9 in MessageLoop::Run() 
    #33 0x48d2f5 in TestShell::waitTestFinished() 
    #34 0x4847a2 in TestShell::runFileTest(TestParams const&) 
    #35 0x434dda in runTest(TestShell&, TestParams&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool) third_party/WebKit/Tools/DumpRenderTree/chromium/DumpRenderTree.cpp:0
    #36 0x433ab7 in main 
    #37 0x7f6cbf7c7c4d in __libc_start_main /build/buildd/eglibc-2.11.1/csu/libc-start.c:258
    #38 0x419499 in _start 
0x7f6cbb283ab0 is located 48 bytes inside of 184-byte region [0x7f6cbb283a80,0x7f6cbb283b38)
freed by thread T0 here:
    #1 0x27328ef in WebCore::RenderObjectChildList::destroyLeftoverChildren() 
    #2 0x250e3e0 in WebCore::RenderBlock::willBeDestroyed() 
    #3 0x272cd32 in WebCore::RenderObject::destroy() 
    #4 0x252d915 in WebCore::RenderBlock::handleRunInChild(WebCore::RenderBox*) 
    #5 0x25242f6 in WebCore::RenderBlock::layoutBlockChildren(bool, int&) 
    #6 0x251c59b in WebCore::RenderBlock::layoutBlock(bool, int, WebCore::RenderBlock::BlockLayoutPass) 
    #7 0x251afe9 in WebCore::RenderBlock::layout() 
    #8 0x2537e94 in WebCore::RenderBlock::layoutBlockChild(WebCore::RenderBox*, WebCore::RenderBlock::MarginInfo&, int&, int&) 
    #9 0x252431a in WebCore::RenderBlock::layoutBlockChildren(bool, int&) 
    #10 0x251c59b in WebCore::RenderBlock::layoutBlock(bool, int, WebCore::RenderBlock::BlockLayoutPass) 
    #11 0x251afe9 in WebCore::RenderBlock::layout() 
    #12 0x27de57b in WebCore::RenderView::layout() 
    #13 0x2045cab in WebCore::FrameView::layout(bool) 
    #14 0x2050277 in WebCore::FrameView::visibleContentsResized() 
    #15 0x16f7d77 in WebCore::ScrollView::updateScrollbars(WebCore::IntSize const&) 
    #16 0x16fa7e4 in WebCore::ScrollView::setContentsSize(WebCore::IntSize const&) 
    #17 0x2041e3b in WebCore::FrameView::setContentsSize(WebCore::IntSize const&) 
    #18 0x2042291 in WebCore::FrameView::adjustViewSize() 
    #19 0x2045e2f in WebCore::FrameView::layout(bool) 
    #20 0x12d2168 in WebCore::Document::implicitClose() 
    #21 0x1ee65dc in WebCore::FrameLoader::checkCompleted() 
    #22 0x1ee28c8 in WebCore::FrameLoader::finishedParsing() 
    #23 0x12f073e in WebCore::Document::finishedParsing() 
    #24 0x15b9b4e in WebCore::HTMLDocumentParser::prepareToStopParsing() 
    #25 0x1ec4444 in WebCore::DocumentWriter::endIfNotLoadingMainResource() 
    #26 0x1f030f9 in WebCore::FrameLoader::finishedLoading() 
    #27 0x1f28034 in WebCore::MainResourceLoader::didFinishLoading(double) 
    #28 0x338c097 in webkit_glue::WebURLLoaderImpl::Context::OnCompletedRequest(net::URLRequestStatus const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, base::Time const&) 
    #29 0x34c3c03 in (anonymous namespace)::RequestProxy::NotifyCompletedRequest(net::URLRequestStatus const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, base::Time const&) webkit/tools/test_shell/simple_resource_loader_bridge.cc:0
previously allocated by thread T0 here:
    #1 0x2714f6d in WebCore::RenderObject::createObject(WebCore::Node*, WebCore::RenderStyle*) 
    #2 0x273769b in WebCore::RenderObjectChildList::updateBeforeAfterContent(WebCore::RenderObject*, WebCore::PseudoId, WebCore::RenderObject const*) 
    #3 0x25103ba in WebCore::RenderBlock::styleDidChange(WebCore::StyleDifference, WebCore::RenderStyle const*) 
    #4 0x272733e in WebCore::RenderObject::setStyle(WTF::PassRefPtr<WebCore::RenderStyle>) 
    #5 0x272665b in WebCore::RenderObject::setAnimatableStyle(WTF::PassRefPtr<WebCore::RenderStyle>) 
    #6 0x1389b7d in WebCore::NodeRendererFactory::createRenderer() 
    #7 0x138a35e in WebCore::NodeRendererFactory::createRendererIfNeeded() 
    #8 0x13693b6 in WebCore::Node::createRendererIfNeeded() 
    #9 0x132dfd5 in WebCore::Element::attach() 
    #10 0x132ff5c in WebCore::Element::recalcStyle(WebCore::Node::StyleChange) 
    #11 0x1330c6c in WebCore::Element::recalcStyle(WebCore::Node::StyleChange) 
    #12 0x12cf572 in WebCore::Document::recalcStyle(WebCore::Node::StyleChange) 
    #13 0x12d281f in WebCore::Document::updateStyleIfNeeded() 
    #14 0x12d202f in WebCore::Document::implicitClose() 
    #15 0x1ee65dc in WebCore::FrameLoader::checkCompleted() 
    #16 0x1ee28c8 in WebCore::FrameLoader::finishedParsing() 
    #17 0x12f073e in WebCore::Document::finishedParsing() 
    #18 0x15b9b4e in WebCore::HTMLDocumentParser::prepareToStopParsing() 
    #19 0x1ec4444 in WebCore::DocumentWriter::endIfNotLoadingMainResource() 
    #20 0x1f030f9 in WebCore::FrameLoader::finishedLoading() 
    #21 0x1f28034 in WebCore::MainResourceLoader::didFinishLoading(double) 
    #22 0x338c097 in webkit_glue::WebURLLoaderImpl::Context::OnCompletedRequest(net::URLRequestStatus const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, base::Time const&) 
    #23 0x34c3c03 in (anonymous namespace)::RequestProxy::NotifyCompletedRequest(net::URLRequestStatus const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, base::Time const&) webkit/tools/test_shell/simple_resource_loader_bridge.cc:0
==16725== ABORTING
Shadow byte and word:
  0x1fed97650756: fd
  0x1fed97650750: fd fd fd fd fd fd fd fd
More shadow bytes:
  0x1fed97650730: 00 00 00 00 00 00 00 00
  0x1fed97650738: 00 00 00 00 00 00 00 00
  0x1fed97650740: fa fa fa fa fa fa fa fa
  0x1fed97650748: fa fa fa fa fa fa fa fa
=>0x1fed97650750: fd fd fd fd fd fd fd fd
  0x1fed97650758: fd fd fd fd fd fd fd fd
  0x1fed97650760: fd fd fd fd fd fd fd fd
  0x1fed97650768: fd fd fd fd fd fd fd fd
  0x1fed97650770: fa fa fa fa fa fa fa fa
	base::debug::StackTrace::StackTrace() [0x8c5296]
	base::(anonymous namespace)::StackDumpSignalHandler() [0x891e2f]
	0x7f6cbf7dcaf0
	0x7f6cbf7dca75
	0x7f6cbf7e05c0
	asan_report_error() [0x4873140]
	0x7f6cc06ce8f0
	WebCore::RenderBlock::layoutPositionedObjects() [0x2527275]
	WebCore::RenderBlock::layoutBlock() [0x251d37d]
	WebCore::RenderBlock::layout() [0x251afe9]
	WebCore::RenderView::layout() [0x27de57b]
	WebCore::FrameView::layout() [0x2045cab]
	WebCore::FrameView::visibleContentsResized() [0x2050277]
	WebCore::ScrollView::updateScrollbars() [0x16f7d77]
	WebCore::ScrollView::setContentsSize() [0x16fa7e4]
	WebCore::FrameView::setContentsSize() [0x2041e3b]
	WebCore::FrameView::adjustViewSize() [0x2042291]
	WebCore::FrameView::layout() [0x2045e2f]
	WebCore::Document::implicitClose() [0x12d2168]
	WebCore::FrameLoader::checkCompleted() [0x1ee65dc]
	WebCore::FrameLoader::finishedParsing() [0x1ee28c8]
	WebCore::Document::finishedParsing() [0x12f073e]
	WebCore::HTMLDocumentParser::prepareToStopParsing() [0x15b9b4e]
	WebCore::DocumentWriter::endIfNotLoadingMainResource() [0x1ec4444]
	WebCore::FrameLoader::finishedLoading() [0x1f030f9]
	WebCore::MainResourceLoader::didFinishLoading() [0x1f28034]
	webkit_glue::WebURLLoaderImpl::Context::OnCompletedRequest() [0x338c097]
	(anonymous namespace)::RequestProxy::NotifyCompletedRequest() [0x34c3c03]
	base::internal::Invoker4<>::DoInvoke() [0x34c405e]
	MessageLoop::RunTask() [0x866067]
	MessageLoop::DeferOrRunPendingTask() [0x866819]
	MessageLoop::DoWork() [0x867cd8]
	(anonymous namespace)::WorkSourceDispatch() [0x8aef0f]
	0x7f6cc34298c2
	0x7f6cc342d748
	0x7f6cc342d8fc
	base::MessagePumpGtk::RunOnce() [0x8b1361]
	base::MessagePumpGlib::RunWithDispatcher() [0x8afa6d]
	MessageLoop::RunInternal() [0x864ba9]
	MessageLoop::Run() [0x863ad9]
	TestShell::waitTestFinished() [0x48d2f5]
	TestShell::runFileTest() [0x4847a2]
	runTest() [0x434dda]
	main [0x433ab7]
	0x7f6cbf7c7c4d
	0x419499
Comment 1 Lucas Forschler 2011-10-20 09:17:00 PDT
<rdar://problem/10317548>
Comment 2 Abhishek Arya 2011-10-20 10:08:37 PDT
Reduced testcase::
<style>
.testclass::before { position: absolute; content: ""; }
.testclass { display: run-in; }
</style>
<script>
function runTest() 
{
    test1 = document.createElement('div');
    test1.setAttribute('class', 'testclass');
    document.documentElement.appendChild(test1);
    test2 = document.createElement('b');
    test2.setAttribute('class', 'testclass');
    document.documentElement.appendChild(test2);
    test3 = document.createElement('div');
    document.documentElement.appendChild(test3);
}
window.onload = runTest;
</script>
Comment 3 Ken Buchanan 2011-11-15 09:22:19 PST
The run-in is significant. handleRunInChild() removes the run-in block from the render tree before destroying it. So positioned (or possibly floating) children that are getting destroyed are unable to clear themselves from the positioned/floating object list of a higher-level renderer (in the case of absolute positioned generated content, the RenderView).

It only happens with generated content because normal content underneath the block run-in is transferred to the inline run-in, rather than being destroyed.

This seems like it should be an easy fix, but for reasons I don't yet understand, the obvious solution (leave the renderer on the tree until you delete it) breaks a test. Something gets messed up with RenderLayers.
Comment 4 Ken Buchanan 2011-11-15 12:05:03 PST
Discussed with aarya: he is advocating to try to solve the general case: when a node with positioned descendants is removed from the tree, how do we clear those descendants from the positioned object list of its ancestors?

AFAICT, this would imply a full subtree traversal whenever we remove a child, because there could be absolute positioned descendants anywhere down there. It looks like we already do a partial subtree traversal looking for floats, but that is somewhat limited because we don't look at (e.g.) floats that are children of non-floating children. We could turn that partial traversal (i.e. markAllDescendantsWithFloatsForLayout()) into a full traversal that looks for both floats and positioned objects, but this might still have performance concerns.
Comment 5 Ken Buchanan 2011-11-16 17:02:42 PST
Created attachment 115484 [details]
Patch
Comment 6 Ken Buchanan 2011-11-16 17:09:39 PST
The patch I just uploaded is a local solution to this specific case, not a general solution. Given that a general solution to the problem I describe in comment 4 seems difficult (to me, anyway), I'm not inclined to write one unless it is clear it is worth it.
Comment 7 Dave Hyatt 2011-11-17 11:29:32 PST
Comment on attachment 115484 [details]
Patch

r=me
Comment 8 WebKit Review Bot 2011-11-17 14:34:42 PST
Comment on attachment 115484 [details]
Patch

Clearing flags on attachment: 115484

Committed r100677: <http://trac.webkit.org/changeset/100677>
Comment 9 WebKit Review Bot 2011-11-17 14:34:47 PST
All reviewed patches have been landed.  Closing bug.
Comment 10 Abhishek Arya 2012-08-03 07:33:59 PDT
*** Bug 72666 has been marked as a duplicate of this bug. ***