chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

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

#include <errno.h>
#include <fcntl.h>
#include <linux/elf.h>
#include <sched.h>
#include <sys/prctl.h>
#include <sys/ptrace.h>
#include <sys/resource.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/user.h>
#include <time.h>
#include <unistd.h>

#include "base/functional/bind.h"
#include "base/posix/eintr_wrapper.h"
#include "base/synchronization/waitable_event.h"
#include "base/system/sys_info.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
#include "sandbox/linux/bpf_dsl/policy.h"
#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
#include "sandbox/linux/seccomp-bpf/bpf_tests.h"
#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
#include "sandbox/linux/seccomp-bpf/syscall.h"
#include "sandbox/linux/services/syscall_wrappers.h"
#include "sandbox/linux/system_headers/linux_ptrace.h"
#include "sandbox/linux/system_headers/linux_syscalls.h"
#include "sandbox/linux/system_headers/linux_time.h"
#include "sandbox/linux/tests/unit_tests.h"

namespace sandbox {

namespace {

// NOTE: most of the parameter restrictions are tested in
// baseline_policy_unittest.cc as a more end-to-end test.

Allow;
ResultExpr;

class RestrictClockIdPolicy : public bpf_dsl::Policy {};

void CheckClock(clockid_t clockid) {}

BPF_TEST_C(ParameterRestrictions,
           clock_gettime_allowed,
           RestrictClockIdPolicy) {

void CheckClockNanosleep(clockid_t clockid) {}

BPF_TEST_C(ParameterRestrictions,
           clock_nanosleep_allowed,
           RestrictClockIdPolicy) {

BPF_DEATH_TEST_C(ParameterRestrictions,
                 clock_gettime_crash_clock_fd,
                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
                 RestrictClockIdPolicy) {}

BPF_DEATH_TEST_C(ParameterRestrictions,
                 clock_nanosleep_crash_clock_fd,
                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
                 RestrictClockIdPolicy) {}

#if !BUILDFLAG(IS_ANDROID)
BPF_DEATH_TEST_C(ParameterRestrictions,
                 clock_gettime_crash_cpu_clock,
                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
                 RestrictClockIdPolicy) {}
#endif  // !BUILDFLAG(IS_ANDROID)

class RestrictSchedPolicy : public bpf_dsl::Policy {};

void CheckSchedGetParam(pid_t pid, struct sched_param* param) {}

void SchedGetParamThread(base::WaitableEvent* thread_run) {}

BPF_TEST_C(ParameterRestrictions,
           sched_getparam_allowed,
           RestrictSchedPolicy) {}

BPF_DEATH_TEST_C(ParameterRestrictions,
                 sched_getparam_crash_non_zero,
                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
                 RestrictSchedPolicy) {}

class RestrictPrlimit64Policy : public bpf_dsl::Policy {};

BPF_TEST_C(ParameterRestrictions, prlimit64_allowed, RestrictPrlimit64Policy) {

BPF_DEATH_TEST_C(ParameterRestrictions,
                 prlimit64_crash_not_self,
                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
                 RestrictPrlimit64Policy) {}

class RestrictGetrusagePolicy : public bpf_dsl::Policy {};

BPF_TEST_C(ParameterRestrictions, getrusage_allowed, RestrictGetrusagePolicy) {}

BPF_DEATH_TEST_C(ParameterRestrictions,
                 getrusage_crash_not_self,
                 DEATH_SEGV_MESSAGE(sandbox::GetErrorMessageContentForTests()),
                 RestrictGetrusagePolicy) {}

// The following ptrace() tests do not actually set up a tracer/tracee
// relationship, so allowed operations return ESRCH errors. Blocked operations
// are tested with death tests.

class RestrictPtracePolicy : public bpf_dsl::Policy {};

BPF_TEST_C(ParameterRestrictions,
           ptrace_getregs_allowed,
           RestrictPtracePolicy) {}

BPF_DEATH_TEST_C(
    ParameterRestrictions,
    ptrace_syscall_blocked,
    DEATH_SEGV_MESSAGE(sandbox::GetPtraceErrorMessageContentForTests()),
    RestrictPtracePolicy) {}

BPF_DEATH_TEST_C(
    ParameterRestrictions,
    ptrace_setregs_blocked,
    DEATH_SEGV_MESSAGE(sandbox::GetPtraceErrorMessageContentForTests()),
    RestrictPtracePolicy) {}

#if defined(__aarch64__)
BPF_DEATH_TEST_C(
    ParameterRestrictions,
    ptrace_getregs_nt_arm_paca_keys_blocked,
    DEATH_SEGV_MESSAGE(sandbox::GetPtraceErrorMessageContentForTests()),
    RestrictPtracePolicy) {
  user_regs_struct regs{};
  iovec iov;
  iov.iov_base = &regs;
  iov.iov_len = sizeof(regs);
  errno = 0;
  ptrace(PTRACE_GETREGSET, getpid(), reinterpret_cast<void*>(NT_ARM_PACA_KEYS),
         &iov);
}

BPF_DEATH_TEST_C(
    ParameterRestrictions,
    ptrace_getregs_nt_arm_pacg_keys_blocked,
    DEATH_SEGV_MESSAGE(sandbox::GetPtraceErrorMessageContentForTests()),
    RestrictPtracePolicy) {
  user_regs_struct regs{};
  iovec iov;
  iov.iov_base = &regs;
  iov.iov_len = sizeof(regs);
  errno = 0;
  ptrace(PTRACE_GETREGSET, getpid(), reinterpret_cast<void*>(NT_ARM_PACG_KEYS),
         &iov);
}
#endif

}  // namespace

}  // namespace sandbox