diff options
author | Allan Sandfeld Jensen <allan.jensen@digia.com> | 2013-09-13 12:51:20 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-09-19 20:50:05 +0200 |
commit | d441d6f39bb846989d95bcf5caf387b42414718d (patch) | |
tree | e367e64a75991c554930278175d403c072de6bb8 /Source/WebKit2/Shared/linux | |
parent | 0060b2994c07842f4c59de64b5e3e430525c4b90 (diff) | |
download | qtwebkit-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')
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, ×) == -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); |