1/* 2 * Copyright (C) 2012 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#import "config.h" 27 28#if PLATFORM(MAC) 29#import "ChildProcess.h" 30 31#import "SandboxInitializationParameters.h" 32#import "WebKitSystemInterface.h" 33#import <WebCore/FileSystem.h> 34#import <WebCore/SystemVersion.h> 35#import <mach/mach.h> 36#import <mach/task.h> 37#import <pwd.h> 38#import <stdlib.h> 39#import <sysexits.h> 40 41// We have to #undef __APPLE_API_PRIVATE to prevent sandbox.h from looking for a header file that does not exist (<rdar://problem/9679211>). 42#undef __APPLE_API_PRIVATE 43#import <sandbox.h> 44 45#define SANDBOX_NAMED_EXTERNAL 0x0003 46extern "C" int sandbox_init_with_parameters(const char *profile, uint64_t flags, const char *const parameters[], char **errorbuf); 47 48#ifdef __has_include 49#if __has_include(<HIServices/ProcessesPriv.h>) 50#include <HIServices/ProcessesPriv.h> 51#endif 52#endif 53 54#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 55typedef bool (^LSServerConnectionAllowedBlock) ( CFDictionaryRef optionsRef ); 56extern "C" void _LSSetApplicationLaunchServicesServerConnectionStatus(uint64_t flags, LSServerConnectionAllowedBlock block); 57extern "C" CFDictionaryRef _LSApplicationCheckIn(int sessionID, CFDictionaryRef applicationInfo); 58#endif 59 60extern "C" OSStatus SetApplicationIsDaemon(Boolean isDaemon); 61 62using namespace WebCore; 63 64namespace WebKit { 65 66#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 67static void initializeTimerCoalescingPolicy() 68{ 69 // Set task_latency and task_throughput QOS tiers as appropriate for a visible application. 70 struct task_qos_policy qosinfo = { LATENCY_QOS_TIER_0, THROUGHPUT_QOS_TIER_0 }; 71 kern_return_t kr = task_policy_set(mach_task_self(), TASK_BASE_QOS_POLICY, (task_policy_t)&qosinfo, TASK_QOS_POLICY_COUNT); 72 ASSERT_UNUSED(kr, kr == KERN_SUCCESS); 73} 74#endif 75 76void ChildProcess::setApplicationIsDaemon() 77{ 78 OSStatus error = SetApplicationIsDaemon(true); 79 ASSERT_UNUSED(error, error == noErr); 80 81#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 82 _LSSetApplicationLaunchServicesServerConnectionStatus(0, 0); 83 RetainPtr<CFDictionaryRef> unused = _LSApplicationCheckIn(-2, CFBundleGetInfoDictionary(CFBundleGetMainBundle())); 84#endif 85} 86 87void ChildProcess::platformInitialize() 88{ 89#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 90 initializeTimerCoalescingPolicy(); 91#endif 92 93 [[NSFileManager defaultManager] changeCurrentDirectoryPath:[[NSBundle mainBundle] bundlePath]]; 94} 95 96void ChildProcess::initializeSandbox(const ChildProcessInitializationParameters& parameters, SandboxInitializationParameters& sandboxParameters) 97{ 98 NSBundle *webkit2Bundle = [NSBundle bundleForClass:NSClassFromString(@"WKView")]; 99 String defaultProfilePath = [webkit2Bundle pathForResource:[[NSBundle mainBundle] bundleIdentifier] ofType:@"sb"]; 100 101 if (sandboxParameters.systemDirectorySuffix().isNull()) { 102 String defaultSystemDirectorySuffix = String([[NSBundle mainBundle] bundleIdentifier]) + "+" + parameters.clientIdentifier; 103 sandboxParameters.setSystemDirectorySuffix(defaultSystemDirectorySuffix); 104 } 105 106 Vector<String> osVersionParts; 107 String osSystemMarketingVersion = systemMarketingVersion(); 108 osSystemMarketingVersion.split('.', false, osVersionParts); 109 if (osVersionParts.size() < 2) { 110 WTFLogAlways("%s: Couldn't find OS Version\n", getprogname()); 111 exit(EX_NOPERM); 112 } 113 String osVersion = osVersionParts[0] + '.' + osVersionParts[1]; 114 sandboxParameters.addParameter("_OS_VERSION", osVersion.utf8().data()); 115 116#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 117 // Use private temporary and cache directories. 118 setenv("DIRHELPER_USER_DIR_SUFFIX", fileSystemRepresentation(sandboxParameters.systemDirectorySuffix()).data(), 0); 119 char temporaryDirectory[PATH_MAX]; 120 if (!confstr(_CS_DARWIN_USER_TEMP_DIR, temporaryDirectory, sizeof(temporaryDirectory))) { 121 WTFLogAlways("%s: couldn't retrieve private temporary directory path: %d\n", getprogname(), errno); 122 exit(EX_NOPERM); 123 } 124 setenv("TMPDIR", temporaryDirectory, 1); 125#endif 126 127 sandboxParameters.addPathParameter("WEBKIT2_FRAMEWORK_DIR", [[webkit2Bundle bundlePath] stringByDeletingLastPathComponent]); 128 sandboxParameters.addConfDirectoryParameter("DARWIN_USER_TEMP_DIR", _CS_DARWIN_USER_TEMP_DIR); 129 sandboxParameters.addConfDirectoryParameter("DARWIN_USER_CACHE_DIR", _CS_DARWIN_USER_CACHE_DIR); 130 131 char buffer[4096]; 132 int bufferSize = sizeof(buffer); 133 struct passwd pwd; 134 struct passwd* result = 0; 135 if (getpwuid_r(getuid(), &pwd, buffer, bufferSize, &result) || !result) { 136 WTFLogAlways("%s: Couldn't find home directory\n", getprogname()); 137 exit(EX_NOPERM); 138 } 139 140 sandboxParameters.addPathParameter("HOME_DIR", pwd.pw_dir); 141 142 String path = String::fromUTF8(pwd.pw_dir); 143 path.append("/Library"); 144 145 sandboxParameters.addPathParameter("HOME_LIBRARY_DIR", fileSystemRepresentation(path).data()); 146 147 path.append("/Preferences"); 148 149 sandboxParameters.addPathParameter("HOME_LIBRARY_PREFERENCES_DIR", fileSystemRepresentation(path).data()); 150 151 switch (sandboxParameters.mode()) { 152 case SandboxInitializationParameters::UseDefaultSandboxProfilePath: 153 case SandboxInitializationParameters::UseOverrideSandboxProfilePath: { 154 String sandboxProfilePath = sandboxParameters.mode() == SandboxInitializationParameters::UseDefaultSandboxProfilePath ? defaultProfilePath : sandboxParameters.overrideSandboxProfilePath(); 155 if (!sandboxProfilePath.isEmpty()) { 156 CString profilePath = fileSystemRepresentation(sandboxProfilePath); 157 char* errorBuf; 158 if (sandbox_init_with_parameters(profilePath.data(), SANDBOX_NAMED_EXTERNAL, sandboxParameters.namedParameterArray(), &errorBuf)) { 159 WTFLogAlways("%s: Couldn't initialize sandbox profile [%s], error '%s'\n", getprogname(), profilePath.data(), errorBuf); 160 for (size_t i = 0, count = sandboxParameters.count(); i != count; ++i) 161 WTFLogAlways("%s=%s\n", sandboxParameters.name(i), sandboxParameters.value(i)); 162 exit(EX_NOPERM); 163 } 164 } 165 166 break; 167 } 168 case SandboxInitializationParameters::UseSandboxProfile: { 169 char* errorBuf; 170 if (sandbox_init_with_parameters(sandboxParameters.sandboxProfile().utf8().data(), 0, sandboxParameters.namedParameterArray(), &errorBuf)) { 171 WTFLogAlways("%s: Couldn't initialize sandbox profile, error '%s'\n", getprogname(), errorBuf); 172 for (size_t i = 0, count = sandboxParameters.count(); i != count; ++i) 173 WTFLogAlways("%s=%s\n", sandboxParameters.name(i), sandboxParameters.value(i)); 174 exit(EX_NOPERM); 175 } 176 177 break; 178 } 179 } 180 181 // This will override LSFileQuarantineEnabled from Info.plist unless sandbox quarantine is globally disabled. 182 OSStatus error = WKEnableSandboxStyleFileQuarantine(); 183 if (error) { 184 WTFLogAlways("%s: Couldn't enable sandbox style file quarantine: %ld\n", getprogname(), (long)error); 185 exit(EX_NOPERM); 186 } 187} 188 189#if USE(APPKIT) 190void ChildProcess::stopNSAppRunLoop() 191{ 192 ASSERT([NSApp isRunning]); 193 [NSApp stop:nil]; 194 195 NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0.0 windowNumber:0 context:nil subtype:0 data1:0 data2:0]; 196 [NSApp postEvent:event atStart:true]; 197} 198#endif 199 200void ChildProcess::setQOS(int latencyQOS, int throughputQOS) 201{ 202#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 203 if (!latencyQOS && !throughputQOS) 204 return; 205 206 struct task_qos_policy qosinfo = { 207 latencyQOS ? LATENCY_QOS_TIER_0 + latencyQOS - 1 : LATENCY_QOS_TIER_UNSPECIFIED, 208 throughputQOS ? THROUGHPUT_QOS_TIER_0 + throughputQOS - 1 : THROUGHPUT_QOS_TIER_UNSPECIFIED 209 }; 210 211 task_policy_set(mach_task_self(), TASK_OVERRIDE_QOS_POLICY, (task_policy_t)&qosinfo, TASK_QOS_POLICY_COUNT); 212#else 213 UNUSED_PARAM(latencyQOS); 214 UNUSED_PARAM(throughputQOS); 215#endif 216} 217 218} // namespace WebKit 219 220#endif 221