Commit 7217c9c4 authored by Robert Sesek's avatar Robert Sesek Committed by Commit Bot

Add a new BPF helper syscall_broker::BrokerProcess::IsSyscallAllowed().

This helper can be used in bpf_dsl::Policy::EvaluateSyscall() to make it
easier to craft BPF policies that trap to the broker process.

Change-Id: I8588b0a934343d7d0009c0d07bf259a085451ece
Reviewed-on: https://chromium-review.googlesource.com/1175934
Commit-Queue: Robert Sesek <rsesek@chromium.org>
Reviewed-by: default avatarTom Sepez <tsepez@chromium.org>
Cr-Commit-Position: refs/heads/master@{#583407}
parent 53a1e1c5
......@@ -103,6 +103,99 @@ bool BrokerProcess::Init(
return false;
}
bool BrokerProcess::IsSyscallAllowed(int sysno) const {
switch (sysno) {
// In the event that there are no case statements defined, provide a
// "backstop" that returns false, so that one of the below return
// statements does not execute instead.
case 0:
return false;
#if defined(__NR_access)
case __NR_access:
#endif
#if defined(__NR_faccessat)
case __NR_faccessat:
#endif
return !fast_check_in_client_ ||
allowed_command_set_.test(COMMAND_ACCESS);
#if defined(__NR_mkdir)
case __NR_mkdir:
#endif
#if defined(__NR_mkdirat)
case __NR_mkdirat:
#endif
return !fast_check_in_client_ || allowed_command_set_.test(COMMAND_MKDIR);
#if defined(__NR_open)
case __NR_open:
#endif
#if defined(__NR_openat)
case __NR_openat:
#endif
return !fast_check_in_client_ || allowed_command_set_.test(COMMAND_OPEN);
#if defined(__NR_readlink)
case __NR_readlink:
#endif
#if defined(__NR_readlinkat)
case __NR_readlinkat:
#endif
return !fast_check_in_client_ ||
allowed_command_set_.test(COMMAND_READLINK);
#if defined(__NR_rename)
case __NR_rename:
#endif
#if defined(__NR_renameat)
case __NR_renameat:
#endif
return !fast_check_in_client_ ||
allowed_command_set_.test(COMMAND_RENAME);
#if defined(__NR_rmdir)
case __NR_rmdir:
#endif
return !fast_check_in_client_ || allowed_command_set_.test(COMMAND_RMDIR);
#if defined(__NR_stat)
case __NR_stat:
#endif
#if defined(__NR_lstat)
case __NR_lstat:
#endif
#if defined(__NR_fstatat)
case __NR_fstatat:
#endif
#if defined(__NR_newfstatat)
case __NR_newfstatat:
#endif
return !fast_check_in_client_ || allowed_command_set_.test(COMMAND_STAT);
#if defined(__NR_stat64)
case __NR_stat64:
#endif
#if defined(__NR_lstat64)
case __NR_lstat64:
#endif
return !fast_check_in_client_ ||
allowed_command_set_.test(COMMAND_STAT64);
#if defined(__NR_unlink)
case __NR_unlink:
#endif
#if defined(__NR_unlinkat)
case __NR_unlinkat:
#endif
return !fast_check_in_client_ ||
allowed_command_set_.test(COMMAND_UNLINK);
default:
return false;
}
}
void BrokerProcess::CloseChannel() {
broker_client_.reset();
}
......
......@@ -74,6 +74,14 @@ class SANDBOX_EXPORT BrokerProcess {
// Return the PID of the child created by Init().
int broker_pid() const { return broker_pid_; }
// Can be used in bpf_dsl::Policy::EvaluateSyscall() implementations to
// determine if the system call |sysno| should be trapped and forwarded
// to the broker process for handling. This examines the
// |allowed_command_set_| iff |fast_check_in_client_| is true. If
// the fast checks are disabled, then all possible brokerable system
// calls are forwarded to the broker process for handling.
bool IsSyscallAllowed(int sysno) const;
// The following methods are used in place of the equivalently-named
// syscalls by the trap handler. They, in turn, forward the call onto
// |broker_client_| for further processing. They will all be async signal
......
......@@ -27,6 +27,8 @@
#include "base/macros.h"
#include "base/posix/eintr_wrapper.h"
#include "base/posix/unix_domain_socket.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "sandbox/linux/syscall_broker/broker_client.h"
#include "sandbox/linux/tests/scoped_temporary_file.h"
......@@ -1452,5 +1454,99 @@ TEST(BrokerProcess, UnlinkHost) {
TestUnlinkHelper(false);
}
TEST(BrokerProcess, IsSyscallAllowed) {
const struct {
int sysno;
BrokerCommand command;
} kSyscallToCommandMap[] = {
#if defined(__NR_access)
{__NR_access, COMMAND_ACCESS},
#endif
#if defined(__NR_faccessat)
{__NR_faccessat, COMMAND_ACCESS},
#endif
#if defined(__NR_mkdir)
{__NR_mkdir, COMMAND_MKDIR},
#endif
#if defined(__NR_mkdirat)
{__NR_mkdirat, COMMAND_MKDIR},
#endif
#if defined(__NR_open)
{__NR_open, COMMAND_OPEN},
#endif
#if defined(__NR_openat)
{__NR_openat, COMMAND_OPEN},
#endif
#if defined(__NR_readlink)
{__NR_readlink, COMMAND_READLINK},
#endif
#if defined(__NR_readlinkat)
{__NR_readlinkat, COMMAND_READLINK},
#endif
#if defined(__NR_rename)
{__NR_rename, COMMAND_RENAME},
#endif
#if defined(__NR_renameat)
{__NR_renameat, COMMAND_RENAME},
#endif
#if defined(__NR_rmdir)
{__NR_rmdir, COMMAND_RMDIR},
#endif
#if defined(__NR_stat)
{__NR_stat, COMMAND_STAT},
#endif
#if defined(__NR_lstat)
{__NR_lstat, COMMAND_STAT},
#endif
#if defined(__NR_fstatat)
{__NR_fstatat, COMMAND_STAT},
#endif
#if defined(__NR_newfstatat)
{__NR_newfstatat, COMMAND_STAT},
#endif
#if defined(__NR_stat64)
{__NR_stat64, COMMAND_STAT64},
#endif
#if defined(__NR_lstat64)
{__NR_lstat64, COMMAND_STAT64},
#endif
#if defined(__NR_unlink)
{__NR_unlink, COMMAND_UNLINK},
#endif
#if defined(__NR_unlinkat)
{__NR_unlinkat, COMMAND_UNLINK},
#endif
};
EXPECT_GT(base::size(kSyscallToCommandMap), 0u);
for (const auto& test : kSyscallToCommandMap) {
// Test with fast_check_in_client.
{
SCOPED_TRACE(base::StringPrintf("fast check, sysno=%d", test.sysno));
BrokerProcess process(ENOSYS, MakeBrokerCommandSet({test.command}), {},
true, true);
EXPECT_TRUE(process.IsSyscallAllowed(test.sysno));
for (const auto& other : kSyscallToCommandMap) {
SCOPED_TRACE(base::StringPrintf("others test, sysno=%d", other.sysno));
EXPECT_EQ(other.command == test.command,
process.IsSyscallAllowed(other.sysno));
}
}
// Test without fast_check_in_client.
{
SCOPED_TRACE(base::StringPrintf("no fast check, sysno=%d", test.sysno));
BrokerProcess process(ENOSYS, MakeBrokerCommandSet({test.command}), {},
false, true);
EXPECT_TRUE(process.IsSyscallAllowed(test.sysno));
for (const auto& other : kSyscallToCommandMap) {
SCOPED_TRACE(base::StringPrintf("others test, sysno=%d", other.sysno));
EXPECT_TRUE(process.IsSyscallAllowed(other.sysno));
}
}
}
}
} // namespace syscall_broker
} // namespace sandbox
......@@ -55,29 +55,6 @@ ResultExpr GpuProcessPolicy::EvaluateSyscall(int sysno) const {
case __NR_prctl:
case __NR_sysinfo:
return Allow();
#if !defined(__aarch64__)
case __NR_access:
case __NR_open:
#endif // !defined(__aarch64__)
case __NR_faccessat:
case __NR_openat:
#if defined(__NR_stat)
case __NR_stat:
#endif
#if defined(__NR_stat64)
case __NR_stat64:
#endif
#if defined(__NR_fstatat)
case __NR_fstatat:
#endif
#if defined(__NR_newfstatat)
case __NR_newfstatat:
#endif
{
auto* broker_process = SandboxLinux::GetInstance()->broker_process();
DCHECK(broker_process);
return Trap(BrokerProcess::SIGSYS_Handler, broker_process);
}
case __NR_sched_getaffinity:
case __NR_sched_setaffinity:
return sandbox::RestrictSchedTarget(GetPolicyPid(), sysno);
......@@ -85,6 +62,11 @@ ResultExpr GpuProcessPolicy::EvaluateSyscall(int sysno) const {
if (SyscallSets::IsEventFd(sysno))
return Allow();
auto* broker_process = SandboxLinux::GetInstance()->broker_process();
if (broker_process->IsSyscallAllowed(sysno)) {
return Trap(BrokerProcess::SIGSYS_Handler, broker_process);
}
// Default on the baseline policy.
return BPFBasePolicy::EvaluateSyscall(sysno);
}
......
......@@ -33,70 +33,13 @@ NetworkProcessPolicy::NetworkProcessPolicy() {}
NetworkProcessPolicy::~NetworkProcessPolicy() {}
ResultExpr NetworkProcessPolicy::EvaluateSyscall(int sysno) const {
switch (sysno) {
#if defined(__NR_access)
case __NR_access:
#endif
#if defined(__NR_faccessat)
case __NR_faccessat:
#endif
#if defined(__NR_mkdir)
case __NR_mkdir:
#endif
#if defined(__NR_mkdirat)
case __NR_mkdirat:
#endif
#if defined(__NR_open)
case __NR_open:
#endif
#if defined(__NR_openat)
case __NR_openat:
#endif
#if defined(__NR_readlink)
case __NR_readlink:
#endif
#if defined(__NR_readlinkat)
case __NR_readlinkat:
#endif
#if defined(__NR_rmdir)
case __NR_rmdir:
#endif
#if defined(__NR_rename)
case __NR_rename:
#endif
#if defined(__NR_renameat)
case __NR_renameat:
#endif
#if defined(__NR_stat)
case __NR_stat:
#endif
#if defined(__NR_stat64)
case __NR_stat64:
#endif
#if defined(__NR_lstat)
case __NR_lstat:
#endif
#if defined(__NR_lstat64)
case __NR_lstat64:
#endif
#if defined(__NR_fstatat)
case __NR_fstatat:
#endif
#if defined(__NR_newfstatat)
case __NR_newfstatat:
#endif
#if defined(__NR_unlink)
case __NR_unlink:
#endif
#if defined(__NR_unlinkat)
case __NR_unlinkat:
#endif
return Trap(BrokerProcess::SIGSYS_Handler,
SandboxLinux::GetInstance()->broker_process());
default:
// TODO(tsepez): FIX this.
return Allow();
auto* broker_process = SandboxLinux::GetInstance()->broker_process();
if (broker_process->IsSyscallAllowed(sysno)) {
return Trap(BrokerProcess::SIGSYS_Handler, broker_process);
}
// TODO(tsepez): FIX this.
return Allow();
}
} // namespace service_manager
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment