Non-SFI NaCl: Disallow fancy clock IDs
Restrict the admissible set of clock IDs to just CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID, CLOCK_REALTIME, and CLOCK_THREAD_CPUTIME_ID (i.e., the same clocks allowed in regular NaCl). In particular, we do not allow arbitrary per-process CPU clocks, which can leak information about the state of other non-SFI processes. BUG=374479 TBR=cpu@chromium.org Review URL: https://codereview.chromium.org/286363003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271859 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
components/nacl/loader/nonsfi
@ -4,4 +4,5 @@ include_rules = [
|
||||
"+native_client/src/shared/platform/nacl_log.h",
|
||||
"+native_client/src/trusted/service_runtime/nacl_exception.h",
|
||||
"+native_client/src/trusted/service_runtime/nacl_signal.h",
|
||||
"+third_party/lss/linux_syscall_support.h", # for BPF policy tests
|
||||
]
|
||||
|
@ -73,6 +73,28 @@ ErrorCode RestrictFcntlCommands(SandboxBPF* sb) {
|
||||
sb->Trap(sandbox::CrashSIGSYS_Handler, NULL))));
|
||||
}
|
||||
|
||||
ErrorCode RestrictClockID(SandboxBPF* sb) {
|
||||
// We allow accessing only CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID,
|
||||
// CLOCK_REALTIME, and CLOCK_THREAD_CPUTIME_ID. In particular, this disallows
|
||||
// access to arbitrary per-{process,thread} CPU-time clock IDs (such as those
|
||||
// returned by {clock,pthread}_getcpuclockid), which can leak information
|
||||
// about the state of the host OS.
|
||||
COMPILE_ASSERT(4 == sizeof(clockid_t), clockid_is_not_32bit);
|
||||
return sb->Cond(0, ErrorCode::TP_32BIT,
|
||||
ErrorCode::OP_EQUAL, CLOCK_MONOTONIC,
|
||||
ErrorCode(ErrorCode::ERR_ALLOWED),
|
||||
sb->Cond(0, ErrorCode::TP_32BIT,
|
||||
ErrorCode::OP_EQUAL, CLOCK_PROCESS_CPUTIME_ID,
|
||||
ErrorCode(ErrorCode::ERR_ALLOWED),
|
||||
sb->Cond(0, ErrorCode::TP_32BIT,
|
||||
ErrorCode::OP_EQUAL, CLOCK_REALTIME,
|
||||
ErrorCode(ErrorCode::ERR_ALLOWED),
|
||||
sb->Cond(0, ErrorCode::TP_32BIT,
|
||||
ErrorCode::OP_EQUAL, CLOCK_THREAD_CPUTIME_ID,
|
||||
ErrorCode(ErrorCode::ERR_ALLOWED),
|
||||
sb->Trap(sandbox::CrashSIGSYS_Handler, NULL)))));
|
||||
}
|
||||
|
||||
ErrorCode RestrictClone(SandboxBPF* sb) {
|
||||
// We allow clone only for new thread creation.
|
||||
return sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
|
||||
@ -212,9 +234,6 @@ ErrorCode NaClNonSfiBPFSandboxPolicy::EvaluateSyscall(SandboxBPF* sb,
|
||||
#elif defined(__x86_64__)
|
||||
case __NR_lseek:
|
||||
#endif
|
||||
// NaCl runtime exposes clock_gettime and clock_getres to untrusted code.
|
||||
case __NR_clock_getres:
|
||||
case __NR_clock_gettime:
|
||||
case __NR_close:
|
||||
case __NR_dup:
|
||||
case __NR_dup2:
|
||||
@ -252,6 +271,10 @@ ErrorCode NaClNonSfiBPFSandboxPolicy::EvaluateSyscall(SandboxBPF* sb,
|
||||
#endif
|
||||
return ErrorCode(ErrorCode::ERR_ALLOWED);
|
||||
|
||||
case __NR_clock_getres:
|
||||
case __NR_clock_gettime:
|
||||
return RestrictClockID(sb);
|
||||
|
||||
case __NR_clone:
|
||||
return RestrictClone(sb);
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "base/bind.h"
|
||||
@ -32,6 +33,7 @@
|
||||
#include "base/posix/eintr_wrapper.h"
|
||||
#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
|
||||
#include "sandbox/linux/seccomp-bpf/bpf_tests.h"
|
||||
#include "third_party/lss/linux_syscall_support.h" // for MAKE_PROCESS_CPUCLOCK
|
||||
|
||||
namespace {
|
||||
|
||||
@ -391,6 +393,45 @@ BPF_TEST_C(NaClNonSfiSandboxTest,
|
||||
BPF_ASSERT_EQ(ENOMEM, errno);
|
||||
}
|
||||
|
||||
void CheckClock(clockid_t clockid) {
|
||||
struct timespec ts;
|
||||
ts.tv_sec = ts.tv_nsec = -1;
|
||||
BPF_ASSERT_EQ(0, clock_gettime(clockid, &ts));
|
||||
BPF_ASSERT_LE(0, ts.tv_sec);
|
||||
BPF_ASSERT_LE(0, ts.tv_nsec);
|
||||
}
|
||||
|
||||
BPF_TEST_C(NaClNonSfiSandboxTest,
|
||||
clock_gettime_allowed,
|
||||
nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
|
||||
CheckClock(CLOCK_MONOTONIC);
|
||||
CheckClock(CLOCK_PROCESS_CPUTIME_ID);
|
||||
CheckClock(CLOCK_REALTIME);
|
||||
CheckClock(CLOCK_THREAD_CPUTIME_ID);
|
||||
}
|
||||
|
||||
BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
|
||||
clock_gettime_crash_monotonic_raw,
|
||||
DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
|
||||
nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
||||
}
|
||||
|
||||
BPF_DEATH_TEST_C(NaClNonSfiSandboxTest,
|
||||
clock_gettime_crash_cpu_clock,
|
||||
DEATH_MESSAGE(sandbox::GetErrorMessageContentForTests()),
|
||||
nacl::nonsfi::NaClNonSfiBPFSandboxPolicy) {
|
||||
// We can't use clock_getcpuclockid() because it's not implemented in newlib,
|
||||
// and it might not work inside the sandbox anyway.
|
||||
const pid_t kInitPID = 1;
|
||||
const clockid_t kInitCPUClockID =
|
||||
MAKE_PROCESS_CPUCLOCK(kInitPID, CPUCLOCK_SCHED);
|
||||
|
||||
struct timespec ts;
|
||||
clock_gettime(kInitCPUClockID, &ts);
|
||||
}
|
||||
|
||||
// The following test cases check if syscalls return EPERM regardless
|
||||
// of arguments.
|
||||
#define RESTRICT_SYSCALL_EPERM_TEST(name) \
|
||||
|
Reference in New Issue
Block a user