Need to disable FakeSYSVSHM when sandboxing is not enabled
[WebKit-https.git] / Source / WebKit2 / PluginProcess / mac / PluginProcessShim.mm
1 /*
2  * Copyright (C) 2010 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 <wtf/Platform.h>
27 #import "PluginProcessShim.h"
28
29 #import <AppKit/AppKit.h>
30 #import <Carbon/Carbon.h>
31 #import <WebCore/DynamicLinkerInterposing.h>
32 #import <WebKitSystemInterface.h>
33 #import <stdio.h>
34 #import <objc/message.h>
35
36 #include <sys/shm.h>
37 #include <sys/ipc.h>
38 #include <sys/mman.h>
39
40 #undef __APPLE_API_PRIVATE
41 #include <sandbox.h>
42
43 #ifndef _SANDBOX_PRIVATE_H_
44 enum sandbox_filter_type {
45         SANDBOX_FILTER_NONE,
46 };
47 extern "C" int sandbox_check(pid_t pid, const char *operation, enum sandbox_filter_type type, ...);
48 #endif
49
50 namespace WebKit {
51
52 extern "C" void WebKitPluginProcessShimInitialize(const PluginProcessShimCallbacks& callbacks);
53
54 static PluginProcessShimCallbacks pluginProcessShimCallbacks;
55
56 #ifndef __LP64__
57
58 #if COMPILER(CLANG)
59 #pragma clang diagnostic push
60 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
61 #endif
62
63 static void shimDebugger(void)
64 {
65     if (!pluginProcessShimCallbacks.shouldCallRealDebugger())
66         return;
67     
68     Debugger();
69 }
70
71 static UInt32 shimGetCurrentEventButtonState()
72 {
73     return pluginProcessShimCallbacks.getCurrentEventButtonState();
74 }
75
76 static Boolean shimIsWindowActive(WindowRef window)
77 {
78     bool result;
79     if (pluginProcessShimCallbacks.isWindowActive(window, result))
80         return result;
81     
82     return IsWindowActive(window);
83 }
84
85 static void shimModalDialog(ModalFilterUPP modalFilter, DialogItemIndex *itemHit)
86 {
87     pluginProcessShimCallbacks.beginModal();
88     ModalDialog(modalFilter, itemHit);
89     pluginProcessShimCallbacks.endModal();
90 }
91
92 static DialogItemIndex shimAlert(SInt16 alertID, ModalFilterUPP modalFilter)
93 {
94     pluginProcessShimCallbacks.beginModal();
95     DialogItemIndex index = Alert(alertID, modalFilter);
96     pluginProcessShimCallbacks.endModal();
97     
98     return index;
99 }
100
101 static void shimShowWindow(WindowRef window)
102 {
103     pluginProcessShimCallbacks.carbonWindowShown(window);
104     ShowWindow(window);
105 }
106
107 static void shimHideWindow(WindowRef window)
108 {
109     pluginProcessShimCallbacks.carbonWindowHidden(window);
110     HideWindow(window);
111 }
112
113 static OSStatus
114 shimLSOpenCFURLRef(CFURLRef url, CFURLRef* launchedURL)
115 {
116     int32_t returnValue;
117     if (pluginProcessShimCallbacks.openCFURLRef(url, returnValue, launchedURL))
118         return returnValue;
119
120     return LSOpenCFURLRef(url, launchedURL);
121 }
122
123 DYLD_INTERPOSE(shimDebugger, Debugger);
124 DYLD_INTERPOSE(shimGetCurrentEventButtonState, GetCurrentEventButtonState);
125 DYLD_INTERPOSE(shimIsWindowActive, IsWindowActive);
126 DYLD_INTERPOSE(shimModalDialog, ModalDialog);
127 DYLD_INTERPOSE(shimAlert, Alert);
128 DYLD_INTERPOSE(shimShowWindow, ShowWindow);
129 DYLD_INTERPOSE(shimHideWindow, HideWindow);
130 DYLD_INTERPOSE(shimLSOpenCFURLRef, LSOpenCFURLRef);
131
132 #if COMPILER(CLANG)
133 #pragma clang diagnostic pop
134 #endif
135
136 #endif
137
138 // Simple Fake System V shared memory. This replacement API implements
139 // usable system V shared memory for use within a single process. The memory
140 // is not shared outside of the scope of the process.
141 struct FakeSharedMemoryDescriptor {
142     FakeSharedMemoryDescriptor* next;
143     int referenceCount;
144     key_t key;
145     size_t requestedSize;
146     size_t mmapedSize;
147     int sharedMemoryFlags;
148     int sharedMemoryIdentifier;
149     void* mmapedAddress;
150 };
151
152 static FakeSharedMemoryDescriptor* shmDescriptorList = 0;
153 static int fakeSharedMemoryIdentifier = 0;
154
155 static FakeSharedMemoryDescriptor* findBySharedMemoryIdentifier(int sharedMemoryIdentifier)
156 {
157     FakeSharedMemoryDescriptor* descriptorPtr = shmDescriptorList;
158
159     while (descriptorPtr) {
160         if (descriptorPtr->sharedMemoryIdentifier == sharedMemoryIdentifier)
161             break;
162         descriptorPtr = descriptorPtr->next;
163     }
164     return descriptorPtr;
165 }
166
167 static FakeSharedMemoryDescriptor* findBySharedMemoryAddress(const void* mmapedAddress)
168 {
169     FakeSharedMemoryDescriptor* descriptorPtr = shmDescriptorList;
170
171     while (descriptorPtr) {
172         if (descriptorPtr->mmapedAddress == mmapedAddress)
173             break;
174
175         descriptorPtr = descriptorPtr->next;
176     }
177     return descriptorPtr;
178 }
179
180 static Boolean shim_disabled(void)
181 {
182     static Boolean isFakeSHMDisabled;
183
184     static dispatch_once_t once;
185     dispatch_once(&once, ^() {
186         Boolean keyExistsAndHasValidFormat = false;
187         Boolean prefValue = CFPreferencesGetAppBooleanValue(CFSTR("WebKitDisableFakeSYSVSHM"), kCFPreferencesCurrentApplication, &keyExistsAndHasValidFormat);
188
189         if (keyExistsAndHasValidFormat && prefValue)
190             isFakeSHMDisabled = true;
191         else if (sandbox_check(getpid(), NULL, SANDBOX_FILTER_NONE) == 1)
192             isFakeSHMDisabled = false;  // Sandboxed
193         else
194             isFakeSHMDisabled = true;   // Not Sandboxed
195
196     });
197
198     return isFakeSHMDisabled;
199 }
200
201 static int shim_shmdt(const void* sharedAddress)
202 {
203     if (shim_disabled())
204         return shmdt(sharedAddress);
205
206     FakeSharedMemoryDescriptor* descriptorPtr = findBySharedMemoryAddress(sharedAddress);
207     if (!descriptorPtr) {
208         errno = EINVAL;
209         return -1;
210     }
211
212     descriptorPtr->referenceCount--;
213     if (!descriptorPtr->referenceCount) {
214         munmap(descriptorPtr->mmapedAddress, descriptorPtr->mmapedSize);
215         descriptorPtr->mmapedAddress = 0;
216     }
217
218     return 0;
219 }
220
221 static void* shim_shmat(int sharedMemoryIdentifier, const void* requestedSharedAddress, int shmflg)
222 {
223     if (shim_disabled())
224         return shmat(sharedMemoryIdentifier, requestedSharedAddress, shmflg);
225
226     FakeSharedMemoryDescriptor* descriptorPtr = findBySharedMemoryIdentifier(sharedMemoryIdentifier);
227     void* mappedAddress = (void*)-1;
228
229     if (!descriptorPtr) {
230         errno = EINVAL;
231         return mappedAddress;
232     }
233
234     if (descriptorPtr->mmapedAddress) {
235         if (!requestedSharedAddress || requestedSharedAddress == descriptorPtr->mmapedAddress) {
236             mappedAddress = descriptorPtr->mmapedAddress;
237             descriptorPtr->referenceCount++;
238         }
239     } else {
240         descriptorPtr->mmapedSize = (descriptorPtr->requestedSize + PAGE_SIZE) & ~(PAGE_SIZE - 1);
241         mappedAddress = descriptorPtr->mmapedAddress = mmap((void*)requestedSharedAddress,
242             descriptorPtr->mmapedSize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
243         descriptorPtr->referenceCount++;
244     }
245
246     return mappedAddress;
247 }
248
249 static int shim_shmget(key_t key, size_t requestedSizeOfSharedMemory, int sharedMemoryFlags)
250 {
251     if (shim_disabled())
252         return shmget(key, requestedSizeOfSharedMemory, sharedMemoryFlags);
253
254     FakeSharedMemoryDescriptor* descriptorPtr = shmDescriptorList;
255
256     while (descriptorPtr) {
257         // Are we looking for something we've already created?
258         if (descriptorPtr->key == key
259             && descriptorPtr->requestedSize == requestedSizeOfSharedMemory
260             && !((descriptorPtr->sharedMemoryFlags ^ sharedMemoryFlags) & 0777))
261             break;
262         descriptorPtr = descriptorPtr->next;
263     }
264
265     if (!descriptorPtr) {
266         descriptorPtr = (FakeSharedMemoryDescriptor*)malloc(sizeof(FakeSharedMemoryDescriptor));
267         if (!descriptorPtr) {
268             errno = ENOMEM;
269             return -1;
270         }
271         descriptorPtr->key = key;
272         descriptorPtr->requestedSize = requestedSizeOfSharedMemory;
273         descriptorPtr->sharedMemoryFlags = sharedMemoryFlags;
274         descriptorPtr->sharedMemoryIdentifier = ++fakeSharedMemoryIdentifier;
275         descriptorPtr->referenceCount = 0;
276         descriptorPtr->mmapedAddress = 0;
277         descriptorPtr->mmapedSize = 0;
278         descriptorPtr->next = shmDescriptorList;
279         shmDescriptorList = descriptorPtr;
280     }
281     return descriptorPtr->sharedMemoryIdentifier;
282 }
283
284 static int shim_shmctl(int sharedMemoryIdentifier, int cmd, struct shmid_ds* outputDescriptor)
285 {
286     if (shim_disabled())
287         return shmctl(sharedMemoryIdentifier, cmd, outputDescriptor);
288
289     FakeSharedMemoryDescriptor* descriptorPtr = findBySharedMemoryIdentifier(sharedMemoryIdentifier);
290
291     if (!descriptorPtr) {
292         errno = EINVAL;
293         return -1;
294     }
295
296     switch (cmd) {
297     case IPC_SET:
298     case IPC_RMID:
299         errno = EPERM;
300         return -1;
301
302     case IPC_STAT:
303         outputDescriptor->shm_perm.cuid = outputDescriptor->shm_perm.uid = getuid();
304         outputDescriptor->shm_perm.cgid = outputDescriptor->shm_perm.gid = getgid();
305         outputDescriptor->shm_perm.mode = descriptorPtr->sharedMemoryFlags & 0777;
306
307         outputDescriptor->shm_segsz = descriptorPtr->requestedSize;
308
309         outputDescriptor->shm_cpid = outputDescriptor->shm_lpid = getpid();
310
311         outputDescriptor->shm_nattch = descriptorPtr->referenceCount;
312
313         outputDescriptor->shm_ctime = outputDescriptor->shm_atime = outputDescriptor->shm_dtime = time(0);
314
315         return 0;
316     }
317
318     errno = EINVAL;
319     return -1;
320 }
321
322 DYLD_INTERPOSE(shim_shmat, shmat);
323 DYLD_INTERPOSE(shim_shmdt, shmdt);
324 DYLD_INTERPOSE(shim_shmget, shmget);
325 DYLD_INTERPOSE(shim_shmctl, shmctl);
326
327 __attribute__((visibility("default")))
328 void WebKitPluginProcessShimInitialize(const PluginProcessShimCallbacks& callbacks)
329 {
330     pluginProcessShimCallbacks = callbacks;
331 }
332
333 } // namespace WebKit
334