| /* |
| * Copyright (C) 2010 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 !PLATFORM(IOS_FAMILY) |
| |
| #import <wtf/Platform.h> |
| #import "PluginProcessShim.h" |
| |
| #import <AppKit/AppKit.h> |
| #import <Carbon/Carbon.h> |
| #import <WebCore/DynamicLinkerInterposing.h> |
| #import <mach/mach_vm.h> |
| #import <objc/message.h> |
| #import <stdio.h> |
| #import <sys/ipc.h> |
| #import <sys/mman.h> |
| #import <sys/shm.h> |
| #import <wtf/Compiler.h> |
| #import <wtf/spi/darwin/SandboxSPI.h> |
| |
| namespace WebKit { |
| |
| extern "C" void WebKitPluginProcessShimInitialize(const PluginProcessShimCallbacks& callbacks); |
| |
| static PluginProcessShimCallbacks pluginProcessShimCallbacks; |
| |
| // Simple Fake System V shared memory. This replacement API implements |
| // usable system V shared memory for use within a single process. The memory |
| // is not shared outside of the scope of the process. |
| struct FakeSharedMemoryDescriptor { |
| FakeSharedMemoryDescriptor* next; |
| int referenceCount; |
| key_t key; |
| size_t requestedSize; |
| size_t mmapedSize; |
| int sharedMemoryFlags; |
| int sharedMemoryIdentifier; |
| void* mmapedAddress; |
| }; |
| |
| static FakeSharedMemoryDescriptor* shmDescriptorList = 0; |
| static int fakeSharedMemoryIdentifier = 0; |
| |
| static FakeSharedMemoryDescriptor* findBySharedMemoryIdentifier(int sharedMemoryIdentifier) |
| { |
| FakeSharedMemoryDescriptor* descriptorPtr = shmDescriptorList; |
| |
| while (descriptorPtr) { |
| if (descriptorPtr->sharedMemoryIdentifier == sharedMemoryIdentifier) |
| break; |
| descriptorPtr = descriptorPtr->next; |
| } |
| return descriptorPtr; |
| } |
| |
| static FakeSharedMemoryDescriptor* findBySharedMemoryAddress(const void* mmapedAddress) |
| { |
| FakeSharedMemoryDescriptor* descriptorPtr = shmDescriptorList; |
| |
| while (descriptorPtr) { |
| if (descriptorPtr->mmapedAddress == mmapedAddress) |
| break; |
| |
| descriptorPtr = descriptorPtr->next; |
| } |
| return descriptorPtr; |
| } |
| |
| static Boolean shim_disabled(void) |
| { |
| static Boolean isFakeSHMDisabled; |
| |
| static dispatch_once_t once; |
| dispatch_once(&once, ^() { |
| Boolean keyExistsAndHasValidFormat = false; |
| Boolean prefValue = CFPreferencesGetAppBooleanValue(CFSTR("WebKitDisableFakeSYSVSHM"), kCFPreferencesCurrentApplication, &keyExistsAndHasValidFormat); |
| |
| if (keyExistsAndHasValidFormat && prefValue) |
| isFakeSHMDisabled = true; |
| else if (sandbox_check(getpid(), NULL, SANDBOX_FILTER_NONE) == 1) |
| isFakeSHMDisabled = false; // Sandboxed |
| else |
| isFakeSHMDisabled = true; // Not Sandboxed |
| |
| }); |
| |
| return isFakeSHMDisabled; |
| } |
| |
| static int shim_shmdt(const void* sharedAddress) |
| { |
| if (shim_disabled()) |
| return shmdt(sharedAddress); |
| |
| FakeSharedMemoryDescriptor* descriptorPtr = findBySharedMemoryAddress(sharedAddress); |
| if (!descriptorPtr) { |
| errno = EINVAL; |
| return -1; |
| } |
| |
| descriptorPtr->referenceCount--; |
| if (!descriptorPtr->referenceCount) { |
| munmap(descriptorPtr->mmapedAddress, descriptorPtr->mmapedSize); |
| descriptorPtr->mmapedAddress = 0; |
| } |
| |
| return 0; |
| } |
| |
| static void* shim_shmat(int sharedMemoryIdentifier, const void* requestedSharedAddress, int shmflg) |
| { |
| if (shim_disabled()) |
| return shmat(sharedMemoryIdentifier, requestedSharedAddress, shmflg); |
| |
| FakeSharedMemoryDescriptor* descriptorPtr = findBySharedMemoryIdentifier(sharedMemoryIdentifier); |
| void* mappedAddress = (void*)-1; |
| |
| if (!descriptorPtr) { |
| errno = EINVAL; |
| return mappedAddress; |
| } |
| |
| if (descriptorPtr->mmapedAddress) { |
| if (!requestedSharedAddress || requestedSharedAddress == descriptorPtr->mmapedAddress) { |
| mappedAddress = descriptorPtr->mmapedAddress; |
| descriptorPtr->referenceCount++; |
| } |
| } else { |
| descriptorPtr->mmapedSize = (descriptorPtr->requestedSize + PAGE_SIZE) & ~(PAGE_SIZE - 1); |
| mappedAddress = descriptorPtr->mmapedAddress = mmap(const_cast<void*>(requestedSharedAddress), |
| descriptorPtr->mmapedSize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); |
| descriptorPtr->referenceCount++; |
| } |
| |
| return mappedAddress; |
| } |
| |
| static int shim_shmget(key_t key, size_t requestedSizeOfSharedMemory, int sharedMemoryFlags) |
| { |
| if (shim_disabled()) |
| return shmget(key, requestedSizeOfSharedMemory, sharedMemoryFlags); |
| |
| FakeSharedMemoryDescriptor* descriptorPtr = shmDescriptorList; |
| |
| while (descriptorPtr) { |
| // Are we looking for something we've already created? |
| if (descriptorPtr->key == key |
| && descriptorPtr->requestedSize == requestedSizeOfSharedMemory |
| && !((descriptorPtr->sharedMemoryFlags ^ sharedMemoryFlags) & 0777)) |
| break; |
| descriptorPtr = descriptorPtr->next; |
| } |
| |
| if (!descriptorPtr) { |
| descriptorPtr = (FakeSharedMemoryDescriptor*)malloc(sizeof(FakeSharedMemoryDescriptor)); |
| if (!descriptorPtr) { |
| errno = ENOMEM; |
| return -1; |
| } |
| descriptorPtr->key = key; |
| descriptorPtr->requestedSize = requestedSizeOfSharedMemory; |
| descriptorPtr->sharedMemoryFlags = sharedMemoryFlags; |
| descriptorPtr->sharedMemoryIdentifier = ++fakeSharedMemoryIdentifier; |
| descriptorPtr->referenceCount = 0; |
| descriptorPtr->mmapedAddress = 0; |
| descriptorPtr->mmapedSize = 0; |
| descriptorPtr->next = shmDescriptorList; |
| shmDescriptorList = descriptorPtr; |
| } |
| return descriptorPtr->sharedMemoryIdentifier; |
| } |
| |
| static int shim_shmctl(int sharedMemoryIdentifier, int cmd, struct shmid_ds* outputDescriptor) |
| { |
| if (shim_disabled()) |
| return shmctl(sharedMemoryIdentifier, cmd, outputDescriptor); |
| |
| FakeSharedMemoryDescriptor* descriptorPtr = findBySharedMemoryIdentifier(sharedMemoryIdentifier); |
| |
| if (!descriptorPtr) { |
| errno = EINVAL; |
| return -1; |
| } |
| |
| switch (cmd) { |
| case IPC_SET: |
| case IPC_RMID: |
| errno = EPERM; |
| return -1; |
| |
| case IPC_STAT: |
| outputDescriptor->shm_perm.cuid = outputDescriptor->shm_perm.uid = getuid(); |
| outputDescriptor->shm_perm.cgid = outputDescriptor->shm_perm.gid = getgid(); |
| outputDescriptor->shm_perm.mode = descriptorPtr->sharedMemoryFlags & 0777; |
| |
| outputDescriptor->shm_segsz = descriptorPtr->requestedSize; |
| |
| outputDescriptor->shm_cpid = outputDescriptor->shm_lpid = getpid(); |
| |
| outputDescriptor->shm_nattch = descriptorPtr->referenceCount; |
| |
| outputDescriptor->shm_ctime = outputDescriptor->shm_atime = outputDescriptor->shm_dtime = time(0); |
| |
| return 0; |
| } |
| |
| errno = EINVAL; |
| return -1; |
| } |
| |
| DYLD_INTERPOSE(shim_shmat, shmat); |
| DYLD_INTERPOSE(shim_shmdt, shmdt); |
| DYLD_INTERPOSE(shim_shmget, shmget); |
| DYLD_INTERPOSE(shim_shmctl, shmctl); |
| |
| static CFComparisonResult shimCFStringCompare(CFStringRef a, CFStringRef b, CFStringCompareFlags options) |
| { |
| if (pluginProcessShimCallbacks.stringCompare) { |
| CFComparisonResult result; |
| if (pluginProcessShimCallbacks.stringCompare(a, b, options, __builtin_return_address(0), result)) |
| return result; |
| } |
| |
| return CFStringCompare(a, b, options); |
| } |
| |
| DYLD_INTERPOSE(shimCFStringCompare, CFStringCompare); |
| |
| |
| __attribute__((visibility("default"))) |
| void WebKitPluginProcessShimInitialize(const PluginProcessShimCallbacks& callbacks) |
| { |
| pluginProcessShimCallbacks = callbacks; |
| } |
| |
| } // namespace WebKit |
| |
| #endif // !PLATFORM(IOS_FAMILY) |