Fix entitlements and sandboxing for iphoneminimalsimulator
[WebKit-https.git] / Source / WebKit / Shared / mac / ChildProcessMac.mm
1 /*
2  * Copyright (C) 2012-2018 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) || ENABLE(MINIMAL_SIMULATOR)
29 #import "ChildProcess.h"
30
31 #import "CodeSigning.h"
32 #import "QuarantineSPI.h"
33 #import "SandboxInitializationParameters.h"
34 #import "XPCServiceEntryPoint.h"
35 #import <WebCore/FileSystem.h>
36 #import <WebCore/SystemVersion.h>
37 #import <mach/mach.h>
38 #import <mach/task.h>
39 #import <pwd.h>
40 #import <stdlib.h>
41 #import <sysexits.h>
42 #import <wtf/Scope.h>
43 #import <wtf/spi/darwin/SandboxSPI.h>
44
45 #if USE(APPLE_INTERNAL_SDK)
46 #include <HIServices/ProcessesPriv.h>
47 #endif
48
49 typedef bool (^LSServerConnectionAllowedBlock) ( CFDictionaryRef optionsRef );
50 extern "C" void _LSSetApplicationLaunchServicesServerConnectionStatus(uint64_t flags, LSServerConnectionAllowedBlock block);
51 extern "C" CFDictionaryRef _LSApplicationCheckIn(int sessionID, CFDictionaryRef applicationInfo);
52
53 extern "C" OSStatus SetApplicationIsDaemon(Boolean isDaemon);
54
55 using namespace WebCore;
56
57 namespace WebKit {
58
59 static void initializeTimerCoalescingPolicy()
60 {
61     // Set task_latency and task_throughput QOS tiers as appropriate for a visible application.
62     struct task_qos_policy qosinfo = { LATENCY_QOS_TIER_0, THROUGHPUT_QOS_TIER_0 };
63     kern_return_t kr = task_policy_set(mach_task_self(), TASK_BASE_QOS_POLICY, (task_policy_t)&qosinfo, TASK_QOS_POLICY_COUNT);
64     ASSERT_UNUSED(kr, kr == KERN_SUCCESS);
65 }
66
67 void ChildProcess::setApplicationIsDaemon()
68 {
69 #if !ENABLE(MINIMAL_SIMULATOR)
70     OSStatus error = SetApplicationIsDaemon(true);
71     ASSERT_UNUSED(error, error == noErr);
72 #endif
73
74     launchServicesCheckIn();
75 }
76
77 void ChildProcess::launchServicesCheckIn()
78 {
79     _LSSetApplicationLaunchServicesServerConnectionStatus(0, 0);
80     RetainPtr<CFDictionaryRef> unused = _LSApplicationCheckIn(-2, CFBundleGetInfoDictionary(CFBundleGetMainBundle()));
81 }
82
83 void ChildProcess::platformInitialize()
84 {
85     initializeTimerCoalescingPolicy();
86     [[NSFileManager defaultManager] changeCurrentDirectoryPath:[[NSBundle mainBundle] bundlePath]];
87 }
88
89 static OSStatus enableSandboxStyleFileQuarantine()
90 {
91 #if !ENABLE(MINIMAL_SIMULATOR)
92     int error;
93     qtn_proc_t quarantineProperties = qtn_proc_alloc();
94     auto quarantinePropertiesDeleter = makeScopeExit([quarantineProperties]() {
95         qtn_proc_free(quarantineProperties);
96     });
97
98     if ((error = qtn_proc_init_with_self(quarantineProperties)))
99         return error;
100
101     if ((error = qtn_proc_set_flags(quarantineProperties, QTN_FLAG_SANDBOX)))
102         return error;
103
104     // QTN_FLAG_SANDBOX is silently ignored if security.mac.qtn.sandbox_enforce sysctl is 0.
105     // In that case, quarantine falls back to advisory QTN_FLAG_DOWNLOAD.
106     return qtn_proc_apply_to_self(quarantineProperties);
107 #else
108     return false;
109 #endif
110 }
111
112 void ChildProcess::initializeSandbox(const ChildProcessInitializationParameters& parameters, SandboxInitializationParameters& sandboxParameters)
113 {
114     NSBundle *webkit2Bundle = [NSBundle bundleForClass:NSClassFromString(@"WKView")];
115     String defaultProfilePath = [webkit2Bundle pathForResource:[[NSBundle mainBundle] bundleIdentifier] ofType:@"sb"];
116
117     if (sandboxParameters.userDirectorySuffix().isNull()) {
118         auto userDirectorySuffix = parameters.extraInitializationData.find("user-directory-suffix");
119         if (userDirectorySuffix != parameters.extraInitializationData.end())
120             sandboxParameters.setUserDirectorySuffix([makeString(userDirectorySuffix->value, '/', String([[NSBundle mainBundle] bundleIdentifier])) fileSystemRepresentation]);
121         else {
122             String clientIdentifier = codeSigningIdentifier(parameters.connectionIdentifier.xpcConnection.get());
123             if (clientIdentifier.isNull())
124                 clientIdentifier = parameters.clientIdentifier;
125             String defaultUserDirectorySuffix = makeString(String([[NSBundle mainBundle] bundleIdentifier]), '+', clientIdentifier);
126             sandboxParameters.setUserDirectorySuffix(defaultUserDirectorySuffix);
127         }
128     }
129
130     Vector<String> osVersionParts;
131     String osSystemMarketingVersion = systemMarketingVersion();
132     osSystemMarketingVersion.split('.', false, osVersionParts);
133     if (osVersionParts.size() < 2) {
134         WTFLogAlways("%s: Couldn't find OS Version\n", getprogname());
135         exit(EX_NOPERM);
136     }
137     String osVersion = osVersionParts[0] + '.' + osVersionParts[1];
138     sandboxParameters.addParameter("_OS_VERSION", osVersion.utf8().data());
139
140     // Use private temporary and cache directories.
141     setenv("DIRHELPER_USER_DIR_SUFFIX", FileSystem::fileSystemRepresentation(sandboxParameters.userDirectorySuffix()).data(), 1);
142     char temporaryDirectory[PATH_MAX];
143     if (!confstr(_CS_DARWIN_USER_TEMP_DIR, temporaryDirectory, sizeof(temporaryDirectory))) {
144         WTFLogAlways("%s: couldn't retrieve private temporary directory path: %d\n", getprogname(), errno);
145         exit(EX_NOPERM);
146     }
147     setenv("TMPDIR", temporaryDirectory, 1);
148
149     sandboxParameters.addPathParameter("WEBKIT2_FRAMEWORK_DIR", [[webkit2Bundle bundlePath] stringByDeletingLastPathComponent]);
150     sandboxParameters.addConfDirectoryParameter("DARWIN_USER_TEMP_DIR", _CS_DARWIN_USER_TEMP_DIR);
151     sandboxParameters.addConfDirectoryParameter("DARWIN_USER_CACHE_DIR", _CS_DARWIN_USER_CACHE_DIR);
152
153     char buffer[4096];
154     int bufferSize = sizeof(buffer);
155     struct passwd pwd;
156     struct passwd* result = 0;
157     if (getpwuid_r(getuid(), &pwd, buffer, bufferSize, &result) || !result) {
158         WTFLogAlways("%s: Couldn't find home directory\n", getprogname());
159         exit(EX_NOPERM);
160     }
161
162     sandboxParameters.addPathParameter("HOME_DIR", pwd.pw_dir);
163
164     String path = String::fromUTF8(pwd.pw_dir);
165     path.append("/Library");
166
167     sandboxParameters.addPathParameter("HOME_LIBRARY_DIR", FileSystem::fileSystemRepresentation(path).data());
168
169     path.append("/Preferences");
170
171     sandboxParameters.addPathParameter("HOME_LIBRARY_PREFERENCES_DIR", FileSystem::fileSystemRepresentation(path).data());
172
173     switch (sandboxParameters.mode()) {
174     case SandboxInitializationParameters::UseDefaultSandboxProfilePath:
175     case SandboxInitializationParameters::UseOverrideSandboxProfilePath: {
176         String sandboxProfilePath = sandboxParameters.mode() == SandboxInitializationParameters::UseDefaultSandboxProfilePath ? defaultProfilePath : sandboxParameters.overrideSandboxProfilePath();
177         if (!sandboxProfilePath.isEmpty()) {
178             CString profilePath = FileSystem::fileSystemRepresentation(sandboxProfilePath);
179             char* errorBuf;
180 #pragma clang diagnostic push
181 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
182             if (sandbox_init_with_parameters(profilePath.data(), SANDBOX_NAMED_EXTERNAL, sandboxParameters.namedParameterArray(), &errorBuf)) {
183 #pragma clang diagnostic pop
184                 WTFLogAlways("%s: Couldn't initialize sandbox profile [%s], error '%s'\n", getprogname(), profilePath.data(), errorBuf);
185                 for (size_t i = 0, count = sandboxParameters.count(); i != count; ++i)
186                     WTFLogAlways("%s=%s\n", sandboxParameters.name(i), sandboxParameters.value(i));
187                 exit(EX_NOPERM);
188             }
189         }
190
191         break;
192     }
193     case SandboxInitializationParameters::UseSandboxProfile: {
194         char* errorBuf;
195 #pragma clang diagnostic push
196 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
197         if (sandbox_init_with_parameters(sandboxParameters.sandboxProfile().utf8().data(), 0, sandboxParameters.namedParameterArray(), &errorBuf)) {
198 #pragma clang diagnostic pop
199             WTFLogAlways("%s: Couldn't initialize sandbox profile, error '%s'\n", getprogname(), errorBuf);
200             for (size_t i = 0, count = sandboxParameters.count(); i != count; ++i)
201                 WTFLogAlways("%s=%s\n", sandboxParameters.name(i), sandboxParameters.value(i));
202             exit(EX_NOPERM);
203         }
204
205         break;
206     }
207     }
208
209     // This will override LSFileQuarantineEnabled from Info.plist unless sandbox quarantine is globally disabled.
210     OSStatus error = enableSandboxStyleFileQuarantine();
211     if (error) {
212         WTFLogAlways("%s: Couldn't enable sandbox style file quarantine: %ld\n", getprogname(), static_cast<long>(error));
213         exit(EX_NOPERM);
214     }
215 }
216
217 #if USE(APPKIT)
218 void ChildProcess::stopNSAppRunLoop()
219 {
220     ASSERT([NSApp isRunning]);
221     [NSApp stop:nil];
222
223     NSEvent *event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0.0 windowNumber:0 context:nil subtype:0 data1:0 data2:0];
224     [NSApp postEvent:event atStart:true];
225 }
226 #endif
227
228 #if !ENABLE(MINIMAL_SIMULATOR) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400
229 void ChildProcess::stopNSRunLoop()
230 {
231     ASSERT([NSRunLoop mainRunLoop]);
232     [[NSRunLoop mainRunLoop] performBlock:^{
233         exit(0);
234     }];
235 }
236 #endif
237
238 #if ENABLE(MINIMAL_SIMULATOR)
239 void ChildProcess::platformStopRunLoop()
240 {
241     XPCServiceExit(WTFMove(m_priorityBoostMessage));
242 }
243 #endif
244
245 void ChildProcess::setQOS(int latencyQOS, int throughputQOS)
246 {
247     if (!latencyQOS && !throughputQOS)
248         return;
249
250     struct task_qos_policy qosinfo = {
251         latencyQOS ? LATENCY_QOS_TIER_0 + latencyQOS - 1 : LATENCY_QOS_TIER_UNSPECIFIED,
252         throughputQOS ? THROUGHPUT_QOS_TIER_0 + throughputQOS - 1 : THROUGHPUT_QOS_TIER_UNSPECIFIED
253     };
254
255     task_policy_set(mach_task_self(), TASK_OVERRIDE_QOS_POLICY, (task_policy_t)&qosinfo, TASK_QOS_POLICY_COUNT);
256 }
257
258 } // namespace WebKit
259
260 #endif