Skip to content
This repository has been archived by the owner on Apr 3, 2020. It is now read-only.

Commit

Permalink
Linux sandbox: Allow restricting sched_* on other processes.
Browse files Browse the repository at this point in the history
Adds a RestrictSchedTarget parameter restriction which only allows
sched_* syscalls if the pid argument is the sandboxed process's pid or
if the pid is 0, which means the current thread.  glibc's pthread
implementation sometimes calls these syscalls with pid equal to the
current tid.  On these calls, the policy triggers a SIGSYS, and the
SIGSYS handler reruns the syscall with a pid argument of 0.

R=jln@chromium.org
BUG=413855

Review URL: https://codereview.chromium.org/590213003

Cr-Commit-Position: refs/heads/master@{#297059}
  • Loading branch information
rickyz authored and Commit bot committed Sep 26, 2014
1 parent b1f98f2 commit 282ba30
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 0 deletions.
42 changes: 42 additions & 0 deletions sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@

#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"

#include <sys/syscall.h>
#include <unistd.h>

#include "base/basictypes.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "build/build_config.h"
#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
#include "sandbox/linux/seccomp-bpf/syscall.h"
#include "sandbox/linux/services/linux_syscalls.h"

#if defined(__mips__)
// __NR_Linux, is defined in <asm/unistd.h>.
Expand Down Expand Up @@ -206,6 +210,40 @@ intptr_t SIGSYSFutexFailure(const struct arch_seccomp_data& args,
_exit(1);
}

intptr_t SIGSYSSchedHandler(const struct arch_seccomp_data& args,
void* aux) {
switch (args.nr) {
case __NR_sched_getaffinity:
case __NR_sched_getattr:
case __NR_sched_getparam:
case __NR_sched_getscheduler:
case __NR_sched_rr_get_interval:
case __NR_sched_setaffinity:
case __NR_sched_setattr:
case __NR_sched_setparam:
case __NR_sched_setscheduler:
const pid_t tid = syscall(__NR_gettid);
// The first argument is the pid. If is our thread id, then replace it
// with 0, which is equivalent and allowed by the policy.
if (args.args[0] == static_cast<uint64_t>(tid)) {
return Syscall::Call(args.nr,
0,
static_cast<intptr_t>(args.args[1]),
static_cast<intptr_t>(args.args[2]),
static_cast<intptr_t>(args.args[3]),
static_cast<intptr_t>(args.args[4]),
static_cast<intptr_t>(args.args[5]));
}
break;
}

CrashSIGSYS_Handler(args, aux);

// Should never be reached.
RAW_CHECK(false);
return -ENOSYS;
}

bpf_dsl::ResultExpr CrashSIGSYS() {
return bpf_dsl::Trap(CrashSIGSYS_Handler, NULL);
}
Expand All @@ -230,6 +268,10 @@ bpf_dsl::ResultExpr CrashSIGSYSFutex() {
return bpf_dsl::Trap(SIGSYSFutexFailure, NULL);
}

bpf_dsl::ResultExpr RewriteSchedSIGSYS() {
return bpf_dsl::Trap(SIGSYSSchedHandler, NULL);
}

const char* GetErrorMessageContentForTests() {
return SECCOMP_MESSAGE_COMMON_CONTENT;
}
Expand Down
11 changes: 11 additions & 0 deletions sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ SANDBOX_EXPORT intptr_t
// argument.
SANDBOX_EXPORT intptr_t
SIGSYSFutexFailure(const struct arch_seccomp_data& args, void* aux);
// If the syscall is not being called on the current tid, crashes in the same
// way as CrashSIGSYS_Handler. Otherwise, returns the result of calling the
// syscall with the pid argument set to 0 (which for these calls means the
// current thread). The following syscalls are supported:
//
// sched_getaffinity(), sched_getattr(), sched_getparam(), sched_getscheduler(),
// sched_rr_get_interval(), sched_setaffinity(), sched_setattr(),
// sched_setparam(), sched_setscheduler()
SANDBOX_EXPORT intptr_t
SIGSYSSchedHandler(const struct arch_seccomp_data& args, void* aux);

// Variants of the above functions for use with bpf_dsl.
SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYS();
Expand All @@ -55,6 +65,7 @@ SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSPrctl();
SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSIoctl();
SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSKill();
SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSFutex();
SANDBOX_EXPORT bpf_dsl::ResultExpr RewriteSchedSIGSYS();

// Following four functions return substrings of error messages used
// in the above four functions. They are useful in death tests.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
#include "sandbox/linux/seccomp-bpf/linux_seccomp.h"
#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
#include "sandbox/linux/services/linux_syscalls.h"

#if defined(OS_ANDROID)

Expand Down Expand Up @@ -263,4 +264,26 @@ ResultExpr RestrictClockID() {
Allow()).Else(CrashSIGSYS());
}

ResultExpr RestrictSchedTarget(pid_t target_pid, int sysno) {
switch (sysno) {
case __NR_sched_getaffinity:
case __NR_sched_getattr:
case __NR_sched_getparam:
case __NR_sched_getscheduler:
case __NR_sched_rr_get_interval:
case __NR_sched_setaffinity:
case __NR_sched_setattr:
case __NR_sched_setparam:
case __NR_sched_setscheduler: {
const Arg<pid_t> pid(0);
return If(pid == 0 || pid == target_pid, Allow())
.Else(RewriteSchedSIGSYS());
}
default:
NOTREACHED();
return CrashSIGSYS();
}
}


} // namespace sandbox.
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,17 @@ bpf_dsl::ResultExpr RestrictGetSetpriority(pid_t target_pid);
// On Chrome OS, base::TimeTicks::kClockSystemTrace is also allowed.
SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictClockID();

// Restricts |pid| for sched_* syscalls which take a pid as the first argument.
// We only allow calling these syscalls if the pid argument is equal to the pid
// of the sandboxed process or 0 (indicating the current thread). The following
// syscalls are supported:
//
// sched_getaffinity(), sched_getattr(), sched_getparam(), sched_getscheduler(),
// sched_rr_get_interval(), sched_setaffinity(), sched_setattr(),
// sched_setparam(), sched_setscheduler()
SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictSchedTarget(pid_t target_pid,
int sysno);

} // namespace sandbox.

#endif // SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SYSCALL_PARAMETERS_RESTRICTIONS_H_
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@

#include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"

#include <errno.h>
#include <sched.h>
#include <sys/syscall.h>
#include <time.h>
#include <unistd.h>

#include "base/bind.h"
#include "base/synchronization/waitable_event.h"
#include "base/sys_info.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
Expand Down Expand Up @@ -136,6 +143,72 @@ BPF_DEATH_TEST_C(ParameterRestrictions,
}
#endif // !defined(OS_ANDROID)

class RestrictSchedPolicy : public SandboxBPFDSLPolicy {
public:
RestrictSchedPolicy() {}
virtual ~RestrictSchedPolicy() {}

virtual ResultExpr EvaluateSyscall(int sysno) const OVERRIDE {
switch (sysno) {
case __NR_sched_getparam:
return RestrictSchedTarget(getpid(), sysno);
default:
return Allow();
}
}
};

void CheckSchedGetParam(pid_t pid, struct sched_param* param) {
BPF_ASSERT_EQ(0, sched_getparam(pid, param));
}

void SchedGetParamThread(base::WaitableEvent* thread_run) {
const pid_t pid = getpid();
const pid_t tid = syscall(__NR_gettid);
BPF_ASSERT_NE(pid, tid);

struct sched_param current_pid_param;
CheckSchedGetParam(pid, &current_pid_param);

struct sched_param zero_param;
CheckSchedGetParam(0, &zero_param);

struct sched_param tid_param;
CheckSchedGetParam(tid, &tid_param);

BPF_ASSERT_EQ(zero_param.sched_priority, tid_param.sched_priority);

// Verify that the SIGSYS handler sets errno properly.
errno = 0;
BPF_ASSERT_EQ(-1, sched_getparam(tid, NULL));
BPF_ASSERT_EQ(EINVAL, errno);

thread_run->Signal();
}

BPF_TEST_C(ParameterRestrictions,
sched_getparam_allowed,
RestrictSchedPolicy) {
base::WaitableEvent thread_run(true, false);
// Run the actual test in a new thread so that the current pid and tid are
// different.
base::Thread getparam_thread("sched_getparam_thread");
BPF_ASSERT(getparam_thread.Start());
getparam_thread.message_loop()->PostTask(
FROM_HERE, base::Bind(&SchedGetParamThread, &thread_run));
BPF_ASSERT(thread_run.TimedWait(base::TimeDelta::FromMilliseconds(5000)));
getparam_thread.Stop();
}

BPF_DEATH_TEST_C(ParameterRestrictions,
sched_getparam_crash_non_zero,
DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
RestrictSchedPolicy) {
const pid_t kInitPID = 1;
struct sched_param param;
sched_getparam(kInitPID, &param);
}

} // namespace

} // namespace sandbox

0 comments on commit 282ba30

Please sign in to comment.