Add more convenience functions to PolicyBuilder

- Allow to specify multiple syscalls with `BlockSyscallsWithErrno()`
- Add functions to allow `unlink()` and `rename()` in all their spellings

PiperOrigin-RevId: 414987303
Change-Id: Ic0e680b785e8e3a3498f20e6a7403737e63fe876
This commit is contained in:
Christian Blichmann 2021-12-08 06:40:48 -08:00 committed by Copybara-Service
parent 46c09e0024
commit 354cbe89f9
7 changed files with 134 additions and 54 deletions

View File

@ -70,33 +70,37 @@ std::unique_ptr<Policy> BufferTestcasePolicy() {
.AllowExit()
.AllowSafeFcntl()
.AllowTime()
.AllowSyscall(__NR_dup)
.AllowSyscall(__NR_futex)
.AllowSyscall(__NR_getpid)
.AllowSyscall(__NR_gettid)
.AllowSystemMalloc()
.AllowRead()
.AllowWrite()
.AllowSyscall(__NR_nanosleep)
.AllowSyscall(__NR_rt_sigprocmask)
.AllowSyscall(__NR_recvmsg)
.AllowMmap()
.AllowStat()
.AllowSyscall(__NR_lseek)
.AllowSyscall(__NR_close)
.BlockSyscallWithErrno(__NR_prlimit64, EPERM)
.AllowSyscalls({
__NR_dup,
__NR_futex,
__NR_getpid,
__NR_gettid,
__NR_nanosleep,
__NR_rt_sigprocmask,
__NR_recvmsg,
__NR_lseek,
__NR_close,
})
.BlockSyscallsWithErrno(
{
#ifdef __NR_open
.BlockSyscallWithErrno(__NR_open, ENOENT)
__NR_open,
#endif
.BlockSyscallWithErrno(__NR_openat, ENOENT)
__NR_openat,
#ifdef __NR_access
// On Debian, even static binaries check existence of
// /etc/ld.so.nohwcap.
.BlockSyscallWithErrno(__NR_access, ENOENT)
#endif
#ifdef __NR_faccessat
.BlockSyscallWithErrno(__NR_faccessat, ENOENT)
// On Debian, even static binaries check existence of
// /etc/ld.so.nohwcap.
__NR_access,
#endif
__NR_faccessat,
},
ENOENT)
.BlockSyscallWithErrno(__NR_prlimit64, EPERM)
.BuildOrDie();
return s2p;

View File

@ -53,11 +53,6 @@ std::unique_ptr<sandbox2::Policy> GetPolicy() {
// Allow the getpid() syscall.
.AllowSyscall(__NR_getpid)
#ifdef __NR_access
// On Debian, even static binaries check existence of /etc/ld.so.nohwcap.
.BlockSyscallWithErrno(__NR_access, ENOENT)
#endif
// Examples for AddPolicyOnSyscall:
.AddPolicyOnSyscall(__NR_write,
{
@ -89,23 +84,34 @@ std::unique_ptr<sandbox2::Policy> GetPolicy() {
// override this rule.
.AddPolicyOnSyscall(
__NR_exit_group,
{// Load first argument (exit_code).
ARG_32(0),
// Deny every argument except 0.
JNE32(0, KILL),
// Allow all exit() calls that were not previously forbidden
// = exit_code == 0.
ALLOW})
{
// Load first argument (exit_code).
ARG_32(0),
// Deny every argument except 0.
JNE32(0, KILL),
// Allow all exit() calls that were not previously forbidden
// = exit_code == 0.
ALLOW,
})
// = This won't have any effect as we handled every case of this syscall
// in the previous rule.
.AllowSyscall(__NR_exit_group)
#ifdef __NR_open
.BlockSyscallWithErrno(__NR_open, ENOENT)
#else
.BlockSyscallWithErrno(__NR_openat, ENOENT)
.BlockSyscallsWithErrno(
{
#ifdef __NR_access
// On Debian, even static binaries check existence of
// /etc/ld.so.nohwcap.
__NR_access,
#endif
#ifdef __NR_open
__NR_open,
#endif
__NR_openat,
},
ENOENT)
.BuildOrDie();
}

View File

@ -58,12 +58,14 @@ std::unique_ptr<sandbox2::Policy> GetPolicy() {
.AllowStaticStartup()
.AllowSystemMalloc()
.AllowExit()
.BlockSyscallsWithErrno(
{
#ifdef __NR_access
.BlockSyscallWithErrno(__NR_access, ENOENT)
#endif
#ifdef __NR_faccessat
.BlockSyscallWithErrno(__NR_faccessat, ENOENT)
__NR_access,
#endif
__NR_faccessat,
},
ENOENT)
.BuildOrDie();
}

View File

@ -51,13 +51,17 @@ std::unique_ptr<Policy> NotifyTestcasePolicy() {
.AllowWrite()
.AllowSyscall(__NR_close)
.AddPolicyOnSyscall(__NR_personality, {SANDBOX2_TRACE})
.BlockSyscallsWithErrno(
{
#ifdef __NR_open
.BlockSyscallWithErrno(__NR_open, ENOENT)
__NR_open,
#endif
__NR_openat,
#ifdef __NR_access
.BlockSyscallWithErrno(__NR_access, ENOENT)
__NR_access,
#endif
.BlockSyscallWithErrno(__NR_openat, ENOENT)
},
ENOENT)
.BlockSyscallWithErrno(__NR_prlimit64, EPERM)
.BuildOrDie();
}

View File

@ -51,16 +51,20 @@ PolicyBuilder CreatePolicyTestPolicyBuilder() {
.AllowSyscall(__NR_close)
.AllowSyscall(__NR_getppid)
.AllowTCGETS()
.BlockSyscallsWithErrno(
{
#ifdef __NR_open
.BlockSyscallWithErrno(__NR_open, ENOENT)
__NR_open,
#endif
.BlockSyscallWithErrno(__NR_openat, ENOENT)
__NR_openat,
#ifdef __NR_access
.BlockSyscallWithErrno(__NR_access, ENOENT)
__NR_access,
#endif
#ifdef __NR_faccessat
.BlockSyscallWithErrno(__NR_faccessat, ENOENT)
__NR_faccessat,
#endif
},
ENOENT)
.BlockSyscallWithErrno(__NR_prlimit64, EPERM);
}
@ -282,10 +286,6 @@ TEST(MultipleSyscalls, AddPolicyOnSyscallsWorks) {
auto executor = absl::make_unique<Executor>(path, args);
auto policy = PolicyBuilder()
#ifdef __NR_open
.BlockSyscallWithErrno(__NR_open, ENOENT)
#endif
.BlockSyscallWithErrno(__NR_openat, ENOENT)
.AllowStaticStartup()
.AllowTcMalloc()
.AllowExit()
@ -323,10 +323,18 @@ TEST(MultipleSyscalls, AddPolicyOnSyscallsWorks) {
{ERRNO(42)})
.AddPolicyOnSyscalls({__NR_read, __NR_write}, {ERRNO(43)})
.AddPolicyOnSyscall(__NR_umask, {DENY})
.BlockSyscallWithErrno(__NR_prlimit64, EPERM)
#ifdef __NR_access
.BlockSyscallWithErrno(__NR_access, ENOENT)
.BlockSyscallsWithErrno(
{
#ifdef __NR_open
__NR_open,
#endif
__NR_openat,
#ifdef __NR_access
__NR_access,
#endif
},
ENOENT)
.BlockSyscallWithErrno(__NR_prlimit64, EPERM)
.BuildOrDie();
Sandbox2 s2(std::move(executor), std::move(policy));

View File

@ -93,6 +93,22 @@ PolicyBuilder& PolicyBuilder::AllowSyscalls(SyscallInitializer nums) {
return *this;
}
PolicyBuilder& PolicyBuilder::BlockSyscallsWithErrno(
const std::vector<uint32_t> nums, int error) {
for (auto num : nums) {
AllowSyscall(num);
}
return *this;
}
PolicyBuilder& PolicyBuilder::BlockSyscallsWithErrno(SyscallInitializer nums,
int error) {
for (auto num : nums) {
AllowSyscall(num);
}
return *this;
}
PolicyBuilder& PolicyBuilder::BlockSyscallWithErrno(unsigned int num,
int error) {
if (handled_syscalls_.insert(num).second) {
@ -574,6 +590,29 @@ PolicyBuilder& PolicyBuilder::AllowLogForwarding() {
});
}
PolicyBuilder& PolicyBuilder::AllowUnlink() {
AllowSyscalls({
#ifdef __NR_unlink
__NR_unlink,
#endif
__NR_unlinkat,
});
return *this;
}
PolicyBuilder& PolicyBuilder::AllowRename() {
AllowSyscalls({
#ifdef __NR_rename
__NR_rename,
#endif
__NR_renameat,
#ifdef __NR_renameat2
__NR_renameat2,
#endif
});
return *this;
}
PolicyBuilder& PolicyBuilder::AllowFutexOp(int op) {
return AddPolicyOnSyscall(
__NR_futex, {

View File

@ -114,8 +114,12 @@ class PolicyBuilder final {
PolicyBuilder& AllowSyscalls(const std::vector<uint32_t>& nums);
PolicyBuilder& AllowSyscalls(SyscallInitializer nums);
// Appends code to block a specific syscall while setting errno to the error
// given
// Appends code to block a syscalls while setting errno to the error given.
PolicyBuilder& BlockSyscallsWithErrno(const std::vector<uint32_t> nums,
int error);
PolicyBuilder& BlockSyscallsWithErrno(SyscallInitializer nums, int error);
// Appends code to block a specific syscall and setting errno.
PolicyBuilder& BlockSyscallWithErrno(unsigned int num, int error);
// Appends code to allow exiting.
@ -354,6 +358,19 @@ class PolicyBuilder final {
// - close
PolicyBuilder& AllowLogForwarding();
// Appends code to allow deleting files
// Allows these syscalls:
// - unlink (if available)
// - unlinkat
PolicyBuilder& AllowUnlink();
// Appends code to allow renaming files
// Allows these syscalls:
// - rename (if available)
// - renameat
// - renameat2
PolicyBuilder& AllowRename();
// Enables the syscalls necessary to start a statically linked binary
//
// NOTE: This will call BlockSyscallWithErrno(__NR_readlink, ENOENT). If you