summaryrefslogtreecommitdiffstats
path: root/sandbox/linux/seccomp/ipc.cc
diff options
context:
space:
mode:
authornsylvain@chromium.org <nsylvain@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-31 01:16:35 +0000
committernsylvain@chromium.org <nsylvain@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-31 01:16:35 +0000
commitfb7b5328a5fd3aecfc27f765dea94b961c657597 (patch)
tree84adc617db0031a881265e95f9c569de66fa733d /sandbox/linux/seccomp/ipc.cc
parent7302ea910ce937d482780649d6a84bbfff4ac521 (diff)
downloadchromium_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.cc351
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