PolicyBuilder: ignore duplicate calls to more complex helpers

PiperOrigin-RevId: 608318563
Change-Id: I3db1dd4e4a8d83a8069b68f1e84a1a8b7277bcdc
This commit is contained in:
Wiktor Garbacz 2024-02-19 06:13:03 -08:00 committed by Copybara-Service
parent 34f129dc51
commit 008b45c9b7
3 changed files with 135 additions and 39 deletions

View File

@ -221,6 +221,10 @@ PolicyBuilder& PolicyBuilder::AllowExit() {
} }
PolicyBuilder& PolicyBuilder::AllowScudoMalloc() { PolicyBuilder& PolicyBuilder::AllowScudoMalloc() {
if (allowed_complex_.scudo_malloc) {
return *this;
}
allowed_complex_.scudo_malloc = true;
AllowTime(); AllowTime();
AllowSyscalls({__NR_munmap, __NR_nanosleep}); AllowSyscalls({__NR_munmap, __NR_nanosleep});
AllowFutexOp(FUTEX_WAKE); AllowFutexOp(FUTEX_WAKE);
@ -259,6 +263,10 @@ PolicyBuilder& PolicyBuilder::AllowScudoMalloc() {
} }
PolicyBuilder& PolicyBuilder::AllowTcMalloc() { PolicyBuilder& PolicyBuilder::AllowTcMalloc() {
if (allowed_complex_.tcmalloc) {
return *this;
}
allowed_complex_.tcmalloc = true;
AllowTime(); AllowTime();
AllowRestartableSequences(kRequireFastFences); AllowRestartableSequences(kRequireFastFences);
AllowSyscalls( AllowSyscalls(
@ -298,6 +306,10 @@ PolicyBuilder& PolicyBuilder::AllowTcMalloc() {
} }
PolicyBuilder& PolicyBuilder::AllowSystemMalloc() { PolicyBuilder& PolicyBuilder::AllowSystemMalloc() {
if (allowed_complex_.system_malloc) {
return *this;
}
allowed_complex_.system_malloc = true;
AllowSyscalls({__NR_munmap, __NR_brk}); AllowSyscalls({__NR_munmap, __NR_brk});
AllowFutexOp(FUTEX_WAKE); AllowFutexOp(FUTEX_WAKE);
AddPolicyOnSyscall(__NR_mremap, { AddPolicyOnSyscall(__NR_mremap, {
@ -330,6 +342,10 @@ PolicyBuilder& PolicyBuilder::AllowLlvmSanitizers() {
if constexpr (!sapi::sanitizers::IsAny()) { if constexpr (!sapi::sanitizers::IsAny()) {
return *this; return *this;
} }
if (allowed_complex_.llvm_sanitizers) {
return *this;
}
allowed_complex_.llvm_sanitizers = true;
// *san use a custom allocator that runs mmap/unmap under the hood. For // *san use a custom allocator that runs mmap/unmap under the hood. For
// example: // example:
// https://github.com/llvm/llvm-project/blob/596d534ac3524052df210be8d3c01a33b2260a42/compiler-rt/lib/asan/asan_allocator.cpp#L980 // https://github.com/llvm/llvm-project/blob/596d534ac3524052df210be8d3c01a33b2260a42/compiler-rt/lib/asan/asan_allocator.cpp#L980
@ -383,6 +399,10 @@ PolicyBuilder& PolicyBuilder::AllowLlvmCoverage() {
if (!sapi::IsCoverageRun()) { if (!sapi::IsCoverageRun()) {
return *this; return *this;
} }
if (allowed_complex_.llvm_coverage) {
return *this;
}
allowed_complex_.llvm_coverage = true;
AllowStat(); AllowStat();
AllowGetPIDs(); AllowGetPIDs();
AllowOpen(); AllowOpen();
@ -411,6 +431,10 @@ PolicyBuilder& PolicyBuilder::AllowLlvmCoverage() {
} }
PolicyBuilder& PolicyBuilder::AllowLimitedMadvise() { PolicyBuilder& PolicyBuilder::AllowLimitedMadvise() {
if (allowed_complex_.limited_madvise) {
return *this;
}
allowed_complex_.limited_madvise = true;
return AddPolicyOnSyscall(__NR_madvise, { return AddPolicyOnSyscall(__NR_madvise, {
ARG_32(2), ARG_32(2),
JEQ32(MADV_DONTNEED, ALLOW), JEQ32(MADV_DONTNEED, ALLOW),
@ -421,6 +445,10 @@ PolicyBuilder& PolicyBuilder::AllowLimitedMadvise() {
} }
PolicyBuilder& PolicyBuilder::AllowMmapWithoutExec() { PolicyBuilder& PolicyBuilder::AllowMmapWithoutExec() {
if (allowed_complex_.mmap_without_exec) {
return *this;
}
allowed_complex_.mmap_without_exec = true;
return AddPolicyOnMmap({ return AddPolicyOnMmap({
ARG_32(2), ARG_32(2),
BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, PROT_EXEC, 1, 0), BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, PROT_EXEC, 1, 0),
@ -639,6 +667,10 @@ PolicyBuilder& PolicyBuilder::AllowUtime() {
} }
PolicyBuilder& PolicyBuilder::AllowSafeFcntl() { PolicyBuilder& PolicyBuilder::AllowSafeFcntl() {
if (allowed_complex_.safe_fcntl) {
return *this;
}
allowed_complex_.safe_fcntl = true;
return AddPolicyOnSyscalls({__NR_fcntl, return AddPolicyOnSyscalls({__NR_fcntl,
#ifdef __NR_fcntl64 #ifdef __NR_fcntl64
__NR_fcntl64 __NR_fcntl64
@ -709,6 +741,10 @@ PolicyBuilder& PolicyBuilder::AllowHandleSignals() {
} }
PolicyBuilder& PolicyBuilder::AllowTCGETS() { PolicyBuilder& PolicyBuilder::AllowTCGETS() {
if (allowed_complex_.tcgets) {
return *this;
}
allowed_complex_.tcgets = true;
return AddPolicyOnSyscall(__NR_ioctl, { return AddPolicyOnSyscall(__NR_ioctl, {
ARG_32(1), ARG_32(1),
JEQ32(TCGETS, ALLOW), JEQ32(TCGETS, ALLOW),
@ -752,43 +788,47 @@ PolicyBuilder& PolicyBuilder::AllowGetIDs() {
PolicyBuilder& PolicyBuilder::AllowRestartableSequences( PolicyBuilder& PolicyBuilder::AllowRestartableSequences(
CpuFenceMode cpu_fence_mode) { CpuFenceMode cpu_fence_mode) {
if (!allowed_complex_.slow_fences && !allowed_complex_.fast_fences) {
#ifdef __NR_rseq #ifdef __NR_rseq
AllowSyscall(__NR_rseq); AllowSyscall(__NR_rseq);
#endif #endif
AddPolicyOnMmap([](bpf_labels& labels) -> std::vector<sock_filter> { AddPolicyOnMmap([](bpf_labels& labels) -> std::vector<sock_filter> {
return { return {
ARG_32(2), // prot ARG_32(2), // prot
JNE32(PROT_READ | PROT_WRITE, JUMP(&labels, mmap_end)), JNE32(PROT_READ | PROT_WRITE, JUMP(&labels, mmap_end)),
ARG_32(3), // flags ARG_32(3), // flags
JNE32(MAP_PRIVATE | MAP_ANONYMOUS, JUMP(&labels, mmap_end)), JNE32(MAP_PRIVATE | MAP_ANONYMOUS, JUMP(&labels, mmap_end)),
ALLOW, ALLOW,
LABEL(&labels, mmap_end), LABEL(&labels, mmap_end),
}; };
}); });
AllowSyscall(__NR_getcpu); AllowSyscall(__NR_getcpu);
AllowSyscall(__NR_membarrier); AllowSyscall(__NR_membarrier);
AllowFutexOp(FUTEX_WAIT); AllowFutexOp(FUTEX_WAIT);
AllowFutexOp(FUTEX_WAKE); AllowFutexOp(FUTEX_WAKE);
AllowRead(); AllowRead();
AllowOpen(); AllowOpen();
AllowPoll(); AllowPoll();
AllowSyscall(__NR_close); AllowSyscall(__NR_close);
AddPolicyOnSyscall(__NR_rt_sigprocmask, { AddPolicyOnSyscall(__NR_rt_sigprocmask, {
ARG_32(0), ARG_32(0),
JEQ32(SIG_SETMASK, ALLOW), JEQ32(SIG_SETMASK, ALLOW),
}); });
AllowPrctlSetVma(); AllowPrctlSetVma();
if (cpu_fence_mode == kAllowSlowFences) {
AddFileIfNamespaced("/proc/cpuinfo");
AddFileIfNamespaced("/proc/stat");
AddDirectoryIfNamespaced("/sys/devices/system/cpu");
}
if (cpu_fence_mode == kAllowSlowFences && !allowed_complex_.slow_fences) {
AllowSyscall(__NR_sched_getaffinity); AllowSyscall(__NR_sched_getaffinity);
AllowSyscall(__NR_sched_setaffinity); AllowSyscall(__NR_sched_setaffinity);
}
AddFileIfNamespaced("/proc/cpuinfo");
AddFileIfNamespaced("/proc/stat");
AddDirectoryIfNamespaced("/sys/devices/system/cpu");
if (cpu_fence_mode == kAllowSlowFences) {
AddFileIfNamespaced("/proc/self/cpuset"); AddFileIfNamespaced("/proc/self/cpuset");
allowed_complex_.slow_fences = true;
} else if (cpu_fence_mode == kRequireFastFences) {
allowed_complex_.fast_fences = true;
} }
return *this; return *this;
} }
@ -811,6 +851,10 @@ PolicyBuilder& PolicyBuilder::AllowGetPGIDs() {
} }
PolicyBuilder& PolicyBuilder::AllowGetRlimit() { PolicyBuilder& PolicyBuilder::AllowGetRlimit() {
if (allowed_complex_.getrlimit) {
return *this;
}
allowed_complex_.getrlimit = true;
#ifdef __NR_prlimit64 #ifdef __NR_prlimit64
AddPolicyOnSyscall(__NR_prlimit64, {ARG(2), JEQ64(0, 0, ALLOW)}); AddPolicyOnSyscall(__NR_prlimit64, {ARG(2), JEQ64(0, 0, ALLOW)});
#endif #endif
@ -839,6 +883,10 @@ PolicyBuilder& PolicyBuilder::AllowSetRlimit() {
} }
PolicyBuilder& PolicyBuilder::AllowGetRandom() { PolicyBuilder& PolicyBuilder::AllowGetRandom() {
if (allowed_complex_.getrandom) {
return *this;
}
allowed_complex_.getrandom = true;
return AddPolicyOnSyscall(__NR_getrandom, { return AddPolicyOnSyscall(__NR_getrandom, {
ARG_32(2), ARG_32(2),
JEQ32(0, ALLOW), JEQ32(0, ALLOW),
@ -847,6 +895,10 @@ PolicyBuilder& PolicyBuilder::AllowGetRandom() {
} }
PolicyBuilder& PolicyBuilder::AllowWipeOnFork() { PolicyBuilder& PolicyBuilder::AllowWipeOnFork() {
if (allowed_complex_.wipe_on_fork) {
return *this;
}
allowed_complex_.wipe_on_fork = true;
// System headers may not be recent enough to include MADV_WIPEONFORK. // System headers may not be recent enough to include MADV_WIPEONFORK.
static constexpr uint32_t kMadv_WipeOnFork = 18; static constexpr uint32_t kMadv_WipeOnFork = 18;
// The -1 value is used by code to probe that the kernel returns -EINVAL for // The -1 value is used by code to probe that the kernel returns -EINVAL for
@ -861,6 +913,10 @@ PolicyBuilder& PolicyBuilder::AllowWipeOnFork() {
} }
PolicyBuilder& PolicyBuilder::AllowLogForwarding() { PolicyBuilder& PolicyBuilder::AllowLogForwarding() {
if (allowed_complex_.log_forwarding) {
return *this;
}
allowed_complex_.log_forwarding = true;
AllowWrite(); AllowWrite();
AllowSystemMalloc(); AllowSystemMalloc();
AllowTcMalloc(); AllowTcMalloc();
@ -939,11 +995,19 @@ PolicyBuilder& PolicyBuilder::AllowEventFd() {
} }
PolicyBuilder& PolicyBuilder::AllowPrctlSetName() { PolicyBuilder& PolicyBuilder::AllowPrctlSetName() {
if (allowed_complex_.prctl_set_name) {
return *this;
}
allowed_complex_.prctl_set_name = true;
AddPolicyOnSyscall(__NR_prctl, {ARG_32(0), JEQ32(PR_SET_NAME, ALLOW)}); AddPolicyOnSyscall(__NR_prctl, {ARG_32(0), JEQ32(PR_SET_NAME, ALLOW)});
return *this; return *this;
} }
PolicyBuilder& PolicyBuilder::AllowPrctlSetVma() { PolicyBuilder& PolicyBuilder::AllowPrctlSetVma() {
if (allowed_complex_.prctl_set_vma) {
return *this;
}
allowed_complex_.prctl_set_vma = true;
AddPolicyOnSyscall(__NR_prctl, AddPolicyOnSyscall(__NR_prctl,
[](bpf_labels& labels) -> std::vector<sock_filter> { [](bpf_labels& labels) -> std::vector<sock_filter> {
return { return {
@ -969,19 +1033,25 @@ PolicyBuilder& PolicyBuilder::AllowFutexOp(int op) {
} }
PolicyBuilder& PolicyBuilder::AllowStaticStartup() { PolicyBuilder& PolicyBuilder::AllowStaticStartup() {
if (allowed_complex_.static_startup) {
return *this;
}
allowed_complex_.static_startup = true;
AllowGetRlimit(); AllowGetRlimit();
AllowSyscalls({ AllowSyscalls({
// These syscalls take a pointer, so no restriction. // These syscalls take a pointer, so no restriction.
__NR_uname, __NR_brk, __NR_set_tid_address, __NR_uname,
__NR_brk,
__NR_set_tid_address,
#if defined(__ARM_NR_set_tls) #if defined(__ARM_NR_set_tls)
// libc sets the TLS during startup // libc sets the TLS during startup
__ARM_NR_set_tls, __ARM_NR_set_tls,
#endif #endif
// This syscall takes a pointer and a length. // This syscall takes a pointer and a length.
// We could restrict length, but it might change, so not worth it. // We could restrict length, but it might change, so not worth it.
__NR_set_robust_list, __NR_set_robust_list,
}); });
AllowFutexOp(FUTEX_WAIT_BITSET); AllowFutexOp(FUTEX_WAIT_BITSET);
@ -1023,6 +1093,10 @@ PolicyBuilder& PolicyBuilder::AllowStaticStartup() {
} }
PolicyBuilder& PolicyBuilder::AllowDynamicStartup() { PolicyBuilder& PolicyBuilder::AllowDynamicStartup() {
if (allowed_complex_.dynamic_startup) {
return *this;
}
allowed_complex_.dynamic_startup = true;
#ifdef __ANDROID__ #ifdef __ANDROID__
AllowSafeFcntl(); AllowSafeFcntl();
AllowGetIDs(); AllowGetIDs();

View File

@ -812,6 +812,28 @@ class PolicyBuilder final {
absl::Status last_status_; absl::Status last_status_;
bool already_built_ = false; bool already_built_ = false;
struct {
bool static_startup = false;
bool dynamic_startup = false;
bool system_malloc = false;
bool scudo_malloc = false;
bool tcmalloc = false;
bool llvm_sanitizers = false;
bool llvm_coverage = false;
bool limited_madvise = false;
bool mmap_without_exec = false;
bool safe_fcntl = false;
bool tcgets = false;
bool slow_fences = false;
bool fast_fences = false;
bool getrlimit = false;
bool getrandom = false;
bool wipe_on_fork = false;
bool log_forwarding = false;
bool prctl_set_name = false;
bool prctl_set_vma = false;
} allowed_complex_;
// Contains list of allowed hosts. // Contains list of allowed hosts.
absl::optional<AllowedHosts> allowed_hosts_; absl::optional<AllowedHosts> allowed_hosts_;
}; };

View File

@ -89,8 +89,8 @@ TEST(PolicyBuilderTest, Testpolicy_size) {
assert_increased(); assert_increased();
builder.AllowTCGETS(); assert_increased(); builder.AllowTCGETS(); assert_increased();
builder.AllowTCGETS(); assert_increased(); builder.AllowTCGETS(); assert_same();
builder.AllowTCGETS(); assert_increased(); builder.AllowTCGETS(); assert_same();
builder.AddPolicyOnSyscall(__NR_fchmod, { ALLOW }); assert_increased(); builder.AddPolicyOnSyscall(__NR_fchmod, { ALLOW }); assert_increased();
builder.AddPolicyOnSyscall(__NR_fchmod, { ALLOW }); assert_increased(); builder.AddPolicyOnSyscall(__NR_fchmod, { ALLOW }); assert_increased();