diff --git a/Source/WTF/wtf/spi/darwin/XPCSPI.h b/Source/WTF/wtf/spi/darwin/XPCSPI.h index 5a135c6adea4..2f965ba7fd10 100644 --- a/Source/WTF/wtf/spi/darwin/XPCSPI.h +++ b/Source/WTF/wtf/spi/darwin/XPCSPI.h @@ -154,6 +154,7 @@ void xpc_dictionary_set_string(xpc_object_t, const char* key, const char* string void xpc_dictionary_set_uint64(xpc_object_t, const char* key, uint64_t value); void xpc_dictionary_set_value(xpc_object_t, const char* key, xpc_object_t value); xpc_type_t xpc_get_type(xpc_object_t); +const char* xpc_type_get_name(xpc_type_t); void xpc_main(xpc_connection_handler_t); const char* xpc_string_get_string_ptr(xpc_object_t); os_transaction_t os_transaction_create(const char *description); diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog index 5480867597fd..bfddf8906cb8 100644 --- a/Source/WebKit/ChangeLog +++ b/Source/WebKit/ChangeLog @@ -1,3 +1,20 @@ +2021-06-10 Chris Dumez + + Do some hardening in XPCServiceEventHandler() + https://bugs.webkit.org/show_bug.cgi?id=226860 + + + Reviewed by Geoffrey Garen. + + Do some hardening in XPCServiceEventHandler() to deal with unexpected values and add + some more logging as well. + + * Shared/EntryPointUtilities/Cocoa/XPCService/XPCServiceMain.mm: + (WebKit::XPCServiceEventHandler): + * WebProcess/cocoa/HandleXPCEndpointMessages.h: + * WebProcess/cocoa/HandleXPCEndpointMessages.mm: + (WebKit::handleXPCEndpointMessages): + 2021-06-10 Chris Dumez Enable WebPage's release logging in ephemeral sessions diff --git a/Source/WebKit/Shared/EntryPointUtilities/Cocoa/XPCService/XPCServiceMain.mm b/Source/WebKit/Shared/EntryPointUtilities/Cocoa/XPCService/XPCServiceMain.mm index 42f0d257a6cc..8d4b0865b95f 100644 --- a/Source/WebKit/Shared/EntryPointUtilities/Cocoa/XPCService/XPCServiceMain.mm +++ b/Source/WebKit/Shared/EntryPointUtilities/Cocoa/XPCService/XPCServiceMain.mm @@ -69,73 +69,88 @@ static void XPCServiceEventHandler(xpc_connection_t peer) xpc_connection_set_target_queue(peer, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); xpc_connection_set_event_handler(peer, ^(xpc_object_t event) { xpc_type_t type = xpc_get_type(event); - if (type == XPC_TYPE_ERROR) { - if (event == XPC_ERROR_CONNECTION_INVALID || event == XPC_ERROR_TERMINATION_IMMINENT) { - RELEASE_LOG_FAULT(IPC, "Exiting: Received XPC event type: %s", event == XPC_ERROR_CONNECTION_INVALID ? "XPC_ERROR_CONNECTION_INVALID" : "XPC_ERROR_TERMINATION_IMMINENT"); - // FIXME: Handle this case more gracefully. - [[NSRunLoop mainRunLoop] performBlock:^{ - exit(EXIT_FAILURE); - }]; - } - } else { - assert(type == XPC_TYPE_DICTIONARY); - - if (!strcmp(xpc_dictionary_get_string(event, "message-name"), "bootstrap")) { - CFBundleRef webKitBundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.WebKit")); - - const char* serviceName = xpc_dictionary_get_string(event, "service-name"); - CFStringRef entryPointFunctionName = nullptr; - if (strstr(serviceName, "com.apple.WebKit.WebContent") == serviceName) - entryPointFunctionName = CFSTR(STRINGIZE_VALUE_OF(WEBCONTENT_SERVICE_INITIALIZER)); - else if (!strcmp(serviceName, "com.apple.WebKit.Networking")) - entryPointFunctionName = CFSTR(STRINGIZE_VALUE_OF(NETWORK_SERVICE_INITIALIZER)); - else if (!strcmp(serviceName, "com.apple.WebKit.Plugin.64")) - entryPointFunctionName = CFSTR(STRINGIZE_VALUE_OF(PLUGIN_SERVICE_INITIALIZER)); - else if (!strcmp(serviceName, "com.apple.WebKit.GPU")) - entryPointFunctionName = CFSTR(STRINGIZE_VALUE_OF(GPU_SERVICE_INITIALIZER)); - else if (!strcmp(serviceName, "com.apple.WebKit.WebAuthn")) - entryPointFunctionName = CFSTR(STRINGIZE_VALUE_OF(WEBAUTHN_SERVICE_INITIALIZER)); - else - RELEASE_ASSERT_NOT_REACHED(); - - typedef void (*InitializerFunction)(xpc_connection_t, xpc_object_t, xpc_object_t); - InitializerFunction initializerFunctionPtr = reinterpret_cast(CFBundleGetFunctionPointerForName(webKitBundle, entryPointFunctionName)); - if (!initializerFunctionPtr) { - RELEASE_LOG_FAULT(IPC, "Exiting: Unable to find entry point in WebKit.framework with name: %s", [(__bridge NSString *)entryPointFunctionName UTF8String]); + if (type != XPC_TYPE_DICTIONARY) { + RELEASE_LOG_ERROR(IPC, "XPCServiceEventHandler: Received unexpected XPC event type: %{public}s", xpc_type_get_name(type)); + if (type == XPC_TYPE_ERROR) { + if (event == XPC_ERROR_CONNECTION_INVALID || event == XPC_ERROR_TERMINATION_IMMINENT) { + RELEASE_LOG_ERROR(IPC, "Exiting: Received XPC event type: %{public}s", event == XPC_ERROR_CONNECTION_INVALID ? "XPC_ERROR_CONNECTION_INVALID" : "XPC_ERROR_TERMINATION_IMMINENT"); + // FIXME: Handle this case more gracefully. [[NSRunLoop mainRunLoop] performBlock:^{ exit(EXIT_FAILURE); }]; } + } + return; + } - auto reply = adoptOSObject(xpc_dictionary_create_reply(event)); - xpc_dictionary_set_string(reply.get(), "message-name", "process-finished-launching"); - xpc_connection_send_message(xpc_dictionary_get_remote_connection(event), reply.get()); + auto* messageName = xpc_dictionary_get_string(event, "message-name"); + if (!messageName) { + RELEASE_LOG_ERROR(IPC, "XPCServiceEventHandler: 'message-name' is not present in the XPC dictionary"); + return; + } + if (!strcmp(messageName, "bootstrap")) { + const char* serviceName = xpc_dictionary_get_string(event, "service-name"); + if (!serviceName) { + RELEASE_LOG_ERROR(IPC, "XPCServiceEventHandler: 'service-name' is not present in the XPC dictionary"); + return; + } + CFStringRef entryPointFunctionName = nullptr; + if (!strncmp(serviceName, "com.apple.WebKit.WebContent", strlen("com.apple.WebKit.WebContent"))) + entryPointFunctionName = CFSTR(STRINGIZE_VALUE_OF(WEBCONTENT_SERVICE_INITIALIZER)); + else if (!strcmp(serviceName, "com.apple.WebKit.Networking")) + entryPointFunctionName = CFSTR(STRINGIZE_VALUE_OF(NETWORK_SERVICE_INITIALIZER)); + else if (!strcmp(serviceName, "com.apple.WebKit.Plugin.64")) + entryPointFunctionName = CFSTR(STRINGIZE_VALUE_OF(PLUGIN_SERVICE_INITIALIZER)); + else if (!strcmp(serviceName, "com.apple.WebKit.GPU")) + entryPointFunctionName = CFSTR(STRINGIZE_VALUE_OF(GPU_SERVICE_INITIALIZER)); + else if (!strcmp(serviceName, "com.apple.WebKit.WebAuthn")) + entryPointFunctionName = CFSTR(STRINGIZE_VALUE_OF(WEBAUTHN_SERVICE_INITIALIZER)); + else { + RELEASE_LOG_ERROR(IPC, "XPCServiceEventHandler: Unexpected 'service-name': %{public}s", serviceName); + return; + } - int fd = xpc_dictionary_dup_fd(event, "stdout"); - if (fd != -1) - dup2(fd, STDOUT_FILENO); + CFBundleRef webKitBundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.WebKit")); + typedef void (*InitializerFunction)(xpc_connection_t, xpc_object_t, xpc_object_t); + InitializerFunction initializerFunctionPtr = reinterpret_cast(CFBundleGetFunctionPointerForName(webKitBundle, entryPointFunctionName)); + if (!initializerFunctionPtr) { + RELEASE_LOG_FAULT(IPC, "Exiting: Unable to find entry point in WebKit.framework with name: %s", [(__bridge NSString *)entryPointFunctionName UTF8String]); + [[NSRunLoop mainRunLoop] performBlock:^{ + exit(EXIT_FAILURE); + }]; + return; + } - fd = xpc_dictionary_dup_fd(event, "stderr"); - if (fd != -1) - dup2(fd, STDERR_FILENO); + auto reply = adoptOSObject(xpc_dictionary_create_reply(event)); + xpc_dictionary_set_string(reply.get(), "message-name", "process-finished-launching"); + xpc_connection_send_message(xpc_dictionary_get_remote_connection(event), reply.get()); - WorkQueue::main().dispatchSync([initializerFunctionPtr, event = OSObjectPtr(event), retainedPeerConnection] { - initializerFunctionPtr(retainedPeerConnection.get(), event.get(), priorityBoostMessage.get().get()); + int fd = xpc_dictionary_dup_fd(event, "stdout"); + if (fd != -1) + dup2(fd, STDOUT_FILENO); - setAppleLanguagesPreference(); - }); + fd = xpc_dictionary_dup_fd(event, "stderr"); + if (fd != -1) + dup2(fd, STDERR_FILENO); - priorityBoostMessage.get() = nullptr; - } + WorkQueue::main().dispatchSync([initializerFunctionPtr, event = OSObjectPtr(event), retainedPeerConnection] { + initializerFunctionPtr(retainedPeerConnection.get(), event.get(), priorityBoostMessage.get().get()); - // Leak a boost onto the NetworkProcess. - if (!strcmp(xpc_dictionary_get_string(event, "message-name"), "pre-bootstrap")) { - assert(!priorityBoostMessage.get()); - priorityBoostMessage.get() = event; - } + setAppleLanguagesPreference(); + }); - handleXPCEndpointMessages(event); + priorityBoostMessage.get() = nullptr; + return; } + + // Leak a boost onto the NetworkProcess. + if (!strcmp(messageName, "pre-bootstrap")) { + assert(!priorityBoostMessage.get()); + priorityBoostMessage.get() = event; + return; + } + + handleXPCEndpointMessages(event, messageName); }); xpc_connection_resume(peer); diff --git a/Source/WebKit/WebProcess/cocoa/HandleXPCEndpointMessages.h b/Source/WebKit/WebProcess/cocoa/HandleXPCEndpointMessages.h index 6b13fc3cceb4..811815d3e9a6 100644 --- a/Source/WebKit/WebProcess/cocoa/HandleXPCEndpointMessages.h +++ b/Source/WebKit/WebProcess/cocoa/HandleXPCEndpointMessages.h @@ -29,6 +29,6 @@ namespace WebKit { -void handleXPCEndpointMessages(xpc_object_t event); +void handleXPCEndpointMessages(xpc_object_t event, const char* messageName); } diff --git a/Source/WebKit/WebProcess/cocoa/HandleXPCEndpointMessages.mm b/Source/WebKit/WebProcess/cocoa/HandleXPCEndpointMessages.mm index 5720fd50660a..817871cfeaa9 100644 --- a/Source/WebKit/WebProcess/cocoa/HandleXPCEndpointMessages.mm +++ b/Source/WebKit/WebProcess/cocoa/HandleXPCEndpointMessages.mm @@ -34,17 +34,13 @@ namespace WebKit { -void handleXPCEndpointMessages(xpc_object_t event) +void handleXPCEndpointMessages(xpc_object_t event, const char* messageName) { - if (xpc_get_type(event) != XPC_TYPE_DICTIONARY) - return; + ASSERT_UNUSED(event, xpc_get_type(event) == XPC_TYPE_DICTIONARY); + ASSERT_UNUSED(messageName, messageName); #if HAVE(LSDATABASECONTEXT) - String messageName = xpc_dictionary_get_string(event, XPCEndpoint::xpcMessageNameKey); - if (messageName.isEmpty()) - return; - - if (messageName == LaunchServicesDatabaseXPCConstants::xpcLaunchServicesDatabaseXPCEndpointMessageName) { + if (!strcmp(messageName, LaunchServicesDatabaseXPCConstants::xpcLaunchServicesDatabaseXPCEndpointMessageName)) { auto xpcEndPoint = xpc_dictionary_get_value(event, LaunchServicesDatabaseXPCConstants::xpcLaunchServicesDatabaseXPCEndpointNameKey); if (!xpcEndPoint || xpc_get_type(xpcEndPoint) != XPC_TYPE_ENDPOINT) return;