diff options
author | nsylvain@chromium.org <nsylvain@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-31 01:16:35 +0000 |
---|---|---|
committer | nsylvain@chromium.org <nsylvain@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-31 01:16:35 +0000 |
commit | fb7b5328a5fd3aecfc27f765dea94b961c657597 (patch) | |
tree | 84adc617db0031a881265e95f9c569de66fa733d /sandbox/linux/seccomp/ipc.cc | |
parent | 7302ea910ce937d482780649d6a84bbfff4ac521 (diff) | |
download | chromium_src-fb7b5328a5fd3aecfc27f765dea94b961c657597.zip chromium_src-fb7b5328a5fd3aecfc27f765dea94b961c657597.tar.gz chromium_src-fb7b5328a5fd3aecfc27f765dea94b961c657597.tar.bz2 |
Revert 57921 - Pull seccomp-sandbox in via DEPS rather than using an in-tree copy
This means changes to the sandbox won't have to be committed twice, to
both trees.
BUG=none
TEST=smoke test of running chromium with --enable-seccomp-sandbox
Review URL: http://codereview.chromium.org/3249003
TBR=mseaborn@chromium.org
Review URL: http://codereview.chromium.org/3245011
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@57933 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox/linux/seccomp/ipc.cc')
-rw-r--r-- | sandbox/linux/seccomp/ipc.cc | 351 |
1 files changed, 351 insertions, 0 deletions
diff --git a/sandbox/linux/seccomp/ipc.cc b/sandbox/linux/seccomp/ipc.cc new file mode 100644 index 0000000..67a4e34 --- /dev/null +++ b/sandbox/linux/seccomp/ipc.cc @@ -0,0 +1,351 @@ +// 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 "debug.h" +#include "sandbox_impl.h" + +namespace playground { + +#ifndef IPC_PRIVATE +#define IPC_PRIVATE 0 +#endif +#ifndef IPC_RMID +#define IPC_RMID 0 +#endif +#ifndef IPC_64 +#define IPC_64 256 +#endif + +#if defined(__NR_shmget) +void* Sandbox::sandbox_shmat(int shmid, const void* shmaddr, int shmflg) { + long long tm; + Debug::syscall(&tm, __NR_shmat, "Executing handler"); + + struct { + int sysnum; + long long cookie; + ShmAt shmat_req; + } __attribute__((packed)) request; + request.sysnum = __NR_shmat; + request.cookie = cookie(); + request.shmat_req.shmid = shmid; + request.shmat_req.shmaddr = shmaddr; + request.shmat_req.shmflg = shmflg; + + long rc; + SysCalls sys; + if (write(sys, processFdPub(), &request, sizeof(request)) != + sizeof(request) || + read(sys, threadFdPub(), &rc, sizeof(rc)) != sizeof(rc)) { + die("Failed to forward shmat() request [sandbox]"); + } + Debug::elapsed(tm, __NR_shmat); + return reinterpret_cast<void *>(rc); +} + +long Sandbox::sandbox_shmctl(int shmid, int cmd, void* buf) { + long long tm; + Debug::syscall(&tm, __NR_shmctl, "Executing handler"); + + struct { + int sysnum; + long long cookie; + ShmCtl shmctl_req; + } __attribute__((packed)) request; + request.sysnum = __NR_shmctl; + request.cookie = cookie(); + request.shmctl_req.shmid = shmid; + request.shmctl_req.cmd = cmd; + request.shmctl_req.buf = buf; + + long rc; + SysCalls sys; + if (write(sys, processFdPub(), &request, sizeof(request)) != + sizeof(request) || + read(sys, threadFdPub(), &rc, sizeof(rc)) != sizeof(rc)) { + die("Failed to forward shmctl() request [sandbox]"); + } + Debug::elapsed(tm, __NR_shmctl); + return rc; +} + +long Sandbox::sandbox_shmdt(const void* shmaddr) { + long long tm; + Debug::syscall(&tm, __NR_shmdt, "Executing handler"); + + struct { + int sysnum; + long long cookie; + ShmDt shmdt_req; + } __attribute__((packed)) request; + request.sysnum = __NR_shmdt; + request.cookie = cookie(); + request.shmdt_req.shmaddr = shmaddr; + + long rc; + SysCalls sys; + if (write(sys, processFdPub(), &request, sizeof(request)) != + sizeof(request) || + read(sys, threadFdPub(), &rc, sizeof(rc)) != sizeof(rc)) { + die("Failed to forward shmdt() request [sandbox]"); + } + Debug::elapsed(tm, __NR_shmdt); + return rc; +} + +long Sandbox::sandbox_shmget(int key, size_t size, int shmflg) { + long long tm; + Debug::syscall(&tm, __NR_shmget, "Executing handler"); + + struct { + int sysnum; + long long cookie; + ShmGet shmget_req; + } __attribute__((packed)) request; + request.sysnum = __NR_shmget; + request.cookie = cookie(); + request.shmget_req.key = key; + request.shmget_req.size = size; + request.shmget_req.shmflg = shmflg; + + long rc; + SysCalls sys; + if (write(sys, processFdPub(), &request, sizeof(request)) != + sizeof(request) || + read(sys, threadFdPub(), &rc, sizeof(rc)) != sizeof(rc)) { + die("Failed to forward shmget() request [sandbox]"); + } + Debug::elapsed(tm, __NR_shmget); + return rc; +} + +bool Sandbox::process_shmat(int parentMapsFd, int sandboxFd, int threadFdPub, + int threadFd, SecureMem::Args* mem) { + // Read request + ShmAt shmat_req; + SysCalls sys; + if (read(sys, sandboxFd, &shmat_req, sizeof(shmat_req)) != + sizeof(shmat_req)) { + die("Failed to read parameters for shmat() [process]"); + } + + // We only allow attaching to the shm identifier that was returned by + // the most recent call to shmget(IPC_PRIVATE) + if (shmat_req.shmaddr || shmat_req.shmflg || shmat_req.shmid != mem->shmId) { + mem->shmId = -1; + SecureMem::abandonSystemCall(threadFd, -EINVAL); + return false; + } + + mem->shmId = -1; + SecureMem::sendSystemCall(threadFdPub, false, -1, mem, + __NR_shmat, shmat_req.shmid, shmat_req.shmaddr, + shmat_req.shmflg); + return true; +} + +bool Sandbox::process_shmctl(int parentMapsFd, int sandboxFd, int threadFdPub, + int threadFd, SecureMem::Args* mem) { + // Read request + ShmCtl shmctl_req; + SysCalls sys; + if (read(sys, sandboxFd, &shmctl_req, sizeof(shmctl_req)) != + sizeof(shmctl_req)) { + die("Failed to read parameters for shmctl() [process]"); + } + + // The only shmctl() operation that we need to support is removal. This + // operation is generally safe. + if ((shmctl_req.cmd & ~(IPC_64 | IPC_RMID)) || shmctl_req.buf) { + mem->shmId = -1; + SecureMem::abandonSystemCall(threadFd, -EINVAL); + return false; + } + + mem->shmId = -1; + SecureMem::sendSystemCall(threadFdPub, false, -1, mem, + __NR_shmctl, shmctl_req.shmid, shmctl_req.cmd, + shmctl_req.buf); + return true; +} + +bool Sandbox::process_shmdt(int parentMapsFd, int sandboxFd, int threadFdPub, + int threadFd, SecureMem::Args* mem) { + // Read request + ShmDt shmdt_req; + SysCalls sys; + if (read(sys, sandboxFd, &shmdt_req, sizeof(shmdt_req)) != + sizeof(shmdt_req)) { + die("Failed to read parameters for shmdt() [process]"); + } + + // Detaching shared memory segments it generally safe, but just in case + // of a kernel bug, we make sure that the address does not fall into any + // of the reserved memory regions. + ProtectedMap::const_iterator iter = protectedMap_.lower_bound( + (void *)shmdt_req.shmaddr); + if (iter != protectedMap_.begin()) { + --iter; + } + for (; iter != protectedMap_.end() && iter->first <= shmdt_req.shmaddr; + ++iter){ + if (shmdt_req.shmaddr < reinterpret_cast<void *>( + reinterpret_cast<char *>(iter->first) + iter->second) && + shmdt_req.shmaddr >= iter->first) { + mem->shmId = -1; + SecureMem::abandonSystemCall(threadFd, -EINVAL); + return false; + } + } + + mem->shmId = -1; + SecureMem::sendSystemCall(threadFdPub, false, -1, mem, + __NR_shmdt, shmdt_req.shmaddr); + return true; +} + +bool Sandbox::process_shmget(int parentMapsFd, int sandboxFd, int threadFdPub, + int threadFd, SecureMem::Args* mem) { + // Read request + ShmGet shmget_req; + SysCalls sys; + if (read(sys, sandboxFd, &shmget_req, sizeof(shmget_req)) != + sizeof(shmget_req)) { + die("Failed to read parameters for shmget() [process]"); + } + + // We do not want to allow the sandboxed application to access arbitrary + // shared memory regions. We only allow it to access regions that it + // created itself. + if (shmget_req.key != IPC_PRIVATE || shmget_req.shmflg & ~0777) { + mem->shmId = -1; + SecureMem::abandonSystemCall(threadFd, -EINVAL); + return false; + } + + mem->shmId = -1; + SecureMem::sendSystemCall(threadFdPub, false, -1, mem, + __NR_shmget, shmget_req.key, shmget_req.size, + shmget_req.shmflg); + return true; +} +#endif + +#if defined(__NR_ipc) +#ifndef SHMAT +#define SHMAT 21 +#endif +#ifndef SHMDT +#define SHMDT 22 +#endif +#ifndef SHMGET +#define SHMGET 23 +#endif +#ifndef SHMCTL +#define SHMCTL 24 +#endif + +long Sandbox::sandbox_ipc(unsigned call, int first, int second, int third, + void* ptr, long fifth) { + long long tm; + Debug::syscall(&tm, __NR_ipc, "Executing handler", call); + struct { + int sysnum; + long long cookie; + IPC ipc_req; + } __attribute__((packed)) request; + request.sysnum = __NR_ipc; + request.cookie = cookie(); + request.ipc_req.call = call; + request.ipc_req.first = first; + request.ipc_req.second = second; + request.ipc_req.third = third; + request.ipc_req.ptr = ptr; + request.ipc_req.fifth = fifth; + + long rc; + SysCalls sys; + if (write(sys, processFdPub(), &request, sizeof(request)) != + sizeof(request) || + read(sys, threadFdPub(), &rc, sizeof(rc)) != sizeof(rc)) { + die("Failed to forward ipc() request [sandbox]"); + } + Debug::elapsed(tm, __NR_ipc, call); + return rc; +} + +bool Sandbox::process_ipc(int parentMapsFd, int sandboxFd, int threadFdPub, + int threadFd, SecureMem::Args* mem) { + // Read request + IPC ipc_req; + SysCalls sys; + if (read(sys, sandboxFd, &ipc_req, sizeof(ipc_req)) != sizeof(ipc_req)) { + die("Failed to read parameters for ipc() [process]"); + } + + // We do not support all of the SysV IPC calls. In fact, we only support + // the minimum feature set necessary for Chrome's renderers to share memory + // with the X server. + switch (ipc_req.call) { + case SHMAT: { + // We only allow attaching to the shm identifier that was returned by + // the most recent call to shmget(IPC_PRIVATE) + if (ipc_req.ptr || ipc_req.second || ipc_req.first != mem->shmId) { + goto deny; + } + accept: + mem->shmId = -1; + SecureMem::sendSystemCall(threadFdPub, false, -1, mem, + __NR_ipc, ipc_req.call, ipc_req.first, + ipc_req.second, ipc_req.third, ipc_req.ptr, + ipc_req.fifth); + return true; + } + case SHMCTL: + // The only shmctl() operation that we need to support is removal. This + // operation is generally safe. + if ((ipc_req.second & ~(IPC_64 | IPC_RMID)) || ipc_req.ptr) { + goto deny; + } else { + goto accept; + } + case SHMDT: { + // Detaching shared memory segments it generally safe, but just in case + // of a kernel bug, we make sure that the address does not fall into any + // of the reserved memory regions. + ProtectedMap::const_iterator iter = protectedMap_.lower_bound( + (void *)ipc_req.ptr); + if (iter != protectedMap_.begin()) { + --iter; + } + for (; iter != protectedMap_.end() && iter->first <=ipc_req.ptr; ++iter){ + if (ipc_req.ptr < reinterpret_cast<void *>( + reinterpret_cast<char *>(iter->first) + iter->second) && + ipc_req.ptr >= iter->first) { + goto deny; + } + } + goto accept; + } + case SHMGET: + // We do not want to allow the sandboxed application to access arbitrary + // shared memory regions. We only allow it to access regions that it + // created itself. + if (ipc_req.first != IPC_PRIVATE || ipc_req.third & ~0777) { + goto deny; + } else { + goto accept; + } + default: + // Other than SysV shared memory, we do not actually need to support any + // other SysV IPC calls. + deny: + mem->shmId = -1; + SecureMem::abandonSystemCall(threadFd, -EINVAL); + return false; + } +} +#endif + +} // namespace |