All 32-bit plug-ins should use the XPC service
authorandersca@apple.com <andersca@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 Feb 2016 18:57:05 +0000 (18:57 +0000)
committerandersca@apple.com <andersca@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 Feb 2016 18:57:05 +0000 (18:57 +0000)
https://bugs.webkit.org/show_bug.cgi?id=154036
rdar://problem/16059483

Reviewed by Dan Bernstein.

Silverlight expects malloced memory from the tiny zone to be executable. It also expects
the data segment from its coreclr image to be executable.

Make this possible by:

1. Shimming mach_vm_map, making sure to add the VM_PROT_EXECUTABLE bit to any memory in the tiny zone.
2. Go through the address space, looking for any existing ranges from the tiny zone and mach_vm_protect them
   to be executable.
3. Register with dyld so we'll get callbacks whenever a library is bound, look for the coreclr image, and
   mach_vm_protect its __DATA segment to be executable.

* Platform/spi/Cocoa/DyldSPI.h: Copied from Source/WebKit2/PluginProcess/mac/PluginProcessShim.h.
* PluginProcess/mac/PluginProcessMac.mm:
(WebKit::isMallocMemoryTag):
(WebKit::shouldMapMemoryExecutable):
(WebKit::initializeShim):
(WebKit::PluginProcess::platformInitializeProcess):
* PluginProcess/mac/PluginProcessShim.h:
* PluginProcess/mac/PluginProcessShim.mm:
(WebKit::shimMachVMMap):
* UIProcess/Plugins/mac/PluginProcessProxyMac.mm:
(WebKit::PluginProcessProxy::platformGetLaunchOptions):
(WebKit::shouldUseXPC): Deleted.
* WebKit2.xcodeproj/project.pbxproj:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@196321 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit2/ChangeLog
Source/WebKit2/Platform/spi/Cocoa/DyldSPI.h [new file with mode: 0644]
Source/WebKit2/PluginProcess/mac/PluginProcessMac.mm
Source/WebKit2/PluginProcess/mac/PluginProcessShim.h
Source/WebKit2/PluginProcess/mac/PluginProcessShim.mm
Source/WebKit2/UIProcess/Plugins/mac/PluginProcessProxyMac.mm
Source/WebKit2/WebKit2.xcodeproj/project.pbxproj

index 879435a..1ea0668 100644 (file)
@@ -1,3 +1,36 @@
+2016-02-09  Anders Carlsson  <andersca@apple.com>
+
+        All 32-bit plug-ins should use the XPC service
+        https://bugs.webkit.org/show_bug.cgi?id=154036
+        rdar://problem/16059483
+
+        Reviewed by Dan Bernstein.
+        
+        Silverlight expects malloced memory from the tiny zone to be executable. It also expects
+        the data segment from its coreclr image to be executable.
+        
+        Make this possible by:
+        
+        1. Shimming mach_vm_map, making sure to add the VM_PROT_EXECUTABLE bit to any memory in the tiny zone.
+        2. Go through the address space, looking for any existing ranges from the tiny zone and mach_vm_protect them
+           to be executable.
+        3. Register with dyld so we'll get callbacks whenever a library is bound, look for the coreclr image, and
+           mach_vm_protect its __DATA segment to be executable.
+
+        * Platform/spi/Cocoa/DyldSPI.h: Copied from Source/WebKit2/PluginProcess/mac/PluginProcessShim.h.
+        * PluginProcess/mac/PluginProcessMac.mm:
+        (WebKit::isMallocMemoryTag):
+        (WebKit::shouldMapMemoryExecutable):
+        (WebKit::initializeShim):
+        (WebKit::PluginProcess::platformInitializeProcess):
+        * PluginProcess/mac/PluginProcessShim.h:
+        * PluginProcess/mac/PluginProcessShim.mm:
+        (WebKit::shimMachVMMap):
+        * UIProcess/Plugins/mac/PluginProcessProxyMac.mm:
+        (WebKit::PluginProcessProxy::platformGetLaunchOptions):
+        (WebKit::shouldUseXPC): Deleted.
+        * WebKit2.xcodeproj/project.pbxproj:
+
 2016-02-09  Fujii Hironori  <Hironori.Fujii@jp.sony.com>
 
         possible buffer overrun in Connection::processMessage of Source/WebKit2/Platform/IPC/unix/ConnectionUnix.cpp
diff --git a/Source/WebKit2/Platform/spi/Cocoa/DyldSPI.h b/Source/WebKit2/Platform/spi/Cocoa/DyldSPI.h
new file mode 100644 (file)
index 0000000..5aac82d
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if USE(APPLE_INTERNAL_SDK)
+
+#import <mach-o/dyld_priv.h>
+
+#else
+
+#import <mach-o/dyld_images.h>
+#import <stdint.h>
+
+enum dyld_image_states {
+    dyld_image_state_bound = 40,
+};
+
+typedef const char* (*dyld_image_state_change_handler)(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[]);
+
+extern "C" void dyld_register_image_state_change_handler(enum dyld_image_states state, bool batch, dyld_image_state_change_handler handler);
+
+#endif
index f93009a..c93c546 100644 (file)
@@ -30,6 +30,7 @@
 #if ENABLE(NETSCAPE_PLUGIN_API)
 
 #import "ArgumentCoders.h"
+#import "DyldSPI.h"
 #import "NetscapePlugin.h"
 #import "PluginProcessCreationParameters.h"
 #import "PluginProcessProxyMessages.h"
@@ -41,6 +42,9 @@
 #import <WebCore/LocalizedStrings.h>
 #import <WebKitSystemInterface.h>
 #import <dlfcn.h>
+#import <mach-o/getsect.h>
+#import <mach/mach_vm.h>
+#import <mach/vm_statistics.h>
 #import <objc/runtime.h>
 #import <sysexits.h>
 #import <wtf/HashSet.h>
@@ -203,6 +207,30 @@ static bool openCFURLRef(CFURLRef url, int32_t& status, CFURLRef* launchedURL)
     return true;
 }
 
+static bool isMallocTinyMemoryTag(int tag)
+{
+    switch (tag) {
+    case VM_MEMORY_MALLOC_TINY:
+        return true;
+
+    default:
+        return false;
+    }
+}
+
+static bool shouldMapMallocMemoryExecutable;
+
+static bool shouldMapMemoryExecutable(int flags)
+{
+    if (!shouldMapMallocMemoryExecutable)
+        return false;
+
+    if (!isMallocTinyMemoryTag((flags >> 24) & 0xff))
+        return false;
+
+    return true;
+}
+
 #endif
 
 static void setModal(bool modalWindowIsShowing)
@@ -257,6 +285,7 @@ static void initializeShim()
         carbonWindowHidden,
         setModal,
         openCFURLRef,
+        shouldMapMemoryExecutable,
     };
 
     PluginProcessShimInitializeFunc initFunc = reinterpret_cast<PluginProcessShimInitializeFunc>(dlsym(RTLD_DEFAULT, "WebKitPluginProcessShimInitialize"));
@@ -419,11 +448,9 @@ void PluginProcess::platformInitializePluginProcess(PluginProcessCreationParamet
 void PluginProcess::platformInitializeProcess(const ChildProcessInitializationParameters& parameters)
 {
 #if defined(__i386__)
-    // Initialize the shim.
     initializeShim();
 #endif
 
-    // Initialize Cocoa overrides.
     initializeCocoaOverrides();
 
     // FIXME: It would be better to proxy SetCursor calls over to the UI process instead of
@@ -440,6 +467,65 @@ void PluginProcess::platformInitializeProcess(const ChildProcessInitializationPa
 
     m_pluginBundleIdentifier = CFBundleGetIdentifier(pluginBundle.get());
 
+#if defined(__i386__)
+    if (m_pluginBundleIdentifier == "com.microsoft.SilverlightPlugin") {
+        // Set this so that any calls to mach_vm_map for pages reserved by malloc will be executable.
+        shouldMapMallocMemoryExecutable = true;
+
+        // Go through the address space looking for already existing malloc regions and change the
+        // protection to make them executable.
+        mach_vm_size_t size;
+        uint32_t depth = 0;
+        struct vm_region_submap_info_64 info = { };
+        mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
+        for (mach_vm_address_t addr = 0; ; addr += size) {
+            kern_return_t kr = mach_vm_region_recurse(mach_task_self(), &addr, &size, &depth, (vm_region_recurse_info_64_t)&info, &count);
+            if (kr != KERN_SUCCESS)
+                break;
+
+            if (isMallocTinyMemoryTag(info.user_tag))
+                mach_vm_protect(mach_task_self(), addr, size, false, info.protection | VM_PROT_EXECUTE);
+        }
+
+        // Silverlight expects the data segment of its coreclr library to be executable.
+        // Register with dyld to get notified when libraries are bound, then look for the
+        // coreclr image and make its __DATA segment executable.
+        dyld_register_image_state_change_handler(dyld_image_state_bound, false, [](enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[]) -> const char* {
+            for (uint32_t i = 0; i < infoCount; ++i) {
+                const char* pathSuffix = "/Silverlight.plugin/Contents/MacOS/CoreCLR.bundle/Contents/MacOS/coreclr";
+
+                int pathSuffixLength = strlen(pathSuffix);
+                int imageFilePathLength = strlen(info[i].imageFilePath);
+
+                if (imageFilePathLength < pathSuffixLength)
+                    continue;
+
+                if (strcmp(info[i].imageFilePath + (imageFilePathLength - pathSuffixLength), pathSuffix))
+                    continue;
+
+                unsigned long segmentSize;
+                const uint8_t* segmentData = getsegmentdata(info[i].imageLoadAddress, "__DATA", &segmentSize);
+                if (!segmentData)
+                    break;
+
+                mach_vm_size_t size;
+                uint32_t depth = 0;
+                struct vm_region_submap_info_64 info = { };
+                mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
+                for (mach_vm_address_t addr = reinterpret_cast<mach_vm_address_t>(segmentData); addr < reinterpret_cast<mach_vm_address_t>(segmentData) + segmentSize ; addr += size) {
+                    kern_return_t kr = mach_vm_region_recurse(mach_task_self(), &addr, &size, &depth, (vm_region_recurse_info_64_t)&info, &count);
+                    if (kr != KERN_SUCCESS)
+                        break;
+
+                    mach_vm_protect(mach_task_self(), addr, size, false, info.protection | VM_PROT_EXECUTE);
+                }
+            }
+
+            return nullptr;
+        });
+    }
+#endif
+
     // FIXME: Workaround for Java not liking its plugin process to be suppressed - <rdar://problem/14267843>
     if (m_pluginBundleIdentifier == "com.oracle.java.JavaAppletPlugin")
         (new UserActivity("com.oracle.java.JavaAppletPlugin"))->start();
index 5a788a3..0501202 100644 (file)
@@ -42,6 +42,7 @@ struct PluginProcessShimCallbacks {
     void (*carbonWindowHidden)(WindowRef);
     void (*setModal)(bool);
     bool (*openCFURLRef)(CFURLRef, int32_t& returnValue, CFURLRef* launchedURL);
+    bool (*shouldMapMemoryExecutable)(int flags);
 };
 
 typedef void (*PluginProcessShimInitializeFunc)(const PluginProcessShimCallbacks&);
index ae285ad..ea9fcd3 100644 (file)
@@ -32,6 +32,7 @@
 #import <Carbon/Carbon.h>
 #import <WebCore/DynamicLinkerInterposing.h>
 #import <WebKitSystemInterface.h>
+#import <mach/mach_vm.h>
 #import <objc/message.h>
 #import <stdio.h>
 #import <sys/ipc.h>
@@ -110,6 +111,18 @@ shimLSOpenCFURLRef(CFURLRef url, CFURLRef* launchedURL)
     return LSOpenCFURLRef(url, launchedURL);
 }
 
+static kern_return_t shimMachVMMap(vm_map_t task, mach_vm_address_t *address, mach_vm_size_t size, mach_vm_offset_t mask, int flags, mem_entry_name_port_t object, memory_object_offset_t offset, boolean_t copy, vm_prot_t currentProtection, vm_prot_t maxProtection, vm_inherit_t inheritance)
+{
+    if (task == mach_task_self()) {
+        if (pluginProcessShimCallbacks.shouldMapMemoryExecutable && pluginProcessShimCallbacks.shouldMapMemoryExecutable(flags)) {
+            currentProtection |= VM_PROT_EXECUTE;
+            maxProtection |= VM_PROT_EXECUTE;
+        }
+    }
+
+    return mach_vm_map(task, address, size, mask, flags, object, offset, copy, currentProtection, maxProtection, inheritance);
+}
+
 DYLD_INTERPOSE(shimDebugger, Debugger);
 DYLD_INTERPOSE(shimGetCurrentEventButtonState, GetCurrentEventButtonState);
 DYLD_INTERPOSE(shimIsWindowActive, IsWindowActive);
@@ -118,6 +131,7 @@ DYLD_INTERPOSE(shimAlert, Alert);
 DYLD_INTERPOSE(shimShowWindow, ShowWindow);
 DYLD_INTERPOSE(shimHideWindow, HideWindow);
 DYLD_INTERPOSE(shimLSOpenCFURLRef, LSOpenCFURLRef);
+DYLD_INTERPOSE(shimMachVMMap, mach_vm_map);
 
 #pragma clang diagnostic pop
 
index 180bcdb..4d6027c 100644 (file)
@@ -129,22 +129,6 @@ bool PluginProcessProxy::createPropertyListFile(const PluginModuleInfo& plugin)
 }
 #endif
 
-static bool shouldUseXPC(ProcessLauncher::LaunchOptions& launchOptions, const PluginProcessAttributes& pluginProcessAttributes)
-{
-    if (id value = [[NSUserDefaults standardUserDefaults] objectForKey:@"WebKitUseXPCServiceForPlugIns"])
-        return [value boolValue];
-
-    // FIXME: This can be removed when <rdar://problem/16856490> is resolved.
-    if (pluginProcessAttributes.moduleInfo.bundleIdentifier == "com.adobe.acrobat.pdfviewerNPAPI")
-        return false;
-
-    // FIXME: We should still use XPC for plug-ins that want the heap to be executable, see <rdar://problem/16059483>.
-    if (launchOptions.executableHeap)
-        return false;
-
-    return true;
-}
-
 void PluginProcessProxy::platformGetLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions, const PluginProcessAttributes& pluginProcessAttributes)
 {
     launchOptions.architecture = pluginProcessAttributes.moduleInfo.pluginArchitecture;
@@ -158,7 +142,7 @@ void PluginProcessProxy::platformGetLaunchOptions(ProcessLauncher::LaunchOptions
             WTFLogAlways("Main process is sandboxed, ignoring plug-in sandbox policy");
     }
 
-    launchOptions.useXPC = shouldUseXPC(launchOptions, pluginProcessAttributes);
+    launchOptions.useXPC = true;
 }
 
 void PluginProcessProxy::platformInitializePluginProcess(PluginProcessCreationParameters& parameters)
index 3be1d84..640b56b 100644 (file)
                1A2D92211281DC1B001EB962 /* PluginProxyMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A2D92201281DC1B001EB962 /* PluginProxyMac.mm */; };
                1A2D956F12848564001EB962 /* ChildProcess.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A2D956D12848564001EB962 /* ChildProcess.h */; };
                1A2D957012848564001EB962 /* ChildProcess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A2D956E12848564001EB962 /* ChildProcess.cpp */; };
+               1A2E17EF1C6A590C00D04CF6 /* DyldSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A2E17EE1C6A590C00D04CF6 /* DyldSPI.h */; };
                1A30066E1110F4F70031937C /* ResponsivenessTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A30066C1110F4F70031937C /* ResponsivenessTimer.h */; };
                1A30EAC6115D7DA30053E937 /* ConnectionMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A30EAC5115D7DA30053E937 /* ConnectionMac.mm */; };
                1A334DED16DE8F88006A8E38 /* StorageAreaMapMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A334DEB16DE8F88006A8E38 /* StorageAreaMapMessageReceiver.cpp */; };
                1A2D92201281DC1B001EB962 /* PluginProxyMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PluginProxyMac.mm; sourceTree = "<group>"; };
                1A2D956D12848564001EB962 /* ChildProcess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChildProcess.h; sourceTree = "<group>"; };
                1A2D956E12848564001EB962 /* ChildProcess.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ChildProcess.cpp; sourceTree = "<group>"; };
+               1A2E17EE1C6A590C00D04CF6 /* DyldSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DyldSPI.h; sourceTree = "<group>"; };
                1A30066C1110F4F70031937C /* ResponsivenessTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResponsivenessTimer.h; sourceTree = "<group>"; };
                1A30EAC5115D7DA30053E937 /* ConnectionMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ConnectionMac.mm; sourceTree = "<group>"; };
                1A334DEA16DE8B68006A8E38 /* StorageAreaMap.messages.in */ = {isa = PBXFileReference; lastKnownFileType = text; path = StorageAreaMap.messages.in; sourceTree = "<group>"; };
                        isa = PBXGroup;
                        children = (
                                1A5705101BE410E500874AF1 /* BlockSPI.h */,
+                               1A2E17EE1C6A590C00D04CF6 /* DyldSPI.h */,
                                3754D5441B3A29FD003A4C7F /* NSInvocationSPI.h */,
                        );
                        path = Cocoa;
                                51F060E01654317F00F3281B /* WebResourceLoaderMessages.h in Headers */,
                                7C361D731927FA360036A59D /* WebScriptMessageHandler.h in Headers */,
                                D3B9484911FF4B6500032B39 /* WebSearchPopupMenu.h in Headers */,
+                               1A2E17EF1C6A590C00D04CF6 /* DyldSPI.h in Headers */,
                                1A4832D71A9CDF96008B4DFE /* WebsiteData.h in Headers */,
                                1A4832D11A9BDC2F008B4DFE /* WebsiteDataRecord.h in Headers */,
                                1A53C2AA1A325730004E8C70 /* WebsiteDataStore.h in Headers */,