chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.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.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

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

#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <sched.h>
#include <signal.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>

#include <tuple>

#include "base/clang_profiling_buildflags.h"
#include "base/files/scoped_file.h"
#include "base/posix/eintr_wrapper.h"
#include "base/threading/thread.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.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/services/thread_helpers.h"
#include "sandbox/linux/system_headers/linux_futex.h"
#include "sandbox/linux/system_headers/linux_syscalls.h"
#include "sandbox/linux/system_headers/linux_time.h"
#include "sandbox/linux/tests/test_utils.h"
#include "sandbox/linux/tests/unit_tests.h"

#if !defined(SO_PEEK_OFF)
#define SO_PEEK_OFF
#endif

namespace sandbox {

namespace {

// This also tests that read(), write(), fstat(), and fstatat(.., "", ..,
// AT_EMPTY_PATH) are allowed.
void TestPipeOrSocketPair(base::ScopedFD read_end, base::ScopedFD write_end) {}

// Test that a few easy-to-test system calls are allowed.
BPF_TEST_C(BaselinePolicy, BaselinePolicyBasicAllowed, BaselinePolicy) {}

BPF_TEST_C(BaselinePolicy, FchmodErrno, BaselinePolicy) {}

BPF_TEST_C(BaselinePolicy, ForkErrno, BaselinePolicy) {}

pid_t ForkX86Glibc() {}

BPF_TEST_C(BaselinePolicy, ForkX86Eperm, BaselinePolicy) {}

pid_t ForkARMGlibc() {}

BPF_TEST_C(BaselinePolicy, ForkArmEperm, BaselinePolicy) {}

// system() calls into vfork() on old Android builds and returns when vfork is
// blocked. This causes undefined behavior on x86 Android builds on versions
// prior to Q, which causes the stack to get corrupted, so this test cannot be
// made to pass.
#if BUILDFLAG(IS_ANDROID) && defined(__i386__)
#define MAYBE_SystemEperm
#else
#define MAYBE_SystemEperm
#endif
BPF_TEST_C(BaselinePolicy, MAYBE_SystemEperm, BaselinePolicy) {}

BPF_TEST_C(BaselinePolicy, CloneVforkEperm, BaselinePolicy) {}

BPF_TEST_C(BaselinePolicy, CreateThread, BaselinePolicy) {}

// Rseq should be enabled if it exists (i.e. shouldn't receive EPERM).
#if !BUILDFLAG(IS_ANDROID)
BPF_TEST_C(BaselinePolicy, RseqEnabled, BaselinePolicy) {}
#endif  // !BUILDFLAG(IS_ANDROID)

BPF_DEATH_TEST_C(BaselinePolicy,
                 DisallowedCloneFlagCrashes,
                 DEATH_SEGV_MESSAGE(GetCloneErrorMessageContentForTests()),
                 BaselinePolicy) {}

BPF_DEATH_TEST_C(BaselinePolicy,
                 DisallowedKillCrashes,
                 DEATH_SEGV_MESSAGE(GetKillErrorMessageContentForTests()),
                 BaselinePolicy) {}

BPF_TEST_C(BaselinePolicy, CanKillSelf, BaselinePolicy) {}

BPF_TEST_C(BaselinePolicy, Socketpair, BaselinePolicy) {}

#if !defined(GRND_NONBLOCK)
#define GRND_NONBLOCK
#endif

#if !defined(GRND_INSECURE)
#define GRND_INSECURE
#endif

BPF_TEST_C(BaselinePolicy, GetRandom, BaselinePolicy) {}

// Not all architectures can restrict the domain for socketpair().
#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
BPF_DEATH_TEST_C(BaselinePolicy,
                 SocketpairWrongDomain,
                 DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
                 BaselinePolicy) {}
#endif  // defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)

BPF_TEST_C(BaselinePolicy, EPERM_open, BaselinePolicy) {}

BPF_TEST_C(BaselinePolicy, EPERM_access, BaselinePolicy) {}

BPF_TEST_C(BaselinePolicy, EPERM_getcwd, BaselinePolicy) {}

BPF_DEATH_TEST_C(BaselinePolicy,
                 SIGSYS_InvalidSyscall,
                 DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
                 BaselinePolicy) {}

// A failing test using this macro could be problematic since we perform
// system calls by passing "0" as every argument.
// The kernel could SIGSEGV the process or the system call itself could reboot
// the machine. Some thoughts have been given when hand-picking the system
// calls below to limit any potential side effects outside of the current
// process.
#define TEST_BASELINE_SIGSYS(sysno)

TEST_BASELINE_SIGSYS()
TEST_BASELINE_SIGSYS()
TEST_BASELINE_SIGSYS()
TEST_BASELINE_SIGSYS()
TEST_BASELINE_SIGSYS()
TEST_BASELINE_SIGSYS()
TEST_BASELINE_SIGSYS()
TEST_BASELINE_SIGSYS()
TEST_BASELINE_SIGSYS()
TEST_BASELINE_SIGSYS()
TEST_BASELINE_SIGSYS()
TEST_BASELINE_SIGSYS()
TEST_BASELINE_SIGSYS()
TEST_BASELINE_SIGSYS()
TEST_BASELINE_SIGSYS()
TEST_BASELINE_SIGSYS()
TEST_BASELINE_SIGSYS()

#if !defined(__aarch64__)
TEST_BASELINE_SIGSYS()
TEST_BASELINE_SIGSYS()
#endif

#if defined(LIBC_GLIBC) && !BUILDFLAG(IS_CHROMEOS_ASH)
BPF_TEST_C(BaselinePolicy, FutexEINVAL, BaselinePolicy) {}
#else
BPF_DEATH_TEST_C(BaselinePolicy,
                 FutexWithRequeuePriorityInheritence,
                 DEATH_SEGV_MESSAGE(GetFutexErrorMessageContentForTests()),
                 BaselinePolicy) {
  syscall(__NR_futex, nullptr, FUTEX_CMP_REQUEUE_PI, 0, nullptr, nullptr, 0);
  _exit(1);
}

BPF_DEATH_TEST_C(BaselinePolicy,
                 FutexWithRequeuePriorityInheritencePrivate,
                 DEATH_SEGV_MESSAGE(GetFutexErrorMessageContentForTests()),
                 BaselinePolicy) {
  syscall(__NR_futex, nullptr, FUTEX_CMP_REQUEUE_PI_PRIVATE, 0, nullptr,
          nullptr, 0);
  _exit(1);
}

BPF_DEATH_TEST_C(BaselinePolicy,
                 FutexWithUnlockPIPrivate,
                 DEATH_SEGV_MESSAGE(GetFutexErrorMessageContentForTests()),
                 BaselinePolicy) {
  syscall(__NR_futex, nullptr, FUTEX_UNLOCK_PI_PRIVATE, 0, nullptr, nullptr, 0);
  _exit(1);
}
#endif  // defined(LIBC_GLIBC) && !BUILDFLAG(IS_CHROMEOS_ASH)

BPF_TEST_C(BaselinePolicy, PrctlDumpable, BaselinePolicy) {}

// Workaround incomplete Android headers.
#if !defined(PR_CAPBSET_READ)
#define PR_CAPBSET_READ
#endif

#if !BUILDFLAG(CLANG_PROFILING_INSIDE_SANDBOX)
BPF_DEATH_TEST_C(BaselinePolicy,
                 PrctlSigsys,
                 DEATH_SEGV_MESSAGE(GetPrctlErrorMessageContentForTests()),
                 BaselinePolicy) {}
#endif

BPF_TEST_C(BaselinePolicy, GetOrSetPriority, BaselinePolicy) {}

BPF_DEATH_TEST_C(BaselinePolicy,
                 GetPrioritySigsys,
                 DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
                 BaselinePolicy) {}

BPF_DEATH_TEST_C(BaselinePolicy,
                 ClockGettimeWithDisallowedClockCrashes,
                 DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
                 BaselinePolicy) {}

BPF_DEATH_TEST_C(BaselinePolicy,
                 ClockNanosleepWithDisallowedClockCrashes,
                 DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
                 BaselinePolicy) {}

#if !defined(GRND_RANDOM)
#define GRND_RANDOM
#endif

BPF_DEATH_TEST_C(BaselinePolicy,
                 GetRandomOfDevRandomCrashes,
                 DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
                 BaselinePolicy) {}

#if !defined(__i386__)
BPF_DEATH_TEST_C(BaselinePolicy,
                 GetSockOptWrongLevelSigsys,
                 DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
                 BaselinePolicy) {}

BPF_DEATH_TEST_C(BaselinePolicy,
                 GetSockOptWrongOptionSigsys,
                 DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
                 BaselinePolicy) {}

BPF_DEATH_TEST_C(BaselinePolicy,
                 SetSockOptWrongLevelSigsys,
                 DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
                 BaselinePolicy) {}

BPF_DEATH_TEST_C(BaselinePolicy,
                 SetSockOptWrongOptionSigsys,
                 DEATH_SEGV_MESSAGE(GetErrorMessageContentForTests()),
                 BaselinePolicy) {}
#endif

}  // namespace

}  // namespace sandbox