Title: [271772] trunk/Source/WebKit
Revision
271772
Author
[email protected]
Date
2021-01-22 18:13:17 -0800 (Fri, 22 Jan 2021)

Log Message

The web process should be killed after failing to decode display list items in the GPU process
https://bugs.webkit.org/show_bug.cgi?id=219097
<rdar://problem/71546526>

Reviewed by Chris Dumez.

Handle `StopReplayReason::InvalidItem` by terminating the web process via MESSAGE_CHECK. See below for more
details.

* GPUProcess/GPUConnectionToWebProcess.cpp:
(WebKit::GPUConnectionToWebProcess::didReceiveInvalidMessage):
(WebKit::GPUConnectionToWebProcess::terminateWebProcess):
* GPUProcess/GPUConnectionToWebProcess.h:

Pull logic for terminating the web process out into a separate helper method on `GPUConnectionToWebProcess`, and
use this helper in `GPUConnectionToWebProcess::didReceiveInvalidMessage`, as well as in `RemoteRenderingBackend`
below.

* GPUProcess/graphics/RemoteRenderingBackend.cpp:

Add macro definitions for `MESSAGE_CHECK` and `MESSAGE_CHECK_WITH_RETURN_VALUE`. Since the methods on
`RemoteRenderingBackend` that trigger message checks all run on a background queue, the normal (main-thread) way
of defining these macros (`MESSAGE_CHECK_WITH_RETURN_VALUE_BASE` and `MESSAGE_CHECK_BASE`) don't work. We
instead call into the GPU to web process connection object directly to send a `TerminateWebProcess` message to
the parent (UI) process, and additionally log a given failure message.

(WebKit::RemoteRenderingBackend::nextDestinationImageBufferAfterApplyingDisplayLists):

Replace a number FIXMEs throughout these IPC message handlers with `MESSAGE_CHECK`s. Additionally, add a new
`MESSAGE_CHECK` for the case where we stopped replay early due to a corrupted or invalid display list item.

(WebKit::RemoteRenderingBackend::wakeUpAndApplyDisplayList):
(WebKit::RemoteRenderingBackend::setNextItemBufferToRead):

Simply remove the FIXME and early return here; this can only happen in the case where a compromised web content
process attempts to append redundant item buffer change items. However, doing so will either be (1) harmless,
since the pending item buffer information will just be overwritten, or (2) result in hitting a MESSAGE_CHECK
when decoding items if we try to execute the contents of another item buffer that has not been written to.

(WebKit::RemoteRenderingBackend::didCreateSharedDisplayListHandle):
* GPUProcess/graphics/RemoteRenderingBackend.h:

Modified Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (271771 => 271772)


--- trunk/Source/WebKit/ChangeLog	2021-01-23 01:28:11 UTC (rev 271771)
+++ trunk/Source/WebKit/ChangeLog	2021-01-23 02:13:17 UTC (rev 271772)
@@ -1,3 +1,47 @@
+2021-01-22  Wenson Hsieh  <[email protected]>
+
+        The web process should be killed after failing to decode display list items in the GPU process
+        https://bugs.webkit.org/show_bug.cgi?id=219097
+        <rdar://problem/71546526>
+
+        Reviewed by Chris Dumez.
+
+        Handle `StopReplayReason::InvalidItem` by terminating the web process via MESSAGE_CHECK. See below for more
+        details.
+
+        * GPUProcess/GPUConnectionToWebProcess.cpp:
+        (WebKit::GPUConnectionToWebProcess::didReceiveInvalidMessage):
+        (WebKit::GPUConnectionToWebProcess::terminateWebProcess):
+        * GPUProcess/GPUConnectionToWebProcess.h:
+
+        Pull logic for terminating the web process out into a separate helper method on `GPUConnectionToWebProcess`, and
+        use this helper in `GPUConnectionToWebProcess::didReceiveInvalidMessage`, as well as in `RemoteRenderingBackend`
+        below.
+
+        * GPUProcess/graphics/RemoteRenderingBackend.cpp:
+
+        Add macro definitions for `MESSAGE_CHECK` and `MESSAGE_CHECK_WITH_RETURN_VALUE`. Since the methods on
+        `RemoteRenderingBackend` that trigger message checks all run on a background queue, the normal (main-thread) way
+        of defining these macros (`MESSAGE_CHECK_WITH_RETURN_VALUE_BASE` and `MESSAGE_CHECK_BASE`) don't work. We
+        instead call into the GPU to web process connection object directly to send a `TerminateWebProcess` message to
+        the parent (UI) process, and additionally log a given failure message.
+
+        (WebKit::RemoteRenderingBackend::nextDestinationImageBufferAfterApplyingDisplayLists):
+
+        Replace a number FIXMEs throughout these IPC message handlers with `MESSAGE_CHECK`s. Additionally, add a new
+        `MESSAGE_CHECK` for the case where we stopped replay early due to a corrupted or invalid display list item.
+
+        (WebKit::RemoteRenderingBackend::wakeUpAndApplyDisplayList):
+        (WebKit::RemoteRenderingBackend::setNextItemBufferToRead):
+
+        Simply remove the FIXME and early return here; this can only happen in the case where a compromised web content
+        process attempts to append redundant item buffer change items. However, doing so will either be (1) harmless,
+        since the pending item buffer information will just be overwritten, or (2) result in hitting a MESSAGE_CHECK
+        when decoding items if we try to execute the contents of another item buffer that has not been written to.
+
+        (WebKit::RemoteRenderingBackend::didCreateSharedDisplayListHandle):
+        * GPUProcess/graphics/RemoteRenderingBackend.h:
+
 2021-01-22  Simon Fraser  <[email protected]>
 
         [iOS WK2] Make the "in stable state" bit in visible content rect updates more fine-grained

Modified: trunk/Source/WebKit/GPUProcess/GPUConnectionToWebProcess.cpp (271771 => 271772)


--- trunk/Source/WebKit/GPUProcess/GPUConnectionToWebProcess.cpp	2021-01-23 01:28:11 UTC (rev 271771)
+++ trunk/Source/WebKit/GPUProcess/GPUConnectionToWebProcess.cpp	2021-01-23 02:13:17 UTC (rev 271772)
@@ -224,6 +224,11 @@
 void GPUConnectionToWebProcess::didReceiveInvalidMessage(IPC::Connection& connection, IPC::MessageName messageName)
 {
     RELEASE_LOG_FAULT(IPC, "Received an invalid message '%" PUBLIC_LOG_STRING "' from WebContent process %" PRIu64 ", requesting for it to be terminated.", description(messageName), m_webProcessIdentifier.toUInt64());
+    terminateWebProcess();
+}
+
+void GPUConnectionToWebProcess::terminateWebProcess()
+{
     gpuProcess().parentProcessConnection()->send(Messages::GPUProcessProxy::TerminateWebProcess(m_webProcessIdentifier), 0);
 }
 

Modified: trunk/Source/WebKit/GPUProcess/GPUConnectionToWebProcess.h (271771 => 271772)


--- trunk/Source/WebKit/GPUProcess/GPUConnectionToWebProcess.h	2021-01-23 01:28:11 UTC (rev 271771)
+++ trunk/Source/WebKit/GPUProcess/GPUConnectionToWebProcess.h	2021-01-23 02:13:17 UTC (rev 271772)
@@ -112,6 +112,8 @@
     RemoteAudioSessionProxyManager& audioSessionManager();
 #endif
 
+    void terminateWebProcess();
+
 private:
     GPUConnectionToWebProcess(GPUProcess&, WebCore::ProcessIdentifier, IPC::Connection::Identifier, PAL::SessionID);
 

Modified: trunk/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.cpp (271771 => 271772)


--- trunk/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.cpp	2021-01-23 01:28:11 UTC (rev 271771)
+++ trunk/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.cpp	2021-01-23 02:13:17 UTC (rev 271772)
@@ -44,6 +44,24 @@
 #include <wtf/cocoa/MachSemaphore.h>
 #endif
 
+#define TERMINATE_WEB_PROCESS_WITH_MESSAGE(message) \
+    RELEASE_LOG_FAULT(IPC, "Requesting termination of web process %" PRIu64 " for reason: %" PUBLIC_LOG_STRING, m_gpuConnectionToWebProcess->webProcessIdentifier().toUInt64(), #message); \
+    m_gpuConnectionToWebProcess->terminateWebProcess();
+
+#define MESSAGE_CHECK(assertion, message) do { \
+    if (UNLIKELY(!(assertion))) { \
+        TERMINATE_WEB_PROCESS_WITH_MESSAGE(message); \
+        return; \
+    } \
+} while (0)
+
+#define MESSAGE_CHECK_WITH_RETURN_VALUE(assertion, returnValue, message) do { \
+    if (UNLIKELY(!(assertion))) { \
+        TERMINATE_WEB_PROCESS_WITH_MESSAGE(message); \
+        return (returnValue); \
+    } \
+} while (0)
+
 namespace WebKit {
 using namespace WebCore;
 
@@ -173,31 +191,19 @@
 
     while (destination) {
         auto displayList = handle.displayListForReading(offset, sizeToRead, *this);
-        if (UNLIKELY(!displayList)) {
-            // FIXME: Add a message check to terminate the web process.
-            ASSERT_NOT_REACHED();
-            break;
-        }
+        MESSAGE_CHECK_WITH_RETURN_VALUE(displayList, nullptr, "Failed to map display list from shared memory");
 
         auto result = submit(*displayList, *destination);
         sizeToRead = handle.advance(result.numberOfBytesRead);
+        MESSAGE_CHECK_WITH_RETURN_VALUE(result.reasonForStopping != DisplayList::StopReplayReason::InvalidItem, nullptr, "Detected invalid display list item");
 
         CheckedSize checkedOffset = offset;
         checkedOffset += result.numberOfBytesRead;
-        if (UNLIKELY(checkedOffset.hasOverflowed())) {
-            // FIXME: Add a message check to terminate the web process.
-            ASSERT_NOT_REACHED();
-            break;
-        }
+        MESSAGE_CHECK_WITH_RETURN_VALUE(!checkedOffset.hasOverflowed(), nullptr, "Overflowed when advancing shared display list handle offset");
 
         offset = checkedOffset.unsafeGet();
+        MESSAGE_CHECK_WITH_RETURN_VALUE(offset <= handle.sharedMemory().size(), nullptr, "Out-of-bounds offset into shared display list handle");
 
-        if (UNLIKELY(offset > handle.sharedMemory().size())) {
-            // FIXME: Add a message check to terminate the web process.
-            ASSERT_NOT_REACHED();
-            break;
-        }
-
         if (result.reasonForStopping == DisplayList::StopReplayReason::ChangeDestinationImageBuffer) {
             destination = makeRefPtr(m_remoteResourceCache.cachedImageBuffer(*result.nextDestinationImageBuffer));
             if (!destination) {
@@ -232,27 +238,14 @@
                 break;
 
             sizeToRead = handle.unreadBytes();
-            if (UNLIKELY(!sizeToRead)) {
-                // FIXME: Add a message check to terminate the web process.
-                ASSERT_NOT_REACHED();
-                break;
-            }
+            MESSAGE_CHECK_WITH_RETURN_VALUE(sizeToRead, nullptr, "No unread bytes when resuming display list processing");
 
             auto newDestinationIdentifier = makeObjectIdentifier<RenderingResourceIdentifierType>(resumeReadingInfo->destination);
-            if (UNLIKELY(!newDestinationIdentifier)) {
-                // FIXME: Add a message check to terminate the web process.
-                ASSERT_NOT_REACHED();
-                break;
-            }
+            MESSAGE_CHECK_WITH_RETURN_VALUE(newDestinationIdentifier, nullptr, "Invalid image buffer destination when resuming display list processing");
 
             destination = makeRefPtr(m_remoteResourceCache.cachedImageBuffer(newDestinationIdentifier));
+            MESSAGE_CHECK_WITH_RETURN_VALUE(destination, nullptr, "Missing image buffer destination when resuming display list processing");
 
-            if (UNLIKELY(!destination)) {
-                // FIXME: Add a message check to terminate the web process.
-                ASSERT_NOT_REACHED();
-                break;
-            }
-
             offset = resumeReadingInfo->offset;
 
             if (!destination) {
@@ -272,24 +265,14 @@
 
     TraceScope tracingScope(WakeUpAndApplyDisplayListStart, WakeUpAndApplyDisplayListEnd);
     auto destinationImageBuffer = makeRefPtr(m_remoteResourceCache.cachedImageBuffer(arguments.destinationImageBufferIdentifier));
-    if (UNLIKELY(!destinationImageBuffer)) {
-        // FIXME: Add a message check to terminate the web process.
-        ASSERT_NOT_REACHED();
-        return;
-    }
+    MESSAGE_CHECK(destinationImageBuffer, "Missing destination image buffer");
 
     auto initialHandle = m_sharedDisplayListHandles.get(arguments.itemBufferIdentifier);
-    if (UNLIKELY(!initialHandle)) {
-        // FIXME: Add a message check to terminate the web process.
-        ASSERT_NOT_REACHED();
-        return;
-    }
+    MESSAGE_CHECK(initialHandle, "Missing initial shared display list handle");
 
     destinationImageBuffer = nextDestinationImageBufferAfterApplyingDisplayLists(*destinationImageBuffer, arguments.offset, *initialHandle, arguments.reason);
-    if (!destinationImageBuffer) {
-        RELEASE_ASSERT(m_pendingWakeupInfo);
+    if (!destinationImageBuffer)
         return;
-    }
 
     while (m_pendingWakeupInfo) {
         if (m_pendingWakeupInfo->missingCachedResourceIdentifier)
@@ -305,20 +288,13 @@
         // Otherwise, continue reading the next display list item buffer from the start.
         auto arguments = std::exchange(m_pendingWakeupInfo, WTF::nullopt)->arguments;
         destinationImageBuffer = nextDestinationImageBufferAfterApplyingDisplayLists(*destinationImageBuffer, arguments.offset, *nextHandle, arguments.reason);
-        if (!destinationImageBuffer) {
-            RELEASE_ASSERT(m_pendingWakeupInfo);
+        if (!destinationImageBuffer)
             break;
-        }
     }
 }
 
 void RemoteRenderingBackend::setNextItemBufferToRead(DisplayList::ItemBufferIdentifier identifier, WebCore::RenderingResourceIdentifier destinationIdentifier)
 {
-    if (UNLIKELY(m_pendingWakeupInfo)) {
-        // FIXME: Add a message check to terminate the web process.
-        ASSERT_NOT_REACHED();
-        return;
-    }
     m_pendingWakeupInfo = {{{ identifier, SharedDisplayListHandle::headerSize(), destinationIdentifier, GPUProcessWakeupReason::Unspecified }, WTF::nullopt }};
 }
 
@@ -405,13 +381,8 @@
 void RemoteRenderingBackend::didCreateSharedDisplayListHandle(DisplayList::ItemBufferIdentifier identifier, const SharedMemory::IPCHandle& handle, RenderingResourceIdentifier destinationBufferIdentifier)
 {
     ASSERT(!RunLoop::isMain());
+    MESSAGE_CHECK(!m_sharedDisplayListHandles.contains(identifier), "Duplicate shared display list handle");
 
-    if (UNLIKELY(m_sharedDisplayListHandles.contains(identifier))) {
-        // FIXME: Add a message check to terminate the web process.
-        ASSERT_NOT_REACHED();
-        return;
-    }
-
     if (auto sharedMemory = SharedMemory::map(handle.handle, SharedMemory::Protection::ReadWrite))
         m_sharedDisplayListHandles.set(identifier, DisplayListReaderHandle::create(identifier, sharedMemory.releaseNonNull()));
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to