Commit 282ba301 authored by rickyz's avatar rickyz Committed by Commit bot

Linux sandbox: Allow restricting sched_* on other processes.

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}
parent b1f98f2b
...@@ -6,12 +6,16 @@ ...@@ -6,12 +6,16 @@
#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
#include <sys/syscall.h>
#include <unistd.h> #include <unistd.h>
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h" #include "base/posix/eintr_wrapper.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "sandbox/linux/seccomp-bpf/sandbox_bpf.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__) #if defined(__mips__)
// __NR_Linux, is defined in <asm/unistd.h>. // __NR_Linux, is defined in <asm/unistd.h>.
...@@ -206,6 +210,40 @@ intptr_t SIGSYSFutexFailure(const struct arch_seccomp_data& args, ...@@ -206,6 +210,40 @@ intptr_t SIGSYSFutexFailure(const struct arch_seccomp_data& args,
_exit(1); _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() { bpf_dsl::ResultExpr CrashSIGSYS() {
return bpf_dsl::Trap(CrashSIGSYS_Handler, NULL); return bpf_dsl::Trap(CrashSIGSYS_Handler, NULL);
} }
...@@ -230,6 +268,10 @@ bpf_dsl::ResultExpr CrashSIGSYSFutex() { ...@@ -230,6 +268,10 @@ bpf_dsl::ResultExpr CrashSIGSYSFutex() {
return bpf_dsl::Trap(SIGSYSFutexFailure, NULL); return bpf_dsl::Trap(SIGSYSFutexFailure, NULL);
} }
bpf_dsl::ResultExpr RewriteSchedSIGSYS() {
return bpf_dsl::Trap(SIGSYSSchedHandler, NULL);
}
const char* GetErrorMessageContentForTests() { const char* GetErrorMessageContentForTests() {
return SECCOMP_MESSAGE_COMMON_CONTENT; return SECCOMP_MESSAGE_COMMON_CONTENT;
} }
......
...@@ -47,6 +47,16 @@ SANDBOX_EXPORT intptr_t ...@@ -47,6 +47,16 @@ SANDBOX_EXPORT intptr_t
// argument. // argument.
SANDBOX_EXPORT intptr_t SANDBOX_EXPORT intptr_t
SIGSYSFutexFailure(const struct arch_seccomp_data& args, void* aux); 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. // Variants of the above functions for use with bpf_dsl.
SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYS(); SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYS();
...@@ -55,6 +65,7 @@ SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSPrctl(); ...@@ -55,6 +65,7 @@ SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSPrctl();
SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSIoctl(); SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSIoctl();
SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSKill(); SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSKill();
SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSFutex(); SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSFutex();
SANDBOX_EXPORT bpf_dsl::ResultExpr RewriteSchedSIGSYS();
// Following four functions return substrings of error messages used // Following four functions return substrings of error messages used
// in the above four functions. They are useful in death tests. // in the above four functions. They are useful in death tests.
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
#include "sandbox/linux/seccomp-bpf/linux_seccomp.h" #include "sandbox/linux/seccomp-bpf/linux_seccomp.h"
#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
#include "sandbox/linux/services/linux_syscalls.h"
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
...@@ -263,4 +264,26 @@ ResultExpr RestrictClockID() { ...@@ -263,4 +264,26 @@ ResultExpr RestrictClockID() {
Allow()).Else(CrashSIGSYS()); 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. } // namespace sandbox.
...@@ -75,6 +75,17 @@ bpf_dsl::ResultExpr RestrictGetSetpriority(pid_t target_pid); ...@@ -75,6 +75,17 @@ bpf_dsl::ResultExpr RestrictGetSetpriority(pid_t target_pid);
// On Chrome OS, base::TimeTicks::kClockSystemTrace is also allowed. // On Chrome OS, base::TimeTicks::kClockSystemTrace is also allowed.
SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictClockID(); 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. } // namespace sandbox.
#endif // SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SYSCALL_PARAMETERS_RESTRICTIONS_H_ #endif // SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SYSCALL_PARAMETERS_RESTRICTIONS_H_
...@@ -4,9 +4,16 @@ ...@@ -4,9 +4,16 @@
#include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h" #include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
#include <errno.h>
#include <sched.h>
#include <sys/syscall.h>
#include <time.h> #include <time.h>
#include <unistd.h>
#include "base/bind.h"
#include "base/synchronization/waitable_event.h"
#include "base/sys_info.h" #include "base/sys_info.h"
#include "base/threading/thread.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "sandbox/linux/bpf_dsl/bpf_dsl.h" #include "sandbox/linux/bpf_dsl/bpf_dsl.h"
...@@ -136,6 +143,72 @@ BPF_DEATH_TEST_C(ParameterRestrictions, ...@@ -136,6 +143,72 @@ BPF_DEATH_TEST_C(ParameterRestrictions,
} }
#endif // !defined(OS_ANDROID) #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
} // namespace sandbox } // namespace sandbox
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment