blob: a8935e6481f1e962e02983bd3b56f6de89cfbdfb [file] [log] [blame]
/*
* 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)