summaryrefslogtreecommitdiff
path: root/Source/WebKit2/Shared/linux
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@digia.com>2013-09-13 12:51:20 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-19 20:50:05 +0200
commitd441d6f39bb846989d95bcf5caf387b42414718d (patch)
treee367e64a75991c554930278175d403c072de6bb8 /Source/WebKit2/Shared/linux
parent0060b2994c07842f4c59de64b5e3e430525c4b90 (diff)
downloadqtwebkit-d441d6f39bb846989d95bcf5caf387b42414718d.tar.gz
Import Qt5x2 branch of QtWebkit for Qt 5.2
Importing a new snapshot of webkit. Change-Id: I2d01ad12cdc8af8cb015387641120a9d7ea5f10c Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
Diffstat (limited to 'Source/WebKit2/Shared/linux')
-rw-r--r--Source/WebKit2/Shared/linux/SandboxProcess/SandboxEnvironmentLinux.cpp812
-rw-r--r--Source/WebKit2/Shared/linux/SandboxProcess/SandboxEnvironmentLinux.h32
-rw-r--r--Source/WebKit2/Shared/linux/SeccompFilters/OpenSyscall.cpp219
-rw-r--r--Source/WebKit2/Shared/linux/SeccompFilters/OpenSyscall.h86
-rw-r--r--Source/WebKit2/Shared/linux/SeccompFilters/SeccompBroker.cpp350
-rw-r--r--Source/WebKit2/Shared/linux/SeccompFilters/SeccompBroker.h62
-rw-r--r--Source/WebKit2/Shared/linux/SeccompFilters/SeccompFilters.cpp101
-rw-r--r--Source/WebKit2/Shared/linux/SeccompFilters/SeccompFilters.h75
-rw-r--r--Source/WebKit2/Shared/linux/SeccompFilters/SigactionSyscall.cpp48
-rw-r--r--Source/WebKit2/Shared/linux/SeccompFilters/SigactionSyscall.h43
-rw-r--r--Source/WebKit2/Shared/linux/SeccompFilters/SigprocmaskSyscall.cpp64
-rw-r--r--Source/WebKit2/Shared/linux/SeccompFilters/SigprocmaskSyscall.h43
-rw-r--r--Source/WebKit2/Shared/linux/SeccompFilters/Syscall.cpp108
-rw-r--r--Source/WebKit2/Shared/linux/SeccompFilters/Syscall.h113
-rw-r--r--Source/WebKit2/Shared/linux/SeccompFilters/SyscallPolicy.cpp203
-rw-r--r--Source/WebKit2/Shared/linux/SeccompFilters/SyscallPolicy.h65
-rw-r--r--Source/WebKit2/Shared/linux/WebMemorySamplerLinux.cpp7
17 files changed, 2427 insertions, 4 deletions
diff --git a/Source/WebKit2/Shared/linux/SandboxProcess/SandboxEnvironmentLinux.cpp b/Source/WebKit2/Shared/linux/SandboxProcess/SandboxEnvironmentLinux.cpp
new file mode 100644
index 000000000..2c1593008
--- /dev/null
+++ b/Source/WebKit2/Shared/linux/SandboxProcess/SandboxEnvironmentLinux.cpp
@@ -0,0 +1,812 @@
+/*
+ * Copyright (C) 2013 University of Szeged
+ * Copyright (C) 2013 Renata Hodovan <reni@inf.u-szeged.hu>
+ * All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "SandboxEnvironmentLinux.h"
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <limits.h>
+#include <link.h>
+#include <pwd.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/capability.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <utime.h>
+#include <vector>
+
+static const unsigned maximumPathLength = 512;
+static char sandboxDirectory[maximumPathLength];
+static uid_t sandboxUserUID;
+static uid_t sandboxUserGID;
+
+static inline void strlcpy(char *destination, const char* source, int maxLength)
+{
+ destination[0] = '\0';
+ strncat(destination, source, maxLength - 1);
+}
+
+static inline void strlcat(char* destination, const char* source, int maxLength)
+{
+ strncat(destination, source, maxLength - 1 - strnlen(destination, maxLength - 1));
+}
+
+static inline void appendDirectoryComponent(char* fullPath, const char* directoryPath, const char* fileName)
+{
+ strlcpy(fullPath, directoryPath, maximumPathLength);
+ strlcat(fullPath, fileName, maximumPathLength);
+}
+
+// This function runs in a cloned process and it is waiting for a request message
+// from WebProcess to perform the chroot(). If the operation was successful the function
+// never returns. So this function has no return value.
+static void launchChangeRootHelper(int helperSocket, int webProcessSocket)
+{
+ // We need to restrict the resources available to our process to avoid opening
+ // a file by mistake. However, CAP_SYS_RESOURCE capability should be dropped
+ // otherwise it won't work.
+ struct rlimit restrictedResource = { 0, 0 };
+ if (setrlimit(RLIMIT_NOFILE, &restrictedResource) == -1) {
+ fprintf(stderr, "Helper couldn't set the resource limit: %s.\n", strerror(errno));
+ return;
+ }
+
+ if (close(webProcessSocket) == -1) {
+ fprintf(stderr, "Failed to close socket %d: %s.\n", webProcessSocket, strerror(errno));
+ return;
+ }
+
+ char message;
+ // We expect a 'C' (ChrootMe) message from the WebProcess.
+ if (read(helperSocket, &message, 1) != 1) {
+ fprintf(stderr, "Failed to read message from the web process: %s %d.\n", strerror(errno), errno);
+ return;
+ }
+
+ if (message != MSG_CHROOTME) {
+ fprintf(stderr, "Wrong message recieved: %x.\n", message);
+ return;
+ }
+
+ struct stat sandboxDirectoryInfo;
+ if (lstat(sandboxDirectory, &sandboxDirectoryInfo) == -1) {
+ fprintf(stderr, "Sandbox directory (%s) is not available: %s.\n", sandboxDirectory, strerror(errno));
+ return;
+ }
+
+ if (!S_ISDIR(sandboxDirectoryInfo.st_mode)) {
+ fprintf(stderr, "%s is not a directory!\n", sandboxDirectory);
+ return;
+ }
+
+ if (chroot(sandboxDirectory) == -1) {
+ fprintf(stderr, "Chrooting failed: %s.\n", strerror(errno));
+ return;
+ }
+
+ // Chroot only changes the root directory of the calling process but doesn't change
+ // the current working directory. Therefore, if we don't do it manually a malicious user
+ // could break out the jail with relative paths.
+ if (chdir("/") == -1) {
+ fprintf(stderr, "Couldn't change the working directory to /.: %s\n", strerror(errno));
+ return;
+ }
+
+ // Sending acknowledgement to the WebProcess that the sandboxing was successfull.
+ message = MSG_CHROOTED;
+ if (write(helperSocket, &message, 1) != 1) {
+ fprintf(stderr, "Couldn't send acknowledgement to WebProcess: %s.\n", strerror(errno));
+ return;
+ }
+ exit(EXIT_SUCCESS);
+}
+
+static bool setEnvironmentVariablesForChangeRootHelper(pid_t pid, int helperSocket, int webProcessSocket)
+{
+ const int descriptorSize = 32;
+ char socketDescriptor[descriptorSize];
+ char sandboxHelperPID[descriptorSize];
+
+ int length = snprintf(sandboxHelperPID, sizeof(sandboxHelperPID), "%u", pid);
+ if (length < 0 || length >= sizeof(sandboxHelperPID)) {
+ fprintf(stderr, "Failed to convert the sandbox helper PID to a string.\n");
+ return false;
+ }
+
+ if (setenv(SANDBOX_HELPER_PID, sandboxHelperPID, 1) == -1) {
+ fprintf(stderr, "Couldn't set the SBX_HELPER_PID environment variable: %s\n", strerror(errno));
+ return false;
+ }
+
+ length = snprintf(socketDescriptor, sizeof(socketDescriptor), "%u", webProcessSocket);
+ if (length < 0 || length >= sizeof(socketDescriptor)) {
+ fprintf(stderr, "Failed to convert the sandbox helper file descriptor to a string.\n");
+ return false;
+ }
+
+ if (setenv(SANDBOX_DESCRIPTOR, socketDescriptor, 1) == -1) {
+ fprintf(stderr, "Failed to store the helper's file descriptor into an environment variable: %s.\n", strerror(errno));
+ return false;
+ }
+
+ if (close(helperSocket) == -1) {
+ fprintf(stderr, "Closing of %d failed: %s.\n", helperSocket, strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+static bool prepareAndStartChangeRootHelper()
+{
+ int socketPair[2];
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, socketPair) == -1) {
+ fprintf(stderr, "Couldn't create socketpair: %s\n", strerror(errno));
+ return false;
+ }
+
+ pid_t pid = syscall(SYS_clone, CLONE_FS | SIGCHLD, 0, 0, 0);
+ if (pid == -1) {
+ fprintf(stderr, "Clone failed: %s\n", strerror(errno));
+ return false;
+ }
+ if (!pid) {
+ // Child process: we start the chroot helper which waits for the "ChrootMe"
+ // message from the WebProcess. If we are successed, then we won't return.
+ launchChangeRootHelper(socketPair[0], socketPair[1]);
+ // We reach this part only if launchChrootHelper() failed, instead it should have exited.
+ exit(EXIT_FAILURE);
+ return false;
+ }
+
+ // Parent process: exports the pid of the helper and the socket id so the
+ // helper and the WebProcess can communicate.
+ return setEnvironmentVariablesForChangeRootHelper(pid, socketPair[0], socketPair[1]);
+}
+
+// Setting linux capabilities (permitted, effective and inheritable) for the current process.
+// Permitted set indicates the capabilities what could be set for the process.
+// Effective set is a subset of permitted set, they are actually effective.
+// Inheritable set indicates the capabilities what the children will inherit from the current process.
+static bool setCapabilities(cap_value_t* capabilityList, int length)
+{
+ // Capabilities should be initialized without flags.
+ cap_t capabilities = cap_init();
+ if (!capabilities) {
+ fprintf(stderr, "Failed to initialize process capabilities: %s.\n", strerror(errno));
+ return false;
+ }
+
+ if (cap_clear(capabilities) == -1) {
+ fprintf(stderr, "Failed to clear process capabilities: %s.\n", strerror(errno));
+ return false;
+ }
+
+ if (capabilityList && length) {
+ if (cap_set_flag(capabilities, CAP_EFFECTIVE, length, capabilityList, CAP_SET) == -1
+ || cap_set_flag(capabilities, CAP_INHERITABLE, length, capabilityList, CAP_SET) == -1
+ || cap_set_flag(capabilities, CAP_PERMITTED, length, capabilityList, CAP_SET) == -1) {
+ fprintf(stderr, "Failed to set process capability flags: %s.\n", strerror(errno));
+ cap_free(capabilities);
+ return false;
+ }
+ }
+
+ if (cap_set_proc(capabilities) == -1) {
+ fprintf(stderr, "Failed to set process capabilities: %s.\n", strerror(errno));
+ cap_free(capabilities);
+ return false;
+ }
+
+ cap_free(capabilities);
+ return true;
+}
+
+static bool dropPrivileges()
+{
+ // We become explicitely non dumpable.
+ if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) {
+ fprintf(stderr, "Setting dumpable is failed: %s\n", strerror(errno));
+ return false;
+ }
+
+ if (setresgid(sandboxUserGID, sandboxUserGID, sandboxUserGID) == -1) {
+ fprintf(stderr, "Failed to fallback to group: %d.\n", sandboxUserGID);
+ return false;
+ }
+
+ if (setresuid(sandboxUserUID, sandboxUserUID, sandboxUserUID) == -1) {
+ fprintf(stderr, "Failed to fallback to user: %d.\n", sandboxUserUID);
+ return false;
+ }
+
+ // Drop all capabilities. Again, setuid() normally takes care of this if we had euid 0.
+ return setCapabilities(0, 0);
+}
+
+static bool fileExists(const char* path)
+{
+ struct stat fileStat;
+ if (lstat(path, &fileStat) == -1) {
+ if (errno == ENOENT)
+ return false;
+ }
+ return true;
+}
+
+static mode_t directoryPermissions(const char* directory)
+{
+ struct stat fileStat;
+ if (lstat(directory, &fileStat) == -1) {
+ fprintf(stderr, "Failed to obtain information about directory (%s): %s\n", directory, strerror(errno));
+ return false;
+ }
+ return fileStat.st_mode;
+}
+
+static bool createDirectory(char* pathToCreate, const char* nextDirectoryToCreate)
+{
+ strlcat(pathToCreate, nextDirectoryToCreate, maximumPathLength);
+
+ char pathToCreateInSandbox[maximumPathLength];
+ appendDirectoryComponent(pathToCreateInSandbox, sandboxDirectory, pathToCreate);
+
+ mode_t mode = directoryPermissions(pathToCreate);
+ if (mkdir(pathToCreateInSandbox, mode) == -1) {
+ if (errno != EEXIST) {
+ fprintf(stderr, "Creation of %s failed: %s\n", pathToCreateInSandbox, strerror(errno));
+ return false;
+ }
+ }
+
+ struct stat fileInfo;
+ if (lstat(pathToCreate, &fileInfo) == -1) {
+ fprintf(stderr, "Couldn't obtain information about directory (%s): %s\n", pathToCreate, strerror(errno));
+ return false;
+ }
+ if (fileInfo.st_uid == getuid()) {
+ if (chown(pathToCreateInSandbox, sandboxUserUID, sandboxUserGID) == -1) {
+ fprintf(stderr, "Failed to assign the ownership of %s to the sandbox user: %s.\n", pathToCreateInSandbox, strerror(errno));
+ return false;
+ }
+ }
+ if (chmod(pathToCreateInSandbox, fileInfo.st_mode) == -1) {
+ fprintf(stderr, "Failed to set the permissions of %s: %s.\n", pathToCreateInSandbox, strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+// This function creates a directory chain with the given path.
+// First, it splits up the path by '/'-s and walks through the chunks from the base directory.
+// It checks the existance of the actual path and creates it if it doesn't exist yet.
+static bool createDirectoryChain(const char* path)
+{
+ char fullPathInSandbox[maximumPathLength];
+ appendDirectoryComponent(fullPathInSandbox, sandboxDirectory, path);
+
+ if (fileExists(fullPathInSandbox))
+ return true;
+
+ char alreadyCreatedPath[maximumPathLength];
+ alreadyCreatedPath[0] = '\0';
+ // startPos is (path + 1) because we skip the first '/'.
+ const char* startPos = path + 1;
+ const char* endPos;
+ while ((endPos = strchr(startPos, '/'))) {
+ char nextDirectoryToCreate[maximumPathLength];
+ strlcpy(nextDirectoryToCreate, startPos - 1, strnlen(startPos - 1, endPos - startPos + 1) + 1);
+
+ if (!createDirectory(alreadyCreatedPath, nextDirectoryToCreate))
+ return false;
+ startPos = endPos + 1;
+ }
+ // Create the last directory of the directory path.
+ alreadyCreatedPath[0] = '\0';
+ return createDirectory(alreadyCreatedPath, path);
+}
+
+static bool createDeviceFiles()
+{
+ const char* devDirectory = "/dev";
+ if (!createDirectoryChain(devDirectory))
+ return false;
+
+ const char* devices[2] = { "/dev/random", "/dev/urandom" };
+ for (int i = 0; i < sizeof(devices) / sizeof(devices[0]); ++i) {
+ struct stat status;
+ if (lstat(devices[i], &status)) {
+ fprintf(stderr, "Failed to stat device file (%s): %s\n", devices[i], strerror(errno));
+ return false;
+ }
+ dev_t dev = status.st_rdev;
+
+ // Both needed device files (/dev/random and /dev/urandom) are character m_devices and their permissions should be: rw-rw-rw-.
+ char device[maximumPathLength];
+ appendDirectoryComponent(device, sandboxDirectory, devices[i]);
+
+ if (mknod(device, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, makedev(major(dev), minor(dev))) == -1) {
+ if (errno != EEXIST) {
+ fprintf(stderr, "Couldn't create device file %s: %s\n", device, strerror(errno));
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static bool mountFileSystems()
+{
+ const char* procPath = "/proc";
+ if (!createDirectoryChain(procPath))
+ return false;
+ char procPathInSandbox[maximumPathLength];
+ appendDirectoryComponent(procPathInSandbox, sandboxDirectory, procPath);
+
+ if (mount(procPath, procPathInSandbox, "proc", 0, 0) == -1) {
+ if (errno != EBUSY) {
+ fprintf(stderr, "Failed to mount '%s': %s\n", procPath, strerror(errno));
+ return false;
+ }
+ }
+
+ const char* sharedMemoryPath = "/run/shm";
+ if (!createDirectoryChain(sharedMemoryPath)) {
+ fprintf(stderr, "Failed to create directory for /run/shm in the sandbox: %s.\n", strerror(errno));
+ return false;
+ }
+ char sharedMemoryPathInSandbox[maximumPathLength];
+ appendDirectoryComponent(sharedMemoryPathInSandbox, sandboxDirectory, sharedMemoryPath);
+
+ if (mount(sharedMemoryPath, sharedMemoryPathInSandbox, "tmpfs", 0, 0) == -1) {
+ if (errno != EBUSY) {
+ fprintf(stderr, "Failed to mount '%s': %s.\n", sharedMemoryPath, strerror(errno));
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool linkFile(const char* sourceFile, const char* targetFile)
+{
+ char oldPath[maximumPathLength];
+ char targetPath[maximumPathLength];
+ strlcpy(oldPath, sourceFile, maximumPathLength);
+ strlcpy(targetPath, targetFile, maximumPathLength);
+
+ while (true) {
+ struct stat fileInfo;
+ if (lstat(oldPath, &fileInfo) == -1) {
+ if (errno != ENOENT) {
+ fprintf(stderr, "Couldn't obtain information about %s: %s\n", oldPath, strerror(errno));
+ return false;
+ }
+ // If the original file doesn't exist (e.g. dangling links) then we can ignore it
+ // in the sandbox too.
+ return true;
+ }
+ const char* endOfBaseDirectoryInSource = strrchr(oldPath, '/');
+ if (!endOfBaseDirectoryInSource) {
+ fprintf(stderr, "Invalid source: %s.\n", oldPath);
+ return false;
+ }
+
+ char baseDirectoryOfSource[maximumPathLength];
+ // To determine the length of the base directory we have to consider the tailing
+ // slash (+1) and adding plus one because strlcpy() copies (maxLength - 1) characters
+ // from the source.
+ strlcpy(baseDirectoryOfSource, oldPath, endOfBaseDirectoryInSource - oldPath + 2);
+
+ if (!createDirectoryChain(baseDirectoryOfSource)) {
+ fprintf(stderr, "Creating %s failed: %s.\n", baseDirectoryOfSource, strerror(errno));
+ return false;
+ }
+
+ if (link(oldPath, targetPath) == -1) {
+ if (errno != EEXIST && errno != ENOENT) {
+ fprintf(stderr, "Linking %s failed: %s.\n", oldPath, strerror(errno));
+ return false;
+ }
+ }
+
+ // Handle symlinks. We don't want to have dangling links in the sandbox. So we have to
+ // follow them and put the whole link chain into the sandbox.
+ if ((fileInfo.st_mode & S_IFMT) != S_IFLNK)
+ break;
+
+ char symlinkTarget[maximumPathLength];
+ int lengthOfTheLink = readlink(oldPath, symlinkTarget, sizeof(symlinkTarget) - 1);
+ if (lengthOfTheLink > 0)
+ symlinkTarget[lengthOfTheLink] = '\0';
+
+ char symlinkTargetInRealWorld[maximumPathLength];
+ char symlinkTargetInSandbox[maximumPathLength];
+
+ // Making difference between relative and absolute paths.
+ // If the symlinks target starts with '/' then we have nothing to do with it.
+ // Otherwise it's a relative path and we have to concatenate it to the current
+ // path to obtain the target.
+ if (symlinkTarget[0] == '/') {
+ strlcpy(symlinkTargetInRealWorld, symlinkTarget, maximumPathLength);
+ appendDirectoryComponent(symlinkTargetInSandbox, sandboxDirectory, symlinkTarget);
+ } else {
+ appendDirectoryComponent(symlinkTargetInRealWorld, baseDirectoryOfSource, symlinkTarget);
+ appendDirectoryComponent(symlinkTargetInSandbox, sandboxDirectory, symlinkTargetInRealWorld);
+ }
+
+ // Initialize oldPath and targetPath variables for the next loop of while.
+ oldPath[0] = '\0';
+ targetPath[0] = '\0';
+ strlcat(oldPath, symlinkTargetInRealWorld, maximumPathLength);
+ strlcat(targetPath, symlinkTargetInSandbox, maximumPathLength);
+ }
+ return true;
+}
+
+// This function extends the standard link function by linking directories and all their contents
+// and subdirectories recursively.
+static bool linkDirectory(const char* sourceDirectoryPath, const char* targetDirectoryPath)
+{
+ if (!createDirectoryChain(sourceDirectoryPath))
+ return false;
+ DIR* directory = opendir(sourceDirectoryPath);
+ if (!directory) {
+ fprintf(stderr, "Couldn't open directory %s: %s\n", sourceDirectoryPath, strerror(errno));
+ return false;
+ }
+
+ while (struct dirent *directoryInfo = readdir(directory)) {
+ char* fileName = directoryInfo->d_name;
+ // We must not link '.' and ".." into the sandbox.
+ if (!strcmp(fileName, ".") || !strcmp(fileName, ".."))
+ continue;
+ char sourceFile[maximumPathLength];
+ char targetFile[maximumPathLength];
+ appendDirectoryComponent(sourceFile, sourceDirectoryPath, fileName);
+ appendDirectoryComponent(targetFile, targetDirectoryPath, fileName);
+
+ bool returnValue;
+ if (directoryInfo->d_type == DT_DIR) {
+ strncat(sourceFile, "/", 1);
+ strncat(targetFile, "/", 1);
+ returnValue = linkDirectory(sourceFile, targetFile);
+ } else
+ returnValue = linkFile(sourceFile, targetFile);
+ if (!returnValue)
+ return false;
+ }
+
+ // Restore the original modification time of the directories because
+ // it could have meaning e.g. in the hash generation of cache files.
+ struct stat fileStat;
+ if (lstat(sourceDirectoryPath, &fileStat) == -1) {
+ fprintf(stderr, "Failed to obtain information about the directory '%s': %s\n", sourceDirectoryPath, strerror(errno));
+ return false;
+ }
+ struct utimbuf times;
+ times.actime = fileStat.st_atime;
+ times.modtime = fileStat.st_mtime;
+ if (utime(targetDirectoryPath, &times) == -1) {
+ fprintf(stderr, "Couldn't set back the last modification time of '%s': %s\n", targetDirectoryPath, strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+static bool collectRunTimeDependencies()
+{
+ // The list of empirically gathered library dependencies.
+ const char* runtimeDependencies[] = {
+ "libnss_dns.so",
+ "libresolv.so",
+ "libssl.so",
+ "libcrypto.so"
+ };
+
+ for (int i = 0; i < sizeof(runtimeDependencies) / sizeof(runtimeDependencies[0]); ++i) {
+ // To obtain the path of the runtime dependencies we open them with dlopen.
+ // With the handle supplied by dlopen we can obtain information about the dynamically
+ // linked libraries, so the path where are they installed.
+ void* handle = dlopen(runtimeDependencies[i], RTLD_LAZY);
+ if (!handle) {
+ fprintf(stderr, "Couldn't get the handler of %s: %s\n", runtimeDependencies[i], dlerror());
+ return false;
+ }
+
+ struct link_map* linkMap;
+ if (dlinfo(handle, RTLD_DI_LINKMAP, &linkMap) == -1) {
+ fprintf(stderr, "Couldn't get information about %s: %s\n", runtimeDependencies[i], dlerror());
+ return false;
+ }
+
+ if (!linkMap) {
+ fprintf(stderr, "Couldn't get the linkmap of %s: %s.\n", runtimeDependencies[i], strerror(errno));
+ return false;
+ }
+
+ char pathOfTheLibraryInSandbox[maximumPathLength];
+ appendDirectoryComponent(pathOfTheLibraryInSandbox, sandboxDirectory, linkMap->l_name);
+ if (!linkFile(linkMap->l_name, pathOfTheLibraryInSandbox)) {
+ fprintf(stderr, "Linking runtime dependency: %s failed: %s\n", linkMap->l_name, strerror(errno));
+ dlclose(handle);
+ return false;
+ }
+ dlclose(handle);
+ }
+ return true;
+}
+
+static bool setupXauthorityForNobodyUser()
+{
+ // To be able use X inside the sandbox an .Xauthority file must be exist inside it,
+ // owned by the sandboxuser. Furthermore, XAUTHORITY environment variable must point to it.
+ char buffer[BUFSIZ];
+ size_t size;
+ struct passwd* realUser = getpwuid(getuid());
+ if (!realUser) {
+ fprintf(stderr, "Couldn't obtain the current user: %s\n", strerror(errno));
+ return false;
+ }
+
+ char xauthorityOfRealUser[maximumPathLength];
+ char xauthorityInSandbox[maximumPathLength];
+ appendDirectoryComponent(xauthorityOfRealUser, realUser->pw_dir, "/.Xauthority");
+ appendDirectoryComponent(xauthorityInSandbox, sandboxDirectory, xauthorityOfRealUser);
+
+ FILE* source = fopen(xauthorityOfRealUser, "rb");
+ if (!source) {
+ fprintf(stderr, "Couldn't open %s: %s\n", xauthorityOfRealUser, strerror(errno));
+ return false;
+ }
+
+ FILE* dest = fopen(xauthorityInSandbox, "wb");
+ if (!dest) {
+ fprintf(stderr, "Couldn't open %s: %s\n", xauthorityInSandbox, strerror(errno));
+ return false;
+ }
+
+ // We copy the .Xauthority file of the real user (instead of linking) because 'nobody' user
+ // should own it but we don't want to change the permissions of the original file.
+ while ((size = fread(buffer, 1, BUFSIZ, source))) {
+ if (fwrite(buffer, 1, size, dest) != size) {
+ fprintf(stderr, "Failed to copy .Xauthority to the sandbox: %s.\n", strerror(errno));
+ return false;
+ }
+ }
+
+ if (fclose(source)) {
+ fprintf(stderr, "Closing the .Xauthority file of the real user failed: %s\n", strerror(errno));
+ return false;
+ }
+
+ if (fclose(dest)) {
+ fprintf(stderr, "Closing the .Xauthority file of the sandbox user failed: %s\n", strerror(errno));
+ return false;
+ }
+
+ if (chown(xauthorityInSandbox, sandboxUserUID, sandboxUserGID) == -1) {
+ fprintf(stderr, "Chowning .Xauthority (%s) failed: %s.\n", xauthorityInSandbox, strerror(errno));
+ return false;
+ }
+
+ if (setenv("XAUTHORITY", xauthorityInSandbox, 1) == -1) {
+ fprintf(stderr, "Couldn't set the XAUTHORITY envrionment variable: %s\n", strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+static bool initializeSandbox()
+{
+ // Create the sandbox directory. We only need to enter it, so
+ // the executable permission is needed only.
+ if (mkdir(sandboxDirectory, S_IFDIR | S_IXUSR | S_IXOTH) == -1) {
+ if (errno != EEXIST) {
+ fprintf(stderr, "Couldn't create the sandbox directory: %s\n", strerror(errno));
+ return false;
+ }
+ }
+
+ if (!createDeviceFiles())
+ return false;
+
+ if (!mountFileSystems())
+ return false;
+
+ // Hard link cache and font directories into the sandbox environment.
+ struct passwd* userInfo = getpwuid(getuid());
+ const char* home = userInfo->pw_dir;
+
+ char localDirectory[maximumPathLength];
+ char cacheDirectory[maximumPathLength];
+ char fontDirectory[maximumPathLength];
+
+ appendDirectoryComponent(localDirectory, home, "/.local/share/");
+ appendDirectoryComponent(cacheDirectory, home, "/.cache/");
+ appendDirectoryComponent(fontDirectory, home, "/.fontconfig/");
+
+ const char* linkedDirectories[] = {
+ cacheDirectory,
+ fontDirectory,
+ localDirectory,
+ "/etc/fonts/",
+ "/etc/ssl/certs/",
+ "/var/cache/fontconfig/",
+ "/usr/share/fonts/"
+ };
+
+ for (int i = 0; i < sizeof(linkedDirectories) / sizeof(linkedDirectories[0]); ++i) {
+ char linkedDirectoryInSandbox[maximumPathLength];
+ appendDirectoryComponent(linkedDirectoryInSandbox, sandboxDirectory, linkedDirectories[i]);
+
+ if (!linkDirectory(linkedDirectories[i], linkedDirectoryInSandbox))
+ return false;
+ }
+
+ if (!setupXauthorityForNobodyUser())
+ return false;
+
+ return collectRunTimeDependencies();
+}
+
+static bool restrictCapabilities()
+{
+ // Capabilities we need.
+ // CAP_SYS_ADMIN capabilty is added because cloning with CLONE_NEWPID flag later will need it.
+ cap_value_t capabilityList[] = { CAP_SETUID, CAP_SETGID, CAP_SYS_ADMIN, CAP_SYS_CHROOT};
+
+ // Reduce capabilities to what we need.
+ // Although we still have root euid and we keep root equivalent capabilities,
+ // we removed (= didn't add) CAP_SYS_RESSOURCE capabilites and this resulted that
+ // the setrlimit function with RLIMIT_NOFILE will be effective later.
+ if (!setCapabilities(capabilityList, sizeof(capabilityList) / sizeof(capabilityList[0]))) {
+ fprintf(stderr, "Could not adjust process capabilities: %s.\n", strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+static bool moveToNewPIDNamespace()
+{
+ // CLONE_NEWPID and CLONE_FS should be in that order.
+ // We can't share filesystems accross namespaces.
+ int status;
+ pid_t expectedPID;
+ pid_t pid = syscall(SYS_clone, CLONE_NEWPID | SIGCHLD, 0, 0, 0);
+
+ if (pid == -1) {
+ fprintf(stderr, "Cloning is failed: %s\n", strerror(errno));
+ return false;
+ }
+ if (!pid) {
+ // Child should run with pid number 1 in the new namespace.
+ if (getpid() != 1) {
+ fprintf(stderr, "Couldn't create a new PID namespace.\n");
+ return false;
+ }
+ return true;
+ }
+
+ // We are waiting for our child (WebProcess).
+ // If this wait is successful it means that our child is terminated.
+ expectedPID = waitpid(pid, &status, 0);
+ if (expectedPID != pid) {
+ fprintf(stderr, "Process with PID %d terminated instead of the expected one with PID %d: %s.\n", expectedPID, pid, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ if (WIFEXITED(status))
+ exit(WEXITSTATUS(status));
+ exit(EXIT_SUCCESS);
+}
+
+static bool run(int argc, char *const argv[])
+{
+ struct passwd* userInfo = getpwuid(getuid());
+ if (!userInfo) {
+ fprintf(stderr, "Couldn't get the current user: %s.\n", strerror(errno));
+ return false;
+ }
+ appendDirectoryComponent(sandboxDirectory, userInfo->pw_dir, "/.wk2-sandbox");
+
+ // Currently we use 'nobody' user as the sandbox user and fall back to the real user
+ // if we failed to get it (we could extend this in the future with a specific restricted user).
+ if (struct passwd* nobodyUser = getpwnam("nobody")) {
+ sandboxUserUID = nobodyUser->pw_uid;
+ sandboxUserGID = nobodyUser->pw_gid;
+ } else {
+ sandboxUserUID = getuid();
+ sandboxUserGID = getgid();
+ }
+
+ // We should have three parameters:
+ // path_of_this_binary path_of_the_webprocess socket_to_communicate_with_uiprocess
+ if (argc != 3) {
+ fprintf(stderr, "Starting SandboxProcess requires 3 parameters!\n");
+ return false;
+ }
+
+ // SandboxProcess should be run with suid flag ...
+ if (geteuid()) {
+ fprintf(stderr, "The sandbox is not seteuid root.\n");
+ return false;
+ }
+
+ // ... but not as root (not with sudo).
+ if (!getuid()) {
+ fprintf(stderr, "The sandbox is not designed to be run by root.\n");
+ return false;
+ }
+
+ if (!initializeSandbox())
+ return false;
+
+ if (!restrictCapabilities())
+ return false;
+
+ // We move ourself and our children into a new PID namespace,
+ // where process IDs start from 0 again.
+ if (!moveToNewPIDNamespace())
+ return false;
+
+ // Starting a helper what will waiting for the "chrootme" message from WebProcess.
+ if (!prepareAndStartChangeRootHelper())
+ return false;
+
+ // We don't need any special privileges anymore.
+ if (!dropPrivileges())
+ return false;
+
+ // Sanity check: if our effective or real uid/gid is still 0 (root) or
+ // we can set any of them to 0, then the dropping of privileges is failed.
+ // We ensure here that we cannot set root id after here.
+ if (!geteuid() || !getegid() || !setuid(0) || !setgid(0)) {
+ fprintf(stderr, "Dropping privileges failed!\n");
+ return false;
+ }
+
+ // Start the WebProcess.
+ if (execl(argv[1], argv[1], argv[2], reinterpret_cast<char*>(0)) == -1) {
+ fprintf(stderr, "Couldn't start WebProcess: %s\n", strerror(errno));
+ return false;
+ }
+ return true;
+}
+
+int main(int argc, char *const argv[])
+{
+ return run(argc, argv) ? 0 : 1;
+}
diff --git a/Source/WebKit2/Shared/linux/SandboxProcess/SandboxEnvironmentLinux.h b/Source/WebKit2/Shared/linux/SandboxProcess/SandboxEnvironmentLinux.h
new file mode 100644
index 000000000..c3aaf1bcf
--- /dev/null
+++ b/Source/WebKit2/Shared/linux/SandboxProcess/SandboxEnvironmentLinux.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2013 University of Szeged
+ * Copyright (C) 2013 Renata Hodovan <reni@inf.u-szeged.hu>
+ * All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef SandboxEnvironmentLinux_h
+#define SandboxEnvironmentLinux_h
+
+#define SANDBOX_DESCRIPTOR "SANDBOX_DESCRIPTOR"
+#define SANDBOX_HELPER_PID "SANDBOX_HELPER_PID"
+
+#define MSG_CHROOTME 'C'
+#define MSG_CHROOTED 'O'
+
+#endif // SandboxEnvironmentLinux_h
+
diff --git a/Source/WebKit2/Shared/linux/SeccompFilters/OpenSyscall.cpp b/Source/WebKit2/Shared/linux/SeccompFilters/OpenSyscall.cpp
new file mode 100644
index 000000000..2be4938ca
--- /dev/null
+++ b/Source/WebKit2/Shared/linux/SeccompFilters/OpenSyscall.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2013 Intel Corporation. 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.
+ */
+
+#include "config.h"
+#include "OpenSyscall.h"
+
+#if ENABLE(SECCOMP_FILTERS)
+
+#include "ArgumentCoders.h"
+#include "SyscallPolicy.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <seccomp.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebKit {
+
+COMPILE_ASSERT(!O_RDONLY, O_RDONLY);
+COMPILE_ASSERT(O_WRONLY == 1, O_WRONLY);
+COMPILE_ASSERT(O_RDWR == 2, O_RDWR);
+
+PassOwnPtr<Syscall> OpenSyscall::createFromOpenatContext(mcontext_t* context)
+{
+ OwnPtr<OpenSyscall> open = adoptPtr(new OpenSyscall(0));
+
+ open->setFlags(context->gregs[REG_ARG2]);
+ open->setMode(context->gregs[REG_ARG3]);
+ open->setContext(context);
+
+ int fd = context->gregs[REG_ARG0];
+ char* path = reinterpret_cast<char*>(context->gregs[REG_ARG1]);
+
+ if (path[0] == '/') {
+ open->setPath(path);
+ return open.release();
+ }
+
+ struct stat pathStat;
+ if (fstat(fd, &pathStat) == -1) {
+ context->gregs[REG_SYSCALL] = -errno;
+ return nullptr;
+ }
+
+ if (!S_ISDIR(pathStat.st_mode)) {
+ context->gregs[REG_SYSCALL] = -ENOTDIR;
+ return nullptr;
+ }
+
+ char fdLinkPath[32];
+ snprintf(fdLinkPath, sizeof(fdLinkPath), "/proc/self/fd/%d", fd);
+
+ char fdPath[PATH_MAX];
+ ssize_t size = readlink(fdLinkPath, fdPath, sizeof(fdPath) - 1);
+ if (size == -1) {
+ context->gregs[REG_SYSCALL] = -errno;
+ return nullptr;
+ }
+
+ // The "+ 2" here stands for the '/' and null terminator.
+ if (size + strlen(path) + 2 > PATH_MAX) {
+ context->gregs[REG_SYSCALL] = -ENAMETOOLONG;
+ return nullptr;
+ }
+
+ sprintf(&fdPath[size], "/%s", path);
+ open->setPath(fdPath);
+
+ return open.release();
+}
+
+PassOwnPtr<Syscall> OpenSyscall::createFromCreatContext(mcontext_t* context)
+{
+ OpenSyscall* open = new OpenSyscall(0);
+
+ open->setPath(CString(reinterpret_cast<char*>(context->gregs[REG_ARG0])));
+ open->setFlags(O_CREAT | O_WRONLY | O_TRUNC);
+ open->setMode(context->gregs[REG_ARG1]);
+ open->setContext(context);
+
+ return adoptPtr(open);
+}
+
+OpenSyscall::OpenSyscall(mcontext_t* context)
+ : Syscall(__NR_open, context)
+ , m_flags(0)
+ , m_mode(0)
+{
+ if (!context)
+ return;
+
+ m_path = CString(reinterpret_cast<char*>(context->gregs[REG_ARG0]));
+ m_flags = context->gregs[REG_ARG1];
+ m_mode = context->gregs[REG_ARG2];
+}
+
+void OpenSyscall::setResult(const SyscallResult* result)
+{
+ ASSERT(context() && result->type() == type());
+
+ const OpenSyscallResult* openResult = static_cast<const OpenSyscallResult*>(result);
+
+ if (openResult->fd() >= 0)
+ context()->gregs[REG_SYSCALL] = dup(openResult->fd());
+ else
+ context()->gregs[REG_SYSCALL] = -openResult->errorNumber();
+}
+
+PassOwnPtr<SyscallResult> OpenSyscall::execute(const SyscallPolicy& policy)
+{
+ if (!strncmp("/proc/self/", m_path.data(), 11)) {
+ String resolvedSelfPath = ASCIILiteral("/proc/") + String::number(getppid()) + &m_path.data()[10];
+ m_path = resolvedSelfPath.utf8().data();
+ }
+
+ SyscallPolicy::Permission permission = SyscallPolicy::NotAllowed;
+ if (m_flags & O_RDWR)
+ permission = static_cast<SyscallPolicy::Permission>(permission | SyscallPolicy::ReadAndWrite);
+ else if (m_flags & O_WRONLY)
+ permission = static_cast<SyscallPolicy::Permission>(permission | SyscallPolicy::Write);
+ else
+ permission = static_cast<SyscallPolicy::Permission>(permission | SyscallPolicy::Read);
+
+ // Create a file implies write permission on the directory.
+ if (m_flags & O_CREAT || m_flags & O_EXCL)
+ permission = static_cast<SyscallPolicy::Permission>(permission | SyscallPolicy::Write);
+
+ if (!policy.hasPermissionForPath(m_path.data(), permission))
+ return adoptPtr(new OpenSyscallResult(-1, EACCES));
+
+ // Permission granted, execute the syscall. The syscall might still
+ // fail because of hard permissions enforced by the filesystem and
+ // things like if the entry does not exist.
+ int fd = open(m_path.data(), m_flags, m_mode);
+ int errorNumber = fd == -1 ? errno : 0;
+
+ return adoptPtr(new OpenSyscallResult(fd, errorNumber));
+}
+
+void OpenSyscall::encode(CoreIPC::ArgumentEncoder& encoder) const
+{
+ encoder << type();
+ encoder << m_path;
+ encoder << m_flags;
+ encoder << m_mode;
+}
+
+bool OpenSyscall::decode(CoreIPC::ArgumentDecoder* decoder)
+{
+ // m_type already decoded by the parent class.
+
+ if (!decoder->decode(m_path))
+ return false;
+ if (!decoder->decode(m_flags))
+ return false;
+
+ return decoder->decode(m_mode);
+}
+
+OpenSyscallResult::OpenSyscallResult(int fd, int errorNumber)
+ : SyscallResult(__NR_open)
+ , m_fd(fd)
+ , m_errorNumber(errorNumber)
+{
+}
+
+OpenSyscallResult::~OpenSyscallResult()
+{
+ if (m_fd >= 0)
+ close(m_fd);
+}
+
+void OpenSyscallResult::encode(CoreIPC::ArgumentEncoder& encoder) const
+{
+ encoder << type();
+
+ if (m_fd >= 0) {
+ CoreIPC::Attachment attachment(m_fd);
+ encoder.addAttachment(attachment);
+ }
+
+ encoder << m_errorNumber;
+}
+
+bool OpenSyscallResult::decode(CoreIPC::ArgumentDecoder* decoder, int fd)
+{
+ if (fd >= 0)
+ m_fd = fd;
+
+ return decoder->decode(m_errorNumber);
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(SECCOMP_FILTERS)
diff --git a/Source/WebKit2/Shared/linux/SeccompFilters/OpenSyscall.h b/Source/WebKit2/Shared/linux/SeccompFilters/OpenSyscall.h
new file mode 100644
index 000000000..c303588e4
--- /dev/null
+++ b/Source/WebKit2/Shared/linux/SeccompFilters/OpenSyscall.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2013 Intel Corporation. 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.
+ */
+
+#ifndef OpenSyscall_h
+#define OpenSyscall_h
+
+#if ENABLE(SECCOMP_FILTERS)
+
+#include "Syscall.h"
+#include <wtf/text/CString.h>
+
+namespace CoreIPC {
+class ArgumentDecoder;
+class ArgumentEncoder;
+}
+
+namespace WebKit {
+
+class OpenSyscall : public Syscall {
+public:
+ static PassOwnPtr<Syscall> createFromOpenatContext(mcontext_t*);
+ static PassOwnPtr<Syscall> createFromCreatContext(mcontext_t*);
+
+ explicit OpenSyscall(mcontext_t*);
+
+ void setPath(const CString& path) { m_path = path; };
+ void setFlags(const int flags) { m_flags = flags; };
+ void setMode(const mode_t mode) { m_mode = mode; };
+
+ // Syscall implementation.
+ virtual void setResult(const SyscallResult*);
+ virtual PassOwnPtr<SyscallResult> execute(const SyscallPolicy&);
+ virtual void encode(CoreIPC::ArgumentEncoder&) const;
+ virtual bool decode(CoreIPC::ArgumentDecoder*);
+
+private:
+ CString m_path;
+ int m_flags;
+ mode_t m_mode;
+};
+
+class OpenSyscallResult : public SyscallResult {
+public:
+ OpenSyscallResult(int fd, int errorNumber);
+ ~OpenSyscallResult();
+
+ int fd() const { return m_fd; }
+ int errorNumber() const { return m_errorNumber; }
+
+ // SyscallResult implementation.
+ virtual void encode(CoreIPC::ArgumentEncoder&) const;
+ virtual bool decode(CoreIPC::ArgumentDecoder*, int fd);
+
+private:
+ int m_fd;
+ int m_errorNumber;
+};
+
+
+} // namespace WebKit
+
+#endif // ENABLE(SECCOMP_FILTERS)
+
+#endif // OpenSyscall_h
diff --git a/Source/WebKit2/Shared/linux/SeccompFilters/SeccompBroker.cpp b/Source/WebKit2/Shared/linux/SeccompFilters/SeccompBroker.cpp
new file mode 100644
index 000000000..e14545dd5
--- /dev/null
+++ b/Source/WebKit2/Shared/linux/SeccompFilters/SeccompBroker.cpp
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2011 Igalia S.L.
+ * Copyright (C) 2013 Intel Corporation. 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.
+ */
+
+#include "config.h"
+#include "SeccompBroker.h"
+
+#if ENABLE(SECCOMP_FILTERS)
+
+#include "ArgumentCoders.h"
+#include "Syscall.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <seccomp.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#ifndef SYS_SECCOMP
+#define SYS_SECCOMP 1
+#endif
+
+static const size_t messageMaxSize = 4096;
+static const char onlineCPUCountPath[] = "/sys/devices/system/cpu/online";
+
+namespace WebKit {
+
+class SeccompBrokerClient {
+public:
+ static SeccompBrokerClient& shared(int socket = -1);
+ ~SeccompBrokerClient();
+
+ void dispatch(Syscall*) const;
+
+ bool handleIfOpeningOnlineCPUCount(mcontext_t*) const;
+
+private:
+ SeccompBrokerClient(int socket);
+
+ int m_socket;
+ int m_onlineCPUCountFd;
+
+ mutable Mutex m_socketLock;
+};
+
+static ssize_t sendMessage(int socket, void* data, size_t size, int fd = -1)
+{
+ ASSERT(size <= messageMaxSize);
+
+ struct msghdr message;
+ memset(&message, 0, sizeof(message));
+
+ struct iovec iov;
+ memset(&iov, 0, sizeof(iov));
+ iov.iov_base = data;
+ iov.iov_len = size;
+
+ message.msg_iov = &iov;
+ message.msg_iovlen = 1;
+
+ char control[CMSG_SPACE(sizeof(fd))];
+ if (fd >= 0) {
+ message.msg_control = control;
+ message.msg_controllen = sizeof(control);
+ memset(message.msg_control, 0, message.msg_controllen);
+
+ struct cmsghdr* cmsg = CMSG_FIRSTHDR(&message);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+
+ memmove(CMSG_DATA(cmsg), &fd, sizeof(fd));
+ }
+
+ return sendmsg(socket, &message, 0);
+}
+
+static ssize_t receiveMessage(int socket, void* data, size_t size, int* fd = 0)
+{
+ struct msghdr message;
+ memset(&message, 0, sizeof(message));
+
+ struct iovec iov;
+ memset(&iov, 0, sizeof(iov));
+ iov.iov_base = data;
+ iov.iov_len = size;
+
+ message.msg_iov = &iov;
+ message.msg_iovlen = 1;
+
+ char control[CMSG_SPACE(sizeof(fd))];
+ message.msg_control = control;
+ message.msg_controllen = sizeof(control);
+ memset(message.msg_control, 0, message.msg_controllen);
+
+ ssize_t receivedBytes = recvmsg(socket, &message, 0);
+
+ if (fd && receivedBytes > 0) {
+ struct cmsghdr* cmsg = CMSG_FIRSTHDR(&message);
+ if (cmsg && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
+ memcpy(fd, CMSG_DATA(cmsg), sizeof(*fd));
+ else
+ *fd = -1;
+ }
+
+ return receivedBytes >= 0 ? receivedBytes : -errno;
+}
+
+static void SIGSYSHandler(int signal, siginfo_t* info, void* data)
+{
+ if (signal != SIGSYS || info->si_code != SYS_SECCOMP)
+ CRASH();
+
+ ucontext_t* ucontext = static_cast<ucontext_t*>(data);
+ if (!ucontext)
+ CRASH();
+
+ SeccompBrokerClient* client = &SeccompBrokerClient::shared();
+
+ if (client->handleIfOpeningOnlineCPUCount(&ucontext->uc_mcontext))
+ return;
+
+ // createFromContext might return a nullptr if it is able to resolve the
+ // syscall locally without sending it to the broker process. In this case,
+ // we just return. Examples of locally resolved syscalls are the ones
+ // with cached resources and invalid arguments.
+ OwnPtr<Syscall> syscall = Syscall::createFromContext(ucontext);
+ if (!syscall)
+ return;
+
+ client->dispatch(syscall.get());
+}
+
+static void registerSIGSYSHandler()
+{
+ struct sigaction action;
+ memset(&action, 0, sizeof(action));
+ action.sa_sigaction = &SIGSYSHandler;
+ action.sa_flags = SA_SIGINFO | SA_NODEFER;
+
+ if (sigaction(SIGSYS, &action, 0) < 0)
+ CRASH();
+
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGSYS);
+
+ if (sigprocmask(SIG_UNBLOCK, &mask, 0) < 0)
+ CRASH();
+}
+
+SeccompBrokerClient& SeccompBrokerClient::shared(int socket)
+{
+ DEFINE_STATIC_LOCAL(SeccompBrokerClient, brokerClient, (socket));
+
+ return brokerClient;
+}
+
+SeccompBrokerClient::SeccompBrokerClient(int socket)
+ : m_socket(socket)
+ , m_onlineCPUCountFd(open(onlineCPUCountPath, O_RDONLY))
+{
+ ASSERT(m_socket >= 0 && m_onlineCPUCountFd >= 0);
+}
+
+SeccompBrokerClient::~SeccompBrokerClient()
+{
+ close(m_socket);
+ close(m_onlineCPUCountFd);
+}
+
+void SeccompBrokerClient::dispatch(Syscall* syscall) const
+{
+ OwnPtr<CoreIPC::ArgumentEncoder> encoder = CoreIPC::ArgumentEncoder::create();
+ encoder->encode(*syscall);
+
+ char buffer[messageMaxSize];
+ ssize_t receivedBytes = 0;
+ int fd = -1;
+
+ m_socketLock.lock();
+
+ if (sendMessage(m_socket, encoder->buffer(), encoder->bufferSize()) < 0)
+ CRASH();
+
+ while (true) {
+ receivedBytes = receiveMessage(m_socket, &buffer, sizeof(buffer), &fd);
+ if (receivedBytes > 0)
+ break;
+
+ if (receivedBytes != -EINTR)
+ CRASH();
+ }
+
+ m_socketLock.unlock();
+
+ OwnPtr<CoreIPC::ArgumentDecoder> decoder = CoreIPC::ArgumentDecoder::create((const uint8_t*) buffer, receivedBytes);
+ OwnPtr<SyscallResult> result = SyscallResult::createFromDecoder(decoder.get(), fd);
+ if (!result)
+ CRASH();
+
+ syscall->setResult(result.get());
+}
+
+bool SeccompBrokerClient::handleIfOpeningOnlineCPUCount(mcontext_t* context) const
+{
+ if (context->gregs[REG_SYSCALL] != __NR_open)
+ return false;
+
+ const char *path = reinterpret_cast<char*>(context->gregs[REG_ARG0]);
+ if (strcmp(onlineCPUCountPath, path))
+ return false;
+
+ // Malloc will eventually check the number of online CPUs (i.e being
+ // scheduled) present on the system by opening a special file. If it does
+ // that in the middle of the SIGSYS signal handler, it might trigger a
+ // recursive attempt of proxying the open() syscall to the broker.
+ // Because of that, we cache this resource.
+ context->gregs[REG_SYSCALL] = dup(m_onlineCPUCountFd);
+
+ return true;
+}
+
+void SeccompBroker::launchProcess(SeccompFilters* filters, const SyscallPolicy& policy)
+{
+ static bool initialized = false;
+ if (initialized)
+ return;
+
+ // The sigprocmask filters bellow are needed to trap sigprocmask()
+ // so we can prevent the running processes from blocking SIGSYS.
+ filters->addRule("sigprocmask", SeccompFilters::Trap,
+ 0, SeccompFilters::Equal, SIG_BLOCK,
+ 1, SeccompFilters::NotEqual, 0);
+ filters->addRule("sigprocmask", SeccompFilters::Trap,
+ 0, SeccompFilters::Equal, SIG_SETMASK,
+ 1, SeccompFilters::NotEqual, 0);
+ filters->addRule("rt_sigprocmask", SeccompFilters::Trap,
+ 0, SeccompFilters::Equal, SIG_BLOCK,
+ 1, SeccompFilters::NotEqual, 0);
+ filters->addRule("rt_sigprocmask", SeccompFilters::Trap,
+ 0, SeccompFilters::Equal, SIG_SETMASK,
+ 1, SeccompFilters::NotEqual, 0);
+
+ // The sigaction filters bellow are needed to trap sigaction()
+ // so we can prevent the running processes from handling SIGSYS.
+ filters->addRule("sigaction", SeccompFilters::Trap,
+ 0, SeccompFilters::Equal, SIGSYS);
+ filters->addRule("rt_sigaction", SeccompFilters::Trap,
+ 0, SeccompFilters::Equal, SIGSYS);
+
+ SeccompBroker seccompBroker;
+ seccompBroker.setSyscallPolicy(policy);
+ seccompBroker.initialize();
+
+ initialized = true;
+}
+
+void SeccompBroker::initialize()
+{
+ int sockets[2];
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0)
+ CRASH();
+
+ pid_t pid = fork();
+ if (pid) { // Sandboxed process.
+ close(sockets[1]);
+ SeccompBrokerClient::shared(sockets[0]);
+ registerSIGSYSHandler();
+ } else { // Broker.
+ // TODO: The broker should setup seccomp filters
+ // for itself and block everything else other than
+ // the minimal set of syscalls needed to execute the
+ // syscalls it is suppose to proxy.
+ close(sockets[0]);
+ runLoop(sockets[1]);
+ }
+}
+
+NO_RETURN void SeccompBroker::runLoop(int socket)
+{
+#ifndef NDEBUG
+ int i = STDERR_FILENO + 1;
+#else
+ int i = 0;
+#endif
+ // Close all inherited file descriptors other
+ // than the socket to the sandboxed process.
+ for (; i < FD_SETSIZE; ++i)
+ if (i != socket)
+ close(i);
+
+ while (true) {
+ char buffer[messageMaxSize];
+ ssize_t receivedBytes = receiveMessage(socket, &buffer, sizeof(buffer));
+ if (receivedBytes == -EINTR)
+ continue;
+
+ if (receivedBytes <= 0)
+ exit(receivedBytes ? EXIT_FAILURE : EXIT_SUCCESS);
+
+ OwnPtr<CoreIPC::ArgumentDecoder> decoder = CoreIPC::ArgumentDecoder::create((const uint8_t*) buffer, receivedBytes);
+ OwnPtr<Syscall> syscall = Syscall::createFromDecoder(decoder.get());
+ if (!syscall)
+ exit(EXIT_FAILURE);
+
+ OwnPtr<SyscallResult> result = syscall->execute(m_policy);
+ if (!result)
+ exit(EXIT_FAILURE);
+
+ OwnPtr<CoreIPC::ArgumentEncoder> encoder = CoreIPC::ArgumentEncoder::create();
+ encoder->encode(*result);
+
+ Vector<CoreIPC::Attachment> attachments = encoder->releaseAttachments();
+ int fd = attachments.size() == 1 ? attachments[0].fileDescriptor() : -1;
+
+ // The client is down, the broker should go away.
+ if (sendMessage(socket, encoder->buffer(), encoder->bufferSize(), fd) < 0)
+ exit(EXIT_SUCCESS);
+ }
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(SECCOMP_FILTERS)
diff --git a/Source/WebKit2/Shared/linux/SeccompFilters/SeccompBroker.h b/Source/WebKit2/Shared/linux/SeccompFilters/SeccompBroker.h
new file mode 100644
index 000000000..a75c86b74
--- /dev/null
+++ b/Source/WebKit2/Shared/linux/SeccompFilters/SeccompBroker.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2013 Intel Corporation. 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.
+ */
+
+#ifndef SeccompBroker_h
+#define SeccompBroker_h
+
+#if ENABLE(SECCOMP_FILTERS)
+
+#include "SeccompFilters.h"
+#include "Syscall.h"
+#include "SyscallPolicy.h"
+#include <signal.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Threading.h>
+#include <wtf/Vector.h>
+
+namespace WebKit {
+
+class SeccompBroker {
+ WTF_MAKE_NONCOPYABLE(SeccompBroker);
+
+public:
+ static void launchProcess(SeccompFilters*, const SyscallPolicy&);
+
+ void initialize();
+ void setSyscallPolicy(const SyscallPolicy& policy) { m_policy = policy; }
+
+private:
+ SeccompBroker() { }
+
+ void runLoop(int socket);
+
+ SyscallPolicy m_policy;
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(SECCOMP_FILTERS)
+
+#endif // SeccompBroker_h
diff --git a/Source/WebKit2/Shared/linux/SeccompFilters/SeccompFilters.cpp b/Source/WebKit2/Shared/linux/SeccompFilters/SeccompFilters.cpp
new file mode 100644
index 000000000..9491bd167
--- /dev/null
+++ b/Source/WebKit2/Shared/linux/SeccompFilters/SeccompFilters.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2013 Intel Corporation. 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.
+ */
+
+#include "config.h"
+#include "SeccompFilters.h"
+
+#if ENABLE(SECCOMP_FILTERS)
+
+#include "SeccompBroker.h"
+#include <seccomp.h>
+#include <wtf/Assertions.h>
+
+namespace WebKit {
+
+COMPILE_ASSERT(SeccompFilters::Allow == SCMP_ACT_ALLOW, Allow);
+COMPILE_ASSERT(SeccompFilters::Kill == SCMP_ACT_KILL, Kill);
+COMPILE_ASSERT(SeccompFilters::Trap == SCMP_ACT_TRAP, Trap);
+
+COMPILE_ASSERT(SeccompFilters::NotSet == static_cast<SeccompFilters::Operator>(_SCMP_CMP_MIN), NotSet);
+COMPILE_ASSERT(SeccompFilters::NotEqual == static_cast<SeccompFilters::Operator>(SCMP_CMP_NE), NotEqual);
+COMPILE_ASSERT(SeccompFilters::Equal == static_cast<SeccompFilters::Operator>(SCMP_CMP_EQ), Equal);
+
+COMPILE_ASSERT(sizeof(scmp_datum_t) == sizeof(long long), scmp_datum_t);
+
+SeccompFilters::SeccompFilters(Action defaultAction)
+ : m_context(seccomp_init(defaultAction))
+ , m_initialized(false)
+{
+ if (!m_context)
+ CRASH();
+}
+
+SeccompFilters::~SeccompFilters()
+{
+ seccomp_release(m_context);
+}
+
+void SeccompFilters::addRule(const char* syscallName, Action action,
+ unsigned argNum1, Operator operator1, long long data1,
+ unsigned argNum2, Operator operator2, long long data2)
+{
+ int syscall = seccomp_syscall_resolve_name(syscallName);
+ if (syscall == __NR_SCMP_ERROR)
+ CRASH();
+
+ int result;
+ if (operator2 != NotSet)
+ result = seccomp_rule_add(m_context, action, syscall, 2,
+ SCMP_CMP(argNum1, static_cast<scmp_compare>(operator1), data1, 0),
+ SCMP_CMP(argNum2, static_cast<scmp_compare>(operator2), data2, 0));
+ else if (operator1 != NotSet)
+ result = seccomp_rule_add(m_context, action, syscall, 1,
+ SCMP_CMP(argNum1, static_cast<scmp_compare>(operator1), data1, 0));
+ else
+ result = seccomp_rule_add(m_context, action, syscall, 0);
+
+ if (result < 0)
+ CRASH();
+}
+
+void SeccompFilters::initialize()
+{
+ if (m_initialized)
+ return;
+
+ // Implement this is not required in case we are just
+ // setting filters. This is a good place to create the
+ // broker and syscall policy otherwise.
+ platformInitialize();
+
+ if (seccomp_load(m_context) < 0)
+ CRASH();
+
+ m_initialized = true;
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(SECCOMP_FILTERS)
diff --git a/Source/WebKit2/Shared/linux/SeccompFilters/SeccompFilters.h b/Source/WebKit2/Shared/linux/SeccompFilters/SeccompFilters.h
new file mode 100644
index 000000000..d49e1fb62
--- /dev/null
+++ b/Source/WebKit2/Shared/linux/SeccompFilters/SeccompFilters.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2013 Intel Corporation. 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.
+ */
+
+#ifndef SeccompFilters_h
+#define SeccompFilters_h
+
+#if ENABLE(SECCOMP_FILTERS)
+
+#include <wtf/Noncopyable.h>
+
+namespace WebKit {
+
+class SeccompFilters {
+ WTF_MAKE_NONCOPYABLE(SeccompFilters);
+
+public:
+ enum Action {
+ Allow = 0x7fff0000U,
+ Kill = 0x00000000U,
+ Trap = 0x00030000U
+ };
+
+ enum Operator {
+ NotSet = 0,
+ NotEqual = 1,
+ Equal = 4
+ };
+
+ explicit SeccompFilters(Action defaultAction);
+ virtual ~SeccompFilters();
+
+ void* context() { return m_context; };
+
+ void addRule(const char* syscallName, Action,
+ unsigned argNum1 = 0, Operator operator1 = NotSet, long long data1 = 0,
+ unsigned argNum2 = 0, Operator operator2 = NotSet, long long data2 = 0);
+
+ void initialize();
+
+private:
+ virtual void platformInitialize() { }
+
+ typedef void *HANDLE;
+
+ HANDLE m_context;
+ bool m_initialized;
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(SECCOMP_FILTERS)
+
+#endif // SeccompFilters_h
diff --git a/Source/WebKit2/Shared/linux/SeccompFilters/SigactionSyscall.cpp b/Source/WebKit2/Shared/linux/SeccompFilters/SigactionSyscall.cpp
new file mode 100644
index 000000000..ec12f30c2
--- /dev/null
+++ b/Source/WebKit2/Shared/linux/SeccompFilters/SigactionSyscall.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2013 Intel Corporation. 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.
+ */
+
+#include "config.h"
+#include "SigactionSyscall.h"
+
+#if ENABLE(SECCOMP_FILTERS)
+
+#include <signal.h>
+
+namespace WebKit {
+
+PassOwnPtr<Syscall> SigactionSyscall::createFromContext(mcontext_t* context)
+{
+ // We just ignore any attempt of installing a handler for SIGSYS since this
+ // signal is necessary for the sandbox to work.
+ ASSERT(context && context->gregs[REG_ARG0] == SIGSYS);
+
+ context->gregs[REG_SYSCALL] = 0;
+
+ return nullptr;
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(SECCOMP_FILTERS)
diff --git a/Source/WebKit2/Shared/linux/SeccompFilters/SigactionSyscall.h b/Source/WebKit2/Shared/linux/SeccompFilters/SigactionSyscall.h
new file mode 100644
index 000000000..90476d46f
--- /dev/null
+++ b/Source/WebKit2/Shared/linux/SeccompFilters/SigactionSyscall.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2013 Intel Corporation. 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.
+ */
+
+#ifndef SigactionSyscall_h
+#define SigactionSyscall_h
+
+#if ENABLE(SECCOMP_FILTERS)
+
+#include "Syscall.h"
+
+namespace WebKit {
+
+struct SigactionSyscall {
+ static PassOwnPtr<Syscall> createFromContext(mcontext_t*);
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(SECCOMP_FILTERS)
+
+#endif // SigactionSyscall_h
diff --git a/Source/WebKit2/Shared/linux/SeccompFilters/SigprocmaskSyscall.cpp b/Source/WebKit2/Shared/linux/SeccompFilters/SigprocmaskSyscall.cpp
new file mode 100644
index 000000000..242b80d8a
--- /dev/null
+++ b/Source/WebKit2/Shared/linux/SeccompFilters/SigprocmaskSyscall.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2013 Intel Corporation. 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.
+ */
+
+#include "config.h"
+#include "SigprocmaskSyscall.h"
+
+#if ENABLE(SECCOMP_FILTERS)
+
+#include <signal.h>
+#include <string.h>
+
+namespace WebKit {
+
+PassOwnPtr<Syscall> SigprocmaskSyscall::createFromContext(ucontext_t* ucontext)
+{
+ // This syscall is never proxied to the broker process and resolved locally.
+ // What we do here is silently remove SIGSYS from the signal set so no
+ // thread will ever be able to block it.
+ ASSERT(ucontext);
+
+ mcontext_t mcontext = ucontext->uc_mcontext;
+ int how = mcontext.gregs[REG_ARG0];
+ sigset_t* set = reinterpret_cast<sigset_t*>(mcontext.gregs[REG_ARG1]);
+ sigset_t* oldSet = reinterpret_cast<sigset_t*>(mcontext.gregs[REG_ARG2]);
+
+ if (oldSet)
+ memcpy(oldSet, &ucontext->uc_sigmask, sizeof(sigset_t));
+
+ if (how == SIG_SETMASK)
+ memcpy(&ucontext->uc_sigmask, set, sizeof(sigset_t));
+ else
+ sigorset(&ucontext->uc_sigmask, set, &ucontext->uc_sigmask);
+
+ sigdelset(&ucontext->uc_sigmask, SIGSYS);
+ mcontext.gregs[REG_SYSCALL] = 0;
+
+ return nullptr;
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(SECCOMP_FILTERS)
diff --git a/Source/WebKit2/Shared/linux/SeccompFilters/SigprocmaskSyscall.h b/Source/WebKit2/Shared/linux/SeccompFilters/SigprocmaskSyscall.h
new file mode 100644
index 000000000..4d0453a36
--- /dev/null
+++ b/Source/WebKit2/Shared/linux/SeccompFilters/SigprocmaskSyscall.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2013 Intel Corporation. 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.
+ */
+
+#ifndef SigprocmaskSyscall_h
+#define SigprocmaskSyscall_h
+
+#if ENABLE(SECCOMP_FILTERS)
+
+#include "Syscall.h"
+
+namespace WebKit {
+
+struct SigprocmaskSyscall {
+ static PassOwnPtr<Syscall> createFromContext(ucontext_t*);
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(SECCOMP_FILTERS)
+
+#endif // SigprocmaskSyscall_h
diff --git a/Source/WebKit2/Shared/linux/SeccompFilters/Syscall.cpp b/Source/WebKit2/Shared/linux/SeccompFilters/Syscall.cpp
new file mode 100644
index 000000000..b39cab558
--- /dev/null
+++ b/Source/WebKit2/Shared/linux/SeccompFilters/Syscall.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2013 Intel Corporation. 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.
+ */
+
+#include "config.h"
+#include "Syscall.h"
+
+#if ENABLE(SECCOMP_FILTERS)
+
+#include "ArgumentCoders.h"
+#include "OpenSyscall.h"
+#include "SigactionSyscall.h"
+#include "SigprocmaskSyscall.h"
+#include <seccomp.h>
+
+namespace WebKit {
+
+PassOwnPtr<Syscall> Syscall::createFromContext(ucontext_t* ucontext)
+{
+ mcontext_t* mcontext = &ucontext->uc_mcontext;
+
+ switch (mcontext->gregs[REG_SYSCALL]) {
+ case __NR_open:
+ return adoptPtr(new OpenSyscall(mcontext));
+ case __NR_openat:
+ return OpenSyscall::createFromOpenatContext(mcontext);
+ case __NR_creat:
+ return OpenSyscall::createFromCreatContext(mcontext);
+ case __NR_sigprocmask:
+ case __NR_rt_sigprocmask:
+ return SigprocmaskSyscall::createFromContext(ucontext);
+ case __NR_sigaction:
+ case __NR_rt_sigaction:
+ return SigactionSyscall::createFromContext(mcontext);
+ default:
+ CRASH();
+ }
+
+ return nullptr;
+}
+
+PassOwnPtr<Syscall> Syscall::createFromDecoder(CoreIPC::ArgumentDecoder* decoder)
+{
+ int type;
+ if (!decoder->decode(type))
+ return nullptr;
+
+ OwnPtr<Syscall> syscall;
+ if (type == __NR_open)
+ syscall = adoptPtr(new OpenSyscall(0));
+
+ if (!syscall->decode(decoder))
+ return nullptr;
+
+ return syscall.release();
+}
+
+Syscall::Syscall(int type, mcontext_t* context)
+ : m_type(type)
+ , m_context(context)
+{
+}
+
+PassOwnPtr<SyscallResult> SyscallResult::createFromDecoder(CoreIPC::ArgumentDecoder* decoder, int fd)
+{
+ int type;
+ if (!decoder->decode(type))
+ return nullptr;
+
+ OwnPtr<SyscallResult> result;
+ if (type == __NR_open)
+ result = adoptPtr(new OpenSyscallResult(-1, 0));
+
+ if (!result->decode(decoder, fd))
+ return nullptr;
+
+ return result.release();
+}
+
+SyscallResult::SyscallResult(int type)
+ : m_type(type)
+{
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(SECCOMP_FILTERS)
diff --git a/Source/WebKit2/Shared/linux/SeccompFilters/Syscall.h b/Source/WebKit2/Shared/linux/SeccompFilters/Syscall.h
new file mode 100644
index 000000000..e7f0b4b8b
--- /dev/null
+++ b/Source/WebKit2/Shared/linux/SeccompFilters/Syscall.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2013 Intel Corporation. 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.
+ */
+
+#ifndef Syscall_h
+#define Syscall_h
+
+#if ENABLE(SECCOMP_FILTERS)
+
+#if CPU(X86_64)
+#define REG_SYSCALL REG_RAX
+#define REG_ARG0 REG_RDI
+#define REG_ARG1 REG_RSI
+#define REG_ARG2 REG_RDX
+#define REG_ARG3 REG_R10
+#elif CPU(X86)
+#define REG_SYSCALL REG_EAX
+#define REG_ARG0 REG_EBX
+#define REG_ARG1 REG_ECX
+#define REG_ARG2 REG_EDX
+#define REG_ARG3 REG_ESI
+#else
+#error "CPU not supported."
+#endif
+
+#include <signal.h>
+#include <sys/types.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace CoreIPC {
+class ArgumentDecoder;
+class ArgumentEncoder;
+}
+
+namespace WebKit {
+
+class SyscallResult;
+class SyscallPolicy;
+
+class Syscall {
+ WTF_MAKE_NONCOPYABLE(Syscall);
+
+public:
+ virtual ~Syscall() { }
+
+ static PassOwnPtr<Syscall> createFromContext(ucontext_t*);
+ static PassOwnPtr<Syscall> createFromDecoder(CoreIPC::ArgumentDecoder*);
+
+ int type() const { return m_type; }
+
+ void setContext(mcontext_t* context) { m_context = context; }
+ mcontext_t* context() const { return m_context; }
+
+ virtual void setResult(const SyscallResult*) = 0;
+ virtual PassOwnPtr<SyscallResult> execute(const SyscallPolicy&) = 0;
+ virtual void encode(CoreIPC::ArgumentEncoder&) const = 0;
+ virtual bool decode(CoreIPC::ArgumentDecoder*) = 0;
+
+protected:
+ Syscall(int type, mcontext_t*);
+
+private:
+ int m_type;
+ mcontext_t* m_context;
+};
+
+class SyscallResult {
+ WTF_MAKE_NONCOPYABLE(SyscallResult);
+
+public:
+ virtual ~SyscallResult() { }
+
+ static PassOwnPtr<SyscallResult> createFromDecoder(CoreIPC::ArgumentDecoder*, int fd);
+
+ int type() const { return m_type; }
+
+ virtual void encode(CoreIPC::ArgumentEncoder&) const = 0;
+ virtual bool decode(CoreIPC::ArgumentDecoder*, int fd=-1) = 0;
+
+protected:
+ SyscallResult(int type);
+
+private:
+ int m_type;
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(SECCOMP_FILTERS)
+
+#endif // Syscall_h
diff --git a/Source/WebKit2/Shared/linux/SeccompFilters/SyscallPolicy.cpp b/Source/WebKit2/Shared/linux/SeccompFilters/SyscallPolicy.cpp
new file mode 100644
index 000000000..089c4bb03
--- /dev/null
+++ b/Source/WebKit2/Shared/linux/SeccompFilters/SyscallPolicy.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2013 Intel Corporation. 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.
+ */
+
+#include "config.h"
+#include "SyscallPolicy.h"
+
+#if ENABLE(SECCOMP_FILTERS)
+
+#include "WebProcessCreationParameters.h"
+#include <libgen.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebKit {
+
+static String removeTrailingSlash(const String& path)
+{
+ if (path.endsWith('/'))
+ return path.left(path.length() - 1);
+
+ return path;
+}
+
+bool SyscallPolicy::hasPermissionForPath(const char* path, Permission permission) const
+{
+ // The root directory policy needs to be set because it is the
+ // ultimate fallback when rewinding directories.
+ ASSERT(m_directoryPermission.contains("/"));
+
+ if (permission == NotAllowed)
+ return false;
+
+ char* basePath = strdup(path);
+ char* canonicalPath = canonicalize_file_name(basePath);
+
+ while (canonicalPath) {
+ struct stat pathStat;
+ if (stat(canonicalPath, &pathStat) == -1) {
+ free(basePath);
+ free(canonicalPath);
+ return false;
+ }
+
+ if (S_ISDIR(pathStat.st_mode))
+ break;
+
+ PermissionMap::const_iterator policy = m_filePermission.find(String(canonicalPath));
+ if (policy != m_filePermission.end()) {
+ free(basePath);
+ free(canonicalPath);
+ return (permission & policy->value) == permission;
+ }
+
+ // If not a directory neither a file with a policy defined,
+ // we set canonicalPath to zero to force a rewind to the parent
+ // directory.
+ free(canonicalPath);
+ canonicalPath = 0;
+ }
+
+ while (!canonicalPath) {
+ char* currentBaseDirectory = dirname(basePath);
+ canonicalPath = canonicalize_file_name(currentBaseDirectory);
+ }
+
+ PermissionMap::const_iterator policy = m_directoryPermission.find(String(canonicalPath));
+ while (policy == m_directoryPermission.end()) {
+ char* currentBaseDirectory = dirname(canonicalPath);
+ policy = m_directoryPermission.find(String(currentBaseDirectory));
+ }
+
+ free(basePath);
+ free(canonicalPath);
+
+ return (permission & policy->value) == permission;
+}
+
+void SyscallPolicy::addFilePermission(const String& path, Permission permission)
+{
+ ASSERT(!path.isEmpty() && path.startsWith('/') && !path.endsWith('/') && !path.contains("//"));
+
+ m_filePermission.set(path, permission);
+}
+
+void SyscallPolicy::addDirectoryPermission(const String& path, Permission permission)
+{
+ ASSERT(path.startsWith('/') && !path.contains("//") && (path.length() == 1 || !path.endsWith('/')));
+
+ m_directoryPermission.set(path, permission);
+}
+
+void SyscallPolicy::addDefaultWebProcessPolicy(const WebProcessCreationParameters& parameters)
+{
+ // Directories settings coming from the UIProcess.
+ if (!parameters.applicationCacheDirectory.isEmpty())
+ addDirectoryPermission(removeTrailingSlash(parameters.applicationCacheDirectory), ReadAndWrite);
+ if (!parameters.databaseDirectory.isEmpty())
+ addDirectoryPermission(removeTrailingSlash(parameters.databaseDirectory), ReadAndWrite);
+ if (!parameters.localStorageDirectory.isEmpty())
+ addDirectoryPermission(removeTrailingSlash(parameters.localStorageDirectory), ReadAndWrite);
+ if (!parameters.diskCacheDirectory.isEmpty())
+ addDirectoryPermission(removeTrailingSlash(parameters.diskCacheDirectory), ReadAndWrite);
+ if (!parameters.cookieStorageDirectory.isEmpty())
+ addDirectoryPermission(removeTrailingSlash(parameters.cookieStorageDirectory), ReadAndWrite);
+#if USE(SOUP)
+ if (!parameters.cookiePersistentStoragePath.isEmpty())
+ addDirectoryPermission(removeTrailingSlash(parameters.cookiePersistentStoragePath), ReadAndWrite);
+#endif
+
+ // The root policy will block access to any directory or
+ // file unless white listed bellow or by platform.
+ addDirectoryPermission(ASCIILiteral("/"), NotAllowed);
+
+ // Shared libraries, plugins and fonts.
+ addDirectoryPermission(ASCIILiteral("/lib"), Read);
+ addDirectoryPermission(ASCIILiteral("/usr/lib"), Read);
+ addDirectoryPermission(ASCIILiteral("/usr/share"), Read);
+
+ // SSL Certificates.
+ addDirectoryPermission(ASCIILiteral("/etc/ssl/certs"), Read);
+
+ // Fontconfig cache.
+ addDirectoryPermission(ASCIILiteral("/etc/fonts"), Read);
+ addDirectoryPermission(ASCIILiteral("/var/cache/fontconfig"), Read);
+
+ // Audio devices, random number generators, etc.
+ addDirectoryPermission(ASCIILiteral("/dev"), ReadAndWrite);
+
+ // Temporary files and process self information.
+ addDirectoryPermission(ASCIILiteral("/tmp"), ReadAndWrite);
+ addDirectoryPermission(ASCIILiteral("/proc/") + String::number(getpid()), ReadAndWrite);
+
+ // In some distros /dev/shm is a symbolic link to /run/shm, and in
+ // this case, the canonical path resolver will follow the link. If
+ // inside /dev, the policy is already set.
+ addDirectoryPermission(ASCIILiteral("/run/shm"), ReadAndWrite);
+
+ // Needed by glibc for networking and locale.
+ addFilePermission(ASCIILiteral("/etc/gai.conf"), Read);
+ addFilePermission(ASCIILiteral("/etc/host.conf"), Read);
+ addFilePermission(ASCIILiteral("/etc/hosts"), Read);
+ addFilePermission(ASCIILiteral("/etc/localtime"), Read);
+ addFilePermission(ASCIILiteral("/etc/nsswitch.conf"), Read);
+
+ // Needed for DNS resoltion. In some distros, the resolv.conf inside
+ // /etc is just a symbolic link.
+ addFilePermission(ASCIILiteral("/etc/resolv.conf"), Read);
+ addFilePermission(ASCIILiteral("/run/resolvconf/resolv.conf"), Read);
+
+ // Needed to convert uid and gid into names.
+ addFilePermission(ASCIILiteral("/etc/group"), Read);
+ addFilePermission(ASCIILiteral("/etc/passwd"), Read);
+
+ // Needed by the loader.
+ addFilePermission(ASCIILiteral("/etc/ld.so.cache"), Read);
+
+ // Needed by various, including toolkits, for optimizations based
+ // on the current amount of free system memory.
+ addFilePermission(ASCIILiteral("/proc/cpuinfo"), Read);
+ addFilePermission(ASCIILiteral("/proc/filesystems"), Read);
+ addFilePermission(ASCIILiteral("/proc/meminfo"), Read);
+ addFilePermission(ASCIILiteral("/proc/stat"), Read);
+
+ // Needed by D-Bus.
+ addFilePermission(ASCIILiteral("/var/lib/dbus/machine-id"), Read);
+
+ char* homeDir = getenv("HOME");
+ if (homeDir) {
+ // X11 connection token.
+ addFilePermission(String::fromUTF8(homeDir) + "/.Xauthority", Read);
+ // MIME type resolution.
+ addDirectoryPermission(String::fromUTF8(homeDir) + "/.local/share/mime", Read);
+ }
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(SECCOMP_FILTERS)
diff --git a/Source/WebKit2/Shared/linux/SeccompFilters/SyscallPolicy.h b/Source/WebKit2/Shared/linux/SeccompFilters/SyscallPolicy.h
new file mode 100644
index 000000000..cae0e45d2
--- /dev/null
+++ b/Source/WebKit2/Shared/linux/SeccompFilters/SyscallPolicy.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2013 Intel Corporation. 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.
+ */
+
+#ifndef SyscallPolicy_h
+#define SyscallPolicy_h
+
+#if ENABLE(SECCOMP_FILTERS)
+
+#include <wtf/HashMap.h>
+#include <wtf/text/StringHash.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebKit {
+
+class WebProcessCreationParameters;
+
+class SyscallPolicy {
+public:
+ enum Permission {
+ NotAllowed = 0,
+ Read = 1,
+ Write = 1 << 1,
+ ReadAndWrite = Read | Write
+ };
+
+ bool hasPermissionForPath(const char* path, Permission) const;
+
+ void addFilePermission(const String& path, Permission);
+ void addDirectoryPermission(const String& path, Permission);
+
+ void addDefaultWebProcessPolicy(const WebProcessCreationParameters&);
+
+private:
+ typedef HashMap<String, int> PermissionMap;
+ PermissionMap m_filePermission;
+ PermissionMap m_directoryPermission;
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(SECCOMP_FILTERS)
+
+#endif // SyscallPolicy_h
diff --git a/Source/WebKit2/Shared/linux/WebMemorySamplerLinux.cpp b/Source/WebKit2/Shared/linux/WebMemorySamplerLinux.cpp
index 599e4cead..31e95eaf0 100644
--- a/Source/WebKit2/Shared/linux/WebMemorySamplerLinux.cpp
+++ b/Source/WebKit2/Shared/linux/WebMemorySamplerLinux.cpp
@@ -32,6 +32,7 @@
#include <JavaScriptCore/MemoryStatistics.h>
#include <WebCore/JSDOMWindow.h>
#include <runtime/JSLock.h>
+#include <runtime/Operations.h>
#include <string.h>
#include <sys/sysinfo.h>
#include <wtf/CurrentTime.h>
@@ -153,9 +154,8 @@ WebMemoryStatistics WebMemorySampler::sampleWebKit() const
appendKeyValuePair(webKitMemoryStats, ASCIILiteral("Fast Malloc Committed Memory"), fastMallocBytesCommitted);
#endif
-#if USE(JSC)
- size_t jscHeapBytesInUse = JSDOMWindow::commonJSGlobalData()->heap.size();
- size_t jscHeapBytesCommitted = JSDOMWindow::commonJSGlobalData()->heap.capacity();
+ size_t jscHeapBytesInUse = JSDOMWindow::commonVM()->heap.size();
+ size_t jscHeapBytesCommitted = JSDOMWindow::commonVM()->heap.capacity();
totalBytesInUse += jscHeapBytesInUse;
totalBytesCommitted += jscHeapBytesCommitted;
@@ -168,7 +168,6 @@ WebMemoryStatistics WebMemorySampler::sampleWebKit() const
appendKeyValuePair(webKitMemoryStats, ASCIILiteral("JavaScript Stack Bytes"), globalMemoryStats.stackBytes);
appendKeyValuePair(webKitMemoryStats, ASCIILiteral("JavaScript JIT Bytes"), globalMemoryStats.JITBytes);
-#endif
appendKeyValuePair(webKitMemoryStats, ASCIILiteral("Total Memory In Use"), totalBytesInUse);
appendKeyValuePair(webKitMemoryStats, ASCIILiteral("Total Committed Memory"), totalBytesCommitted);