blob: d106fe561f304765a5fc65707850a59ed28cd785 [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 "debug.h"
#include "sandbox_impl.h"
namespace playground {
#if defined(__NR_sigaction)
long Sandbox::sandbox_sigaction(int signum, const void* a_, void* oa_) {
const SysCalls::kernel_old_sigaction* action =
reinterpret_cast<const SysCalls::kernel_old_sigaction*>(a_);
SysCalls::kernel_old_sigaction* old_action =
reinterpret_cast<SysCalls::kernel_old_sigaction*>(oa_);
long rc = 0;
long long tm;
Debug::syscall(&tm, __NR_sigaction, "Executing handler");
if (signum == SIGSEGV) {
if (old_action) {
old_action->sa_handler_ = sa_segv_.sa_handler_;
old_action->sa_mask = sa_segv_.sa_mask.sig[0];
old_action->sa_flags = sa_segv_.sa_flags;
old_action->sa_restorer = sa_segv_.sa_restorer;
}
if (action) {
sa_segv_.sa_handler_ = action->sa_handler_;
sa_segv_.sa_mask.sig[0] = action->sa_mask;
sa_segv_.sa_flags = action->sa_flags;
sa_segv_.sa_restorer = action->sa_restorer;
}
} else {
struct {
struct RequestHeader header;
SigAction sigaction_req;
} __attribute__((packed)) request;
request.sigaction_req.signum = signum;
request.sigaction_req.action =
reinterpret_cast<const SysCalls::kernel_sigaction *>(action);
request.sigaction_req.old_action =
reinterpret_cast<const SysCalls::kernel_sigaction *>(old_action);
request.sigaction_req.sigsetsize = 8;
rc = forwardSyscall(__NR_sigaction, &request.header, sizeof(request));
}
Debug::elapsed(tm, __NR_sigaction);
return rc;
}
#endif
#if defined(__NR_rt_sigaction)
#define min(a,b) ({ typeof(a) a_=(a); typeof(b) b_=(b); a_ < b_ ? a_ : b_; })
#define max(a,b) ({ typeof(a) a_=(a); typeof(b) b_=(b); a_ > b_ ? a_ : b_; })
long Sandbox::sandbox_rt_sigaction(int signum, const void* a_, void* oa_,
size_t sigsetsize) {
const SysCalls::kernel_sigaction* action =
reinterpret_cast<const SysCalls::kernel_sigaction*>(a_);
SysCalls::kernel_sigaction* old_action =
reinterpret_cast<SysCalls::kernel_sigaction*>(oa_);
long rc = 0;
long long tm;
Debug::syscall(&tm, __NR_rt_sigaction, "Executing handler");
if (signum == SIGSEGV) {
size_t theirSize = offsetof(SysCalls::kernel_sigaction, sa_mask) +
sigsetsize;
if (old_action) {
memcpy(old_action, &sa_segv_, min(sizeof(sa_segv_), theirSize));
memset(old_action + 1, 0, max(0u, theirSize - sizeof(sa_segv_)));
}
if (action) {
memcpy(&sa_segv_, action, min(sizeof(sa_segv_), theirSize));
memset(&sa_segv_.sa_mask, 0, max(0u, 8 - sigsetsize));
}
} else {
struct {
struct RequestHeader header;
SigAction sigaction_req;
} __attribute__((packed)) request;
request.sigaction_req.signum = signum;
request.sigaction_req.action = action;
request.sigaction_req.old_action = old_action;
request.sigaction_req.sigsetsize = sigsetsize;
rc = forwardSyscall(__NR_rt_sigaction, &request.header, sizeof(request));
}
Debug::elapsed(tm, __NR_rt_sigaction);
return rc;
}
#endif
#if defined(__NR_signal)
void* Sandbox::sandbox_signal(int signum, const void* handler) {
struct kernel_old_sigaction sa, osa;
sa.sa_handler_ = (void (*)(int))(handler);
sa.sa_flags = SA_NODEFER | SA_RESETHAND | SA_RESTORER;
sa.sa_mask = 0;
asm volatile(
"call 1f\n"
"0:pop %%eax\n"
"mov $119, %%eax\n" // __NR_sigreturn
"int $0x80\n"
"1:pop %0\n"
: "=r"(sa.sa_restorer));
long rc = sandbox_sigaction(signum, &sa, &osa);
if (rc < 0) {
return (void *)rc;
}
return reinterpret_cast<void *>(osa.sa_handler_);
}
#endif
bool Sandbox::process_sigaction(const SyscallRequestInfo* info) {
// We need to intercept sigaction() in order to properly rewrite calls to
// sigaction(SEGV). While there is no security implication if we didn't do
// so, it would end up preventing the program from running correctly as the
// the sandbox's SEGV handler could accidentally get removed. All of this is
// done in sandbox_{,rt_}sigaction(). But we still bounce through the
// trusted process as that is the only way we can instrument system calls.
// This is somewhat needlessly complicated. But as sigaction() is not a
// performance critical system call, it is easier to do this way than to
// extend the format of the syscall_table so that it could deal with this
// special case.
// Read request
SigAction sigaction_req;
SysCalls sys;
if (read(sys, info->trustedProcessFd, &sigaction_req,
sizeof(sigaction_req)) != sizeof(sigaction_req)) {
die("Failed to read parameters for sigaction() [process]");
}
if (sigaction_req.signum == SIGSEGV) {
// This should never happen. Something went wrong when intercepting the
// system call. This is not a security problem, but it clearly doesn't
// make sense to let the system call pass.
SecureMem::abandonSystemCall(*info, -EINVAL);
return false;
}
SecureMem::sendSystemCall(*info, SecureMem::SEND_UNLOCKED,
sigaction_req.signum,
const_cast<SysCalls::kernel_sigaction*>(sigaction_req.action),
const_cast<SysCalls::kernel_sigaction*>(sigaction_req.old_action),
sigaction_req.sigsetsize);
return true;
}
} // namespace