Unreviewed, rolling out r241559 and r241566.
[WebKit-https.git] / Source / WebKit / PluginProcess / mac / PluginProcessMac.mm
1 /*
2  * Copyright (C) 2010-2017 Apple Inc. All rights reserved.
3  * Copyright (C) 2011 Google Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #import "config.h"
28 #import "PluginProcess.h"
29
30 #if ENABLE(NETSCAPE_PLUGIN_API)
31
32 #import "ArgumentCoders.h"
33 #import "NetscapePlugin.h"
34 #import "PluginInfoStore.h"
35 #import "PluginProcessCreationParameters.h"
36 #import "PluginProcessProxyMessages.h"
37 #import "PluginProcessShim.h"
38 #import "PluginSandboxProfile.h"
39 #import "SandboxInitializationParameters.h"
40 #import "SandboxUtilities.h"
41 #import <CoreAudio/AudioHardware.h>
42 #import <WebCore/LocalizedStrings.h>
43 #import <WebCore/RuntimeEnabledFeatures.h>
44 #import <dlfcn.h>
45 #import <mach-o/dyld.h>
46 #import <mach-o/getsect.h>
47 #import <mach/mach_vm.h>
48 #import <mach/vm_statistics.h>
49 #import <objc/runtime.h>
50 #import <pal/spi/cg/CoreGraphicsSPI.h>
51 #import <pal/spi/cocoa/LaunchServicesSPI.h>
52 #import <pal/spi/mac/HIToolboxSPI.h>
53 #import <pal/spi/mac/NSApplicationSPI.h>
54 #import <pal/spi/mac/NSWindowSPI.h>
55 #import <sysexits.h>
56 #import <wtf/HashSet.h>
57 #import <wtf/NeverDestroyed.h>
58
59 const CFStringRef kLSPlugInBundleIdentifierKey = CFSTR("LSPlugInBundleIdentifierKey");
60
61 // These values were chosen to match default NSURLCache sizes at the time of this writing.
62 const NSUInteger pluginMemoryCacheSize = 512000;
63 const NSUInteger pluginDiskCacheSize = 20000000;
64
65 namespace WebKit {
66
67 class FullscreenWindowTracker {
68     WTF_MAKE_NONCOPYABLE(FullscreenWindowTracker);
69
70 public:
71     FullscreenWindowTracker() { }
72     
73     template<typename T> void windowShown(T window);
74     template<typename T> void windowHidden(T window);
75
76 private:
77     HashSet<CGWindowID> m_windows;
78 };
79
80 static bool rectCoversAnyScreen(NSRect rect)
81 {
82     for (NSScreen *screen in [NSScreen screens]) {
83         if (NSContainsRect(rect, [screen frame]))
84             return YES;
85     }
86     return NO;
87 }
88
89 #ifndef NP_NO_CARBON
90 static bool windowCoversAnyScreen(WindowRef window)
91 {
92     HIRect bounds;
93     HIWindowGetBounds(window, kWindowStructureRgn, kHICoordSpaceScreenPixel, &bounds);
94
95     // Convert to Cocoa-style screen coordinates that use a Y offset relative to the zeroth screen's origin.
96     bounds.origin.y = NSHeight([(NSScreen *)[[NSScreen screens] objectAtIndex:0] frame]) - CGRectGetMaxY(bounds);
97
98     return rectCoversAnyScreen(NSRectFromCGRect(bounds));
99 }
100
101 static CGWindowID cgWindowID(WindowRef window)
102 {
103     return reinterpret_cast<CGWindowID>(GetNativeWindowFromWindowRef(window));
104 }
105
106 #endif
107
108 static bool windowCoversAnyScreen(NSWindow *window)
109 {
110     return rectCoversAnyScreen(window.frame);
111 }
112
113 static CGWindowID cgWindowID(NSWindow *window)
114 {
115     return window.windowNumber;
116 }
117
118 template<typename T>
119 void FullscreenWindowTracker::windowShown(T window)
120 {
121     CGWindowID windowID = cgWindowID(window);
122     if (!windowID)
123         return;
124
125     // If this window is already visible then there is nothing to do.
126     if (m_windows.contains(windowID))
127         return;
128     
129     // If the window is not full-screen then we're not interested in it.
130     if (!windowCoversAnyScreen(window))
131         return;
132
133     bool windowSetWasEmpty = m_windows.isEmpty();
134
135     m_windows.add(windowID);
136     
137     // If this is the first full screen window to be shown, notify the UI process.
138     if (windowSetWasEmpty)
139         PluginProcess::singleton().setFullscreenWindowIsShowing(true);
140 }
141
142 template<typename T>
143 void FullscreenWindowTracker::windowHidden(T window)
144 {
145     CGWindowID windowID = cgWindowID(window);
146     if (!windowID)
147         return;
148
149     // If this is not a window that we're tracking then there is nothing to do.
150     if (!m_windows.remove(windowID))
151         return;
152
153     // If this was the last full screen window that was visible, notify the UI process.
154     if (m_windows.isEmpty())
155         PluginProcess::singleton().setFullscreenWindowIsShowing(false);
156 }
157
158 static FullscreenWindowTracker& fullscreenWindowTracker()
159 {
160     static NeverDestroyed<FullscreenWindowTracker> fullscreenWindowTracker;
161     return fullscreenWindowTracker;
162 }
163
164 #if defined(__i386__)
165
166 static bool shouldCallRealDebugger()
167 {
168     static bool isUserbreakSet = false;
169     static dispatch_once_t flag;
170     dispatch_once(&flag, ^{
171         char* var = getenv("USERBREAK");
172
173         if (var)
174             isUserbreakSet = atoi(var);
175     });
176     
177     return isUserbreakSet;
178 }
179
180 static bool isWindowActive(WindowRef windowRef, bool& result)
181 {
182 #ifndef NP_NO_CARBON
183     if (NetscapePlugin* plugin = NetscapePlugin::netscapePluginFromWindow(windowRef)) {
184         result = plugin->isWindowActive();
185         return true;
186     }
187 #endif
188     return false;
189 }
190
191 static UInt32 getCurrentEventButtonState()
192 {
193 #ifndef NP_NO_CARBON
194     return NetscapePlugin::buttonState();
195 #else
196     ASSERT_NOT_REACHED();
197     return 0;
198 #endif
199 }
200
201 static void carbonWindowShown(WindowRef window)
202 {
203 #ifndef NP_NO_CARBON
204     fullscreenWindowTracker().windowShown(window);
205 #endif
206 }
207
208 static void carbonWindowHidden(WindowRef window)
209 {
210 #ifndef NP_NO_CARBON
211     fullscreenWindowTracker().windowHidden(window);
212 #endif
213 }
214
215 static bool openCFURLRef(CFURLRef url, int32_t& status, CFURLRef* launchedURL)
216 {
217     String launchedURLString;
218     if (!PluginProcess::singleton().openURL(URL(url).string(), status, launchedURLString))
219         return false;
220
221     if (!launchedURLString.isNull() && launchedURL)
222         *launchedURL = URL(URL(), launchedURLString).createCFURL().leakRef();
223     return true;
224 }
225
226 static bool isMallocTinyMemoryTag(int tag)
227 {
228     switch (tag) {
229     case VM_MEMORY_MALLOC_TINY:
230         return true;
231
232     default:
233         return false;
234     }
235 }
236
237 static bool shouldMapMallocMemoryExecutable;
238
239 static bool shouldMapMemoryExecutable(int flags)
240 {
241     if (!shouldMapMallocMemoryExecutable)
242         return false;
243
244     if (!isMallocTinyMemoryTag((flags >> 24) & 0xff))
245         return false;
246
247     return true;
248 }
249
250 #endif
251
252 static void setModal(bool modalWindowIsShowing)
253 {
254     PluginProcess::singleton().setModalWindowIsShowing(modalWindowIsShowing);
255 }
256
257 static unsigned modalCount;
258
259 static void beginModal()
260 {
261     ALLOW_DEPRECATED_DECLARATIONS_BEGIN
262     // Make sure to make ourselves the front process
263     ProcessSerialNumber psn;
264     GetCurrentProcess(&psn);
265     SetFrontProcess(&psn);
266     ALLOW_DEPRECATED_DECLARATIONS_END
267
268     if (!modalCount++)
269         setModal(true);
270 }
271
272 static void endModal()
273 {
274     if (!--modalCount)
275         setModal(false);
276 }
277
278 static IMP NSApplication_RunModalForWindow;
279
280 static NSInteger replacedRunModalForWindow(id self, SEL _cmd, NSWindow* window)
281 {
282     beginModal();
283     NSInteger result = ((NSInteger (*)(id, SEL, NSWindow *))NSApplication_RunModalForWindow)(self, _cmd, window);
284     endModal();
285
286     return result;
287 }
288
289 static bool oldPluginProcessNameShouldEqualNewPluginProcessNameForAdobeReader;
290
291 static bool isAdobeAcrobatAddress(const void* address)
292 {
293     Dl_info imageInfo;
294     if (!dladdr(address, &imageInfo))
295         return false;
296
297     const char* pathSuffix = "/Contents/Frameworks/Acrobat.framework/Acrobat";
298
299     int pathSuffixLength = strlen(pathSuffix);
300     int imageFilePathLength = strlen(imageInfo.dli_fname);
301
302     if (imageFilePathLength < pathSuffixLength)
303         return false;
304
305     if (strcmp(imageInfo.dli_fname + (imageFilePathLength - pathSuffixLength), pathSuffix))
306         return false;
307
308     return true;
309 }
310
311 static bool stringCompare(CFStringRef a, CFStringRef b, CFStringCompareFlags options, void* returnAddress, CFComparisonResult& result)
312 {
313     if (pthread_main_np() != 1)
314         return false;
315
316     if (!oldPluginProcessNameShouldEqualNewPluginProcessNameForAdobeReader)
317         return false;
318
319     if (options != kCFCompareCaseInsensitive)
320         return false;
321
322     const char* aCString = CFStringGetCStringPtr(a, kCFStringEncodingASCII);
323     if (!aCString)
324         return false;
325
326     const char* bCString = CFStringGetCStringPtr(b, kCFStringEncodingASCII);
327     if (!bCString)
328         return false;
329
330     if (strcmp(aCString, "com.apple.WebKit.PluginProcess"))
331         return false;
332
333     if (strcmp(bCString, "com.apple.WebKit.Plugin.64"))
334         return false;
335
336     // Check if the LHS string comes from the Acrobat framework.
337     if (!isAdobeAcrobatAddress(a))
338         return false;
339
340     // Check if the return adress is part of the Acrobat framework as well.
341     if (!isAdobeAcrobatAddress(returnAddress))
342         return false;
343
344     result = kCFCompareEqualTo;
345     return true;
346 }
347
348 static void initializeShim()
349 {
350     // Initialize the shim for 32-bit only.
351     const PluginProcessShimCallbacks callbacks = {
352 #if defined(__i386__)
353         shouldCallRealDebugger,
354         isWindowActive,
355         getCurrentEventButtonState,
356         beginModal,
357         endModal,
358         carbonWindowShown,
359         carbonWindowHidden,
360         setModal,
361         openCFURLRef,
362         shouldMapMemoryExecutable,
363 #endif
364         stringCompare,
365     };
366
367     PluginProcessShimInitializeFunc initFunc = reinterpret_cast<PluginProcessShimInitializeFunc>(dlsym(RTLD_DEFAULT, "WebKitPluginProcessShimInitialize"));
368     initFunc(callbacks);
369 }
370
371 static void (*NSConcreteTask_launch)(NSTask *, SEL);
372
373 static void replacedNSConcreteTask_launch(NSTask *self, SEL _cmd)
374 {
375     String launchPath = self.launchPath;
376
377     Vector<String> arguments;
378     arguments.reserveInitialCapacity(self.arguments.count);
379     for (NSString *argument in self.arguments)
380         arguments.uncheckedAppend(argument);
381
382     if (PluginProcess::singleton().launchProcess(launchPath, arguments))
383         return;
384
385     NSConcreteTask_launch(self, _cmd);
386 }
387
388 static NSRunningApplication *(*NSWorkspace_launchApplicationAtURL_options_configuration_error)(NSWorkspace *, SEL, NSURL *, NSWorkspaceLaunchOptions, NSDictionary *, NSError **);
389
390 static NSRunningApplication *replacedNSWorkspace_launchApplicationAtURL_options_configuration_error(NSWorkspace *self, SEL _cmd, NSURL *url, NSWorkspaceLaunchOptions options, NSDictionary *configuration, NSError **error)
391 {
392     Vector<String> arguments;
393     if (NSArray *argumentsArray = [configuration objectForKey:NSWorkspaceLaunchConfigurationArguments]) {
394         if ([argumentsArray isKindOfClass:[NSArray array]]) {
395             for (NSString *argument in argumentsArray) {
396                 if ([argument isKindOfClass:[NSString class]])
397                     arguments.append(argument);
398             }
399         }
400     }
401
402     if (PluginProcess::singleton().launchApplicationAtURL(URL(url).string(), arguments)) {
403         if (error)
404             *error = nil;
405         return nil;
406     }
407
408     return NSWorkspace_launchApplicationAtURL_options_configuration_error(self, _cmd, url, options, configuration, error);
409 }
410
411 static BOOL (*NSWorkspace_openFile)(NSWorkspace *, SEL, NSString *);
412
413 static BOOL replacedNSWorkspace_openFile(NSWorkspace *self, SEL _cmd, NSString *fullPath)
414 {
415     if (PluginProcess::singleton().openFile(fullPath))
416         return true;
417
418     return NSWorkspace_openFile(self, _cmd, fullPath);
419 }
420
421 static void initializeCocoaOverrides()
422 {
423     // Override -[NSConcreteTask launch:]
424     Method launchMethod = class_getInstanceMethod(objc_getClass("NSConcreteTask"), @selector(launch));
425     NSConcreteTask_launch = reinterpret_cast<void (*)(NSTask *, SEL)>(method_setImplementation(launchMethod, reinterpret_cast<IMP>(replacedNSConcreteTask_launch)));
426
427     // Override -[NSWorkspace launchApplicationAtURL:options:configuration:error:]
428     Method launchApplicationAtURLOptionsConfigurationErrorMethod = class_getInstanceMethod(objc_getClass("NSWorkspace"), @selector(launchApplicationAtURL:options:configuration:error:));
429     NSWorkspace_launchApplicationAtURL_options_configuration_error = reinterpret_cast<NSRunningApplication *(*)(NSWorkspace *, SEL, NSURL *, NSWorkspaceLaunchOptions, NSDictionary *, NSError **)>(method_setImplementation(launchApplicationAtURLOptionsConfigurationErrorMethod, reinterpret_cast<IMP>(replacedNSWorkspace_launchApplicationAtURL_options_configuration_error)));
430
431     // Override -[NSWorkspace openFile:]
432     Method openFileMethod = class_getInstanceMethod(objc_getClass("NSWorkspace"), @selector(openFile:));
433     NSWorkspace_openFile = reinterpret_cast<BOOL (*)(NSWorkspace *, SEL, NSString *)>(method_setImplementation(openFileMethod, reinterpret_cast<IMP>(replacedNSWorkspace_openFile)));
434
435     // Override -[NSApplication runModalForWindow:]
436     Method runModalForWindowMethod = class_getInstanceMethod(objc_getClass("NSApplication"), @selector(runModalForWindow:));
437     NSApplication_RunModalForWindow = method_setImplementation(runModalForWindowMethod, reinterpret_cast<IMP>(replacedRunModalForWindow));
438
439     NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
440
441     // Track when any Cocoa window is about to be be shown.
442     id orderOnScreenObserver = [defaultCenter addObserverForName:NSWindowWillOrderOnScreenNotification
443                                                           object:nil
444                                                            queue:nil
445                                                            usingBlock:^(NSNotification *notification) { fullscreenWindowTracker().windowShown([notification object]); }];
446     // Track when any Cocoa window is about to be hidden.
447     id orderOffScreenObserver = [defaultCenter addObserverForName:NSWindowWillOrderOffScreenNotification
448                                                            object:nil
449                                                             queue:nil
450                                                        usingBlock:^(NSNotification *notification) { fullscreenWindowTracker().windowHidden([notification object]); }];
451
452     // Leak the two observers so that they observe notifications for the lifetime of the process.
453     CFRetain((__bridge CFTypeRef)orderOnScreenObserver);
454     CFRetain((__bridge CFTypeRef)orderOffScreenObserver);
455 }
456
457 void PluginProcess::setModalWindowIsShowing(bool modalWindowIsShowing)
458 {
459     parentProcessConnection()->send(Messages::PluginProcessProxy::SetModalWindowIsShowing(modalWindowIsShowing), 0);
460 }
461
462 void PluginProcess::setFullscreenWindowIsShowing(bool fullscreenWindowIsShowing)
463 {
464     parentProcessConnection()->send(Messages::PluginProcessProxy::SetFullscreenWindowIsShowing(fullscreenWindowIsShowing), 0);
465 }
466
467 bool PluginProcess::launchProcess(const String& launchPath, const Vector<String>& arguments)
468 {
469     bool result;
470     if (!parentProcessConnection()->sendSync(Messages::PluginProcessProxy::LaunchProcess(launchPath, arguments), Messages::PluginProcessProxy::LaunchProcess::Reply(result), 0))
471         return false;
472
473     return result;
474 }
475
476 bool PluginProcess::launchApplicationAtURL(const String& urlString, const Vector<String>& arguments)
477 {
478     bool result = false;
479     if (!parentProcessConnection()->sendSync(Messages::PluginProcessProxy::LaunchApplicationAtURL(urlString, arguments), Messages::PluginProcessProxy::LaunchProcess::Reply(result), 0))
480         return false;
481
482     return result;
483 }
484
485 bool PluginProcess::openURL(const String& urlString, int32_t& status, String& launchedURLString)
486 {
487     bool result;
488     if (!parentProcessConnection()->sendSync(Messages::PluginProcessProxy::OpenURL(urlString), Messages::PluginProcessProxy::OpenURL::Reply(result, status, launchedURLString), 0))
489         return false;
490
491     return result;
492 }
493
494 bool PluginProcess::openFile(const String& fullPath)
495 {
496     bool result;
497     if (!parentProcessConnection()->sendSync(Messages::PluginProcessProxy::OpenFile(fullPath), Messages::PluginProcessProxy::OpenFile::Reply(result), 0))
498         return false;
499
500     return result;
501 }
502
503 static void muteAudio(void)
504 {
505     AudioObjectPropertyAddress propertyAddress = { kAudioHardwarePropertyProcessIsAudible, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
506     UInt32 propertyData = 0;
507     OSStatus result = AudioObjectSetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, 0, sizeof(UInt32), &propertyData);
508     ASSERT_UNUSED(result, result == noErr);
509 }
510
511 void PluginProcess::platformInitializePluginProcess(PluginProcessCreationParameters&& parameters)
512 {
513     m_compositingRenderServerPort = WTFMove(parameters.acceleratedCompositingPort);
514     if (parameters.processType == PluginProcessTypeSnapshot)
515         muteAudio();
516
517     [NSURLCache setSharedURLCache:adoptNS([[NSURLCache alloc]
518         initWithMemoryCapacity:pluginMemoryCacheSize
519         diskCapacity:pluginDiskCacheSize
520         diskPath:m_nsurlCacheDirectory]).get()];
521
522 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400
523     // Disable Dark Mode in the plugin process to avoid rendering issues.
524     [NSApp setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameAqua]];
525 #endif
526 }
527
528 void PluginProcess::platformInitializeProcess(const AuxiliaryProcessInitializationParameters& parameters)
529 {
530     initializeShim();
531
532     initializeCocoaOverrides();
533
534     bool experimentalPlugInSandboxProfilesEnabled = parameters.extraInitializationData.get("experimental-sandbox-plugin") == "1";
535     WebCore::RuntimeEnabledFeatures::sharedFeatures().setExperimentalPlugInSandboxProfilesEnabled(experimentalPlugInSandboxProfilesEnabled);
536
537     // FIXME: It would be better to proxy SetCursor calls over to the UI process instead of
538     // allowing plug-ins to change the mouse cursor at any time.
539     // FIXME: SetsCursorInBackground connection property is deprecated in favor of kCGSSetsCursorInBackgroundTagBit window tag bit.
540     // <rdar://problem/7752422> asks for an API to set cursor from background processes.
541     CGSConnectionID cid = CGSMainConnectionID();
542     CGSSetConnectionProperty(cid, cid, CFSTR("SetsCursorInBackground"), (CFTypeRef)kCFBooleanTrue);
543
544     RetainPtr<CFURLRef> pluginURL = adoptCF(CFURLCreateWithFileSystemPath(0, m_pluginPath.createCFString().get(), kCFURLPOSIXPathStyle, false));
545     if (!pluginURL)
546         return;
547
548     RetainPtr<CFBundleRef> pluginBundle = adoptCF(CFBundleCreate(kCFAllocatorDefault, pluginURL.get()));
549     if (!pluginBundle)
550         return;
551
552     m_pluginBundleIdentifier = CFBundleGetIdentifier(pluginBundle.get());
553
554     if (m_pluginBundleIdentifier == "com.adobe.acrobat.pdfviewerNPAPI")
555         oldPluginProcessNameShouldEqualNewPluginProcessNameForAdobeReader = true;
556
557 #if defined(__i386__)
558     if (m_pluginBundleIdentifier == "com.microsoft.SilverlightPlugin") {
559         // Set this so that any calls to mach_vm_map for pages reserved by malloc will be executable.
560         shouldMapMallocMemoryExecutable = true;
561
562         // Go through the address space looking for already existing malloc regions and change the
563         // protection to make them executable.
564         mach_vm_size_t size;
565         uint32_t depth = 0;
566         struct vm_region_submap_info_64 info = { };
567         mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
568         for (mach_vm_address_t addr = 0; ; addr += size) {
569             kern_return_t kr = mach_vm_region_recurse(mach_task_self(), &addr, &size, &depth, (vm_region_recurse_info_64_t)&info, &count);
570             if (kr != KERN_SUCCESS)
571                 break;
572
573             if (isMallocTinyMemoryTag(info.user_tag))
574                 mach_vm_protect(mach_task_self(), addr, size, false, info.protection | VM_PROT_EXECUTE);
575         }
576
577         // Silverlight expects the data segment of its coreclr library to be executable.
578         // Register with dyld to get notified when libraries are bound, then look for the
579         // coreclr image and make its __DATA segment executable.
580         _dyld_register_func_for_add_image([](const struct mach_header* mh, intptr_t vmaddr_slide) {
581             Dl_info imageInfo;
582             if (!dladdr(mh, &imageInfo))
583                 return;
584
585             const char* pathSuffix = "/Silverlight.plugin/Contents/MacOS/CoreCLR.bundle/Contents/MacOS/coreclr";
586
587             int pathSuffixLength = strlen(pathSuffix);
588             int imageFilePathLength = strlen(imageInfo.dli_fname);
589
590             if (imageFilePathLength < pathSuffixLength)
591                 return;
592
593             if (strcmp(imageInfo.dli_fname + (imageFilePathLength - pathSuffixLength), pathSuffix))
594                 return;
595
596             unsigned long segmentSize;
597             const uint8_t* segmentData = getsegmentdata(mh, "__DATA", &segmentSize);
598             if (!segmentData)
599                 return;
600
601             mach_vm_size_t size;
602             uint32_t depth = 0;
603             struct vm_region_submap_info_64 info = { };
604             mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
605             for (mach_vm_address_t addr = reinterpret_cast<mach_vm_address_t>(segmentData); addr < reinterpret_cast<mach_vm_address_t>(segmentData) + segmentSize ; addr += size) {
606                 kern_return_t kr = mach_vm_region_recurse(mach_task_self(), &addr, &size, &depth, (vm_region_recurse_info_64_t)&info, &count);
607                 if (kr != KERN_SUCCESS)
608                     break;
609
610                 mach_vm_protect(mach_task_self(), addr, size, false, info.protection | VM_PROT_EXECUTE);
611             }
612         });
613     }
614 #endif
615
616     // FIXME: Workaround for Java not liking its plugin process to be suppressed - <rdar://problem/14267843>
617     if (m_pluginBundleIdentifier == "com.oracle.java.JavaAppletPlugin")
618         (new UserActivity("com.oracle.java.JavaAppletPlugin"))->start();
619     
620     if (!pluginHasSandboxProfile(m_pluginBundleIdentifier)) {
621         // Allow Apple Events from Citrix plugin. This can be removed when <rdar://problem/14012823> is fixed.
622         setenv("__APPLEEVENTSSERVICENAME", "com.apple.coreservices.appleevents", 1);
623     }
624 }
625
626 void PluginProcess::initializeProcessName(const AuxiliaryProcessInitializationParameters& parameters)
627 {
628     NSString *applicationName = [NSString stringWithFormat:WEB_UI_STRING("%@ (%@ Internet plug-in)", "visible name of the plug-in host process. The first argument is the plug-in name and the second argument is the application name."), [[(NSString *)m_pluginPath lastPathComponent] stringByDeletingPathExtension], (NSString *)parameters.uiProcessName];
629     _LSSetApplicationInformationItem(kLSDefaultSessionID, _LSGetCurrentApplicationASN(), _kLSDisplayNameKey, (CFStringRef)applicationName, nullptr);
630     if (!m_pluginBundleIdentifier.isEmpty())
631         _LSSetApplicationInformationItem(kLSDefaultSessionID, _LSGetCurrentApplicationASN(), kLSPlugInBundleIdentifierKey, m_pluginBundleIdentifier.createCFString().get(), nullptr);
632 }
633
634 void PluginProcess::initializeSandbox(const AuxiliaryProcessInitializationParameters& parameters, SandboxInitializationParameters& sandboxParameters)
635 {
636     // PluginProcess may already be sandboxed if its parent process was sandboxed, and launched a child process instead of an XPC service.
637     // This is generally not expected, however we currently always spawn a child process to create a MIME type preferences file.
638     if (currentProcessIsSandboxed()) {
639         RELEASE_ASSERT(!parameters.connectionIdentifier.xpcConnection);
640         return;
641     }
642
643     char cacheDirectory[PATH_MAX];
644     if (!confstr(_CS_DARWIN_USER_CACHE_DIR, cacheDirectory, sizeof(cacheDirectory))) {
645         WTFLogAlways("PluginProcess: couldn't retrieve system cache directory path: %d\n", errno);
646         exit(EX_OSERR);
647     }
648
649     m_nsurlCacheDirectory = [[[NSFileManager defaultManager] stringWithFileSystemRepresentation:cacheDirectory length:strlen(cacheDirectory)] stringByAppendingPathComponent:[[NSBundle mainBundle] bundleIdentifier]];
650     if (![[NSFileManager defaultManager] createDirectoryAtURL:[NSURL fileURLWithPath:m_nsurlCacheDirectory isDirectory:YES] withIntermediateDirectories:YES attributes:nil error:nil]) {
651         WTFLogAlways("PluginProcess: couldn't create NSURL cache directory '%s'\n", cacheDirectory);
652         exit(EX_OSERR);
653     }
654
655     if (PluginInfoStore::shouldAllowPluginToRunUnsandboxed(m_pluginBundleIdentifier))
656         return;
657
658     bool parentIsSandboxed = parameters.connectionIdentifier.xpcConnection && connectedProcessIsSandboxed(parameters.connectionIdentifier.xpcConnection.get());
659
660     if (parameters.extraInitializationData.get("disable-sandbox") == "1") {
661         if (parentIsSandboxed) {
662             WTFLogAlways("Sandboxed processes may not disable plug-in sandbox, terminating %s.", parameters.clientIdentifier.utf8().data());
663             exit(EX_OSERR);
664         }
665         return;
666     }
667
668     String sandboxProfile = pluginSandboxProfile(m_pluginBundleIdentifier);
669     if (sandboxProfile.isEmpty()) {
670         if (parentIsSandboxed) {
671             WTFLogAlways("Sandboxed processes may only use sandboxed plug-ins, terminating %s.", parameters.clientIdentifier.utf8().data());
672             exit(EX_OSERR);
673         }
674         return;
675     }
676
677     sandboxParameters.setSandboxProfile(sandboxProfile);
678
679     char temporaryDirectory[PATH_MAX];
680     if (!confstr(_CS_DARWIN_USER_TEMP_DIR, temporaryDirectory, sizeof(temporaryDirectory))) {
681         WTFLogAlways("PluginProcess: couldn't retrieve system temporary directory path: %d\n", errno);
682         exit(EX_OSERR);
683     }
684
685     if (strlcpy(temporaryDirectory, [[[[NSFileManager defaultManager] stringWithFileSystemRepresentation:temporaryDirectory length:strlen(temporaryDirectory)] stringByAppendingPathComponent:@"WebKitPlugin-XXXXXX"] fileSystemRepresentation], sizeof(temporaryDirectory)) >= sizeof(temporaryDirectory)
686         || !mkdtemp(temporaryDirectory)) {
687         WTFLogAlways("PluginProcess: couldn't create private temporary directory '%s'\n", temporaryDirectory);
688         exit(EX_OSERR);
689     }
690
691     sandboxParameters.setUserDirectorySuffix([[[[NSFileManager defaultManager] stringWithFileSystemRepresentation:temporaryDirectory length:strlen(temporaryDirectory)] lastPathComponent] fileSystemRepresentation]);
692
693     sandboxParameters.addPathParameter("PLUGIN_PATH", m_pluginPath);
694     sandboxParameters.addPathParameter("NSURL_CACHE_DIR", m_nsurlCacheDirectory);
695
696     [[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"NSUseRemoteSavePanel" : @YES }];
697
698     AuxiliaryProcess::initializeSandbox(parameters, sandboxParameters);
699 }
700
701 bool PluginProcess::shouldOverrideQuarantine()
702 {
703     return m_pluginBundleIdentifier != "com.cisco.webex.plugin.gpc64";
704 }
705
706 void PluginProcess::stopRunLoop()
707 {
708     AuxiliaryProcess::stopNSAppRunLoop();
709 }
710
711 } // namespace WebKit
712
713 #endif // ENABLE(NETSCAPE_PLUGIN_API)