xref: /aosp_15_r20/external/sandboxed-api/sandboxed_api/sandbox2/policybuilder.cc (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
1*ec63e07aSXin Li // Copyright 2019 Google LLC
2*ec63e07aSXin Li //
3*ec63e07aSXin Li // Licensed under the Apache License, Version 2.0 (the "License");
4*ec63e07aSXin Li // you may not use this file except in compliance with the License.
5*ec63e07aSXin Li // You may obtain a copy of the License at
6*ec63e07aSXin Li //
7*ec63e07aSXin Li //     https://www.apache.org/licenses/LICENSE-2.0
8*ec63e07aSXin Li //
9*ec63e07aSXin Li // Unless required by applicable law or agreed to in writing, software
10*ec63e07aSXin Li // distributed under the License is distributed on an "AS IS" BASIS,
11*ec63e07aSXin Li // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*ec63e07aSXin Li // See the License for the specific language governing permissions and
13*ec63e07aSXin Li // limitations under the License.
14*ec63e07aSXin Li 
15*ec63e07aSXin Li #include "sandboxed_api/sandbox2/policybuilder.h"
16*ec63e07aSXin Li 
17*ec63e07aSXin Li #include <fcntl.h>  // For the fcntl flags
18*ec63e07aSXin Li #include <linux/bpf_common.h>
19*ec63e07aSXin Li #include <linux/filter.h>
20*ec63e07aSXin Li #include <linux/futex.h>
21*ec63e07aSXin Li #include <linux/random.h>  // For GRND_NONBLOCK
22*ec63e07aSXin Li #include <linux/seccomp.h>
23*ec63e07aSXin Li #include <stddef.h>
24*ec63e07aSXin Li #include <sys/ioctl.h>
25*ec63e07aSXin Li #include <sys/mman.h>  // For mmap arguments
26*ec63e07aSXin Li #include <sys/prctl.h>
27*ec63e07aSXin Li #include <sys/socket.h>
28*ec63e07aSXin Li #include <sys/stat.h>
29*ec63e07aSXin Li #include <sys/statvfs.h>
30*ec63e07aSXin Li #include <syscall.h>
31*ec63e07aSXin Li #include <unistd.h>
32*ec63e07aSXin Li 
33*ec63e07aSXin Li #include <array>
34*ec63e07aSXin Li #include <cerrno>
35*ec63e07aSXin Li #include <csignal>
36*ec63e07aSXin Li #include <cstdint>
37*ec63e07aSXin Li #include <cstdlib>
38*ec63e07aSXin Li #include <deque>
39*ec63e07aSXin Li #include <functional>
40*ec63e07aSXin Li #include <iterator>
41*ec63e07aSXin Li #include <limits>
42*ec63e07aSXin Li #include <memory>
43*ec63e07aSXin Li #include <optional>
44*ec63e07aSXin Li #include <string>
45*ec63e07aSXin Li #include <utility>
46*ec63e07aSXin Li #include <vector>
47*ec63e07aSXin Li 
48*ec63e07aSXin Li #include "absl/container/flat_hash_set.h"
49*ec63e07aSXin Li #include "absl/log/log.h"
50*ec63e07aSXin Li #include "absl/memory/memory.h"
51*ec63e07aSXin Li #include "absl/status/status.h"
52*ec63e07aSXin Li #include "absl/status/statusor.h"
53*ec63e07aSXin Li #include "absl/strings/match.h"
54*ec63e07aSXin Li #include "absl/strings/str_cat.h"
55*ec63e07aSXin Li #include "absl/strings/string_view.h"
56*ec63e07aSXin Li #include "absl/types/span.h"
57*ec63e07aSXin Li #include "sandboxed_api/config.h"
58*ec63e07aSXin Li #include "sandboxed_api/sandbox2/allow_all_syscalls.h"
59*ec63e07aSXin Li #include "sandboxed_api/sandbox2/allow_unrestricted_networking.h"
60*ec63e07aSXin Li #include "sandboxed_api/sandbox2/namespace.h"
61*ec63e07aSXin Li #include "sandboxed_api/sandbox2/policy.h"
62*ec63e07aSXin Li #include "sandboxed_api/sandbox2/syscall.h"
63*ec63e07aSXin Li #include "sandboxed_api/sandbox2/trace_all_syscalls.h"
64*ec63e07aSXin Li #include "sandboxed_api/sandbox2/util/bpf_helper.h"
65*ec63e07aSXin Li #include "sandboxed_api/sandbox2/violation.pb.h"
66*ec63e07aSXin Li #include "sandboxed_api/util/path.h"
67*ec63e07aSXin Li 
68*ec63e07aSXin Li #if defined(SAPI_X86_64)
69*ec63e07aSXin Li #include <asm/prctl.h>
70*ec63e07aSXin Li #elif defined(SAPI_PPC64_LE)
71*ec63e07aSXin Li #include <asm/termbits.h>  // On PPC, TCGETS macro needs termios
72*ec63e07aSXin Li #endif
73*ec63e07aSXin Li 
74*ec63e07aSXin Li #ifndef MAP_FIXED_NOREPLACE
75*ec63e07aSXin Li #define MAP_FIXED_NOREPLACE 0x100000
76*ec63e07aSXin Li #endif
77*ec63e07aSXin Li #ifndef PR_SET_VMA
78*ec63e07aSXin Li #define PR_SET_VMA 0x53564d41
79*ec63e07aSXin Li #endif
80*ec63e07aSXin Li #ifndef PR_SET_VMA_ANON_NAME
81*ec63e07aSXin Li #define PR_SET_VMA_ANON_NAME 0
82*ec63e07aSXin Li #endif
83*ec63e07aSXin Li 
84*ec63e07aSXin Li namespace sandbox2 {
85*ec63e07aSXin Li namespace {
86*ec63e07aSXin Li 
87*ec63e07aSXin Li namespace file = ::sapi::file;
88*ec63e07aSXin Li 
89*ec63e07aSXin Li constexpr std::array<uint32_t, 2> kMmapSyscalls = {
90*ec63e07aSXin Li #ifdef __NR_mmap2
91*ec63e07aSXin Li     __NR_mmap2,
92*ec63e07aSXin Li #endif
93*ec63e07aSXin Li #ifdef __NR_mmap
94*ec63e07aSXin Li     __NR_mmap,
95*ec63e07aSXin Li #endif
96*ec63e07aSXin Li };
97*ec63e07aSXin Li 
CheckBpfBounds(const sock_filter & filter,size_t max_jmp)98*ec63e07aSXin Li bool CheckBpfBounds(const sock_filter& filter, size_t max_jmp) {
99*ec63e07aSXin Li   if (BPF_CLASS(filter.code) == BPF_JMP) {
100*ec63e07aSXin Li     if (BPF_OP(filter.code) == BPF_JA) {
101*ec63e07aSXin Li       return filter.k <= max_jmp;
102*ec63e07aSXin Li     }
103*ec63e07aSXin Li     return filter.jt <= max_jmp && filter.jf <= max_jmp;
104*ec63e07aSXin Li   }
105*ec63e07aSXin Li   return true;
106*ec63e07aSXin Li }
107*ec63e07aSXin Li 
IsOnReadOnlyDev(const std::string & path)108*ec63e07aSXin Li bool IsOnReadOnlyDev(const std::string& path) {
109*ec63e07aSXin Li   struct statvfs vfs;
110*ec63e07aSXin Li   if (TEMP_FAILURE_RETRY(statvfs(path.c_str(), &vfs)) == -1) {
111*ec63e07aSXin Li     PLOG(ERROR) << "Could not statvfs: " << path.c_str();
112*ec63e07aSXin Li     return false;
113*ec63e07aSXin Li   }
114*ec63e07aSXin Li   return vfs.f_flag & ST_RDONLY;
115*ec63e07aSXin Li }
116*ec63e07aSXin Li 
117*ec63e07aSXin Li }  // namespace
118*ec63e07aSXin Li 
Allow(UnrestrictedNetworking tag)119*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::Allow(UnrestrictedNetworking tag) {
120*ec63e07aSXin Li   EnableNamespaces();  // NOLINT(clang-diagnostic-deprecated-declarations)
121*ec63e07aSXin Li   allow_unrestricted_networking_ = true;
122*ec63e07aSXin Li   return *this;
123*ec63e07aSXin Li }
124*ec63e07aSXin Li 
AllowSyscall(uint32_t num)125*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowSyscall(uint32_t num) {
126*ec63e07aSXin Li   if (handled_syscalls_.insert(num).second) {
127*ec63e07aSXin Li     user_policy_.insert(user_policy_.end(), {SYSCALL(num, ALLOW)});
128*ec63e07aSXin Li   }
129*ec63e07aSXin Li   return *this;
130*ec63e07aSXin Li }
131*ec63e07aSXin Li 
AllowSyscalls(absl::Span<const uint32_t> nums)132*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowSyscalls(absl::Span<const uint32_t> nums) {
133*ec63e07aSXin Li   for (auto num : nums) {
134*ec63e07aSXin Li     AllowSyscall(num);
135*ec63e07aSXin Li   }
136*ec63e07aSXin Li   return *this;
137*ec63e07aSXin Li }
138*ec63e07aSXin Li 
BlockSyscallsWithErrno(absl::Span<const uint32_t> nums,int error)139*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::BlockSyscallsWithErrno(
140*ec63e07aSXin Li     absl::Span<const uint32_t> nums, int error) {
141*ec63e07aSXin Li   for (auto num : nums) {
142*ec63e07aSXin Li     BlockSyscallWithErrno(num, error);
143*ec63e07aSXin Li   }
144*ec63e07aSXin Li   return *this;
145*ec63e07aSXin Li }
146*ec63e07aSXin Li 
BlockSyscallWithErrno(uint32_t num,int error)147*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::BlockSyscallWithErrno(uint32_t num, int error) {
148*ec63e07aSXin Li   if (handled_syscalls_.insert(num).second) {
149*ec63e07aSXin Li     user_policy_.insert(user_policy_.end(), {SYSCALL(num, ERRNO(error))});
150*ec63e07aSXin Li     if (num == __NR_bpf) {
151*ec63e07aSXin Li       user_policy_handles_bpf_ = true;
152*ec63e07aSXin Li     }
153*ec63e07aSXin Li     if (num == __NR_ptrace) {
154*ec63e07aSXin Li       user_policy_handles_ptrace_ = true;
155*ec63e07aSXin Li     }
156*ec63e07aSXin Li   }
157*ec63e07aSXin Li   return *this;
158*ec63e07aSXin Li }
159*ec63e07aSXin Li 
OverridableBlockSyscallWithErrno(uint32_t num,int error)160*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::OverridableBlockSyscallWithErrno(uint32_t num,
161*ec63e07aSXin Li                                                                int error) {
162*ec63e07aSXin Li   overridable_policy_.insert(overridable_policy_.end(),
163*ec63e07aSXin Li                              {SYSCALL(num, ERRNO(error))});
164*ec63e07aSXin Li   return *this;
165*ec63e07aSXin Li }
166*ec63e07aSXin Li 
AllowEpollWait()167*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowEpollWait() {
168*ec63e07aSXin Li   return AllowSyscalls({
169*ec63e07aSXin Li #ifdef __NR_epoll_wait
170*ec63e07aSXin Li       __NR_epoll_wait,
171*ec63e07aSXin Li #endif
172*ec63e07aSXin Li #ifdef __NR_epoll_pwait
173*ec63e07aSXin Li       __NR_epoll_pwait,
174*ec63e07aSXin Li #endif
175*ec63e07aSXin Li #ifdef __NR_epoll_pwait2
176*ec63e07aSXin Li       __NR_epoll_pwait2,
177*ec63e07aSXin Li #endif
178*ec63e07aSXin Li   });
179*ec63e07aSXin Li }
180*ec63e07aSXin Li 
AllowEpoll()181*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowEpoll() {
182*ec63e07aSXin Li   AllowSyscalls({
183*ec63e07aSXin Li #ifdef __NR_epoll_create
184*ec63e07aSXin Li       __NR_epoll_create,
185*ec63e07aSXin Li #endif
186*ec63e07aSXin Li #ifdef __NR_epoll_create1
187*ec63e07aSXin Li       __NR_epoll_create1,
188*ec63e07aSXin Li #endif
189*ec63e07aSXin Li #ifdef __NR_epoll_ctl
190*ec63e07aSXin Li       __NR_epoll_ctl,
191*ec63e07aSXin Li #endif
192*ec63e07aSXin Li   });
193*ec63e07aSXin Li 
194*ec63e07aSXin Li   return AllowEpollWait();
195*ec63e07aSXin Li }
196*ec63e07aSXin Li 
AllowInotifyInit()197*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowInotifyInit() {
198*ec63e07aSXin Li   return AllowSyscalls({
199*ec63e07aSXin Li #ifdef __NR_inotify_init
200*ec63e07aSXin Li       __NR_inotify_init,
201*ec63e07aSXin Li #endif
202*ec63e07aSXin Li #ifdef __NR_inotify_init1
203*ec63e07aSXin Li       __NR_inotify_init1,
204*ec63e07aSXin Li #endif
205*ec63e07aSXin Li   });
206*ec63e07aSXin Li }
207*ec63e07aSXin Li 
AllowSelect()208*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowSelect() {
209*ec63e07aSXin Li   return AllowSyscalls({
210*ec63e07aSXin Li #ifdef __NR_select
211*ec63e07aSXin Li       __NR_select,
212*ec63e07aSXin Li #endif
213*ec63e07aSXin Li #ifdef __NR_pselect6
214*ec63e07aSXin Li       __NR_pselect6,
215*ec63e07aSXin Li #endif
216*ec63e07aSXin Li   });
217*ec63e07aSXin Li }
218*ec63e07aSXin Li 
AllowExit()219*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowExit() {
220*ec63e07aSXin Li   return AllowSyscalls({__NR_exit, __NR_exit_group});
221*ec63e07aSXin Li }
222*ec63e07aSXin Li 
AllowScudoMalloc()223*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowScudoMalloc() {
224*ec63e07aSXin Li   AllowTime();
225*ec63e07aSXin Li   AllowSyscalls({__NR_munmap, __NR_nanosleep});
226*ec63e07aSXin Li   AllowFutexOp(FUTEX_WAKE);
227*ec63e07aSXin Li   AllowLimitedMadvise();
228*ec63e07aSXin Li   AllowGetRandom();
229*ec63e07aSXin Li   AllowGetPIDs();
230*ec63e07aSXin Li   AllowWipeOnFork();
231*ec63e07aSXin Li #ifdef __NR_open
232*ec63e07aSXin Li   OverridableBlockSyscallWithErrno(__NR_open, ENOENT);
233*ec63e07aSXin Li #endif
234*ec63e07aSXin Li #ifdef __NR_openat
235*ec63e07aSXin Li   OverridableBlockSyscallWithErrno(__NR_openat, ENOENT);
236*ec63e07aSXin Li #endif
237*ec63e07aSXin Li 
238*ec63e07aSXin Li   return AddPolicyOnMmap([](bpf_labels& labels) -> std::vector<sock_filter> {
239*ec63e07aSXin Li     return {
240*ec63e07aSXin Li         ARG_32(2),  // prot
241*ec63e07aSXin Li         JEQ32(PROT_NONE, JUMP(&labels, prot_none)),
242*ec63e07aSXin Li         JNE32(PROT_READ | PROT_WRITE, JUMP(&labels, mmap_end)),
243*ec63e07aSXin Li 
244*ec63e07aSXin Li         // PROT_READ | PROT_WRITE
245*ec63e07aSXin Li         ARG_32(3),  // flags
246*ec63e07aSXin Li         BPF_STMT(BPF_ALU | BPF_AND | BPF_K,
247*ec63e07aSXin Li                  ~uint32_t{MAP_FIXED | MAP_NORESERVE}),
248*ec63e07aSXin Li         JEQ32(MAP_PRIVATE | MAP_ANONYMOUS, ALLOW),
249*ec63e07aSXin Li         JUMP(&labels, mmap_end),
250*ec63e07aSXin Li 
251*ec63e07aSXin Li         // PROT_NONE
252*ec63e07aSXin Li         LABEL(&labels, prot_none),
253*ec63e07aSXin Li         ARG_32(3),  // flags
254*ec63e07aSXin Li         JEQ32(MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, ALLOW),
255*ec63e07aSXin Li 
256*ec63e07aSXin Li         LABEL(&labels, mmap_end),
257*ec63e07aSXin Li     };
258*ec63e07aSXin Li   });
259*ec63e07aSXin Li }
260*ec63e07aSXin Li 
AllowTcMalloc()261*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowTcMalloc() {
262*ec63e07aSXin Li   AllowTime();
263*ec63e07aSXin Li   AllowRestartableSequences(kRequireFastFences);
264*ec63e07aSXin Li   AllowSyscalls(
265*ec63e07aSXin Li       {__NR_munmap, __NR_nanosleep, __NR_brk, __NR_mincore, __NR_membarrier});
266*ec63e07aSXin Li   AllowLimitedMadvise();
267*ec63e07aSXin Li   AllowPrctlSetVma();
268*ec63e07aSXin Li   AllowPoll();
269*ec63e07aSXin Li   AllowGetPIDs();
270*ec63e07aSXin Li 
271*ec63e07aSXin Li   AddPolicyOnSyscall(__NR_mprotect, {
272*ec63e07aSXin Li                                         ARG_32(2),
273*ec63e07aSXin Li                                         JEQ32(PROT_READ | PROT_WRITE, ALLOW),
274*ec63e07aSXin Li                                         JEQ32(PROT_NONE, ALLOW),
275*ec63e07aSXin Li                                     });
276*ec63e07aSXin Li 
277*ec63e07aSXin Li   return AddPolicyOnMmap([](bpf_labels& labels) -> std::vector<sock_filter> {
278*ec63e07aSXin Li     return {
279*ec63e07aSXin Li         ARG_32(2),  // prot
280*ec63e07aSXin Li         JEQ32(PROT_NONE, JUMP(&labels, prot_none)),
281*ec63e07aSXin Li         JNE32(PROT_READ | PROT_WRITE, JUMP(&labels, mmap_end)),
282*ec63e07aSXin Li 
283*ec63e07aSXin Li         // PROT_READ | PROT_WRITE
284*ec63e07aSXin Li         ARG_32(3),  // flags
285*ec63e07aSXin Li         JNE32(MAP_ANONYMOUS | MAP_PRIVATE, JUMP(&labels, mmap_end)),
286*ec63e07aSXin Li         ALLOW,
287*ec63e07aSXin Li 
288*ec63e07aSXin Li         // PROT_NONE
289*ec63e07aSXin Li         LABEL(&labels, prot_none),
290*ec63e07aSXin Li         ARG_32(3),  // flags
291*ec63e07aSXin Li         JEQ32(MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, ALLOW),
292*ec63e07aSXin Li         JEQ32(MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED_NOREPLACE, ALLOW),
293*ec63e07aSXin Li         JEQ32(MAP_ANONYMOUS | MAP_PRIVATE, ALLOW),
294*ec63e07aSXin Li 
295*ec63e07aSXin Li         LABEL(&labels, mmap_end),
296*ec63e07aSXin Li     };
297*ec63e07aSXin Li   });
298*ec63e07aSXin Li }
299*ec63e07aSXin Li 
AllowSystemMalloc()300*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowSystemMalloc() {
301*ec63e07aSXin Li   AllowSyscalls({__NR_munmap, __NR_brk});
302*ec63e07aSXin Li   AllowFutexOp(FUTEX_WAKE);
303*ec63e07aSXin Li   AddPolicyOnSyscall(__NR_mremap, {
304*ec63e07aSXin Li                                       ARG_32(3),
305*ec63e07aSXin Li                                       JEQ32(MREMAP_MAYMOVE, ALLOW),
306*ec63e07aSXin Li                                   });
307*ec63e07aSXin Li   return AddPolicyOnMmap([](bpf_labels& labels) -> std::vector<sock_filter> {
308*ec63e07aSXin Li     return {
309*ec63e07aSXin Li         ARG_32(2),  // prot
310*ec63e07aSXin Li         JEQ32(PROT_NONE, JUMP(&labels, prot_none)),
311*ec63e07aSXin Li         JNE32(PROT_READ | PROT_WRITE, JUMP(&labels, mmap_end)),
312*ec63e07aSXin Li 
313*ec63e07aSXin Li         // PROT_READ | PROT_WRITE
314*ec63e07aSXin Li         ARG_32(3),  // flags
315*ec63e07aSXin Li         JEQ32(MAP_ANONYMOUS | MAP_PRIVATE, ALLOW),
316*ec63e07aSXin Li 
317*ec63e07aSXin Li         // PROT_NONE
318*ec63e07aSXin Li         LABEL(&labels, prot_none),
319*ec63e07aSXin Li         ARG_32(3),  // flags
320*ec63e07aSXin Li         JEQ32(MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE, ALLOW),
321*ec63e07aSXin Li 
322*ec63e07aSXin Li         LABEL(&labels, mmap_end),
323*ec63e07aSXin Li     };
324*ec63e07aSXin Li   });
325*ec63e07aSXin Li 
326*ec63e07aSXin Li   return *this;
327*ec63e07aSXin Li }
328*ec63e07aSXin Li 
AllowLlvmSanitizers()329*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowLlvmSanitizers() {
330*ec63e07aSXin Li   if constexpr (!sapi::sanitizers::IsAny()) {
331*ec63e07aSXin Li     return *this;
332*ec63e07aSXin Li   }
333*ec63e07aSXin Li   // *san use a custom allocator that runs mmap/unmap under the hood.  For
334*ec63e07aSXin Li   // example:
335*ec63e07aSXin Li   // https://github.com/llvm/llvm-project/blob/596d534ac3524052df210be8d3c01a33b2260a42/compiler-rt/lib/asan/asan_allocator.cpp#L980
336*ec63e07aSXin Li   // https://github.com/llvm/llvm-project/blob/62ec4ac90738a5f2d209ed28c822223e58aaaeb7/compiler-rt/lib/sanitizer_common/sanitizer_allocator_secondary.h#L98
337*ec63e07aSXin Li   AllowMmapWithoutExec();
338*ec63e07aSXin Li   AllowSyscall(__NR_munmap);
339*ec63e07aSXin Li   AllowSyscall(__NR_sched_yield);
340*ec63e07aSXin Li 
341*ec63e07aSXin Li   // https://github.com/llvm/llvm-project/blob/4bbc3290a25c0dc26007912a96e0f77b2092ee56/compiler-rt/lib/sanitizer_common/sanitizer_stack_store.cpp#L293
342*ec63e07aSXin Li   AddPolicyOnSyscall(__NR_mprotect,
343*ec63e07aSXin Li                      {
344*ec63e07aSXin Li                          ARG_32(2),
345*ec63e07aSXin Li                          BPF_STMT(BPF_AND | BPF_ALU | BPF_K,
346*ec63e07aSXin Li                                   ~uint32_t{PROT_READ | PROT_WRITE}),
347*ec63e07aSXin Li                          JEQ32(PROT_NONE, ALLOW),
348*ec63e07aSXin Li                      });
349*ec63e07aSXin Li 
350*ec63e07aSXin Li   AddPolicyOnSyscall(__NR_madvise, {
351*ec63e07aSXin Li                                        ARG_32(2),
352*ec63e07aSXin Li                                        JEQ32(MADV_DONTDUMP, ALLOW),
353*ec63e07aSXin Li                                        JEQ32(MADV_NOHUGEPAGE, ALLOW),
354*ec63e07aSXin Li                                    });
355*ec63e07aSXin Li   // Sanitizers read from /proc. For example:
356*ec63e07aSXin Li   // https://github.com/llvm/llvm-project/blob/634da7a1c61ee8c173e90a841eb1f4ea03caa20b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp#L1155
357*ec63e07aSXin Li   AddDirectoryIfNamespaced("/proc");
358*ec63e07aSXin Li   AllowOpen();
359*ec63e07aSXin Li   // Sanitizers need pid for reports. For example:
360*ec63e07aSXin Li   // https://github.com/llvm/llvm-project/blob/634da7a1c61ee8c173e90a841eb1f4ea03caa20b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp#L740
361*ec63e07aSXin Li   AllowGetPIDs();
362*ec63e07aSXin Li   // Sanitizers may try color output. For example:
363*ec63e07aSXin Li   // https://github.com/llvm/llvm-project/blob/87dd3d350c4ce0115b2cdf91d85ddd05ae2661aa/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp#L157
364*ec63e07aSXin Li   OverridableBlockSyscallWithErrno(__NR_ioctl, EPERM);
365*ec63e07aSXin Li   // https://github.com/llvm/llvm-project/blob/9aa39481d9eb718e872993791547053a3c1f16d5/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp#L150
366*ec63e07aSXin Li   // https://sourceware.org/git/?p=glibc.git;a=blob;f=nptl/pthread_getattr_np.c;h=de7edfa0928224eb8375e2fe894d6677570fbb3b;hb=HEAD#l188
367*ec63e07aSXin Li   AllowSyscall(__NR_sched_getaffinity);
368*ec63e07aSXin Li   // https://github.com/llvm/llvm-project/blob/02c2b472b510ff55679844c087b66e7837e13dc2/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp#L434
369*ec63e07aSXin Li #ifdef __NR_readlink
370*ec63e07aSXin Li   OverridableBlockSyscallWithErrno(__NR_readlink, ENOENT);
371*ec63e07aSXin Li #endif
372*ec63e07aSXin Li   OverridableBlockSyscallWithErrno(__NR_readlinkat, ENOENT);
373*ec63e07aSXin Li   if constexpr (sapi::sanitizers::IsASan()) {
374*ec63e07aSXin Li     AllowSyscall(__NR_sigaltstack);
375*ec63e07aSXin Li   }
376*ec63e07aSXin Li   if constexpr (sapi::sanitizers::IsTSan()) {
377*ec63e07aSXin Li     AllowSyscall(__NR_set_robust_list);
378*ec63e07aSXin Li   }
379*ec63e07aSXin Li   return *this;
380*ec63e07aSXin Li }
381*ec63e07aSXin Li 
AllowLlvmCoverage()382*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowLlvmCoverage() {
383*ec63e07aSXin Li   if (!sapi::IsCoverageRun()) {
384*ec63e07aSXin Li     return *this;
385*ec63e07aSXin Li   }
386*ec63e07aSXin Li   AllowStat();
387*ec63e07aSXin Li   AllowGetPIDs();
388*ec63e07aSXin Li   AllowOpen();
389*ec63e07aSXin Li   AllowRead();
390*ec63e07aSXin Li   AllowWrite();
391*ec63e07aSXin Li   AllowMkdir();
392*ec63e07aSXin Li   AllowSafeFcntl();
393*ec63e07aSXin Li   AllowSyscalls({
394*ec63e07aSXin Li       __NR_munmap, __NR_close, __NR_lseek,
395*ec63e07aSXin Li #ifdef __NR__llseek
396*ec63e07aSXin Li       __NR__llseek,  // Newer glibc on PPC
397*ec63e07aSXin Li #endif
398*ec63e07aSXin Li   });
399*ec63e07aSXin Li   AllowTcMalloc();
400*ec63e07aSXin Li   AddPolicyOnMmap([](bpf_labels& labels) -> std::vector<sock_filter> {
401*ec63e07aSXin Li     return {
402*ec63e07aSXin Li         ARG_32(2),  // prot
403*ec63e07aSXin Li         JNE32(PROT_READ | PROT_WRITE, JUMP(&labels, mmap_end)),
404*ec63e07aSXin Li         ARG_32(3),  // flags
405*ec63e07aSXin Li         JEQ32(MAP_SHARED, ALLOW),
406*ec63e07aSXin Li         LABEL(&labels, mmap_end),
407*ec63e07aSXin Li     };
408*ec63e07aSXin Li   });
409*ec63e07aSXin Li   AddDirectoryIfNamespaced(getenv("COVERAGE_DIR"), /*is_ro=*/false);
410*ec63e07aSXin Li   return *this;
411*ec63e07aSXin Li }
412*ec63e07aSXin Li 
AllowLimitedMadvise()413*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowLimitedMadvise() {
414*ec63e07aSXin Li   return AddPolicyOnSyscall(__NR_madvise, {
415*ec63e07aSXin Li                                               ARG_32(2),
416*ec63e07aSXin Li                                               JEQ32(MADV_DONTNEED, ALLOW),
417*ec63e07aSXin Li                                               JEQ32(MADV_REMOVE, ALLOW),
418*ec63e07aSXin Li                                               JEQ32(MADV_HUGEPAGE, ALLOW),
419*ec63e07aSXin Li                                               JEQ32(MADV_NOHUGEPAGE, ALLOW),
420*ec63e07aSXin Li                                           });
421*ec63e07aSXin Li }
422*ec63e07aSXin Li 
AllowMmapWithoutExec()423*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowMmapWithoutExec() {
424*ec63e07aSXin Li   return AddPolicyOnMmap({
425*ec63e07aSXin Li       ARG_32(2),
426*ec63e07aSXin Li       BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, PROT_EXEC, 1, 0),
427*ec63e07aSXin Li       ALLOW,
428*ec63e07aSXin Li   });
429*ec63e07aSXin Li }
430*ec63e07aSXin Li 
AllowMmap()431*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowMmap() {
432*ec63e07aSXin Li   return AllowSyscalls(kMmapSyscalls);
433*ec63e07aSXin Li }
434*ec63e07aSXin Li 
AllowOpen()435*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowOpen() {
436*ec63e07aSXin Li #ifdef __NR_creat
437*ec63e07aSXin Li   AllowSyscall(__NR_creat);
438*ec63e07aSXin Li #endif
439*ec63e07aSXin Li #ifdef __NR_open
440*ec63e07aSXin Li   AllowSyscall(__NR_open);
441*ec63e07aSXin Li #endif
442*ec63e07aSXin Li #ifdef __NR_openat
443*ec63e07aSXin Li   AllowSyscall(__NR_openat);
444*ec63e07aSXin Li #endif
445*ec63e07aSXin Li   return *this;
446*ec63e07aSXin Li }
447*ec63e07aSXin Li 
AllowStat()448*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowStat() {
449*ec63e07aSXin Li #ifdef __NR_fstat
450*ec63e07aSXin Li   AllowSyscall(__NR_fstat);
451*ec63e07aSXin Li #endif
452*ec63e07aSXin Li #ifdef __NR_fstat64
453*ec63e07aSXin Li   AllowSyscall(__NR_fstat64);
454*ec63e07aSXin Li #endif
455*ec63e07aSXin Li #ifdef __NR_fstatat
456*ec63e07aSXin Li   AllowSyscall(__NR_fstatat);
457*ec63e07aSXin Li #endif
458*ec63e07aSXin Li #ifdef __NR_fstatat64
459*ec63e07aSXin Li   AllowSyscall(__NR_fstatat64);
460*ec63e07aSXin Li #endif
461*ec63e07aSXin Li #ifdef __NR_fstatfs
462*ec63e07aSXin Li   AllowSyscall(__NR_fstatfs);
463*ec63e07aSXin Li #endif
464*ec63e07aSXin Li #ifdef __NR_fstatfs64
465*ec63e07aSXin Li   AllowSyscall(__NR_fstatfs64);
466*ec63e07aSXin Li #endif
467*ec63e07aSXin Li #ifdef __NR_lstat
468*ec63e07aSXin Li   AllowSyscall(__NR_lstat);
469*ec63e07aSXin Li #endif
470*ec63e07aSXin Li #ifdef __NR_lstat64
471*ec63e07aSXin Li   AllowSyscall(__NR_lstat64);
472*ec63e07aSXin Li #endif
473*ec63e07aSXin Li #ifdef __NR_newfstatat
474*ec63e07aSXin Li   AllowSyscall(__NR_newfstatat);
475*ec63e07aSXin Li #endif
476*ec63e07aSXin Li #ifdef __NR_oldfstat
477*ec63e07aSXin Li   AllowSyscall(__NR_oldfstat);
478*ec63e07aSXin Li #endif
479*ec63e07aSXin Li #ifdef __NR_oldlstat
480*ec63e07aSXin Li   AllowSyscall(__NR_oldlstat);
481*ec63e07aSXin Li #endif
482*ec63e07aSXin Li #ifdef __NR_oldstat
483*ec63e07aSXin Li   AllowSyscall(__NR_oldstat);
484*ec63e07aSXin Li #endif
485*ec63e07aSXin Li #ifdef __NR_stat
486*ec63e07aSXin Li   AllowSyscall(__NR_stat);
487*ec63e07aSXin Li #endif
488*ec63e07aSXin Li #ifdef __NR_stat64
489*ec63e07aSXin Li   AllowSyscall(__NR_stat64);
490*ec63e07aSXin Li #endif
491*ec63e07aSXin Li #ifdef __NR_statfs
492*ec63e07aSXin Li   AllowSyscall(__NR_statfs);
493*ec63e07aSXin Li #endif
494*ec63e07aSXin Li #ifdef __NR_statfs64
495*ec63e07aSXin Li   AllowSyscall(__NR_statfs64);
496*ec63e07aSXin Li #endif
497*ec63e07aSXin Li   return *this;
498*ec63e07aSXin Li }
499*ec63e07aSXin Li 
AllowAccess()500*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowAccess() {
501*ec63e07aSXin Li #ifdef __NR_access
502*ec63e07aSXin Li   AllowSyscall(__NR_access);
503*ec63e07aSXin Li #endif
504*ec63e07aSXin Li #ifdef __NR_faccessat
505*ec63e07aSXin Li   AllowSyscall(__NR_faccessat);
506*ec63e07aSXin Li #endif
507*ec63e07aSXin Li #ifdef __NR_faccessat2
508*ec63e07aSXin Li   AllowSyscall(__NR_faccessat2);
509*ec63e07aSXin Li #endif
510*ec63e07aSXin Li   return *this;
511*ec63e07aSXin Li }
512*ec63e07aSXin Li 
AllowDup()513*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowDup() {
514*ec63e07aSXin Li   AllowSyscall(__NR_dup);
515*ec63e07aSXin Li #ifdef __NR_dup2
516*ec63e07aSXin Li   AllowSyscall(__NR_dup2);
517*ec63e07aSXin Li #endif
518*ec63e07aSXin Li   AllowSyscall(__NR_dup3);
519*ec63e07aSXin Li   return *this;
520*ec63e07aSXin Li }
521*ec63e07aSXin Li 
AllowPipe()522*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowPipe() {
523*ec63e07aSXin Li #ifdef __NR_pipe
524*ec63e07aSXin Li   AllowSyscall(__NR_pipe);
525*ec63e07aSXin Li #endif
526*ec63e07aSXin Li   AllowSyscall(__NR_pipe2);
527*ec63e07aSXin Li   return *this;
528*ec63e07aSXin Li }
529*ec63e07aSXin Li 
AllowChmod()530*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowChmod() {
531*ec63e07aSXin Li #ifdef __NR_chmod
532*ec63e07aSXin Li   AllowSyscall(__NR_chmod);
533*ec63e07aSXin Li #endif
534*ec63e07aSXin Li   AllowSyscall(__NR_fchmod);
535*ec63e07aSXin Li   AllowSyscall(__NR_fchmodat);
536*ec63e07aSXin Li   return *this;
537*ec63e07aSXin Li }
538*ec63e07aSXin Li 
AllowChown()539*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowChown() {
540*ec63e07aSXin Li #ifdef __NR_chown
541*ec63e07aSXin Li   AllowSyscall(__NR_chown);
542*ec63e07aSXin Li #endif
543*ec63e07aSXin Li #ifdef __NR_lchown
544*ec63e07aSXin Li   AllowSyscall(__NR_lchown);
545*ec63e07aSXin Li #endif
546*ec63e07aSXin Li   AllowSyscall(__NR_fchown);
547*ec63e07aSXin Li   AllowSyscall(__NR_fchownat);
548*ec63e07aSXin Li   return *this;
549*ec63e07aSXin Li }
550*ec63e07aSXin Li 
AllowRead()551*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowRead() {
552*ec63e07aSXin Li   return AllowSyscalls({
553*ec63e07aSXin Li       __NR_read,
554*ec63e07aSXin Li       __NR_readv,
555*ec63e07aSXin Li       __NR_preadv,
556*ec63e07aSXin Li       __NR_pread64,
557*ec63e07aSXin Li   });
558*ec63e07aSXin Li }
559*ec63e07aSXin Li 
AllowWrite()560*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowWrite() {
561*ec63e07aSXin Li   return AllowSyscalls({
562*ec63e07aSXin Li       __NR_write,
563*ec63e07aSXin Li       __NR_writev,
564*ec63e07aSXin Li       __NR_pwritev,
565*ec63e07aSXin Li       __NR_pwrite64,
566*ec63e07aSXin Li   });
567*ec63e07aSXin Li }
568*ec63e07aSXin Li 
AllowReaddir()569*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowReaddir() {
570*ec63e07aSXin Li   return AllowSyscalls({
571*ec63e07aSXin Li #ifdef __NR_getdents
572*ec63e07aSXin Li       __NR_getdents,
573*ec63e07aSXin Li #endif
574*ec63e07aSXin Li #ifdef __NR_getdents64
575*ec63e07aSXin Li       __NR_getdents64,
576*ec63e07aSXin Li #endif
577*ec63e07aSXin Li   });
578*ec63e07aSXin Li }
579*ec63e07aSXin Li 
AllowReadlink()580*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowReadlink() {
581*ec63e07aSXin Li   return AllowSyscalls({
582*ec63e07aSXin Li #ifdef __NR_readlink
583*ec63e07aSXin Li       __NR_readlink,
584*ec63e07aSXin Li #endif
585*ec63e07aSXin Li #ifdef __NR_readlinkat
586*ec63e07aSXin Li       __NR_readlinkat,
587*ec63e07aSXin Li #endif
588*ec63e07aSXin Li   });
589*ec63e07aSXin Li }
590*ec63e07aSXin Li 
AllowLink()591*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowLink() {
592*ec63e07aSXin Li   return AllowSyscalls({
593*ec63e07aSXin Li #ifdef __NR_link
594*ec63e07aSXin Li       __NR_link,
595*ec63e07aSXin Li #endif
596*ec63e07aSXin Li #ifdef __NR_linkat
597*ec63e07aSXin Li       __NR_linkat,
598*ec63e07aSXin Li #endif
599*ec63e07aSXin Li   });
600*ec63e07aSXin Li }
601*ec63e07aSXin Li 
AllowSymlink()602*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowSymlink() {
603*ec63e07aSXin Li   return AllowSyscalls({
604*ec63e07aSXin Li #ifdef __NR_symlink
605*ec63e07aSXin Li       __NR_symlink,
606*ec63e07aSXin Li #endif
607*ec63e07aSXin Li #ifdef __NR_symlinkat
608*ec63e07aSXin Li       __NR_symlinkat,
609*ec63e07aSXin Li #endif
610*ec63e07aSXin Li   });
611*ec63e07aSXin Li }
612*ec63e07aSXin Li 
AllowMkdir()613*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowMkdir() {
614*ec63e07aSXin Li   return AllowSyscalls({
615*ec63e07aSXin Li #ifdef __NR_mkdir
616*ec63e07aSXin Li       __NR_mkdir,
617*ec63e07aSXin Li #endif
618*ec63e07aSXin Li #ifdef __NR_mkdirat
619*ec63e07aSXin Li       __NR_mkdirat,
620*ec63e07aSXin Li #endif
621*ec63e07aSXin Li   });
622*ec63e07aSXin Li }
623*ec63e07aSXin Li 
AllowUtime()624*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowUtime() {
625*ec63e07aSXin Li   return AllowSyscalls({
626*ec63e07aSXin Li #ifdef __NR_futimens
627*ec63e07aSXin Li       __NR_futimens,
628*ec63e07aSXin Li #endif
629*ec63e07aSXin Li #ifdef __NR_utime
630*ec63e07aSXin Li       __NR_utime,
631*ec63e07aSXin Li #endif
632*ec63e07aSXin Li #ifdef __NR_utimes
633*ec63e07aSXin Li       __NR_utimes,
634*ec63e07aSXin Li #endif
635*ec63e07aSXin Li #ifdef __NR_utimensat
636*ec63e07aSXin Li       __NR_utimensat,
637*ec63e07aSXin Li #endif
638*ec63e07aSXin Li   });
639*ec63e07aSXin Li }
640*ec63e07aSXin Li 
AllowSafeFcntl()641*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowSafeFcntl() {
642*ec63e07aSXin Li   return AddPolicyOnSyscalls({__NR_fcntl,
643*ec63e07aSXin Li #ifdef __NR_fcntl64
644*ec63e07aSXin Li                               __NR_fcntl64
645*ec63e07aSXin Li #endif
646*ec63e07aSXin Li                              },
647*ec63e07aSXin Li                              {
648*ec63e07aSXin Li                                  ARG_32(1),
649*ec63e07aSXin Li                                  JEQ32(F_GETFD, ALLOW),
650*ec63e07aSXin Li                                  JEQ32(F_SETFD, ALLOW),
651*ec63e07aSXin Li                                  JEQ32(F_GETFL, ALLOW),
652*ec63e07aSXin Li                                  JEQ32(F_SETFL, ALLOW),
653*ec63e07aSXin Li                                  JEQ32(F_GETLK, ALLOW),
654*ec63e07aSXin Li                                  JEQ32(F_SETLK, ALLOW),
655*ec63e07aSXin Li                                  JEQ32(F_SETLKW, ALLOW),
656*ec63e07aSXin Li                                  JEQ32(F_DUPFD, ALLOW),
657*ec63e07aSXin Li                                  JEQ32(F_DUPFD_CLOEXEC, ALLOW),
658*ec63e07aSXin Li                              });
659*ec63e07aSXin Li }
660*ec63e07aSXin Li 
AllowFork()661*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowFork() {
662*ec63e07aSXin Li   return AllowSyscalls({
663*ec63e07aSXin Li #ifdef __NR_fork
664*ec63e07aSXin Li       __NR_fork,
665*ec63e07aSXin Li #endif
666*ec63e07aSXin Li #ifdef __NR_vfork
667*ec63e07aSXin Li       __NR_vfork,
668*ec63e07aSXin Li #endif
669*ec63e07aSXin Li       __NR_clone});
670*ec63e07aSXin Li }
671*ec63e07aSXin Li 
AllowWait()672*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowWait() {
673*ec63e07aSXin Li   return AllowSyscalls({
674*ec63e07aSXin Li #ifdef __NR_waitpid
675*ec63e07aSXin Li       __NR_waitpid,
676*ec63e07aSXin Li #endif
677*ec63e07aSXin Li       __NR_wait4});
678*ec63e07aSXin Li }
679*ec63e07aSXin Li 
AllowAlarm()680*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowAlarm() {
681*ec63e07aSXin Li   return AllowSyscalls({
682*ec63e07aSXin Li #ifdef __NR_alarm
683*ec63e07aSXin Li       __NR_alarm,
684*ec63e07aSXin Li #endif
685*ec63e07aSXin Li       __NR_setitimer});
686*ec63e07aSXin Li }
687*ec63e07aSXin Li 
AllowHandleSignals()688*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowHandleSignals() {
689*ec63e07aSXin Li   return AllowSyscalls({
690*ec63e07aSXin Li       __NR_rt_sigaction,
691*ec63e07aSXin Li       __NR_rt_sigreturn,
692*ec63e07aSXin Li       __NR_rt_sigprocmask,
693*ec63e07aSXin Li #ifdef __NR_signal
694*ec63e07aSXin Li       __NR_signal,
695*ec63e07aSXin Li #endif
696*ec63e07aSXin Li #ifdef __NR_sigaction
697*ec63e07aSXin Li       __NR_sigaction,
698*ec63e07aSXin Li #endif
699*ec63e07aSXin Li #ifdef __NR_sigreturn
700*ec63e07aSXin Li       __NR_sigreturn,
701*ec63e07aSXin Li #endif
702*ec63e07aSXin Li #ifdef __NR_sigprocmask
703*ec63e07aSXin Li       __NR_sigprocmask,
704*ec63e07aSXin Li #endif
705*ec63e07aSXin Li #ifdef __NR_sigaltstack
706*ec63e07aSXin Li       __NR_sigaltstack,
707*ec63e07aSXin Li #endif
708*ec63e07aSXin Li   });
709*ec63e07aSXin Li }
710*ec63e07aSXin Li 
AllowTCGETS()711*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowTCGETS() {
712*ec63e07aSXin Li   return AddPolicyOnSyscall(__NR_ioctl, {
713*ec63e07aSXin Li                                             ARG_32(1),
714*ec63e07aSXin Li                                             JEQ32(TCGETS, ALLOW),
715*ec63e07aSXin Li                                         });
716*ec63e07aSXin Li }
717*ec63e07aSXin Li 
AllowTime()718*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowTime() {
719*ec63e07aSXin Li   return AllowSyscalls({
720*ec63e07aSXin Li #ifdef __NR_time
721*ec63e07aSXin Li       __NR_time,
722*ec63e07aSXin Li #endif
723*ec63e07aSXin Li       __NR_gettimeofday, __NR_clock_gettime});
724*ec63e07aSXin Li }
725*ec63e07aSXin Li 
AllowSleep()726*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowSleep() {
727*ec63e07aSXin Li   return AllowSyscalls({
728*ec63e07aSXin Li       __NR_clock_nanosleep,
729*ec63e07aSXin Li       __NR_nanosleep,
730*ec63e07aSXin Li   });
731*ec63e07aSXin Li }
732*ec63e07aSXin Li 
AllowGetIDs()733*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowGetIDs() {
734*ec63e07aSXin Li   return AllowSyscalls({
735*ec63e07aSXin Li       __NR_getuid,
736*ec63e07aSXin Li       __NR_geteuid,
737*ec63e07aSXin Li       __NR_getresuid,
738*ec63e07aSXin Li       __NR_getgid,
739*ec63e07aSXin Li       __NR_getegid,
740*ec63e07aSXin Li       __NR_getresgid,
741*ec63e07aSXin Li #ifdef __NR_getuid32
742*ec63e07aSXin Li       __NR_getuid32,
743*ec63e07aSXin Li       __NR_geteuid32,
744*ec63e07aSXin Li       __NR_getresuid32,
745*ec63e07aSXin Li       __NR_getgid32,
746*ec63e07aSXin Li       __NR_getegid32,
747*ec63e07aSXin Li       __NR_getresgid32,
748*ec63e07aSXin Li #endif
749*ec63e07aSXin Li       __NR_getgroups,
750*ec63e07aSXin Li   });
751*ec63e07aSXin Li }
752*ec63e07aSXin Li 
AllowRestartableSequences(CpuFenceMode cpu_fence_mode)753*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowRestartableSequences(
754*ec63e07aSXin Li     CpuFenceMode cpu_fence_mode) {
755*ec63e07aSXin Li #ifdef __NR_rseq
756*ec63e07aSXin Li   AllowSyscall(__NR_rseq);
757*ec63e07aSXin Li #endif
758*ec63e07aSXin Li   AddPolicyOnMmap([](bpf_labels& labels) -> std::vector<sock_filter> {
759*ec63e07aSXin Li     return {
760*ec63e07aSXin Li         ARG_32(2),  // prot
761*ec63e07aSXin Li         JNE32(PROT_READ | PROT_WRITE, JUMP(&labels, mmap_end)),
762*ec63e07aSXin Li 
763*ec63e07aSXin Li         ARG_32(3),  // flags
764*ec63e07aSXin Li         JNE32(MAP_PRIVATE | MAP_ANONYMOUS, JUMP(&labels, mmap_end)),
765*ec63e07aSXin Li 
766*ec63e07aSXin Li         ALLOW,
767*ec63e07aSXin Li         LABEL(&labels, mmap_end),
768*ec63e07aSXin Li     };
769*ec63e07aSXin Li   });
770*ec63e07aSXin Li   AllowSyscall(__NR_getcpu);
771*ec63e07aSXin Li   AllowSyscall(__NR_membarrier);
772*ec63e07aSXin Li   AllowFutexOp(FUTEX_WAIT);
773*ec63e07aSXin Li   AllowFutexOp(FUTEX_WAKE);
774*ec63e07aSXin Li   AllowRead();
775*ec63e07aSXin Li   AllowOpen();
776*ec63e07aSXin Li   AllowPoll();
777*ec63e07aSXin Li   AllowSyscall(__NR_close);
778*ec63e07aSXin Li   AddPolicyOnSyscall(__NR_rt_sigprocmask, {
779*ec63e07aSXin Li                                               ARG_32(0),
780*ec63e07aSXin Li                                               JEQ32(SIG_SETMASK, ALLOW),
781*ec63e07aSXin Li                                           });
782*ec63e07aSXin Li   AllowPrctlSetVma();
783*ec63e07aSXin Li   if (cpu_fence_mode == kAllowSlowFences) {
784*ec63e07aSXin Li     AllowSyscall(__NR_sched_getaffinity);
785*ec63e07aSXin Li     AllowSyscall(__NR_sched_setaffinity);
786*ec63e07aSXin Li   }
787*ec63e07aSXin Li   AddFileIfNamespaced("/proc/cpuinfo");
788*ec63e07aSXin Li   AddFileIfNamespaced("/proc/stat");
789*ec63e07aSXin Li   AddDirectoryIfNamespaced("/sys/devices/system/cpu");
790*ec63e07aSXin Li   if (cpu_fence_mode == kAllowSlowFences) {
791*ec63e07aSXin Li     AddFileIfNamespaced("/proc/self/cpuset");
792*ec63e07aSXin Li   }
793*ec63e07aSXin Li   return *this;
794*ec63e07aSXin Li }
795*ec63e07aSXin Li 
AllowGetPIDs()796*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowGetPIDs() {
797*ec63e07aSXin Li   return AllowSyscalls({
798*ec63e07aSXin Li       __NR_getpid,
799*ec63e07aSXin Li       __NR_getppid,
800*ec63e07aSXin Li       __NR_gettid,
801*ec63e07aSXin Li   });
802*ec63e07aSXin Li }
803*ec63e07aSXin Li 
AllowGetPGIDs()804*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowGetPGIDs() {
805*ec63e07aSXin Li   return AllowSyscalls({
806*ec63e07aSXin Li       __NR_getpgid,
807*ec63e07aSXin Li #ifdef __NR_getpgrp
808*ec63e07aSXin Li       __NR_getpgrp,
809*ec63e07aSXin Li #endif
810*ec63e07aSXin Li   });
811*ec63e07aSXin Li }
812*ec63e07aSXin Li 
AllowGetRlimit()813*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowGetRlimit() {
814*ec63e07aSXin Li #ifdef __NR_prlimit64
815*ec63e07aSXin Li   AddPolicyOnSyscall(__NR_prlimit64, {ARG(2), JEQ64(0, 0, ALLOW)});
816*ec63e07aSXin Li #endif
817*ec63e07aSXin Li   return AllowSyscalls({
818*ec63e07aSXin Li #ifdef __NR_getrlimit
819*ec63e07aSXin Li       __NR_getrlimit,
820*ec63e07aSXin Li #endif
821*ec63e07aSXin Li #ifdef __NR_ugetrlimit
822*ec63e07aSXin Li       __NR_ugetrlimit,
823*ec63e07aSXin Li #endif
824*ec63e07aSXin Li   });
825*ec63e07aSXin Li }
826*ec63e07aSXin Li 
AllowSetRlimit()827*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowSetRlimit() {
828*ec63e07aSXin Li   return AllowSyscalls({
829*ec63e07aSXin Li #ifdef __NR_prlimit64
830*ec63e07aSXin Li       __NR_prlimit64,
831*ec63e07aSXin Li #endif
832*ec63e07aSXin Li #ifdef __NR_setrlimit
833*ec63e07aSXin Li       __NR_setrlimit,
834*ec63e07aSXin Li #endif
835*ec63e07aSXin Li #ifdef __NR_usetrlimit
836*ec63e07aSXin Li       __NR_usetrlimit,
837*ec63e07aSXin Li #endif
838*ec63e07aSXin Li   });
839*ec63e07aSXin Li }
840*ec63e07aSXin Li 
AllowGetRandom()841*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowGetRandom() {
842*ec63e07aSXin Li   return AddPolicyOnSyscall(__NR_getrandom, {
843*ec63e07aSXin Li                                                 ARG_32(2),
844*ec63e07aSXin Li                                                 JEQ32(0, ALLOW),
845*ec63e07aSXin Li                                                 JEQ32(GRND_NONBLOCK, ALLOW),
846*ec63e07aSXin Li                                             });
847*ec63e07aSXin Li }
848*ec63e07aSXin Li 
AllowWipeOnFork()849*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowWipeOnFork() {
850*ec63e07aSXin Li   // System headers may not be recent enough to include MADV_WIPEONFORK.
851*ec63e07aSXin Li   static constexpr uint32_t kMadv_WipeOnFork = 18;
852*ec63e07aSXin Li   // The -1 value is used by code to probe that the kernel returns -EINVAL for
853*ec63e07aSXin Li   // unknown values because some environments, like qemu, ignore madvise
854*ec63e07aSXin Li   // completely, but code needs to know whether WIPEONFORK took effect.
855*ec63e07aSXin Li   return AddPolicyOnSyscall(__NR_madvise,
856*ec63e07aSXin Li                             {
857*ec63e07aSXin Li                                 ARG_32(2),
858*ec63e07aSXin Li                                 JEQ32(kMadv_WipeOnFork, ALLOW),
859*ec63e07aSXin Li                                 JEQ32(static_cast<uint32_t>(-1), ALLOW),
860*ec63e07aSXin Li                             });
861*ec63e07aSXin Li }
862*ec63e07aSXin Li 
AllowLogForwarding()863*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowLogForwarding() {
864*ec63e07aSXin Li   AllowWrite();
865*ec63e07aSXin Li   AllowSystemMalloc();
866*ec63e07aSXin Li   AllowTcMalloc();
867*ec63e07aSXin Li 
868*ec63e07aSXin Li   // From comms
869*ec63e07aSXin Li   AllowGetPIDs();
870*ec63e07aSXin Li   AllowSyscalls({// from logging code
871*ec63e07aSXin Li                  __NR_clock_gettime,
872*ec63e07aSXin Li                  // From comms
873*ec63e07aSXin Li                  __NR_gettid, __NR_close});
874*ec63e07aSXin Li 
875*ec63e07aSXin Li   // For generating stacktraces in logging (e.g. `LOG(FATAL)`)
876*ec63e07aSXin Li   AddPolicyOnSyscall(__NR_rt_sigprocmask, {
877*ec63e07aSXin Li                                               ARG_32(0),
878*ec63e07aSXin Li                                               JEQ32(SIG_BLOCK, ALLOW),
879*ec63e07aSXin Li                                           });
880*ec63e07aSXin Li   AllowGetRlimit();
881*ec63e07aSXin Li 
882*ec63e07aSXin Li   // For LOG(FATAL)
883*ec63e07aSXin Li   return AddPolicyOnSyscall(__NR_kill,
884*ec63e07aSXin Li                             [](bpf_labels& labels) -> std::vector<sock_filter> {
885*ec63e07aSXin Li                               return {
886*ec63e07aSXin Li                                   ARG_32(0),
887*ec63e07aSXin Li                                   JNE32(0, JUMP(&labels, pid_not_null)),
888*ec63e07aSXin Li                                   ARG_32(1),
889*ec63e07aSXin Li                                   JEQ32(SIGABRT, ALLOW),
890*ec63e07aSXin Li                                   LABEL(&labels, pid_not_null),
891*ec63e07aSXin Li                               };
892*ec63e07aSXin Li                             });
893*ec63e07aSXin Li }
894*ec63e07aSXin Li 
AllowUnlink()895*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowUnlink() {
896*ec63e07aSXin Li   AllowSyscalls({
897*ec63e07aSXin Li #ifdef __NR_rmdir
898*ec63e07aSXin Li       __NR_rmdir,
899*ec63e07aSXin Li #endif
900*ec63e07aSXin Li #ifdef __NR_unlink
901*ec63e07aSXin Li       __NR_unlink,
902*ec63e07aSXin Li #endif
903*ec63e07aSXin Li       __NR_unlinkat,
904*ec63e07aSXin Li   });
905*ec63e07aSXin Li   return *this;
906*ec63e07aSXin Li }
907*ec63e07aSXin Li 
AllowPoll()908*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowPoll() {
909*ec63e07aSXin Li   AllowSyscalls({
910*ec63e07aSXin Li #ifdef __NR_poll
911*ec63e07aSXin Li       __NR_poll,
912*ec63e07aSXin Li #endif
913*ec63e07aSXin Li       __NR_ppoll,
914*ec63e07aSXin Li   });
915*ec63e07aSXin Li   return *this;
916*ec63e07aSXin Li }
917*ec63e07aSXin Li 
AllowRename()918*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowRename() {
919*ec63e07aSXin Li   AllowSyscalls({
920*ec63e07aSXin Li #ifdef __NR_rename
921*ec63e07aSXin Li       __NR_rename,
922*ec63e07aSXin Li #endif
923*ec63e07aSXin Li       __NR_renameat,
924*ec63e07aSXin Li #ifdef __NR_renameat2
925*ec63e07aSXin Li       __NR_renameat2,
926*ec63e07aSXin Li #endif
927*ec63e07aSXin Li   });
928*ec63e07aSXin Li   return *this;
929*ec63e07aSXin Li }
930*ec63e07aSXin Li 
AllowEventFd()931*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowEventFd() {
932*ec63e07aSXin Li   AllowSyscalls({
933*ec63e07aSXin Li #ifdef __NR_eventfd
934*ec63e07aSXin Li       __NR_eventfd,
935*ec63e07aSXin Li #endif
936*ec63e07aSXin Li       __NR_eventfd2,
937*ec63e07aSXin Li   });
938*ec63e07aSXin Li   return *this;
939*ec63e07aSXin Li }
940*ec63e07aSXin Li 
AllowPrctlSetName()941*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowPrctlSetName() {
942*ec63e07aSXin Li   AddPolicyOnSyscall(__NR_prctl, {ARG_32(0), JEQ32(PR_SET_NAME, ALLOW)});
943*ec63e07aSXin Li   return *this;
944*ec63e07aSXin Li }
945*ec63e07aSXin Li 
AllowPrctlSetVma()946*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowPrctlSetVma() {
947*ec63e07aSXin Li   AddPolicyOnSyscall(__NR_prctl,
948*ec63e07aSXin Li                      [](bpf_labels& labels) -> std::vector<sock_filter> {
949*ec63e07aSXin Li                        return {
950*ec63e07aSXin Li                            ARG_32(0),
951*ec63e07aSXin Li                            JNE32(PR_SET_VMA, JUMP(&labels, prctlsetvma_end)),
952*ec63e07aSXin Li                            ARG_32(1),
953*ec63e07aSXin Li                            JEQ32(PR_SET_VMA_ANON_NAME, ALLOW),
954*ec63e07aSXin Li                            LABEL(&labels, prctlsetvma_end),
955*ec63e07aSXin Li                        };
956*ec63e07aSXin Li                      });
957*ec63e07aSXin Li   return *this;
958*ec63e07aSXin Li }
959*ec63e07aSXin Li 
AllowFutexOp(int op)960*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowFutexOp(int op) {
961*ec63e07aSXin Li   return AddPolicyOnSyscall(
962*ec63e07aSXin Li       __NR_futex, {
963*ec63e07aSXin Li                       ARG_32(1),
964*ec63e07aSXin Li                       // a <- a & FUTEX_CMD_MASK
965*ec63e07aSXin Li                       BPF_STMT(BPF_ALU + BPF_AND + BPF_K,
966*ec63e07aSXin Li                                static_cast<uint32_t>(FUTEX_CMD_MASK)),
967*ec63e07aSXin Li                       JEQ32(static_cast<uint32_t>(op) & FUTEX_CMD_MASK, ALLOW),
968*ec63e07aSXin Li                   });
969*ec63e07aSXin Li }
970*ec63e07aSXin Li 
AllowStaticStartup()971*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowStaticStartup() {
972*ec63e07aSXin Li   AllowGetRlimit();
973*ec63e07aSXin Li   AllowSyscalls({
974*ec63e07aSXin Li     // These syscalls take a pointer, so no restriction.
975*ec63e07aSXin Li     __NR_uname, __NR_brk, __NR_set_tid_address,
976*ec63e07aSXin Li 
977*ec63e07aSXin Li #if defined(__ARM_NR_set_tls)
978*ec63e07aSXin Li         // libc sets the TLS during startup
979*ec63e07aSXin Li         __ARM_NR_set_tls,
980*ec63e07aSXin Li #endif
981*ec63e07aSXin Li 
982*ec63e07aSXin Li         // This syscall takes a pointer and a length.
983*ec63e07aSXin Li         // We could restrict length, but it might change, so not worth it.
984*ec63e07aSXin Li         __NR_set_robust_list,
985*ec63e07aSXin Li   });
986*ec63e07aSXin Li 
987*ec63e07aSXin Li   AllowFutexOp(FUTEX_WAIT_BITSET);
988*ec63e07aSXin Li 
989*ec63e07aSXin Li   AddPolicyOnSyscall(__NR_rt_sigaction,
990*ec63e07aSXin Li                      {
991*ec63e07aSXin Li                          ARG_32(0),
992*ec63e07aSXin Li                          // This is real-time signals used internally by libc.
993*ec63e07aSXin Li                          JEQ32(__SIGRTMIN + 0, ALLOW),
994*ec63e07aSXin Li                          JEQ32(__SIGRTMIN + 1, ALLOW),
995*ec63e07aSXin Li                      });
996*ec63e07aSXin Li 
997*ec63e07aSXin Li   AllowSyscall(__NR_rt_sigprocmask);
998*ec63e07aSXin Li 
999*ec63e07aSXin Li #ifdef SAPI_X86_64
1000*ec63e07aSXin Li   // The second argument is a pointer.
1001*ec63e07aSXin Li   AddPolicyOnSyscall(__NR_arch_prctl, {
1002*ec63e07aSXin Li                                           ARG_32(0),
1003*ec63e07aSXin Li                                           JEQ32(ARCH_SET_FS, ALLOW),
1004*ec63e07aSXin Li                                       });
1005*ec63e07aSXin Li #endif
1006*ec63e07aSXin Li 
1007*ec63e07aSXin Li   if constexpr (sapi::host_cpu::IsArm64()) {
1008*ec63e07aSXin Li     OverridableBlockSyscallWithErrno(__NR_readlinkat, ENOENT);
1009*ec63e07aSXin Li   }
1010*ec63e07aSXin Li #ifdef __NR_readlink
1011*ec63e07aSXin Li   OverridableBlockSyscallWithErrno(__NR_readlink, ENOENT);
1012*ec63e07aSXin Li #endif
1013*ec63e07aSXin Li 
1014*ec63e07aSXin Li   AllowGetRlimit();
1015*ec63e07aSXin Li   AddPolicyOnSyscall(__NR_mprotect, {
1016*ec63e07aSXin Li                                         ARG_32(2),
1017*ec63e07aSXin Li                                         JEQ32(PROT_READ, ALLOW),
1018*ec63e07aSXin Li                                     });
1019*ec63e07aSXin Li 
1020*ec63e07aSXin Li   OverridableBlockSyscallWithErrno(__NR_sigaltstack, ENOSYS);
1021*ec63e07aSXin Li 
1022*ec63e07aSXin Li   return *this;
1023*ec63e07aSXin Li }
1024*ec63e07aSXin Li 
AllowDynamicStartup()1025*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowDynamicStartup() {
1026*ec63e07aSXin Li #ifdef __ANDROID__
1027*ec63e07aSXin Li   AllowSafeFcntl();
1028*ec63e07aSXin Li   AllowGetIDs();
1029*ec63e07aSXin Li   AllowGetPIDs();
1030*ec63e07aSXin Li   AllowGetRandom();
1031*ec63e07aSXin Li   AllowSyscalls({
1032*ec63e07aSXin Li #ifdef __NR_fstatfs
1033*ec63e07aSXin Li       __NR_fstatfs,
1034*ec63e07aSXin Li #endif
1035*ec63e07aSXin Li #ifdef __NR_fstatfs64
1036*ec63e07aSXin Li       __NR_fstatfs64,
1037*ec63e07aSXin Li #endif
1038*ec63e07aSXin Li       __NR_readlinkat,
1039*ec63e07aSXin Li       __NR_sched_getaffinity,
1040*ec63e07aSXin Li       __NR_sched_getscheduler,
1041*ec63e07aSXin Li   });
1042*ec63e07aSXin Li   AllowHandleSignals();
1043*ec63e07aSXin Li   AllowFutexOp(FUTEX_WAKE_PRIVATE);
1044*ec63e07aSXin Li   AddPolicyOnSyscall(__NR_prctl,
1045*ec63e07aSXin Li                      [](bpf_labels& labels) -> std::vector<sock_filter> {
1046*ec63e07aSXin Li                        return {
1047*ec63e07aSXin Li                            ARG_32(0),  // option
1048*ec63e07aSXin Li                            JEQ32(PR_GET_DUMPABLE, ALLOW),
1049*ec63e07aSXin Li                            JNE32(PR_SET_VMA, JUMP(&labels, prctl_end)),
1050*ec63e07aSXin Li 
1051*ec63e07aSXin Li                            ARG_32(1),  // arg2
1052*ec63e07aSXin Li                            JEQ32(PR_SET_VMA_ANON_NAME, ALLOW),
1053*ec63e07aSXin Li 
1054*ec63e07aSXin Li                            LABEL(&labels, prctl_end),
1055*ec63e07aSXin Li                        };
1056*ec63e07aSXin Li                      });
1057*ec63e07aSXin Li   AddPolicyOnSyscall(__NR_mremap,
1058*ec63e07aSXin Li                      {
1059*ec63e07aSXin Li                          ARG_32(3),
1060*ec63e07aSXin Li                          JEQ32(MREMAP_MAYMOVE | MREMAP_FIXED, ALLOW),
1061*ec63e07aSXin Li                      });
1062*ec63e07aSXin Li   AddPolicyOnMmap([](bpf_labels& labels) -> std::vector<sock_filter> {
1063*ec63e07aSXin Li     return {
1064*ec63e07aSXin Li         ARG_32(2),  // prot
1065*ec63e07aSXin Li         JEQ32(PROT_NONE, JUMP(&labels, prot_none)),
1066*ec63e07aSXin Li         JEQ32(PROT_READ, JUMP(&labels, prot_read)),
1067*ec63e07aSXin Li         JEQ32(PROT_READ | PROT_WRITE, JUMP(&labels, prot_RW_or_RX)),
1068*ec63e07aSXin Li         JEQ32(PROT_READ | PROT_EXEC, JUMP(&labels, prot_RW_or_RX)),
1069*ec63e07aSXin Li 
1070*ec63e07aSXin Li         // PROT_NONE
1071*ec63e07aSXin Li         LABEL(&labels, prot_none),
1072*ec63e07aSXin Li         ARG_32(3),  // flags
1073*ec63e07aSXin Li         JEQ32(MAP_PRIVATE | MAP_ANONYMOUS, ALLOW),
1074*ec63e07aSXin Li         JEQ32(MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, ALLOW),
1075*ec63e07aSXin Li         JUMP(&labels, mmap_end),
1076*ec63e07aSXin Li 
1077*ec63e07aSXin Li         // PROT_READ
1078*ec63e07aSXin Li         LABEL(&labels, prot_read),
1079*ec63e07aSXin Li         ARG_32(3),  // flags
1080*ec63e07aSXin Li         JEQ32(MAP_SHARED, ALLOW),
1081*ec63e07aSXin Li         JEQ32(MAP_PRIVATE, ALLOW),
1082*ec63e07aSXin Li         JEQ32(MAP_PRIVATE | MAP_FIXED, ALLOW),
1083*ec63e07aSXin Li         JUMP(&labels, mmap_end),
1084*ec63e07aSXin Li 
1085*ec63e07aSXin Li         // PROT_READ | PROT_WRITE
1086*ec63e07aSXin Li         // PROT_READ | PROT_EXEC
1087*ec63e07aSXin Li         LABEL(&labels, prot_RW_or_RX),
1088*ec63e07aSXin Li         ARG_32(3),  // flags
1089*ec63e07aSXin Li         JEQ32(MAP_PRIVATE | MAP_FIXED, ALLOW),
1090*ec63e07aSXin Li 
1091*ec63e07aSXin Li         LABEL(&labels, mmap_end),
1092*ec63e07aSXin Li     };
1093*ec63e07aSXin Li   });
1094*ec63e07aSXin Li #endif
1095*ec63e07aSXin Li 
1096*ec63e07aSXin Li   AllowAccess();
1097*ec63e07aSXin Li   AllowOpen();
1098*ec63e07aSXin Li   AllowRead();
1099*ec63e07aSXin Li   AllowStat();
1100*ec63e07aSXin Li   AllowSyscalls({__NR_lseek,
1101*ec63e07aSXin Li #ifdef __NR__llseek
1102*ec63e07aSXin Li                  __NR__llseek,  // Newer glibc on PPC
1103*ec63e07aSXin Li #endif
1104*ec63e07aSXin Li                  __NR_close, __NR_munmap});
1105*ec63e07aSXin Li   AddPolicyOnSyscall(__NR_mprotect, {
1106*ec63e07aSXin Li                                         ARG_32(2),
1107*ec63e07aSXin Li                                         JEQ32(PROT_READ, ALLOW),
1108*ec63e07aSXin Li                                         JEQ32(PROT_NONE, ALLOW),
1109*ec63e07aSXin Li                                         JEQ32(PROT_READ | PROT_WRITE, ALLOW),
1110*ec63e07aSXin Li                                         JEQ32(PROT_READ | PROT_EXEC, ALLOW),
1111*ec63e07aSXin Li                                     });
1112*ec63e07aSXin Li   AllowStaticStartup();
1113*ec63e07aSXin Li 
1114*ec63e07aSXin Li   return AddPolicyOnMmap([](bpf_labels& labels) -> std::vector<sock_filter> {
1115*ec63e07aSXin Li     return {
1116*ec63e07aSXin Li         ARG_32(2),  // prot
1117*ec63e07aSXin Li         JEQ32(PROT_READ | PROT_EXEC, JUMP(&labels, prot_exec)),
1118*ec63e07aSXin Li         JEQ32(PROT_READ | PROT_WRITE, JUMP(&labels, prot_read_write)),
1119*ec63e07aSXin Li         JNE32(PROT_READ, JUMP(&labels, mmap_end)),
1120*ec63e07aSXin Li 
1121*ec63e07aSXin Li         // PROT_READ
1122*ec63e07aSXin Li         ARG_32(3),  // flags
1123*ec63e07aSXin Li         JEQ32(MAP_PRIVATE, ALLOW),
1124*ec63e07aSXin Li         JUMP(&labels, mmap_end),
1125*ec63e07aSXin Li 
1126*ec63e07aSXin Li         // PROT_READ | PROT_WRITE
1127*ec63e07aSXin Li         LABEL(&labels, prot_read_write),
1128*ec63e07aSXin Li         ARG_32(3),  // flags
1129*ec63e07aSXin Li         JEQ32(MAP_FILE | MAP_PRIVATE | MAP_FIXED | MAP_DENYWRITE, ALLOW),
1130*ec63e07aSXin Li         JEQ32(MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, ALLOW),
1131*ec63e07aSXin Li         JEQ32(MAP_ANONYMOUS | MAP_PRIVATE, ALLOW),
1132*ec63e07aSXin Li         JUMP(&labels, mmap_end),
1133*ec63e07aSXin Li 
1134*ec63e07aSXin Li         // PROT_READ | PROT_EXEC
1135*ec63e07aSXin Li         LABEL(&labels, prot_exec),
1136*ec63e07aSXin Li         ARG_32(3),  // flags
1137*ec63e07aSXin Li         JEQ32(MAP_FILE | MAP_PRIVATE | MAP_DENYWRITE, ALLOW),
1138*ec63e07aSXin Li 
1139*ec63e07aSXin Li         LABEL(&labels, mmap_end),
1140*ec63e07aSXin Li     };
1141*ec63e07aSXin Li   });
1142*ec63e07aSXin Li }
1143*ec63e07aSXin Li 
AddPolicyOnSyscall(uint32_t num,absl::Span<const sock_filter> policy)1144*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AddPolicyOnSyscall(
1145*ec63e07aSXin Li     uint32_t num, absl::Span<const sock_filter> policy) {
1146*ec63e07aSXin Li   return AddPolicyOnSyscalls({num}, policy);
1147*ec63e07aSXin Li }
1148*ec63e07aSXin Li 
AddPolicyOnSyscall(uint32_t num,BpfFunc f)1149*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AddPolicyOnSyscall(uint32_t num, BpfFunc f) {
1150*ec63e07aSXin Li   return AddPolicyOnSyscalls({num}, f);
1151*ec63e07aSXin Li }
1152*ec63e07aSXin Li 
AddPolicyOnSyscalls(absl::Span<const uint32_t> nums,absl::Span<const sock_filter> policy)1153*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AddPolicyOnSyscalls(
1154*ec63e07aSXin Li     absl::Span<const uint32_t> nums, absl::Span<const sock_filter> policy) {
1155*ec63e07aSXin Li   if (nums.empty()) {
1156*ec63e07aSXin Li     SetError(absl::InvalidArgumentError(
1157*ec63e07aSXin Li         "Cannot add a policy for empty list of syscalls"));
1158*ec63e07aSXin Li     return *this;
1159*ec63e07aSXin Li   }
1160*ec63e07aSXin Li   std::deque<sock_filter> out;
1161*ec63e07aSXin Li   // Insert and verify the policy.
1162*ec63e07aSXin Li   out.insert(out.end(), policy.begin(), policy.end());
1163*ec63e07aSXin Li   for (size_t i = 0; i < out.size(); ++i) {
1164*ec63e07aSXin Li     sock_filter& filter = out[i];
1165*ec63e07aSXin Li     const size_t max_jump = out.size() - i - 1;
1166*ec63e07aSXin Li     if (!CheckBpfBounds(filter, max_jump)) {
1167*ec63e07aSXin Li       SetError(absl::InvalidArgumentError("bpf jump out of bounds"));
1168*ec63e07aSXin Li       return *this;
1169*ec63e07aSXin Li     }
1170*ec63e07aSXin Li     // Syscall arch is expected as TRACE value
1171*ec63e07aSXin Li     if (filter.code == (BPF_RET | BPF_K) &&
1172*ec63e07aSXin Li         (filter.k & SECCOMP_RET_ACTION) == SECCOMP_RET_TRACE &&
1173*ec63e07aSXin Li         (filter.k & SECCOMP_RET_DATA) != Syscall::GetHostArch()) {
1174*ec63e07aSXin Li       LOG(WARNING) << "SANDBOX2_TRACE should be used in policy instead of "
1175*ec63e07aSXin Li                       "TRACE(value)";
1176*ec63e07aSXin Li       filter = SANDBOX2_TRACE;
1177*ec63e07aSXin Li     }
1178*ec63e07aSXin Li   }
1179*ec63e07aSXin Li   // Pre-/Postcondition: Syscall number loaded into A register
1180*ec63e07aSXin Li   out.push_back(LOAD_SYSCALL_NR);
1181*ec63e07aSXin Li   if (out.size() > std::numeric_limits<uint32_t>::max()) {
1182*ec63e07aSXin Li     SetError(absl::InvalidArgumentError("syscall policy is too long"));
1183*ec63e07aSXin Li     return *this;
1184*ec63e07aSXin Li   }
1185*ec63e07aSXin Li   // Create jumps for each syscall.
1186*ec63e07aSXin Li   size_t do_policy_loc = out.size();
1187*ec63e07aSXin Li   // Iterate in reverse order and prepend instruction, so that jumps can be
1188*ec63e07aSXin Li   // calculated easily.
1189*ec63e07aSXin Li   constexpr size_t kMaxShortJump = 255;
1190*ec63e07aSXin Li   bool last = true;
1191*ec63e07aSXin Li   for (auto it = std::rbegin(nums); it != std::rend(nums); ++it) {
1192*ec63e07aSXin Li     if (*it == __NR_bpf || *it == __NR_ptrace) {
1193*ec63e07aSXin Li       SetError(absl::InvalidArgumentError(
1194*ec63e07aSXin Li           "cannot add policy for bpf/ptrace syscall"));
1195*ec63e07aSXin Li       return *this;
1196*ec63e07aSXin Li     }
1197*ec63e07aSXin Li     // If syscall is not matched try with the next one.
1198*ec63e07aSXin Li     uint8_t jf = 0;
1199*ec63e07aSXin Li     // If last syscall on the list does not match skip the policy by jumping
1200*ec63e07aSXin Li     // over it.
1201*ec63e07aSXin Li     if (last) {
1202*ec63e07aSXin Li       if (out.size() > kMaxShortJump) {
1203*ec63e07aSXin Li         out.push_front(
1204*ec63e07aSXin Li             BPF_STMT(BPF_JMP + BPF_JA, static_cast<uint32_t>(out.size())));
1205*ec63e07aSXin Li       } else {
1206*ec63e07aSXin Li         jf = out.size();
1207*ec63e07aSXin Li       }
1208*ec63e07aSXin Li       last = false;
1209*ec63e07aSXin Li     }
1210*ec63e07aSXin Li     // Add a helper absolute jump if needed - the policy/last helper jump is
1211*ec63e07aSXin Li     // out of reach of a short jump.
1212*ec63e07aSXin Li     if ((out.size() - do_policy_loc) > kMaxShortJump) {
1213*ec63e07aSXin Li       out.push_front(BPF_STMT(
1214*ec63e07aSXin Li           BPF_JMP + BPF_JA, static_cast<uint32_t>(out.size() - policy.size())));
1215*ec63e07aSXin Li       do_policy_loc = out.size();
1216*ec63e07aSXin Li       ++jf;
1217*ec63e07aSXin Li     }
1218*ec63e07aSXin Li     uint8_t jt = out.size() - do_policy_loc;
1219*ec63e07aSXin Li     out.push_front(BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, *it, jt, jf));
1220*ec63e07aSXin Li   }
1221*ec63e07aSXin Li   user_policy_.insert(user_policy_.end(), out.begin(), out.end());
1222*ec63e07aSXin Li   return *this;
1223*ec63e07aSXin Li }
1224*ec63e07aSXin Li 
AddPolicyOnSyscalls(absl::Span<const uint32_t> nums,BpfFunc f)1225*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AddPolicyOnSyscalls(
1226*ec63e07aSXin Li     absl::Span<const uint32_t> nums, BpfFunc f) {
1227*ec63e07aSXin Li   return AddPolicyOnSyscalls(nums, ResolveBpfFunc(f));
1228*ec63e07aSXin Li }
1229*ec63e07aSXin Li 
AddPolicyOnMmap(absl::Span<const sock_filter> policy)1230*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AddPolicyOnMmap(
1231*ec63e07aSXin Li     absl::Span<const sock_filter> policy) {
1232*ec63e07aSXin Li   return AddPolicyOnSyscalls(kMmapSyscalls, policy);
1233*ec63e07aSXin Li }
1234*ec63e07aSXin Li 
AddPolicyOnMmap(BpfFunc f)1235*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AddPolicyOnMmap(BpfFunc f) {
1236*ec63e07aSXin Li   return AddPolicyOnSyscalls(kMmapSyscalls, f);
1237*ec63e07aSXin Li }
1238*ec63e07aSXin Li 
DangerDefaultAllowAll()1239*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::DangerDefaultAllowAll() {
1240*ec63e07aSXin Li   return DefaultAction(AllowAllSyscalls());
1241*ec63e07aSXin Li }
1242*ec63e07aSXin Li 
DefaultAction(AllowAllSyscalls)1243*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::DefaultAction(AllowAllSyscalls) {
1244*ec63e07aSXin Li   default_action_ = ALLOW;
1245*ec63e07aSXin Li   return *this;
1246*ec63e07aSXin Li }
1247*ec63e07aSXin Li 
DefaultAction(TraceAllSyscalls)1248*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::DefaultAction(TraceAllSyscalls) {
1249*ec63e07aSXin Li   default_action_ = SANDBOX2_TRACE;
1250*ec63e07aSXin Li   return *this;
1251*ec63e07aSXin Li }
1252*ec63e07aSXin Li 
ValidateAbsolutePath(absl::string_view path)1253*ec63e07aSXin Li absl::StatusOr<std::string> PolicyBuilder::ValidateAbsolutePath(
1254*ec63e07aSXin Li     absl::string_view path) {
1255*ec63e07aSXin Li   if (!file::IsAbsolutePath(path)) {
1256*ec63e07aSXin Li     return absl::InvalidArgumentError(
1257*ec63e07aSXin Li         absl::StrCat("Path is not absolute: '", path, "'"));
1258*ec63e07aSXin Li   }
1259*ec63e07aSXin Li   return ValidatePath(path);
1260*ec63e07aSXin Li }
1261*ec63e07aSXin Li 
ValidatePath(absl::string_view path)1262*ec63e07aSXin Li absl::StatusOr<std::string> PolicyBuilder::ValidatePath(
1263*ec63e07aSXin Li     absl::string_view path) {
1264*ec63e07aSXin Li   std::string fixed_path = file::CleanPath(path);
1265*ec63e07aSXin Li   if (fixed_path != path) {
1266*ec63e07aSXin Li     return absl::InvalidArgumentError(absl::StrCat(
1267*ec63e07aSXin Li         "Path was not normalized. '", path, "' != '", fixed_path, "'"));
1268*ec63e07aSXin Li   }
1269*ec63e07aSXin Li   return fixed_path;
1270*ec63e07aSXin Li }
1271*ec63e07aSXin Li 
ResolveBpfFunc(BpfFunc f)1272*ec63e07aSXin Li std::vector<sock_filter> PolicyBuilder::ResolveBpfFunc(BpfFunc f) {
1273*ec63e07aSXin Li   bpf_labels l = {0};
1274*ec63e07aSXin Li 
1275*ec63e07aSXin Li   std::vector<sock_filter> policy = f(l);
1276*ec63e07aSXin Li   if (bpf_resolve_jumps(&l, policy.data(), policy.size()) != 0) {
1277*ec63e07aSXin Li     SetError(absl::InternalError("Cannot resolve bpf jumps"));
1278*ec63e07aSXin Li   }
1279*ec63e07aSXin Li 
1280*ec63e07aSXin Li   return policy;
1281*ec63e07aSXin Li }
1282*ec63e07aSXin Li 
TryBuild()1283*ec63e07aSXin Li absl::StatusOr<std::unique_ptr<Policy>> PolicyBuilder::TryBuild() {
1284*ec63e07aSXin Li   if (!last_status_.ok()) {
1285*ec63e07aSXin Li     return last_status_;
1286*ec63e07aSXin Li   }
1287*ec63e07aSXin Li 
1288*ec63e07aSXin Li   if (user_policy_.size() > kMaxUserPolicyLength) {
1289*ec63e07aSXin Li     return absl::FailedPreconditionError(
1290*ec63e07aSXin Li         absl::StrCat("User syscall policy is to long (", user_policy_.size(),
1291*ec63e07aSXin Li                      " > ", kMaxUserPolicyLength, ")."));
1292*ec63e07aSXin Li   }
1293*ec63e07aSXin Li 
1294*ec63e07aSXin Li   // Using `new` to access a non-public constructor.
1295*ec63e07aSXin Li   auto output = absl::WrapUnique(new Policy());
1296*ec63e07aSXin Li 
1297*ec63e07aSXin Li   if (already_built_) {
1298*ec63e07aSXin Li     return absl::FailedPreconditionError("Can only build policy once.");
1299*ec63e07aSXin Li   }
1300*ec63e07aSXin Li 
1301*ec63e07aSXin Li   if (use_namespaces_) {
1302*ec63e07aSXin Li     if (allow_unrestricted_networking_ && hostname_ != kDefaultHostname) {
1303*ec63e07aSXin Li       return absl::FailedPreconditionError(
1304*ec63e07aSXin Li           "Cannot set hostname without network namespaces.");
1305*ec63e07aSXin Li     }
1306*ec63e07aSXin Li     output->namespace_ =
1307*ec63e07aSXin Li         Namespace(allow_unrestricted_networking_, std::move(mounts_), hostname_,
1308*ec63e07aSXin Li                   allow_mount_propagation_);
1309*ec63e07aSXin Li   }
1310*ec63e07aSXin Li 
1311*ec63e07aSXin Li   output->collect_stacktrace_on_signal_ = collect_stacktrace_on_signal_;
1312*ec63e07aSXin Li   output->collect_stacktrace_on_violation_ = collect_stacktrace_on_violation_;
1313*ec63e07aSXin Li   output->collect_stacktrace_on_timeout_ = collect_stacktrace_on_timeout_;
1314*ec63e07aSXin Li   output->collect_stacktrace_on_kill_ = collect_stacktrace_on_kill_;
1315*ec63e07aSXin Li   output->collect_stacktrace_on_exit_ = collect_stacktrace_on_exit_;
1316*ec63e07aSXin Li   output->user_policy_ = std::move(user_policy_);
1317*ec63e07aSXin Li   if (default_action_) {
1318*ec63e07aSXin Li     output->user_policy_.push_back(*default_action_);
1319*ec63e07aSXin Li   }
1320*ec63e07aSXin Li   output->user_policy_.insert(output->user_policy_.end(),
1321*ec63e07aSXin Li                               overridable_policy_.begin(),
1322*ec63e07aSXin Li                               overridable_policy_.end());
1323*ec63e07aSXin Li   output->user_policy_handles_bpf_ = user_policy_handles_bpf_;
1324*ec63e07aSXin Li   output->user_policy_handles_ptrace_ = user_policy_handles_ptrace_;
1325*ec63e07aSXin Li 
1326*ec63e07aSXin Li   PolicyBuilderDescription pb_description;
1327*ec63e07aSXin Li 
1328*ec63e07aSXin Li   StoreDescription(&pb_description);
1329*ec63e07aSXin Li   output->policy_builder_description_ = pb_description;
1330*ec63e07aSXin Li   output->allowed_hosts_ = std::move(allowed_hosts_);
1331*ec63e07aSXin Li   already_built_ = true;
1332*ec63e07aSXin Li   return std::move(output);
1333*ec63e07aSXin Li }
1334*ec63e07aSXin Li 
AddFile(absl::string_view path,bool is_ro)1335*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AddFile(absl::string_view path, bool is_ro) {
1336*ec63e07aSXin Li   return AddFileAt(path, path, is_ro);
1337*ec63e07aSXin Li }
1338*ec63e07aSXin Li 
AddFileAt(absl::string_view outside,absl::string_view inside,bool is_ro)1339*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AddFileAt(absl::string_view outside,
1340*ec63e07aSXin Li                                         absl::string_view inside, bool is_ro) {
1341*ec63e07aSXin Li   EnableNamespaces();  // NOLINT(clang-diagnostic-deprecated-declarations)
1342*ec63e07aSXin Li   return AddFileAtIfNamespaced(outside, inside, is_ro);
1343*ec63e07aSXin Li }
1344*ec63e07aSXin Li 
AddFileIfNamespaced(absl::string_view path,bool is_ro)1345*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AddFileIfNamespaced(absl::string_view path,
1346*ec63e07aSXin Li                                                   bool is_ro) {
1347*ec63e07aSXin Li   return AddFileAtIfNamespaced(path, path, is_ro);
1348*ec63e07aSXin Li }
1349*ec63e07aSXin Li 
AddFileAtIfNamespaced(absl::string_view outside,absl::string_view inside,bool is_ro)1350*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AddFileAtIfNamespaced(absl::string_view outside,
1351*ec63e07aSXin Li                                                     absl::string_view inside,
1352*ec63e07aSXin Li                                                     bool is_ro) {
1353*ec63e07aSXin Li   auto valid_outside = ValidateAbsolutePath(outside);
1354*ec63e07aSXin Li   if (!valid_outside.ok()) {
1355*ec63e07aSXin Li     SetError(valid_outside.status());
1356*ec63e07aSXin Li     return *this;
1357*ec63e07aSXin Li   }
1358*ec63e07aSXin Li 
1359*ec63e07aSXin Li   if (absl::StartsWith(*valid_outside, "/proc/self") &&
1360*ec63e07aSXin Li       *valid_outside != "/proc/self/cpuset") {
1361*ec63e07aSXin Li     SetError(absl::InvalidArgumentError(
1362*ec63e07aSXin Li         absl::StrCat("Cannot add /proc/self mounts, you need to mount the "
1363*ec63e07aSXin Li                      "whole /proc instead. You tried to mount ",
1364*ec63e07aSXin Li                      outside)));
1365*ec63e07aSXin Li     return *this;
1366*ec63e07aSXin Li   }
1367*ec63e07aSXin Li 
1368*ec63e07aSXin Li   if (!is_ro && IsOnReadOnlyDev(*valid_outside)) {
1369*ec63e07aSXin Li     SetError(absl::FailedPreconditionError(
1370*ec63e07aSXin Li         absl::StrCat("Cannot add ", outside,
1371*ec63e07aSXin Li                      " as read-write as it's on a read-only device")));
1372*ec63e07aSXin Li     return *this;
1373*ec63e07aSXin Li   }
1374*ec63e07aSXin Li 
1375*ec63e07aSXin Li   if (auto status = mounts_.AddFileAt(*valid_outside, inside, is_ro);
1376*ec63e07aSXin Li       !status.ok()) {
1377*ec63e07aSXin Li     SetError(
1378*ec63e07aSXin Li         absl::InternalError(absl::StrCat("Could not add file ", outside, " => ",
1379*ec63e07aSXin Li                                          inside, ": ", status.message())));
1380*ec63e07aSXin Li   }
1381*ec63e07aSXin Li   return *this;
1382*ec63e07aSXin Li }
1383*ec63e07aSXin Li 
AddLibrariesForBinary(absl::string_view path,absl::string_view ld_library_path)1384*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AddLibrariesForBinary(
1385*ec63e07aSXin Li     absl::string_view path, absl::string_view ld_library_path) {
1386*ec63e07aSXin Li   EnableNamespaces();  // NOLINT(clang-diagnostic-deprecated-declarations)
1387*ec63e07aSXin Li 
1388*ec63e07aSXin Li   auto valid_path = ValidatePath(path);
1389*ec63e07aSXin Li   if (!valid_path.ok()) {
1390*ec63e07aSXin Li     SetError(valid_path.status());
1391*ec63e07aSXin Li     return *this;
1392*ec63e07aSXin Li   }
1393*ec63e07aSXin Li 
1394*ec63e07aSXin Li   if (auto status = mounts_.AddMappingsForBinary(*valid_path, ld_library_path);
1395*ec63e07aSXin Li       !status.ok()) {
1396*ec63e07aSXin Li     SetError(absl::InternalError(absl::StrCat(
1397*ec63e07aSXin Li         "Could not add libraries for ", *valid_path, ": ", status.message())));
1398*ec63e07aSXin Li   }
1399*ec63e07aSXin Li   return *this;
1400*ec63e07aSXin Li }
1401*ec63e07aSXin Li 
AddLibrariesForBinary(int fd,absl::string_view ld_library_path)1402*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AddLibrariesForBinary(
1403*ec63e07aSXin Li     int fd, absl::string_view ld_library_path) {
1404*ec63e07aSXin Li   return AddLibrariesForBinary(absl::StrCat("/proc/self/fd/", fd),
1405*ec63e07aSXin Li                                ld_library_path);
1406*ec63e07aSXin Li }
1407*ec63e07aSXin Li 
AddDirectory(absl::string_view path,bool is_ro)1408*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AddDirectory(absl::string_view path, bool is_ro) {
1409*ec63e07aSXin Li   return AddDirectoryAt(path, path, is_ro);
1410*ec63e07aSXin Li }
1411*ec63e07aSXin Li 
AddDirectoryAt(absl::string_view outside,absl::string_view inside,bool is_ro)1412*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AddDirectoryAt(absl::string_view outside,
1413*ec63e07aSXin Li                                              absl::string_view inside,
1414*ec63e07aSXin Li                                              bool is_ro) {
1415*ec63e07aSXin Li   EnableNamespaces();  // NOLINT(clang-diagnostic-deprecated-declarations)
1416*ec63e07aSXin Li   return AddDirectoryAtIfNamespaced(outside, inside, is_ro);
1417*ec63e07aSXin Li }
1418*ec63e07aSXin Li 
AddDirectoryIfNamespaced(absl::string_view path,bool is_ro)1419*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AddDirectoryIfNamespaced(absl::string_view path,
1420*ec63e07aSXin Li                                                        bool is_ro) {
1421*ec63e07aSXin Li   return AddDirectoryAtIfNamespaced(path, path, is_ro);
1422*ec63e07aSXin Li }
1423*ec63e07aSXin Li 
AddDirectoryAtIfNamespaced(absl::string_view outside,absl::string_view inside,bool is_ro)1424*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AddDirectoryAtIfNamespaced(
1425*ec63e07aSXin Li     absl::string_view outside, absl::string_view inside, bool is_ro) {
1426*ec63e07aSXin Li   auto valid_outside = ValidateAbsolutePath(outside);
1427*ec63e07aSXin Li   if (!valid_outside.ok()) {
1428*ec63e07aSXin Li     SetError(valid_outside.status());
1429*ec63e07aSXin Li     return *this;
1430*ec63e07aSXin Li   }
1431*ec63e07aSXin Li 
1432*ec63e07aSXin Li   if (absl::StartsWith(*valid_outside, "/proc/self")) {
1433*ec63e07aSXin Li     SetError(absl::InvalidArgumentError(
1434*ec63e07aSXin Li         absl::StrCat("Cannot add /proc/self mounts, you need to mount the "
1435*ec63e07aSXin Li                      "whole /proc instead. You tried to mount ",
1436*ec63e07aSXin Li                      outside)));
1437*ec63e07aSXin Li     return *this;
1438*ec63e07aSXin Li   }
1439*ec63e07aSXin Li 
1440*ec63e07aSXin Li   if (!is_ro && IsOnReadOnlyDev(*valid_outside)) {
1441*ec63e07aSXin Li     SetError(absl::FailedPreconditionError(
1442*ec63e07aSXin Li         absl::StrCat("Cannot add ", outside,
1443*ec63e07aSXin Li                      " as read-write as it's on a read-only device")));
1444*ec63e07aSXin Li     return *this;
1445*ec63e07aSXin Li   }
1446*ec63e07aSXin Li 
1447*ec63e07aSXin Li   if (absl::Status status =
1448*ec63e07aSXin Li           mounts_.AddDirectoryAt(*valid_outside, inside, is_ro);
1449*ec63e07aSXin Li       !status.ok()) {
1450*ec63e07aSXin Li     SetError(absl::InternalError(absl::StrCat("Could not add directory ",
1451*ec63e07aSXin Li                                               outside, " => ", inside, ": ",
1452*ec63e07aSXin Li                                               status.message())));
1453*ec63e07aSXin Li     return *this;
1454*ec63e07aSXin Li   }
1455*ec63e07aSXin Li   return *this;
1456*ec63e07aSXin Li }
1457*ec63e07aSXin Li 
AddTmpfs(absl::string_view inside,size_t size)1458*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AddTmpfs(absl::string_view inside, size_t size) {
1459*ec63e07aSXin Li   EnableNamespaces();  // NOLINT(clang-diagnostic-deprecated-declarations)
1460*ec63e07aSXin Li 
1461*ec63e07aSXin Li   if (auto status = mounts_.AddTmpfs(inside, size); !status.ok()) {
1462*ec63e07aSXin Li     SetError(absl::InternalError(absl::StrCat("Could not mount tmpfs ", inside,
1463*ec63e07aSXin Li                                               ": ", status.message())));
1464*ec63e07aSXin Li   }
1465*ec63e07aSXin Li   return *this;
1466*ec63e07aSXin Li }
1467*ec63e07aSXin Li 
1468*ec63e07aSXin Li // Use Allow(UnrestrictedNetworking()) instead.
AllowUnrestrictedNetworking()1469*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowUnrestrictedNetworking() {
1470*ec63e07aSXin Li   return Allow(UnrestrictedNetworking());
1471*ec63e07aSXin Li }
1472*ec63e07aSXin Li 
SetHostname(absl::string_view hostname)1473*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::SetHostname(absl::string_view hostname) {
1474*ec63e07aSXin Li   EnableNamespaces();  // NOLINT(clang-diagnostic-deprecated-declarations)
1475*ec63e07aSXin Li   hostname_ = std::string(hostname);
1476*ec63e07aSXin Li 
1477*ec63e07aSXin Li   return *this;
1478*ec63e07aSXin Li }
1479*ec63e07aSXin Li 
CollectStacktracesOnViolation(bool enable)1480*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::CollectStacktracesOnViolation(bool enable) {
1481*ec63e07aSXin Li   collect_stacktrace_on_violation_ = enable;
1482*ec63e07aSXin Li   return *this;
1483*ec63e07aSXin Li }
1484*ec63e07aSXin Li 
CollectStacktracesOnSignal(bool enable)1485*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::CollectStacktracesOnSignal(bool enable) {
1486*ec63e07aSXin Li   collect_stacktrace_on_signal_ = enable;
1487*ec63e07aSXin Li   return *this;
1488*ec63e07aSXin Li }
1489*ec63e07aSXin Li 
CollectStacktracesOnTimeout(bool enable)1490*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::CollectStacktracesOnTimeout(bool enable) {
1491*ec63e07aSXin Li   collect_stacktrace_on_timeout_ = enable;
1492*ec63e07aSXin Li   return *this;
1493*ec63e07aSXin Li }
1494*ec63e07aSXin Li 
CollectStacktracesOnKill(bool enable)1495*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::CollectStacktracesOnKill(bool enable) {
1496*ec63e07aSXin Li   collect_stacktrace_on_kill_ = enable;
1497*ec63e07aSXin Li   return *this;
1498*ec63e07aSXin Li }
1499*ec63e07aSXin Li 
CollectStacktracesOnExit(bool enable)1500*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::CollectStacktracesOnExit(bool enable) {
1501*ec63e07aSXin Li   collect_stacktrace_on_exit_ = enable;
1502*ec63e07aSXin Li   return *this;
1503*ec63e07aSXin Li }
1504*ec63e07aSXin Li 
AddNetworkProxyPolicy()1505*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AddNetworkProxyPolicy() {
1506*ec63e07aSXin Li   if (allowed_hosts_) {
1507*ec63e07aSXin Li     SetError(absl::FailedPreconditionError(
1508*ec63e07aSXin Li         "AddNetworkProxyPolicy or AddNetworkProxyHandlerPolicy can be called "
1509*ec63e07aSXin Li         "at most once"));
1510*ec63e07aSXin Li     return *this;
1511*ec63e07aSXin Li   }
1512*ec63e07aSXin Li 
1513*ec63e07aSXin Li   allowed_hosts_ = AllowedHosts();
1514*ec63e07aSXin Li 
1515*ec63e07aSXin Li   AllowFutexOp(FUTEX_WAKE);
1516*ec63e07aSXin Li   AllowFutexOp(FUTEX_WAIT);
1517*ec63e07aSXin Li   AllowFutexOp(FUTEX_WAIT_BITSET);
1518*ec63e07aSXin Li   AllowDup();
1519*ec63e07aSXin Li   AllowSyscalls({
1520*ec63e07aSXin Li       __NR_recvmsg,
1521*ec63e07aSXin Li       __NR_close,
1522*ec63e07aSXin Li       __NR_gettid,
1523*ec63e07aSXin Li   });
1524*ec63e07aSXin Li   AddPolicyOnSyscall(__NR_socket, {
1525*ec63e07aSXin Li                                       ARG_32(0),
1526*ec63e07aSXin Li                                       JEQ32(AF_INET, ALLOW),
1527*ec63e07aSXin Li                                       JEQ32(AF_INET6, ALLOW),
1528*ec63e07aSXin Li                                   });
1529*ec63e07aSXin Li   AddPolicyOnSyscall(__NR_getsockopt,
1530*ec63e07aSXin Li                      [](bpf_labels& labels) -> std::vector<sock_filter> {
1531*ec63e07aSXin Li                        return {
1532*ec63e07aSXin Li                            ARG_32(1),
1533*ec63e07aSXin Li                            JNE32(SOL_SOCKET, JUMP(&labels, getsockopt_end)),
1534*ec63e07aSXin Li                            ARG_32(2),
1535*ec63e07aSXin Li                            JEQ32(SO_TYPE, ALLOW),
1536*ec63e07aSXin Li                            LABEL(&labels, getsockopt_end),
1537*ec63e07aSXin Li                        };
1538*ec63e07aSXin Li                      });
1539*ec63e07aSXin Li #ifdef SAPI_PPC64_LE
1540*ec63e07aSXin Li   AddPolicyOnSyscall(__NR_socketcall, {
1541*ec63e07aSXin Li                                           ARG_32(0),
1542*ec63e07aSXin Li                                           JEQ32(SYS_SOCKET, ALLOW),
1543*ec63e07aSXin Li                                           JEQ32(SYS_GETSOCKOPT, ALLOW),
1544*ec63e07aSXin Li                                           JEQ32(SYS_RECVMSG, ALLOW),
1545*ec63e07aSXin Li                                       });
1546*ec63e07aSXin Li #endif
1547*ec63e07aSXin Li   return *this;
1548*ec63e07aSXin Li }
1549*ec63e07aSXin Li 
AddNetworkProxyHandlerPolicy()1550*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AddNetworkProxyHandlerPolicy() {
1551*ec63e07aSXin Li   AddNetworkProxyPolicy();
1552*ec63e07aSXin Li   AllowSyscall(__NR_rt_sigreturn);
1553*ec63e07aSXin Li 
1554*ec63e07aSXin Li   AddPolicyOnSyscall(__NR_rt_sigaction, {
1555*ec63e07aSXin Li                                             ARG_32(0),
1556*ec63e07aSXin Li                                             JEQ32(SIGSYS, ALLOW),
1557*ec63e07aSXin Li                                         });
1558*ec63e07aSXin Li 
1559*ec63e07aSXin Li   AddPolicyOnSyscall(__NR_rt_sigprocmask, {
1560*ec63e07aSXin Li                                               ARG_32(0),
1561*ec63e07aSXin Li                                               JEQ32(SIG_UNBLOCK, ALLOW),
1562*ec63e07aSXin Li                                           });
1563*ec63e07aSXin Li 
1564*ec63e07aSXin Li   AddPolicyOnSyscall(__NR_connect, {TRAP(0)});
1565*ec63e07aSXin Li #ifdef SAPI_PPC64_LE
1566*ec63e07aSXin Li   AddPolicyOnSyscall(__NR_socketcall, {
1567*ec63e07aSXin Li                                           ARG_32(0),
1568*ec63e07aSXin Li                                           JEQ32(SYS_CONNECT, TRAP(0)),
1569*ec63e07aSXin Li                                       });
1570*ec63e07aSXin Li #endif
1571*ec63e07aSXin Li   return *this;
1572*ec63e07aSXin Li }
1573*ec63e07aSXin Li 
TrapPtrace()1574*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::TrapPtrace() {
1575*ec63e07aSXin Li   if (handled_syscalls_.insert(__NR_ptrace).second) {
1576*ec63e07aSXin Li     user_policy_.insert(user_policy_.end(), {SYSCALL(__NR_ptrace, TRAP(0))});
1577*ec63e07aSXin Li     user_policy_handles_ptrace_ = true;
1578*ec63e07aSXin Li   }
1579*ec63e07aSXin Li   return *this;
1580*ec63e07aSXin Li }
1581*ec63e07aSXin Li 
SetRootWritable()1582*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::SetRootWritable() {
1583*ec63e07aSXin Li   EnableNamespaces();  // NOLINT(clang-diagnostic-deprecated-declarations)
1584*ec63e07aSXin Li   mounts_.SetRootWritable();
1585*ec63e07aSXin Li 
1586*ec63e07aSXin Li   return *this;
1587*ec63e07aSXin Li }
1588*ec63e07aSXin Li 
StoreDescription(PolicyBuilderDescription * pb_description)1589*ec63e07aSXin Li void PolicyBuilder::StoreDescription(PolicyBuilderDescription* pb_description) {
1590*ec63e07aSXin Li   for (const auto& handled_syscall : handled_syscalls_) {
1591*ec63e07aSXin Li     pb_description->add_handled_syscalls(handled_syscall);
1592*ec63e07aSXin Li   }
1593*ec63e07aSXin Li }
1594*ec63e07aSXin Li 
AllowIPv4(const std::string & ip_and_mask,uint32_t port)1595*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowIPv4(const std::string& ip_and_mask,
1596*ec63e07aSXin Li                                         uint32_t port) {
1597*ec63e07aSXin Li   if (!allowed_hosts_) {
1598*ec63e07aSXin Li     SetError(absl::FailedPreconditionError(
1599*ec63e07aSXin Li         "AddNetworkProxyPolicy or AddNetworkProxyHandlerPolicy must be called "
1600*ec63e07aSXin Li         "before adding IP rules"));
1601*ec63e07aSXin Li     return *this;
1602*ec63e07aSXin Li   }
1603*ec63e07aSXin Li 
1604*ec63e07aSXin Li   absl::Status status = allowed_hosts_->AllowIPv4(ip_and_mask, port);
1605*ec63e07aSXin Li   if (!status.ok()) {
1606*ec63e07aSXin Li     SetError(status);
1607*ec63e07aSXin Li   }
1608*ec63e07aSXin Li   return *this;
1609*ec63e07aSXin Li }
1610*ec63e07aSXin Li 
AllowIPv6(const std::string & ip_and_mask,uint32_t port)1611*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::AllowIPv6(const std::string& ip_and_mask,
1612*ec63e07aSXin Li                                         uint32_t port) {
1613*ec63e07aSXin Li   if (!allowed_hosts_) {
1614*ec63e07aSXin Li     SetError(absl::FailedPreconditionError(
1615*ec63e07aSXin Li         "AddNetworkProxyPolicy or AddNetworkProxyHandlerPolicy must be called "
1616*ec63e07aSXin Li         "before adding IP rules"));
1617*ec63e07aSXin Li     return *this;
1618*ec63e07aSXin Li   }
1619*ec63e07aSXin Li 
1620*ec63e07aSXin Li   absl::Status status = allowed_hosts_->AllowIPv6(ip_and_mask, port);
1621*ec63e07aSXin Li   if (!status.ok()) {
1622*ec63e07aSXin Li     SetError(status);
1623*ec63e07aSXin Li   }
1624*ec63e07aSXin Li   return *this;
1625*ec63e07aSXin Li }
1626*ec63e07aSXin Li 
SetError(const absl::Status & status)1627*ec63e07aSXin Li PolicyBuilder& PolicyBuilder::SetError(const absl::Status& status) {
1628*ec63e07aSXin Li   LOG(ERROR) << status;
1629*ec63e07aSXin Li   last_status_ = status;
1630*ec63e07aSXin Li   return *this;
1631*ec63e07aSXin Li }
1632*ec63e07aSXin Li 
1633*ec63e07aSXin Li }  // namespace sandbox2
1634