0

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:
mdempsky@chromium.org
2014-05-21 04:07:37 +00:00
parent 82d1028120
commit f53bd4a9a8
3 changed files with 68 additions and 3 deletions

@ -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) \