mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
64ed644f73
PiperOrigin-RevId: 613568060 Change-Id: Ic81d933b7d16a2dc2ec06d3c2fd127713e608602
847 lines
28 KiB
C++
847 lines
28 KiB
C++
// Copyright 2019 Google LLC
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#ifndef SANDBOXED_API_SANDBOX2_POLICYBUILDER_H_
|
|
#define SANDBOXED_API_SANDBOX2_POLICYBUILDER_H_
|
|
|
|
#include <linux/filter.h>
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "absl/base/attributes.h"
|
|
#include "absl/base/macros.h"
|
|
#include "absl/container/flat_hash_set.h"
|
|
#include "absl/log/check.h"
|
|
#include "absl/status/status.h"
|
|
#include "absl/status/statusor.h"
|
|
#include "absl/strings/string_view.h"
|
|
#include "absl/types/optional.h"
|
|
#include "absl/types/span.h"
|
|
#include "sandboxed_api/sandbox2/mounts.h"
|
|
#include "sandboxed_api/sandbox2/network_proxy/filtering.h"
|
|
#include "sandboxed_api/sandbox2/policy.h"
|
|
|
|
struct bpf_labels;
|
|
|
|
namespace sandbox2 {
|
|
|
|
class AllowAllSyscalls;
|
|
class TraceAllSyscalls;
|
|
class UnrestrictedNetworking;
|
|
class LoadUserBpfCodeFromFile;
|
|
|
|
// PolicyBuilder is a helper class to simplify creation of policies. The builder
|
|
// uses fluent interface for convenience and increased readability of policies.
|
|
//
|
|
// To build a policy you simply create a new builder object, call methods on it
|
|
// specifying what you want and finally call BuildOrDie() to generate you
|
|
// policy.
|
|
//
|
|
// For instance this would generate a simple policy suitable for binaries doing
|
|
// only computations:
|
|
//
|
|
// std::unique_ptr<Policy> policy =
|
|
// PolicyBuilder()
|
|
// .AllowRead()
|
|
// .AllowWrite()
|
|
// .AllowExit()
|
|
// .AllowSystemMalloc()
|
|
// .BuildOrDie();
|
|
//
|
|
// Note that operations are executed in the order they are dictated, though in
|
|
// most cases this has no influence since the operations themselves commute.
|
|
//
|
|
// For instance these two policies are equivalent:
|
|
//
|
|
// auto policy = PolicyBuilder.AllowRead().AllowWrite().BuildOrDie();
|
|
// auto policy = PolicyBuilder.AllowWrite().AllowRead().BuildOrDie();
|
|
//
|
|
// While these two are not:
|
|
//
|
|
// auto policy = PolicyBuilder.AllowRead().BlockSyscallWithErrno(__NR_read, EIO)
|
|
// .BuildOrDie();
|
|
// auto policy = PolicyBuilder.BlockSyscallWithErrno(__NR_read, EIO).AllowRead()
|
|
// .BuildOrDie();
|
|
//
|
|
// In fact the first one is equivalent to:
|
|
//
|
|
// auto policy = PolicyBuilder.AllowRead().BuildOrDie();
|
|
//
|
|
// If you dislike the chained style, it is also possible to write the first
|
|
// example as this:
|
|
//
|
|
// PolicyBuilder builder;
|
|
// builder.AllowRead();
|
|
// builder.AllowWrite();
|
|
// builder.AllowExit();
|
|
// builder.AllowSystemMalloc();
|
|
// auto policy = builder.BuildOrDie();
|
|
//
|
|
// For a more complicated example, see examples/persistent/persistent_sandbox.cc
|
|
class PolicyBuilder final {
|
|
public:
|
|
// Possible CPU fence modes for `AllowRestartableSequences()`
|
|
enum CpuFenceMode {
|
|
// Allow only fast fences for restartable sequences.
|
|
kRequireFastFences,
|
|
|
|
// Allow fast fences as well as slow fences if fast fences are unavailable.
|
|
kAllowSlowFences,
|
|
};
|
|
|
|
static constexpr absl::string_view kDefaultHostname = "sandbox2";
|
|
// Seccomp takes a 16-bit filter length, so the limit would be 64k.
|
|
// We set it lower so that there is for sure some room for the default policy.
|
|
static constexpr size_t kMaxUserPolicyLength = 30000;
|
|
|
|
using BpfFunc = const std::function<std::vector<sock_filter>(bpf_labels&)>&;
|
|
|
|
// Appends code to allow visibility restricted policy functionality.
|
|
//
|
|
// For example:
|
|
// Allow(sandbox2::UnrestrictedNetworking);
|
|
// This allows unrestricted network access by not creating a network
|
|
// namespace.
|
|
//
|
|
// Each type T is defined in an individual library and individually visibility
|
|
// restricted.
|
|
template <typename... T>
|
|
PolicyBuilder& Allow(T... tags) {
|
|
return (Allow(tags), ...);
|
|
}
|
|
|
|
// Allows unrestricted access to the network by *not* creating a network
|
|
// namespace. Note that this only disables the network namespace. To
|
|
// actually allow networking, you would also need to allow networking
|
|
// syscalls. Calling this function will enable use of namespaces
|
|
PolicyBuilder& Allow(UnrestrictedNetworking tag);
|
|
|
|
// Appends code to allow a specific syscall
|
|
PolicyBuilder& AllowSyscall(uint32_t num);
|
|
|
|
// Appends code to allow a number of syscalls
|
|
PolicyBuilder& AllowSyscalls(absl::Span<const uint32_t> nums);
|
|
|
|
// Appends code to block a syscalls while setting errno to the error given.
|
|
PolicyBuilder& BlockSyscallsWithErrno(absl::Span<const uint32_t> nums,
|
|
int error);
|
|
|
|
// Appends code to block a specific syscall and setting errno.
|
|
PolicyBuilder& BlockSyscallWithErrno(uint32_t num, int error);
|
|
|
|
// Appends code to allow waiting for events on epoll file descriptors.
|
|
// Allows these syscalls:
|
|
// - epoll_wait
|
|
// - epoll_pwait
|
|
// - epoll_pwait2
|
|
PolicyBuilder& AllowEpollWait();
|
|
|
|
// Appends code to allow using epoll.
|
|
// Allows these syscalls:
|
|
// - epoll_create
|
|
// - epoll_create1
|
|
// - epoll_ctl
|
|
// - epoll_wait
|
|
// - epoll_pwait
|
|
// - epoll_pwait2
|
|
PolicyBuilder& AllowEpoll();
|
|
|
|
// Appends code to allow initializing an inotify instance.
|
|
// Allows these syscalls:
|
|
// - inotify_init
|
|
// - inotify_init1
|
|
PolicyBuilder& AllowInotifyInit();
|
|
|
|
// Appends code to allow synchronous I/O multiplexing.
|
|
// Allows these syscalls:
|
|
// - pselect6
|
|
// - select
|
|
PolicyBuilder& AllowSelect();
|
|
|
|
// Appends code to allow exiting.
|
|
// Allows these syscalls:
|
|
// - exit
|
|
// - exit_group
|
|
PolicyBuilder& AllowExit();
|
|
|
|
// Appends code to allow restartable sequences and necessary /proc files.
|
|
// Allows these syscalls:
|
|
// - rseq
|
|
// - mmap(..., PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, ...)
|
|
// - getcpu
|
|
// - membarrier
|
|
// - futex(WAIT)
|
|
// - futex(WAKE)
|
|
// - rt_sigprocmask(SIG_SETMASK)
|
|
// Allows these files:
|
|
// - "/proc/cpuinfo"
|
|
// - "/proc/stat"
|
|
// And this directory (including subdirs/files):
|
|
// - "/sys/devices/system/cpu/"
|
|
//
|
|
// If `cpu_fence_mode` is `kAllowSlowFences`, also permits slow CPU fences.
|
|
// Allows these syscalls:
|
|
// - sched_getaffinity
|
|
// - sched_setaffinity
|
|
// Allows these files:
|
|
// - "/proc/self/cpuset"
|
|
//
|
|
// If `cpu_fence_mode` is `kRequireFastFences`, RSEQ functionality may not
|
|
// be enabled if fast CPU fences are not available.
|
|
PolicyBuilder& AllowRestartableSequences(CpuFenceMode cpu_fence_mode);
|
|
ABSL_DEPRECATED("Use AllowRestartableSequences() instead")
|
|
PolicyBuilder& AllowRestartableSequencesWithProcFiles(
|
|
CpuFenceMode cpu_fence_mode) {
|
|
return this->AllowRestartableSequences(cpu_fence_mode);
|
|
}
|
|
|
|
// Appends code to allow the scudo version of malloc, free and
|
|
// friends. This should be used in conjunction with namespaces. If scudo
|
|
// options are passed to the sandboxee through an environment variable, access
|
|
// to "/proc/self/environ" will have to be allowed by the policy.
|
|
//
|
|
// Note: This function is tuned towards the secure scudo allocator. If you are
|
|
// using another implementation, this function might not be the most
|
|
// suitable.
|
|
PolicyBuilder& AllowScudoMalloc();
|
|
|
|
// Appends code to allow the system-allocator version of malloc, free and
|
|
// friends.
|
|
//
|
|
// Note: This function is tuned towards the malloc implementation in glibc. If
|
|
// you are using another implementation, this function might not be the
|
|
// most suitable.
|
|
PolicyBuilder& AllowSystemMalloc();
|
|
|
|
// Appends code to allow the tcmalloc version of malloc, free and
|
|
// friends.
|
|
PolicyBuilder& AllowTcMalloc();
|
|
|
|
// Allows system calls typically used by the LLVM sanitizers (address
|
|
// sanitizer, memory sanitizer, and thread sanitizer). This method is
|
|
// intended as a best effort for adding system calls that are common to many
|
|
// binaries. It may not be fully inclusive of all potential system calls for
|
|
// all binaries.
|
|
PolicyBuilder& AllowLlvmSanitizers();
|
|
|
|
// Allows system calls typically used by the LLVM coverage.
|
|
// This method is intended as a best effort.
|
|
PolicyBuilder& AllowLlvmCoverage();
|
|
|
|
// Appends code to allow mmap. Specifically this allows mmap and mmap2 syscall
|
|
// on architectures where this syscalls exist.
|
|
// Prefer using AllowMmapWithoutExec as allowing mapping executable pages
|
|
// makes exploitation easier.
|
|
PolicyBuilder& AllowMmap();
|
|
|
|
// Appends code to allow mmap calls that don't specify PROT_EXEC.
|
|
PolicyBuilder& AllowMmapWithoutExec();
|
|
|
|
// Appends code to allow calling futex with the given operation.
|
|
PolicyBuilder& AllowFutexOp(int op);
|
|
|
|
// Appends code to allow opening and possibly creating files or directories.
|
|
// Allows these syscalls:
|
|
// - creat
|
|
// - open
|
|
// - openat
|
|
PolicyBuilder& AllowOpen();
|
|
|
|
// Appends code to allow calling stat, fstat and lstat.
|
|
// Allows these syscalls:
|
|
// - fstat
|
|
// - fstat64
|
|
// - fstatat
|
|
// - fstatat64
|
|
// - fstatfs
|
|
// - fstatfs64
|
|
// - lstat
|
|
// - lstat64
|
|
// - newfstatat
|
|
// - oldfstat
|
|
// - oldlstat
|
|
// - oldstat
|
|
// - stat
|
|
// - stat64
|
|
// - statfs
|
|
// - statfs64
|
|
// - ustat
|
|
PolicyBuilder& AllowStat();
|
|
|
|
// Appends code to allow checking file permissions.
|
|
// Allows these syscalls:
|
|
// - access
|
|
// - faccessat
|
|
PolicyBuilder& AllowAccess();
|
|
|
|
// Appends code to allow duplicating file descriptors.
|
|
// Allows these syscalls:
|
|
// - dup
|
|
// - dup2
|
|
// - dup3
|
|
PolicyBuilder& AllowDup();
|
|
|
|
// Appends code to allow creating pipes.
|
|
// Allows these syscalls:
|
|
// - pipe
|
|
// - pipe2
|
|
PolicyBuilder& AllowPipe();
|
|
|
|
// Appends code to allow changing file permissions.
|
|
// Allows these syscalls:
|
|
// - chmod
|
|
// - fchmod
|
|
// - fchmodat
|
|
PolicyBuilder& AllowChmod();
|
|
|
|
// Appends code to allow changing file ownership.
|
|
// Allows these syscalls:
|
|
// - chown
|
|
// - lchown
|
|
// - fchown
|
|
// - fchownat
|
|
PolicyBuilder& AllowChown();
|
|
|
|
// Appends code to the policy to allow reading from file descriptors.
|
|
// Allows these syscalls:
|
|
// - read
|
|
// - readv
|
|
// - preadv
|
|
// - pread64
|
|
PolicyBuilder& AllowRead();
|
|
|
|
// Appends code to the policy to allow writing to file descriptors.
|
|
// Allows these syscalls:
|
|
// - write
|
|
// - writev
|
|
// - pwritev
|
|
// - pwrite64
|
|
PolicyBuilder& AllowWrite();
|
|
|
|
// Appends code to allow reading directories.
|
|
// Allows these syscalls:
|
|
// - getdents
|
|
// - getdents64
|
|
PolicyBuilder& AllowReaddir();
|
|
|
|
// Appends code to allow reading symbolic links.
|
|
// Allows these syscalls:
|
|
// - readlink
|
|
// - readlinkat
|
|
PolicyBuilder& AllowReadlink();
|
|
|
|
// Appends code to allow creating links.
|
|
// Allows these syscalls:
|
|
// - link
|
|
// - linkat
|
|
PolicyBuilder& AllowLink();
|
|
|
|
// Appends code to allow creating symbolic links.
|
|
// Allows these syscalls:
|
|
// - symlink
|
|
// - symlinkat
|
|
PolicyBuilder& AllowSymlink();
|
|
|
|
// Appends code to allow creating directories.
|
|
// Allows these syscalls:
|
|
// - mkdir
|
|
// - mkdirat
|
|
PolicyBuilder& AllowMkdir();
|
|
|
|
// Appends code to allow changing file timestamps.
|
|
// Allows these syscalls:
|
|
// - futimens
|
|
// - utime
|
|
// - utimensat
|
|
// - utimes
|
|
PolicyBuilder& AllowUtime();
|
|
|
|
// Appends code to allow safe calls to fcntl.
|
|
// Allows these syscalls:
|
|
// - fcntl
|
|
// - fcntl64 (on architectures where it exists)
|
|
//
|
|
// The above are only allowed when the cmd is one of:
|
|
// F_GETFD, F_SETFD, F_GETFL, F_SETFL, F_GETLK, F_SETLKW, F_SETLK,
|
|
// F_DUPFD, F_DUPFD_CLOEXEC
|
|
PolicyBuilder& AllowSafeFcntl();
|
|
|
|
// Appends code to allow creating new processes.
|
|
// Allows these syscalls:
|
|
// - fork
|
|
// - vfork
|
|
// - clone
|
|
//
|
|
// Note: while this function allows the calls, the default policy is run first
|
|
// and it has checks for dangerous flags which can create a violation. See
|
|
// sandbox2/policy.cc for more details.
|
|
PolicyBuilder& AllowFork();
|
|
|
|
// Appends code to allow waiting for processes.
|
|
// Allows these syscalls:
|
|
// - waitpid (on architectures where it exists)
|
|
// - wait4
|
|
PolicyBuilder& AllowWait();
|
|
|
|
// Appends code to allow setting alarms / interval timers.
|
|
// Allows these syscalls:
|
|
// - alarm (on architectures where it exists)
|
|
// - setitimer
|
|
PolicyBuilder& AllowAlarm();
|
|
|
|
// Appends code to allow setting up signal handlers, returning from them, etc.
|
|
// Allows these syscalls:
|
|
// - rt_sigaction
|
|
// - rt_sigreturn
|
|
// - rt_procmask
|
|
// - signal (on architectures where it exists)
|
|
// - sigaction (on architectures where it exists)
|
|
// - sigreturn (on architectures where it exists)
|
|
// - sigprocmask (on architectures where it exists)
|
|
PolicyBuilder& AllowHandleSignals();
|
|
|
|
// Appends code to allow doing the TCGETS ioctl.
|
|
// Allows these syscalls:
|
|
// - ioctl (when the first argument is TCGETS)
|
|
PolicyBuilder& AllowTCGETS();
|
|
|
|
// Appends code to allow to getting the current time.
|
|
// Allows these syscalls:
|
|
// - time
|
|
// - gettimeofday
|
|
// - clock_gettime
|
|
PolicyBuilder& AllowTime();
|
|
|
|
// Appends code to allow sleeping in the current thread.
|
|
// Allow these syscalls:
|
|
// - clock_nanosleep
|
|
// - nanosleep
|
|
PolicyBuilder& AllowSleep();
|
|
|
|
// Appends code to allow getting the uid, euid, gid, etc.
|
|
// - getuid + geteuid + getresuid
|
|
// - getgid + getegid + getresgid
|
|
// - getuid32 + geteuid32 + getresuid32 (on architectures where they exist)
|
|
// - getgid32 + getegid32 + getresgid32 (on architectures where they exist)
|
|
// - getgroups
|
|
PolicyBuilder& AllowGetIDs();
|
|
|
|
// Appends code to allow getting the pid, ppid and tid.
|
|
// Allows these syscalls:
|
|
// - getpid
|
|
// - getppid
|
|
// - gettid
|
|
PolicyBuilder& AllowGetPIDs();
|
|
|
|
// Appends code to allow getting process groups.
|
|
// Allows these syscalls:
|
|
// - getpgid
|
|
// - getpgrp
|
|
PolicyBuilder& AllowGetPGIDs();
|
|
|
|
// Appends code to allow getting the rlimits.
|
|
// Allows these syscalls:
|
|
// - getrlimit
|
|
// - ugetrlimit (on architectures where it exist)
|
|
PolicyBuilder& AllowGetRlimit();
|
|
|
|
// Appends code to allow setting the rlimits.
|
|
// Allows these syscalls:
|
|
// - setrlimit
|
|
// - usetrlimit (on architectures where it exist)
|
|
PolicyBuilder& AllowSetRlimit();
|
|
|
|
// Appends code to allow reading random bytes.
|
|
// Allows these syscalls:
|
|
// - getrandom (with no flags or GRND_NONBLOCK)
|
|
//
|
|
PolicyBuilder& AllowGetRandom();
|
|
|
|
// Appends code to allow configuring wipe-on-fork memory
|
|
// Allows these syscalls:
|
|
// - madvise (with advice equal to -1 or MADV_WIPEONFORK).
|
|
PolicyBuilder& AllowWipeOnFork();
|
|
|
|
// Enables syscalls required to use the logging support enabled via
|
|
// Client::SendLogsToSupervisor()
|
|
// Allows the following:
|
|
// - Writes
|
|
// - kill(0, SIGABRT) (for LOG(FATAL))
|
|
// - clock_gettime
|
|
// - gettid
|
|
// - close
|
|
PolicyBuilder& AllowLogForwarding();
|
|
|
|
// Appends code to allow deleting files and directories.
|
|
// Allows these syscalls:
|
|
// - rmdir (if available)
|
|
// - unlink (if available)
|
|
// - unlinkat
|
|
PolicyBuilder& AllowUnlink();
|
|
|
|
// Appends code to allow renaming files
|
|
// Allows these syscalls:
|
|
// - rename (if available)
|
|
// - renameat
|
|
// - renameat2
|
|
PolicyBuilder& AllowRename();
|
|
|
|
// Appends code to allow creating event notification file descriptors.
|
|
// Allows these syscalls:
|
|
// - eventfd (if available)
|
|
// - eventfd2
|
|
PolicyBuilder& AllowEventFd();
|
|
|
|
// Appends code to allow polling files.
|
|
// Allows these syscalls:
|
|
// - poll (if available)
|
|
// - ppoll
|
|
PolicyBuilder& AllowPoll();
|
|
|
|
// Appends code to allow setting the name of a thread
|
|
// Allows the following
|
|
// - prctl(PR_SET_NAME, ...)
|
|
PolicyBuilder& AllowPrctlSetName();
|
|
|
|
// Appends code to allow setting a name for an anonymous memory region.
|
|
// Allows the following
|
|
// - prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ...)
|
|
PolicyBuilder& AllowPrctlSetVma();
|
|
|
|
// Enables the syscalls necessary to start a statically linked binary
|
|
//
|
|
// NOTE: This will call BlockSyscallWithErrno(__NR_readlink, ENOENT). If you
|
|
// do not want readlink blocked, put a different call before this call.
|
|
//
|
|
// The current list of allowed syscalls are below. However you should *not*
|
|
// depend on the specifics, as these will change whenever the startup code
|
|
// changes.
|
|
//
|
|
// - uname,
|
|
// - brk,
|
|
// - set_tid_address,
|
|
// - set_robust_list,
|
|
// - futex(FUTEX_WAIT_BITSET, ...)
|
|
// - rt_sigaction(0x20, ...)
|
|
// - rt_sigaction(0x21, ...)
|
|
// - rt_sigprocmask(SIG_UNBLOCK, ...)
|
|
// - arch_prctl(ARCH_SET_FS)
|
|
//
|
|
// Additionally it will block calls to readlink.
|
|
PolicyBuilder& AllowStaticStartup();
|
|
|
|
// In addition to syscalls allowed by AllowStaticStartup, also allow reading,
|
|
// seeking, mmap()-ing and closing files.
|
|
PolicyBuilder& AllowDynamicStartup();
|
|
|
|
// Appends a policy, which will be run on the specified syscall.
|
|
// This policy must be written without labels. If you need labels, use
|
|
// the overloaded function passing a BpfFunc object instead of the
|
|
// sock_filter.
|
|
PolicyBuilder& AddPolicyOnSyscall(uint32_t num,
|
|
absl::Span<const sock_filter> policy);
|
|
|
|
// Appends a policy, which will be run on the specified syscall.
|
|
// This policy may use labels.
|
|
// Example of how to use it:
|
|
// builder.AddPolicyOnSyscall(
|
|
// __NR_socket, [](bpf_labels& labels) -> std::vector<sock_filter> {
|
|
// return {
|
|
// ARG(0), // domain is first argument of socket
|
|
// JEQ(AF_UNIX, JUMP(&labels, af_unix)),
|
|
// JEQ(AF_NETLINK, JUMP(&labels, af_netlink)),
|
|
// KILL,
|
|
//
|
|
// LABEL(&labels, af_unix),
|
|
// ARG(1),
|
|
// JEQ(SOCK_STREAM | SOCK_NONBLOCK, ALLOW),
|
|
// KILL,
|
|
//
|
|
// LABEL(&labels, af_netlink),
|
|
// ARG(2),
|
|
// JEQ(NETLINK_ROUTE, ALLOW),
|
|
// };
|
|
// });
|
|
PolicyBuilder& AddPolicyOnSyscall(uint32_t num, BpfFunc f);
|
|
|
|
// Appends a policy, which will be run on the specified syscalls.
|
|
// This policy must be written without labels.
|
|
PolicyBuilder& AddPolicyOnSyscalls(absl::Span<const uint32_t> nums,
|
|
absl::Span<const sock_filter> policy);
|
|
|
|
// Appends a policy, which will be run on the specified syscalls.
|
|
// This policy may use labels.
|
|
PolicyBuilder& AddPolicyOnSyscalls(absl::Span<const uint32_t> nums,
|
|
BpfFunc f);
|
|
|
|
// Equivalent to AddPolicyOnSyscalls(mmap_syscalls, policy), where
|
|
// mmap_syscalls is a subset of {__NR_mmap, __NR_mmap2}, which exists on the
|
|
// target architecture.
|
|
PolicyBuilder& AddPolicyOnMmap(absl::Span<const sock_filter> policy);
|
|
|
|
// Equivalent to AddPolicyOnSyscalls(mmap_syscalls, f), where mmap_syscalls
|
|
// is a subset of {__NR_mmap, __NR_mmap2}, which exists on the target
|
|
// architecture.
|
|
PolicyBuilder& AddPolicyOnMmap(BpfFunc f);
|
|
|
|
// Builds the policy returning a unique_ptr to it. This should only be
|
|
// called once.
|
|
absl::StatusOr<std::unique_ptr<Policy>> TryBuild();
|
|
|
|
// Builds the policy returning a unique_ptr to it. This should only be
|
|
// called once. This function will abort if an error happened in any of the
|
|
// PolicyBuilder methods.
|
|
std::unique_ptr<Policy> BuildOrDie() { return TryBuild().value(); }
|
|
|
|
// Adds a bind-mount for a file from outside the namespace to inside. This
|
|
// will also create parent directories inside the namespace if needed.
|
|
//
|
|
// Calling these function will enable use of namespaces.
|
|
PolicyBuilder& AddFile(absl::string_view path, bool is_ro = true);
|
|
PolicyBuilder& AddFileAt(absl::string_view outside, absl::string_view inside,
|
|
bool is_ro = true);
|
|
|
|
// Best-effort function that adds the libraries and linker required by a
|
|
// binary.
|
|
//
|
|
// This does not add the binary itself, only the libraries it depends on.
|
|
//
|
|
// This function should work correctly for most binaries, but you might need
|
|
// to tweak it in some cases.
|
|
//
|
|
// This function is safe even for untrusted/potentially malicious binaries.
|
|
// It adds libraries only from standard library dirs and ld_library_path.
|
|
//
|
|
// run `ldd` yourself and use AddFile or AddDirectory.
|
|
PolicyBuilder& AddLibrariesForBinary(absl::string_view path,
|
|
absl::string_view ld_library_path = {});
|
|
|
|
// Similar to AddLibrariesForBinary, but binary is specified with an open
|
|
// fd.
|
|
PolicyBuilder& AddLibrariesForBinary(int fd,
|
|
absl::string_view ld_library_path = {});
|
|
|
|
// Adds a bind-mount for a directory from outside the namespace to
|
|
// inside. This will also create parent directories inside the namespace if
|
|
// needed.
|
|
//
|
|
// Calling these function will enable use of namespaces.
|
|
PolicyBuilder& AddDirectory(absl::string_view path, bool is_ro = true);
|
|
PolicyBuilder& AddDirectoryAt(absl::string_view outside,
|
|
absl::string_view inside, bool is_ro = true);
|
|
|
|
// Adds a tmpfs inside the namespace. This will also create parent
|
|
// directories inside the namespace if needed.
|
|
//
|
|
// Calling this function will enable use of namespaces.
|
|
PolicyBuilder& AddTmpfs(absl::string_view inside, size_t size);
|
|
|
|
// Allows unrestricted access to the network by *not* creating a network
|
|
// namespace. Note that this only disables the network namespace. To
|
|
// actually allow networking, you would also need to allow networking
|
|
// syscalls. Calling this function will enable use of namespaces.
|
|
PolicyBuilder& AllowUnrestrictedNetworking();
|
|
|
|
// Enables the use of namespaces.
|
|
//
|
|
// Namespaces are enabled by default.
|
|
// This is a no-op.
|
|
ABSL_DEPRECATED("Namespaces are enabled by default; no need to call this")
|
|
PolicyBuilder& EnableNamespaces() {
|
|
CHECK(use_namespaces_) << "Namespaces cannot be both disabled and enabled";
|
|
requires_namespaces_ = true;
|
|
return *this;
|
|
}
|
|
|
|
// Disables the use of namespaces.
|
|
//
|
|
// Call in order to use Sandbox2 without namespaces.
|
|
// This is not recommended.
|
|
PolicyBuilder& DisableNamespaces() {
|
|
CHECK(!requires_namespaces_)
|
|
<< "Namespaces cannot be both disabled and enabled. You're probably "
|
|
"using features that implicitly enable namespaces (SetHostname, "
|
|
"AddFile, AddDirectory, AddDataDependency, AddLibrariesForBinary "
|
|
"or similar)";
|
|
use_namespaces_ = false;
|
|
return *this;
|
|
}
|
|
|
|
// Set hostname in the network namespace instead of default "sandbox2".
|
|
//
|
|
// Calling this function will enable use of namespaces.
|
|
// It is an error to also call AllowUnrestrictedNetworking.
|
|
PolicyBuilder& SetHostname(absl::string_view hostname);
|
|
|
|
// Enables/disables stack trace collection on violations.
|
|
PolicyBuilder& CollectStacktracesOnViolation(bool enable);
|
|
|
|
// Enables/disables stack trace collection on signals (e.g. crashes / killed
|
|
// from a signal).
|
|
PolicyBuilder& CollectStacktracesOnSignal(bool enable);
|
|
|
|
// Enables/disables stack trace collection on hitting a timeout.
|
|
PolicyBuilder& CollectStacktracesOnTimeout(bool enable);
|
|
|
|
// Enables/disables stack trace collection on getting killed by the sandbox
|
|
// monitor / the user.
|
|
PolicyBuilder& CollectStacktracesOnKill(bool enable);
|
|
|
|
// Enables/disables stack trace collection on normal process exit.
|
|
PolicyBuilder& CollectStacktracesOnExit(bool enable);
|
|
|
|
// Changes the default action to ALLOW.
|
|
// All syscalls not handled explicitly by the policy will thus be allowed.
|
|
// Do not use in environment with untrusted code and/or data, ask
|
|
// sandbox-team@ first if unsure.
|
|
PolicyBuilder& DefaultAction(AllowAllSyscalls);
|
|
|
|
// Changes the default action to SANDBOX2_TRACE.
|
|
// All syscalls not handled explicitly by the policy will be passed off to
|
|
// the `sandbox2::Notify` implementation given to the `sandbox2::Sandbox2`
|
|
// instance.
|
|
PolicyBuilder& DefaultAction(TraceAllSyscalls);
|
|
|
|
ABSL_DEPRECATED("Use DefaultAction(sandbox2::AllowAllSyscalls()) instead")
|
|
PolicyBuilder& DangerDefaultAllowAll();
|
|
|
|
// Allows syscalls that are necessary for the NetworkProxyClient
|
|
PolicyBuilder& AddNetworkProxyPolicy();
|
|
|
|
// Allows syscalls that are necessary for the NetworkProxyClient and
|
|
// the NetworkProxyHandler
|
|
PolicyBuilder& AddNetworkProxyHandlerPolicy();
|
|
|
|
// Makes root of the filesystem writeable
|
|
// Not recommended
|
|
PolicyBuilder& SetRootWritable();
|
|
|
|
// Changes mounts propagation from MS_PRIVATE to MS_SLAVE.
|
|
PolicyBuilder& DangerAllowMountPropagation() {
|
|
allow_mount_propagation_ = true;
|
|
return *this;
|
|
}
|
|
|
|
// Allows connections to this IP.
|
|
PolicyBuilder& AllowIPv4(const std::string& ip_and_mask, uint32_t port = 0);
|
|
PolicyBuilder& AllowIPv6(const std::string& ip_and_mask, uint32_t port = 0);
|
|
|
|
// Returns the current status of the PolicyBuilder.
|
|
absl::Status GetStatus() { return last_status_; }
|
|
|
|
private:
|
|
friend class PolicyBuilderPeer; // For testing
|
|
friend class StackTracePeer;
|
|
|
|
static absl::StatusOr<std::string> ValidateAbsolutePath(
|
|
absl::string_view path);
|
|
static absl::StatusOr<std::string> ValidatePath(absl::string_view path);
|
|
|
|
// Similar to AddFile(At)/AddDirectory(At) but it won't force use of
|
|
// namespaces - files will only be added to the namespace if it is not
|
|
// disabled by the time of TryBuild().
|
|
PolicyBuilder& AddFileIfNamespaced(absl::string_view path, bool is_ro = true);
|
|
PolicyBuilder& AddFileAtIfNamespaced(absl::string_view outside,
|
|
absl::string_view inside,
|
|
bool is_ro = true);
|
|
PolicyBuilder& AddDirectoryIfNamespaced(absl::string_view path,
|
|
bool is_ro = true);
|
|
PolicyBuilder& AddDirectoryAtIfNamespaced(absl::string_view outside,
|
|
absl::string_view inside,
|
|
bool is_ro = true);
|
|
|
|
// Allows a limited version of madvise
|
|
PolicyBuilder& AllowLimitedMadvise();
|
|
|
|
// Traps instead of denying ptrace.
|
|
PolicyBuilder& TrapPtrace();
|
|
|
|
// Appends code to block a specific syscall and setting errno at the end of
|
|
// the policy - decision taken by user policy take precedence.
|
|
PolicyBuilder& OverridableBlockSyscallWithErrno(uint32_t num, int error);
|
|
|
|
PolicyBuilder& SetMounts(Mounts mounts) {
|
|
mounts_ = std::move(mounts);
|
|
return *this;
|
|
}
|
|
|
|
std::vector<sock_filter> ResolveBpfFunc(BpfFunc f);
|
|
|
|
void StoreDescription(PolicyBuilderDescription* pb_description);
|
|
|
|
// This function returns a PolicyBuilder so that we can use it in the status
|
|
// macros
|
|
PolicyBuilder& SetError(const absl::Status& status);
|
|
|
|
Mounts mounts_;
|
|
bool use_namespaces_ = true;
|
|
bool requires_namespaces_ = false;
|
|
bool allow_unrestricted_networking_ = false;
|
|
bool allow_mount_propagation_ = false;
|
|
std::string hostname_ = std::string(kDefaultHostname);
|
|
|
|
bool collect_stacktrace_on_violation_ = true;
|
|
bool collect_stacktrace_on_signal_ = true;
|
|
bool collect_stacktrace_on_timeout_ = true;
|
|
bool collect_stacktrace_on_kill_ = false;
|
|
bool collect_stacktrace_on_exit_ = false;
|
|
|
|
// Seccomp fields
|
|
std::vector<sock_filter> user_policy_;
|
|
std::vector<sock_filter> overridable_policy_;
|
|
std::optional<sock_filter> default_action_;
|
|
bool user_policy_handles_bpf_ = false;
|
|
bool user_policy_handles_ptrace_ = false;
|
|
absl::flat_hash_set<uint32_t> handled_syscalls_;
|
|
|
|
// Error handling
|
|
absl::Status last_status_ = absl::OkStatus();
|
|
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.
|
|
absl::optional<AllowedHosts> allowed_hosts_;
|
|
};
|
|
|
|
} // namespace sandbox2
|
|
|
|
#endif // SANDBOXED_API_SANDBOX2_POLICYBUILDER_H_
|