blob: dddb9313080cae8e6c8bae20d459b781c07bb969 [file] [log] [blame]
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "system_call_table.h"
#include <asm/unistd.h>
#include "sandbox_impl.h"
#if defined(__x86_64__)
#ifndef __NR_set_robust_list
#define __NR_set_robust_list 273
#endif
#ifndef __NR_accept4
#define __NR_accept4 288
#endif
#elif defined(__i386__)
#ifndef __NR_set_robust_list
#define __NR_set_robust_list 311
#endif
#else
#error Unsupported target platform
#endif
namespace playground {
struct SyscallTable *SyscallTable::syscallTable;
unsigned SyscallTable::maxSyscall = 0;
void SyscallTable::initializeSyscallTable() {
if (syscallTable) {
return;
}
#define S(x) reinterpret_cast<void (*)()>(&Sandbox::x)
#define P(x) Sandbox::x
static const struct policy {
unsigned syscallNum;
void (*handler)();
bool (*trustedProcess)(const SyscallRequestInfo* info);
} default_policy[] = {
#if defined(__NR_accept)
{ __NR_accept, UNRESTRICTED_SYSCALL, NULL },
{ __NR_accept4, UNRESTRICTED_SYSCALL, NULL },
#endif
{ __NR_access, S(sandbox_access), P(process_access) },
{ __NR_brk, UNRESTRICTED_SYSCALL, NULL },
{ __NR_clock_gettime, UNRESTRICTED_SYSCALL, NULL },
{ __NR_clone, S(sandbox_clone), P(process_clone) },
{ __NR_close, UNRESTRICTED_SYSCALL, NULL },
{ __NR_dup, UNRESTRICTED_SYSCALL, NULL },
{ __NR_dup2, UNRESTRICTED_SYSCALL, NULL },
{ __NR_epoll_create, UNRESTRICTED_SYSCALL, NULL },
{ __NR_epoll_ctl, UNRESTRICTED_SYSCALL, NULL },
{ __NR_epoll_wait, UNRESTRICTED_SYSCALL, NULL },
{ __NR_exit, S(sandbox_exit), P(process_exit) },
{ __NR_exit_group, UNRESTRICTED_SYSCALL, NULL },
{ __NR_fcntl, UNRESTRICTED_SYSCALL, NULL },
#if defined(__NR_fcntl64)
{ __NR_fcntl64, UNRESTRICTED_SYSCALL, NULL },
#endif
{ __NR_fdatasync, UNRESTRICTED_SYSCALL, NULL },
{ __NR_fstat, UNRESTRICTED_SYSCALL, NULL },
#if defined(__NR_fstat64)
{ __NR_fstat64, UNRESTRICTED_SYSCALL, NULL },
#endif
{ __NR_ftruncate, UNRESTRICTED_SYSCALL, NULL },
{ __NR_futex, UNRESTRICTED_SYSCALL, NULL },
{ __NR_getdents, UNRESTRICTED_SYSCALL, NULL },
{ __NR_getdents64, UNRESTRICTED_SYSCALL, NULL },
{ __NR_getegid, UNRESTRICTED_SYSCALL, NULL },
#if defined(__NR_getegid32)
{ __NR_getegid32, UNRESTRICTED_SYSCALL, NULL },
#endif
{ __NR_geteuid, UNRESTRICTED_SYSCALL, NULL },
#if defined(__NR_geteuid32)
{ __NR_geteuid32, UNRESTRICTED_SYSCALL, NULL },
#endif
{ __NR_getgid, UNRESTRICTED_SYSCALL, NULL },
#if defined(__NR_getgid32)
{ __NR_getgid32, UNRESTRICTED_SYSCALL, NULL },
#endif
#if defined(__NR_getpeername)
{ __NR_getpeername, UNRESTRICTED_SYSCALL, NULL },
#endif
{ __NR_getpid, S(sandbox_getpid), NULL },
#if defined(__NR_getsockname)
{ __NR_getsockname, UNRESTRICTED_SYSCALL, NULL },
{ __NR_getsockopt, S(sandbox_getsockopt), P(process_getsockopt)},
#endif
{ __NR_gettid, S(sandbox_gettid), NULL },
{ __NR_gettimeofday, UNRESTRICTED_SYSCALL, NULL },
{ __NR_getuid, UNRESTRICTED_SYSCALL, NULL },
#if defined(__NR_getuid32)
{ __NR_getuid32, UNRESTRICTED_SYSCALL, NULL },
#endif
{ __NR_ioctl, S(sandbox_ioctl), P(process_ioctl) },
#if defined(__NR_ipc)
{ __NR_ipc, S(sandbox_ipc), P(process_ipc) },
#endif
#if defined(__NR__llseek)
{ __NR__llseek, UNRESTRICTED_SYSCALL, NULL },
#endif
{ __NR_lseek, UNRESTRICTED_SYSCALL, NULL },
{ __NR_lstat, S(sandbox_lstat), P(process_stat) },
#if defined(__NR_lstat64)
{ __NR_lstat64, S(sandbox_lstat64), P(process_stat) },
#endif
{ __NR_madvise, S(sandbox_madvise), P(process_madvise) },
{
#if defined(__NR_mmap2)
__NR_mmap2,
#else
__NR_mmap,
#endif
S(sandbox_mmap), P(process_mmap) },
{ __NR_mprotect, S(sandbox_mprotect), P(process_mprotect) },
{ __NR_munmap, S(sandbox_munmap), P(process_munmap) },
{ __NR_nanosleep, UNRESTRICTED_SYSCALL, NULL },
{ __NR_open, S(sandbox_open), P(process_open) },
{ __NR_pipe, UNRESTRICTED_SYSCALL, NULL },
{ __NR_poll, UNRESTRICTED_SYSCALL, NULL },
{ __NR_prctl, S(sandbox_prctl), P(process_prctl) },
{ __NR_pread64, UNRESTRICTED_SYSCALL, NULL },
{ __NR_preadv, UNRESTRICTED_SYSCALL, NULL },
{ __NR_pwrite64, UNRESTRICTED_SYSCALL, NULL },
{ __NR_pwritev, UNRESTRICTED_SYSCALL, NULL },
{ __NR_readv, UNRESTRICTED_SYSCALL, NULL },
#if defined(__NR_recvfrom)
{ __NR_recvfrom, S(sandbox_recvfrom), P(process_recvfrom) },
{ __NR_recvmsg, S(sandbox_recvmsg), P(process_recvmsg) },
#endif
#if defined(__NR_rt_sigaction)
{ __NR_rt_sigaction, S(sandbox_rt_sigaction), P(process_sigaction) },
#endif
#if defined(__NR_rt_sigprocmask)
{ __NR_rt_sigprocmask, S(sandbox_rt_sigprocmask), NULL },
#endif
#if defined(__NR_sendmsg)
{ __NR_sendmsg, S(sandbox_sendmsg), P(process_sendmsg) },
{ __NR_sendto, S(sandbox_sendto), P(process_sendto) },
#endif
{ __NR_set_robust_list, UNRESTRICTED_SYSCALL, NULL },
#if defined(__NR_setsockopt)
{ __NR_setsockopt, S(sandbox_setsockopt), P(process_setsockopt)},
#endif
#if defined(__NR_shmat)
{ __NR_shmat, S(sandbox_shmat), P(process_shmat) },
{ __NR_shmctl, S(sandbox_shmctl), P(process_shmctl) },
{ __NR_shmdt, S(sandbox_shmdt), P(process_shmdt) },
{ __NR_shmget, S(sandbox_shmget), P(process_shmget) },
#endif
#if defined(__NR_shutdown)
{ __NR_shutdown, UNRESTRICTED_SYSCALL, NULL },
#endif
#if defined(__NR_sigaction)
{ __NR_sigaction, S(sandbox_sigaction), P(process_sigaction) },
#endif
#if defined(__NR_signal)
{ __NR_signal, S(sandbox_signal), P(process_sigaction) },
#endif
#if defined(__NR_sigprocmask)
{ __NR_sigprocmask, S(sandbox_sigprocmask), NULL },
#endif
#if defined(__NR_socketpair)
{ __NR_socketpair, UNRESTRICTED_SYSCALL, NULL },
#endif
#if defined(__NR_socketcall)
{ __NR_socketcall, S(sandbox_socketcall), P(process_socketcall)},
#endif
{ __NR_stat, S(sandbox_stat), P(process_stat) },
#if defined(__NR_stat64)
{ __NR_stat64, S(sandbox_stat64), P(process_stat) },
#endif
{ __NR_time, UNRESTRICTED_SYSCALL, NULL },
{ __NR_uname, UNRESTRICTED_SYSCALL, NULL },
{ __NR_writev, UNRESTRICTED_SYSCALL, NULL },
};
// Find the highest used system call number
for (const struct policy *policy = default_policy;
policy-default_policy <
(int)(sizeof(default_policy)/sizeof(struct policy));
++policy) {
if (policy->syscallNum > maxSyscall) {
maxSyscall = policy->syscallNum;
}
}
syscallTable = reinterpret_cast<SyscallTable *>(
mmap(NULL, getSyscallTableSize(),
PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0));
if (syscallTable == MAP_FAILED) {
Sandbox::die("Failed to allocate system call table");
}
for (const struct policy *policy = default_policy;
policy-default_policy <
(int)(sizeof(default_policy)/sizeof(struct policy));
++policy) {
syscallTable[policy->syscallNum].handler = policy->handler;
syscallTable[policy->syscallNum].trustedProcess = policy->trustedProcess;
}
protectSyscallTable();
}
size_t SyscallTable::getSyscallTableSize() {
return ((sizeof(struct SyscallTable) * (maxSyscall + 1)) + 4095) & ~4095;
}
void SyscallTable::protectSyscallTable() {
if (mprotect(syscallTable, getSyscallTableSize(), PROT_READ) != 0) {
Sandbox::die("Failed to protect system call table");
}
}
void SyscallTable::unprotectSyscallTable() {
if (mprotect(syscallTable, getSyscallTableSize(),
PROT_READ | PROT_WRITE) != 0) {
Sandbox::die("Failed to unprotect system call table");
}
}
} // namespace