New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.
Starred by 4 users
Status: Fixed
Owner:
Email to this user bounced
Closed: May 2014



Sign in to add a comment
Safari sandbox IPC memory corruption with WebEvent::Wheel
Project Member Reported by ianbeer@google.com, Apr 3 2014 Back to list
The handler for the WebPageProxy::DidReceiveEvent IPC message fails to check that the WTF::Deque m_currentlyProcessedWheelEvents is not empty before calling takeFirst() when processing an event of type WebEvent::Wheel:

void WebPageProxy::didReceiveEvent(uint32_t opaqueType, bool handled)
...
    case WebEvent::Wheel: {
        ASSERT(!m_currentlyProcessedWheelEvents.isEmpty());

        OwnPtr<Vector<NativeWebWheelEvent>> oldestCoalescedEvent = m_currentlyProcessedWheelEvents.takeFirst();
...

That debug ASSERT should be a runtime CHECK.

takeFirst() simply returns the head of the queue and bumps the pointer (mod the buffer size,) there is no check that the queue isn't empty.

When this scope is left that OwnPtr will be freed. Exploitability depends on the contents of the buffer backing the queue, a crash stack is show below where the faulting address is clearly a poison value, however the memory pointed to by that poisoned pointer doesn't seem to be reserved, and could probably be easily heap-sprayed too. Further investigation of the operation of WTF::Deque would be required to understand if this could be exploited reliably.

Crash stack:
(lldb) attach 9724
Process 9724 stopped
Executable module set to "/Applications/Safari.app/Contents/MacOS/SafariForWebKitDevelopment".
Architecture set to: x86_64-apple-macosx.
(lldb) c
Process 9724 resuming
Process 9724 stopped
* thread #1: tid = 0x9ef7, 0x0000000101bd1513 WebKit2`WTF::Vector<WebKit::NativeWebWheelEvent, 0ul, WTF::CrashOnOverflow>::~Vector(this=0x00000001badbeef5) + 9 at Vector.h:595, queue = 'com.apple.main-thread, stop reason = EXC_BAD_ACCESS (code=1, address=0x1badbef01)
    frame #0: 0x0000000101bd1513 WebKit2`WTF::Vector<WebKit::NativeWebWheelEvent, 0ul, WTF::CrashOnOverflow>::~Vector(this=0x00000001badbeef5) + 9 at Vector.h:595
   592 	
   593 	    ~Vector()
   594 	    {
-> 595 	        if (m_size)
   596 	            shrink(0);
   597 	    }
   598 	
WebKit2`WTF::Vector<WebKit::NativeWebWheelEvent, 0ul, WTF::CrashOnOverflow>::~Vector() + 9 at Vector.h:595:
-> 0x101bd1513:  cmp    DWORD PTR [RBX + 12], 0
   0x101bd1517:  je     0x101bd1523               ; WTF::Vector<WebKit::NativeWebWheelEvent, 0ul, WTF::CrashOnOverflow>::~Vector() + 25 [inlined] WTF::VectorBufferBase<WebKit::NativeWebWheelEvent>::buffer() at Vector.h:373
WTF::Vector<WebKit::NativeWebWheelEvent, 0ul, WTF::CrashOnOverflow>::~Vector() + 25 [inlined] WTF::VectorBuffer<WebKit::NativeWebWheelEvent, 0ul>::~VectorBuffer() at Vector.h:597
WTF::Vector<WebKit::NativeWebWheelEvent, 0ul, WTF::CrashOnOverflow>::~Vector() + 25 at Vector.h:597
   0x101bd1519:  mov    RDI, RBX
(lldb) bt
* thread #1: tid = 0x9ef7, 0x0000000101bd1513 WebKit2`WTF::Vector<WebKit::NativeWebWheelEvent, 0ul, WTF::CrashOnOverflow>::~Vector(this=0x00000001badbeef5) + 9 at Vector.h:595, queue = 'com.apple.main-thread, stop reason = EXC_BAD_ACCESS (code=1, address=0x1badbef01)
    frame #0: 0x0000000101bd1513 WebKit2`WTF::Vector<WebKit::NativeWebWheelEvent, 0ul, WTF::CrashOnOverflow>::~Vector(this=0x00000001badbeef5) + 9 at Vector.h:595
    frame #1: 0x0000000101bd14f4 WebKit2`WTF::OwnPtr<WTF::Vector<WebKit::NativeWebWheelEvent, 0ul, WTF::CrashOnOverflow> >::~OwnPtr() [inlined] WTF::Vector<WebKit::NativeWebWheelEvent, 0ul, WTF::CrashOnOverflow>::~Vector(this=0x00000001badbeef5, p=0x00000001badbeef5) + 8 at Vector.h:594
    frame #2: 0x0000000101bd14ec WebKit2`WTF::OwnPtr<WTF::Vector<WebKit::NativeWebWheelEvent, 0ul, WTF::CrashOnOverflow> >::~OwnPtr() [inlined] void WTF::deleteOwnedPtr<WTF::Vector<WebKit::NativeWebWheelEvent, 0ul, WTF::CrashOnOverflow> >(ptr=0x00000001badbeef5) at OwnPtrCommon.h:37
    frame #3: 0x0000000101bd14ec WebKit2`WTF::OwnPtr<WTF::Vector<WebKit::NativeWebWheelEvent, 0ul, WTF::CrashOnOverflow> >::~OwnPtr(this=<unavailable>) + 14 at OwnPtr.h:47
    frame #4: 0x0000000101bbd198 WebKit2`WebKit::WebPageProxy::didReceiveEvent(unsigned int, bool) [inlined] WTF::OwnPtr<WTF::Vector<WebKit::NativeWebWheelEvent, 0ul, WTF::CrashOnOverflow> >::~OwnPtr(this=0x00000001badbeef5) + 776 at OwnPtr.h:47
    frame #5: 0x0000000101bbd193 WebKit2`WebKit::WebPageProxy::didReceiveEvent(this=<unavailable>, opaqueType=<unavailable>, handled=<unavailable>) + 771 at WebPageProxy.cpp:3699
    frame #6: 0x0000000101bdb648 WebKit2`void IPC::handleMessage<Messages::WebPageProxy::DidReceiveEvent, WebKit::WebPageProxy, void (WebKit::WebPageProxy::*)(unsigned int, bool)>(IPC::MessageDecoder&, WebKit::WebPageProxy*, void (WebKit::WebPageProxy::*)(unsigned int, bool)) [inlined] void IPC::callMemberFunctionImpl<WebKit::WebPageProxy, void (args=0x0000000100000003, __t=0x0000000100000003, object=<unavailable>)(unsigned int, bool), std::__1::tuple<unsigned int, bool>, 0ul, 1ul>(WebKit::WebPageProxy*, void (WebKit::WebPageProxy::*)(unsigned int, bool), std::__1::tuple<unsigned int, bool>&&, std::index_sequence<0ul, 1ul>) + 73 at HandleMessage.h:16
    frame #7: 0x0000000101bdb62a WebKit2`void IPC::handleMessage<Messages::WebPageProxy::DidReceiveEvent, WebKit::WebPageProxy, void (WebKit::WebPageProxy::*)(unsigned int, bool)>(IPC::MessageDecoder&, WebKit::WebPageProxy*, void (WebKit::WebPageProxy::*)(unsigned int, bool)) [inlined] void IPC::callMemberFunction<WebKit::WebPageProxy, void (args=0x0000000100000003, __t=0x0000000100000003)(unsigned int, bool), std::__1::tuple<unsigned int, bool>, std::make_index_sequence<2ul> >(std::__1::tuple<unsigned int, bool>&&, WebKit::WebPageProxy*, void (WebKit::WebPageProxy::*)(unsigned int, bool)) at HandleMessage.h:22
    frame #8: 0x0000000101bdb62a WebKit2`void IPC::handleMessage<Messages::WebPageProxy::DidReceiveEvent, WebKit::WebPageProxy, void (decoder=<unavailable>, object=<unavailable>, function=<unavailable>)(unsigned int, bool)>(IPC::MessageDecoder&, WebKit::WebPageProxy*, void (WebKit::WebPageProxy::*)(unsigned int, bool)) + 43 at HandleMessage.h:117
    frame #9: 0x0000000101bd8c8e WebKit2`WebKit::WebPageProxy::didReceiveMessage(this=0x00007fc8eb80ea18, connection=<unavailable>, decoder=0x0000000107206820) + 916 at WebPageProxyMessageReceiver.cpp:214
    frame #10: 0x0000000101abf7d5 WebKit2`IPC::MessageReceiverMap::dispatchMessage(this=<unavailable>, connection=0x000000010720d780, decoder=0x0000000107206820) + 125 at MessageReceiverMap.cpp:87
    frame #11: 0x0000000101a6c947 WebKit2`WebKit::ChildProcessProxy::dispatchMessage(this=<unavailable>, connection=<unavailable>, decoder=<unavailable>) + 13 at ChildProcessProxy.cpp:118
    frame #12: 0x0000000101c05328 WebKit2`WebKit::WebProcessProxy::didReceiveMessage(this=0x000000010591ea80, connection=0x000000010720d780, decoder=0x0000000107206820) + 24 at WebProcessProxy.cpp:364
    frame #13: 0x0000000101a6dafc WebKit2`IPC::Connection::dispatchMessage(std::__1::unique_ptr<IPC::MessageDecoder, std::__1::default_delete<IPC::MessageDecoder> >) [inlined] IPC::Connection::dispatchMessage(decoder=<unavailable>, this=<unavailable>) + 94 at Connection.cpp:770
    frame #14: 0x0000000101a6daef WebKit2`IPC::Connection::dispatchMessage(this=0x000000010720d780, message=0x00007fff5eb85020) + 81 at Connection.cpp:791
    frame #15: 0x0000000101a6fb70 WebKit2`IPC::Connection::dispatchOneMessage(this=0x000000010720d780) + 106 at Connection.cpp:817
    frame #16: 0x0000000101463a45 JavaScriptCore`WTF::RunLoop::performWork() [inlined] std::__1::function<void (this=0x00007fff5eb850e0)>::operator()() const + 421 at functional:1435
    frame #17: 0x0000000101463a3b JavaScriptCore`WTF::RunLoop::performWork(this=0x000000010590df30) + 411 at RunLoop.cpp:104
    frame #18: 0x0000000101464122 JavaScriptCore`WTF::RunLoop::performWork(context=<unavailable>) + 34 at RunLoopCF.cpp:38
    frame #19: 0x00007fff871bb731 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    frame #20: 0x00007fff871acea2 CoreFoundation`__CFRunLoopDoSources0 + 242
    frame #21: 0x00007fff871ac62f CoreFoundation`__CFRunLoopRun + 831
    frame #22: 0x00007fff871ac0b5 CoreFoundation`CFRunLoopRunSpecific + 309
    frame #23: 0x00007fff90fb1a0d HIToolbox`RunCurrentEventLoopInMode + 226
    frame #24: 0x00007fff90fb17b7 HIToolbox`ReceiveNextEventCommon + 479
    frame #25: 0x00007fff90fb15bc HIToolbox`_BlockUntilNextEventMatchingListInModeWithFilter + 65
    frame #26: 0x00007fff8db9e3de AppKit`_DPSNextEvent + 1434
    frame #27: 0x00007fff8db9da2b AppKit`-[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 122
    frame #28: 0x00007fff8a241290 Safari`-[BrowserApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 161
    frame #29: 0x00007fff8db91b2c AppKit`-[NSApplication run] + 553
    frame #30: 0x00007fff8db7c913 AppKit`NSApplicationMain + 940
    frame #31: 0x00007fff8a41306d Safari`SafariMain + 267
    frame #32: 0x00007fff83a405fd libdyld.dylib`start + 1
    frame #33: 0x00007fff83a405fd libdyld.dylib`start + 1
(lldb) register read
General Purpose Registers:
       rax = 0x0000000000000000
       rbx = 0x00000001badbeef5
       rcx = 0x000000000000000f
       rdx = 0x0000000000000000
       rdi = 0x00000001badbeef5
       rsi = 0x0000000000000003
       rbp = 0x00007fff5eb84d50
       rsp = 0x00007fff5eb84d40
        r8 = 0x0000000000000074
        r9 = 0x0000000000000000
       r10 = 0x00007fc8eb4caf9c
       r11 = 0x00007fff73da4db8  (void *)0x00007fff73da4d90: NSAutoreleasePool
       r12 = 0x00007fc8eb80ea18
       r13 = 0x00007fff5eb85200
       r14 = 0x0000000000000001
       r15 = 0x00000001badbeef5
       rip = 0x0000000101bd1513  WebKit2`WTF::Vector<WebKit::NativeWebWheelEvent, 0ul, WTF::CrashOnOverflow>::~Vector() + 9 at Vector.h:595
    rflags = 0x0000000000010206
        cs = 0x000000000000002b
        fs = 0x0000000000000000
        gs = 0x0000000000000000


This issue can be easily reproduced by applying following patch to the renderer code then scrolling using the mouse on a page:

Source/WebKit2/WebProcess/WebPage/EventDispatcher.cpp:

         ScrollingTree::EventResult result = scrollingTree->tryToHandleWheelEvent(platformWheelEvent);
         if (result == ScrollingTree::DidHandleEvent || result == ScrollingTree::DidNotHandleEvent) {
-            sendDidReceiveEvent(pageID, wheelEvent, result == ScrollingTree::DidHandleEvent);
+            for (int i = 0; i < 128; i++){
+                sendDidReceiveEvent(pageID, wheelEvent, result == ScrollingTree::DidHandleEvent);
+            }
             return;
         }
     }
 
Project Member Comment 1 by ianbeer@google.com, Apr 3 2014
Summary: Safari sandbox IPC memory corruption with WebEvent::Wheel (was: Safari sandbox IPC memory corruption with webWheelEvents)
Project Member Comment 2 by ianbeer@google.com, Apr 4 2014
Labels: Reported-2014-Apr-04 PublicOn-2014-Jul-04
Project Member Comment 3 by ianbeer@google.com, Apr 4 2014
Apple follow-up id: 605055321
Project Member Comment 4 by ianbeer@google.com, Apr 4 2014
Labels: Id-605055321
Project Member Comment 5 by ianbeer@google.com, May 22 2014
Labels: -PublicOn-2014-Jul-04 CVE-2014-1344
Status: Fixed
Project Member Comment 6 by ianbeer@google.com, May 22 2014
Fixed in Safari 7.0.4
Apple advisory: http://support.apple.com/kb/HT6254
Comment 7 by cevans@google.com, Jul 31 2014
Labels: -Restrict-View-Commit
Sign in to add a comment