1*ba1276acSMatthew Dillon /*
2*ba1276acSMatthew Dillon * Copyright (c) 2012 Will Drewry <wad@dataspill.org>
3*ba1276acSMatthew Dillon * Copyright (c) 2015,2017,2019,2020,2023 Damien Miller <djm@mindrot.org>
4*ba1276acSMatthew Dillon *
5*ba1276acSMatthew Dillon * Permission to use, copy, modify, and distribute this software for any
6*ba1276acSMatthew Dillon * purpose with or without fee is hereby granted, provided that the above
7*ba1276acSMatthew Dillon * copyright notice and this permission notice appear in all copies.
8*ba1276acSMatthew Dillon *
9*ba1276acSMatthew Dillon * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10*ba1276acSMatthew Dillon * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*ba1276acSMatthew Dillon * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12*ba1276acSMatthew Dillon * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*ba1276acSMatthew Dillon * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*ba1276acSMatthew Dillon * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15*ba1276acSMatthew Dillon * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*ba1276acSMatthew Dillon */
17*ba1276acSMatthew Dillon
18*ba1276acSMatthew Dillon /*
19*ba1276acSMatthew Dillon * Uncomment the SANDBOX_SECCOMP_FILTER_DEBUG macro below to help diagnose
20*ba1276acSMatthew Dillon * filter breakage during development. *Do not* use this in production,
21*ba1276acSMatthew Dillon * as it relies on making library calls that are unsafe in signal context.
22*ba1276acSMatthew Dillon *
23*ba1276acSMatthew Dillon * Instead, live systems the auditctl(8) may be used to monitor failures.
24*ba1276acSMatthew Dillon * E.g.
25*ba1276acSMatthew Dillon * auditctl -a task,always -F uid=<privsep uid>
26*ba1276acSMatthew Dillon */
27*ba1276acSMatthew Dillon /* #define SANDBOX_SECCOMP_FILTER_DEBUG 1 */
28*ba1276acSMatthew Dillon
29*ba1276acSMatthew Dillon #if 0
30*ba1276acSMatthew Dillon /*
31*ba1276acSMatthew Dillon * For older toolchains, it may be necessary to use the kernel
32*ba1276acSMatthew Dillon * headers directly.
33*ba1276acSMatthew Dillon */
34*ba1276acSMatthew Dillon #ifdef SANDBOX_SECCOMP_FILTER_DEBUG
35*ba1276acSMatthew Dillon # include <asm/siginfo.h>
36*ba1276acSMatthew Dillon # define __have_siginfo_t 1
37*ba1276acSMatthew Dillon # define __have_sigval_t 1
38*ba1276acSMatthew Dillon # define __have_sigevent_t 1
39*ba1276acSMatthew Dillon #endif /* SANDBOX_SECCOMP_FILTER_DEBUG */
40*ba1276acSMatthew Dillon #endif
41*ba1276acSMatthew Dillon
42*ba1276acSMatthew Dillon #include "includes.h"
43*ba1276acSMatthew Dillon
44*ba1276acSMatthew Dillon #ifdef SANDBOX_SECCOMP_FILTER
45*ba1276acSMatthew Dillon
46*ba1276acSMatthew Dillon #include <sys/types.h>
47*ba1276acSMatthew Dillon #include <sys/resource.h>
48*ba1276acSMatthew Dillon #include <sys/prctl.h>
49*ba1276acSMatthew Dillon #include <sys/mman.h>
50*ba1276acSMatthew Dillon #include <sys/syscall.h>
51*ba1276acSMatthew Dillon
52*ba1276acSMatthew Dillon #include <linux/futex.h>
53*ba1276acSMatthew Dillon #include <linux/net.h>
54*ba1276acSMatthew Dillon #include <linux/audit.h>
55*ba1276acSMatthew Dillon #include <linux/filter.h>
56*ba1276acSMatthew Dillon #include <linux/seccomp.h>
57*ba1276acSMatthew Dillon #include <elf.h>
58*ba1276acSMatthew Dillon
59*ba1276acSMatthew Dillon #include <asm/unistd.h>
60*ba1276acSMatthew Dillon #ifdef __s390__
61*ba1276acSMatthew Dillon #include <asm/zcrypt.h>
62*ba1276acSMatthew Dillon #endif
63*ba1276acSMatthew Dillon
64*ba1276acSMatthew Dillon #include <errno.h>
65*ba1276acSMatthew Dillon #include <signal.h>
66*ba1276acSMatthew Dillon #include <stdarg.h>
67*ba1276acSMatthew Dillon #include <stddef.h> /* for offsetof */
68*ba1276acSMatthew Dillon #include <stdio.h>
69*ba1276acSMatthew Dillon #include <stdlib.h>
70*ba1276acSMatthew Dillon #include <string.h>
71*ba1276acSMatthew Dillon #include <unistd.h>
72*ba1276acSMatthew Dillon
73*ba1276acSMatthew Dillon #include "log.h"
74*ba1276acSMatthew Dillon #include "ssh-sandbox.h"
75*ba1276acSMatthew Dillon #include "xmalloc.h"
76*ba1276acSMatthew Dillon
77*ba1276acSMatthew Dillon /* Linux seccomp_filter sandbox */
78*ba1276acSMatthew Dillon #define SECCOMP_FILTER_FAIL SECCOMP_RET_KILL
79*ba1276acSMatthew Dillon
80*ba1276acSMatthew Dillon /* Use a signal handler to emit violations when debugging */
81*ba1276acSMatthew Dillon #ifdef SANDBOX_SECCOMP_FILTER_DEBUG
82*ba1276acSMatthew Dillon # undef SECCOMP_FILTER_FAIL
83*ba1276acSMatthew Dillon # define SECCOMP_FILTER_FAIL SECCOMP_RET_TRAP
84*ba1276acSMatthew Dillon #endif /* SANDBOX_SECCOMP_FILTER_DEBUG */
85*ba1276acSMatthew Dillon
86*ba1276acSMatthew Dillon #if __BYTE_ORDER == __LITTLE_ENDIAN
87*ba1276acSMatthew Dillon # define ARG_LO_OFFSET 0
88*ba1276acSMatthew Dillon # define ARG_HI_OFFSET sizeof(uint32_t)
89*ba1276acSMatthew Dillon #elif __BYTE_ORDER == __BIG_ENDIAN
90*ba1276acSMatthew Dillon # define ARG_LO_OFFSET sizeof(uint32_t)
91*ba1276acSMatthew Dillon # define ARG_HI_OFFSET 0
92*ba1276acSMatthew Dillon #else
93*ba1276acSMatthew Dillon #error "Unknown endianness"
94*ba1276acSMatthew Dillon #endif
95*ba1276acSMatthew Dillon
96*ba1276acSMatthew Dillon /* Simple helpers to avoid manual errors (but larger BPF programs). */
97*ba1276acSMatthew Dillon #define SC_DENY(_nr, _errno) \
98*ba1276acSMatthew Dillon BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (_nr), 0, 1), \
99*ba1276acSMatthew Dillon BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO|(_errno))
100*ba1276acSMatthew Dillon #define SC_ALLOW(_nr) \
101*ba1276acSMatthew Dillon BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (_nr), 0, 1), \
102*ba1276acSMatthew Dillon BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
103*ba1276acSMatthew Dillon #define SC_ALLOW_ARG(_nr, _arg_nr, _arg_val) \
104*ba1276acSMatthew Dillon BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (_nr), 0, 6), \
105*ba1276acSMatthew Dillon /* load and test syscall argument, low word */ \
106*ba1276acSMatthew Dillon BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
107*ba1276acSMatthew Dillon offsetof(struct seccomp_data, args[(_arg_nr)]) + ARG_LO_OFFSET), \
108*ba1276acSMatthew Dillon BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, \
109*ba1276acSMatthew Dillon ((_arg_val) & 0xFFFFFFFF), 0, 3), \
110*ba1276acSMatthew Dillon /* load and test syscall argument, high word */ \
111*ba1276acSMatthew Dillon BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
112*ba1276acSMatthew Dillon offsetof(struct seccomp_data, args[(_arg_nr)]) + ARG_HI_OFFSET), \
113*ba1276acSMatthew Dillon BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, \
114*ba1276acSMatthew Dillon (((uint32_t)((uint64_t)(_arg_val) >> 32)) & 0xFFFFFFFF), 0, 1), \
115*ba1276acSMatthew Dillon BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), \
116*ba1276acSMatthew Dillon /* reload syscall number; all rules expect it in accumulator */ \
117*ba1276acSMatthew Dillon BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
118*ba1276acSMatthew Dillon offsetof(struct seccomp_data, nr))
119*ba1276acSMatthew Dillon /* Allow if syscall argument contains only values in mask */
120*ba1276acSMatthew Dillon #define SC_ALLOW_ARG_MASK(_nr, _arg_nr, _arg_mask) \
121*ba1276acSMatthew Dillon BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (_nr), 0, 8), \
122*ba1276acSMatthew Dillon /* load, mask and test syscall argument, low word */ \
123*ba1276acSMatthew Dillon BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
124*ba1276acSMatthew Dillon offsetof(struct seccomp_data, args[(_arg_nr)]) + ARG_LO_OFFSET), \
125*ba1276acSMatthew Dillon BPF_STMT(BPF_ALU+BPF_AND+BPF_K, ~((_arg_mask) & 0xFFFFFFFF)), \
126*ba1276acSMatthew Dillon BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 4), \
127*ba1276acSMatthew Dillon /* load, mask and test syscall argument, high word */ \
128*ba1276acSMatthew Dillon BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
129*ba1276acSMatthew Dillon offsetof(struct seccomp_data, args[(_arg_nr)]) + ARG_HI_OFFSET), \
130*ba1276acSMatthew Dillon BPF_STMT(BPF_ALU+BPF_AND+BPF_K, \
131*ba1276acSMatthew Dillon ~(((uint32_t)((uint64_t)(_arg_mask) >> 32)) & 0xFFFFFFFF)), \
132*ba1276acSMatthew Dillon BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 1), \
133*ba1276acSMatthew Dillon BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), \
134*ba1276acSMatthew Dillon /* reload syscall number; all rules expect it in accumulator */ \
135*ba1276acSMatthew Dillon BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
136*ba1276acSMatthew Dillon offsetof(struct seccomp_data, nr))
137*ba1276acSMatthew Dillon /* Deny unless syscall argument contains only values in mask */
138*ba1276acSMatthew Dillon #define SC_DENY_UNLESS_ARG_MASK(_nr, _arg_nr, _arg_mask, _errno) \
139*ba1276acSMatthew Dillon BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (_nr), 0, 8), \
140*ba1276acSMatthew Dillon /* load, mask and test syscall argument, low word */ \
141*ba1276acSMatthew Dillon BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
142*ba1276acSMatthew Dillon offsetof(struct seccomp_data, args[(_arg_nr)]) + ARG_LO_OFFSET), \
143*ba1276acSMatthew Dillon BPF_STMT(BPF_ALU+BPF_AND+BPF_K, ~((_arg_mask) & 0xFFFFFFFF)), \
144*ba1276acSMatthew Dillon BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 3), \
145*ba1276acSMatthew Dillon /* load, mask and test syscall argument, high word */ \
146*ba1276acSMatthew Dillon BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
147*ba1276acSMatthew Dillon offsetof(struct seccomp_data, args[(_arg_nr)]) + ARG_HI_OFFSET), \
148*ba1276acSMatthew Dillon BPF_STMT(BPF_ALU+BPF_AND+BPF_K, \
149*ba1276acSMatthew Dillon ~(((uint32_t)((uint64_t)(_arg_mask) >> 32)) & 0xFFFFFFFF)), \
150*ba1276acSMatthew Dillon BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 1, 0), \
151*ba1276acSMatthew Dillon BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO|(_errno)), \
152*ba1276acSMatthew Dillon /* reload syscall number; all rules expect it in accumulator */ \
153*ba1276acSMatthew Dillon BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
154*ba1276acSMatthew Dillon offsetof(struct seccomp_data, nr))
155*ba1276acSMatthew Dillon #define SC_DENY_UNLESS_MASK(_nr, _arg_nr, _arg_val, _errno) \
156*ba1276acSMatthew Dillon /* Special handling for futex(2) that combines a bitmap and operation number */
157*ba1276acSMatthew Dillon #if defined(__NR_futex) || defined(__NR_futex_time64)
158*ba1276acSMatthew Dillon #define SC_FUTEX_MASK (FUTEX_PRIVATE_FLAG|FUTEX_CLOCK_REALTIME)
159*ba1276acSMatthew Dillon #define SC_ALLOW_FUTEX_OP(_nr, _op) \
160*ba1276acSMatthew Dillon BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (_nr), 0, 8), \
161*ba1276acSMatthew Dillon /* load syscall argument, low word */ \
162*ba1276acSMatthew Dillon BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
163*ba1276acSMatthew Dillon offsetof(struct seccomp_data, args[1]) + ARG_LO_OFFSET), \
164*ba1276acSMatthew Dillon /* mask off allowed bitmap values, low word */ \
165*ba1276acSMatthew Dillon BPF_STMT(BPF_ALU+BPF_AND+BPF_K, ~(SC_FUTEX_MASK & 0xFFFFFFFF)), \
166*ba1276acSMatthew Dillon /* test operation number, low word */ \
167*ba1276acSMatthew Dillon BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ((_op) & 0xFFFFFFFF), 0, 4), \
168*ba1276acSMatthew Dillon /* load syscall argument, high word */ \
169*ba1276acSMatthew Dillon BPF_STMT(BPF_LD+BPF_W+BPF_ABS, \
170*ba1276acSMatthew Dillon offsetof(struct seccomp_data, args[1]) + ARG_HI_OFFSET), \
171*ba1276acSMatthew Dillon /* mask off allowed bitmap values, high word */ \
172*ba1276acSMatthew Dillon BPF_STMT(BPF_ALU+BPF_AND+BPF_K, \
173*ba1276acSMatthew Dillon ~(((uint32_t)((uint64_t)SC_FUTEX_MASK >> 32)) & 0xFFFFFFFF)), \
174*ba1276acSMatthew Dillon /* test operation number, high word */ \
175*ba1276acSMatthew Dillon BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, \
176*ba1276acSMatthew Dillon (((uint32_t)((uint64_t)(_op) >> 32)) & 0xFFFFFFFF), 0, 1), \
177*ba1276acSMatthew Dillon BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW), \
178*ba1276acSMatthew Dillon /* reload syscall number; all rules expect it in accumulator */ \
179*ba1276acSMatthew Dillon BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct seccomp_data, nr))
180*ba1276acSMatthew Dillon
181*ba1276acSMatthew Dillon /* Use this for both __NR_futex and __NR_futex_time64 */
182*ba1276acSMatthew Dillon # define SC_FUTEX(_nr) \
183*ba1276acSMatthew Dillon SC_ALLOW_FUTEX_OP(__NR_futex, FUTEX_WAIT), \
184*ba1276acSMatthew Dillon SC_ALLOW_FUTEX_OP(__NR_futex, FUTEX_WAIT_BITSET), \
185*ba1276acSMatthew Dillon SC_ALLOW_FUTEX_OP(__NR_futex, FUTEX_WAKE), \
186*ba1276acSMatthew Dillon SC_ALLOW_FUTEX_OP(__NR_futex, FUTEX_WAKE_BITSET), \
187*ba1276acSMatthew Dillon SC_ALLOW_FUTEX_OP(__NR_futex, FUTEX_REQUEUE), \
188*ba1276acSMatthew Dillon SC_ALLOW_FUTEX_OP(__NR_futex, FUTEX_CMP_REQUEUE)
189*ba1276acSMatthew Dillon #endif /* __NR_futex || __NR_futex_time64 */
190*ba1276acSMatthew Dillon
191*ba1276acSMatthew Dillon #if defined(__NR_mmap) || defined(__NR_mmap2)
192*ba1276acSMatthew Dillon # ifdef MAP_FIXED_NOREPLACE
193*ba1276acSMatthew Dillon # define SC_MMAP_FLAGS MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED|MAP_FIXED_NOREPLACE
194*ba1276acSMatthew Dillon # else
195*ba1276acSMatthew Dillon # define SC_MMAP_FLAGS MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED
196*ba1276acSMatthew Dillon # endif /* MAP_FIXED_NOREPLACE */
197*ba1276acSMatthew Dillon /* Use this for both __NR_mmap and __NR_mmap2 variants */
198*ba1276acSMatthew Dillon # define SC_MMAP(_nr) \
199*ba1276acSMatthew Dillon SC_DENY_UNLESS_ARG_MASK(_nr, 3, SC_MMAP_FLAGS, EINVAL), \
200*ba1276acSMatthew Dillon SC_ALLOW_ARG_MASK(_nr, 2, PROT_READ|PROT_WRITE|PROT_NONE)
201*ba1276acSMatthew Dillon #endif /* __NR_mmap || __NR_mmap2 */
202*ba1276acSMatthew Dillon
203*ba1276acSMatthew Dillon /* Syscall filtering set for preauth. */
204*ba1276acSMatthew Dillon static const struct sock_filter preauth_insns[] = {
205*ba1276acSMatthew Dillon /* Ensure the syscall arch convention is as expected. */
206*ba1276acSMatthew Dillon BPF_STMT(BPF_LD+BPF_W+BPF_ABS,
207*ba1276acSMatthew Dillon offsetof(struct seccomp_data, arch)),
208*ba1276acSMatthew Dillon BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SECCOMP_AUDIT_ARCH, 1, 0),
209*ba1276acSMatthew Dillon BPF_STMT(BPF_RET+BPF_K, SECCOMP_FILTER_FAIL),
210*ba1276acSMatthew Dillon /* Load the syscall number for checking. */
211*ba1276acSMatthew Dillon BPF_STMT(BPF_LD+BPF_W+BPF_ABS,
212*ba1276acSMatthew Dillon offsetof(struct seccomp_data, nr)),
213*ba1276acSMatthew Dillon
214*ba1276acSMatthew Dillon /* Syscalls to non-fatally deny */
215*ba1276acSMatthew Dillon #ifdef __NR_lstat
216*ba1276acSMatthew Dillon SC_DENY(__NR_lstat, EACCES),
217*ba1276acSMatthew Dillon #endif
218*ba1276acSMatthew Dillon #ifdef __NR_lstat64
219*ba1276acSMatthew Dillon SC_DENY(__NR_lstat64, EACCES),
220*ba1276acSMatthew Dillon #endif
221*ba1276acSMatthew Dillon #ifdef __NR_fstat
222*ba1276acSMatthew Dillon SC_DENY(__NR_fstat, EACCES),
223*ba1276acSMatthew Dillon #endif
224*ba1276acSMatthew Dillon #ifdef __NR_fstat64
225*ba1276acSMatthew Dillon SC_DENY(__NR_fstat64, EACCES),
226*ba1276acSMatthew Dillon #endif
227*ba1276acSMatthew Dillon #ifdef __NR_fstatat64
228*ba1276acSMatthew Dillon SC_DENY(__NR_fstatat64, EACCES),
229*ba1276acSMatthew Dillon #endif
230*ba1276acSMatthew Dillon #ifdef __NR_open
231*ba1276acSMatthew Dillon SC_DENY(__NR_open, EACCES),
232*ba1276acSMatthew Dillon #endif
233*ba1276acSMatthew Dillon #ifdef __NR_openat
234*ba1276acSMatthew Dillon SC_DENY(__NR_openat, EACCES),
235*ba1276acSMatthew Dillon #endif
236*ba1276acSMatthew Dillon #ifdef __NR_newfstatat
237*ba1276acSMatthew Dillon SC_DENY(__NR_newfstatat, EACCES),
238*ba1276acSMatthew Dillon #endif
239*ba1276acSMatthew Dillon #ifdef __NR_stat
240*ba1276acSMatthew Dillon SC_DENY(__NR_stat, EACCES),
241*ba1276acSMatthew Dillon #endif
242*ba1276acSMatthew Dillon #ifdef __NR_stat64
243*ba1276acSMatthew Dillon SC_DENY(__NR_stat64, EACCES),
244*ba1276acSMatthew Dillon #endif
245*ba1276acSMatthew Dillon #ifdef __NR_shmget
246*ba1276acSMatthew Dillon SC_DENY(__NR_shmget, EACCES),
247*ba1276acSMatthew Dillon #endif
248*ba1276acSMatthew Dillon #ifdef __NR_shmat
249*ba1276acSMatthew Dillon SC_DENY(__NR_shmat, EACCES),
250*ba1276acSMatthew Dillon #endif
251*ba1276acSMatthew Dillon #ifdef __NR_shmdt
252*ba1276acSMatthew Dillon SC_DENY(__NR_shmdt, EACCES),
253*ba1276acSMatthew Dillon #endif
254*ba1276acSMatthew Dillon #ifdef __NR_ipc
255*ba1276acSMatthew Dillon SC_DENY(__NR_ipc, EACCES),
256*ba1276acSMatthew Dillon #endif
257*ba1276acSMatthew Dillon #ifdef __NR_statx
258*ba1276acSMatthew Dillon SC_DENY(__NR_statx, EACCES),
259*ba1276acSMatthew Dillon #endif
260*ba1276acSMatthew Dillon
261*ba1276acSMatthew Dillon /* Syscalls to permit */
262*ba1276acSMatthew Dillon #ifdef __NR_brk
263*ba1276acSMatthew Dillon SC_ALLOW(__NR_brk),
264*ba1276acSMatthew Dillon #endif
265*ba1276acSMatthew Dillon #ifdef __NR_clock_gettime
266*ba1276acSMatthew Dillon SC_ALLOW(__NR_clock_gettime),
267*ba1276acSMatthew Dillon #endif
268*ba1276acSMatthew Dillon #ifdef __NR_clock_gettime64
269*ba1276acSMatthew Dillon SC_ALLOW(__NR_clock_gettime64),
270*ba1276acSMatthew Dillon #endif
271*ba1276acSMatthew Dillon #ifdef __NR_close
272*ba1276acSMatthew Dillon SC_ALLOW(__NR_close),
273*ba1276acSMatthew Dillon #endif
274*ba1276acSMatthew Dillon #ifdef __NR_exit
275*ba1276acSMatthew Dillon SC_ALLOW(__NR_exit),
276*ba1276acSMatthew Dillon #endif
277*ba1276acSMatthew Dillon #ifdef __NR_exit_group
278*ba1276acSMatthew Dillon SC_ALLOW(__NR_exit_group),
279*ba1276acSMatthew Dillon #endif
280*ba1276acSMatthew Dillon #ifdef __NR_futex
281*ba1276acSMatthew Dillon SC_FUTEX(__NR_futex),
282*ba1276acSMatthew Dillon #endif
283*ba1276acSMatthew Dillon #ifdef __NR_futex_time64
284*ba1276acSMatthew Dillon SC_FUTEX(__NR_futex_time64),
285*ba1276acSMatthew Dillon #endif
286*ba1276acSMatthew Dillon #ifdef __NR_geteuid
287*ba1276acSMatthew Dillon SC_ALLOW(__NR_geteuid),
288*ba1276acSMatthew Dillon #endif
289*ba1276acSMatthew Dillon #ifdef __NR_geteuid32
290*ba1276acSMatthew Dillon SC_ALLOW(__NR_geteuid32),
291*ba1276acSMatthew Dillon #endif
292*ba1276acSMatthew Dillon #ifdef __NR_getpgid
293*ba1276acSMatthew Dillon SC_ALLOW(__NR_getpgid),
294*ba1276acSMatthew Dillon #endif
295*ba1276acSMatthew Dillon #ifdef __NR_getpid
296*ba1276acSMatthew Dillon SC_ALLOW(__NR_getpid),
297*ba1276acSMatthew Dillon #endif
298*ba1276acSMatthew Dillon #ifdef __NR_getrandom
299*ba1276acSMatthew Dillon SC_ALLOW(__NR_getrandom),
300*ba1276acSMatthew Dillon #endif
301*ba1276acSMatthew Dillon #ifdef __NR_gettid
302*ba1276acSMatthew Dillon SC_ALLOW(__NR_gettid),
303*ba1276acSMatthew Dillon #endif
304*ba1276acSMatthew Dillon #ifdef __NR_gettimeofday
305*ba1276acSMatthew Dillon SC_ALLOW(__NR_gettimeofday),
306*ba1276acSMatthew Dillon #endif
307*ba1276acSMatthew Dillon #ifdef __NR_getuid
308*ba1276acSMatthew Dillon SC_ALLOW(__NR_getuid),
309*ba1276acSMatthew Dillon #endif
310*ba1276acSMatthew Dillon #ifdef __NR_getuid32
311*ba1276acSMatthew Dillon SC_ALLOW(__NR_getuid32),
312*ba1276acSMatthew Dillon #endif
313*ba1276acSMatthew Dillon #ifdef __NR_madvise
314*ba1276acSMatthew Dillon SC_ALLOW_ARG(__NR_madvise, 2, MADV_NORMAL),
315*ba1276acSMatthew Dillon # ifdef MADV_FREE
316*ba1276acSMatthew Dillon SC_ALLOW_ARG(__NR_madvise, 2, MADV_FREE),
317*ba1276acSMatthew Dillon # endif
318*ba1276acSMatthew Dillon # ifdef MADV_DONTNEED
319*ba1276acSMatthew Dillon SC_ALLOW_ARG(__NR_madvise, 2, MADV_DONTNEED),
320*ba1276acSMatthew Dillon # endif
321*ba1276acSMatthew Dillon # ifdef MADV_DONTFORK
322*ba1276acSMatthew Dillon SC_ALLOW_ARG(__NR_madvise, 2, MADV_DONTFORK),
323*ba1276acSMatthew Dillon # endif
324*ba1276acSMatthew Dillon # ifdef MADV_DONTDUMP
325*ba1276acSMatthew Dillon SC_ALLOW_ARG(__NR_madvise, 2, MADV_DONTDUMP),
326*ba1276acSMatthew Dillon # endif
327*ba1276acSMatthew Dillon # ifdef MADV_WIPEONFORK
328*ba1276acSMatthew Dillon SC_ALLOW_ARG(__NR_madvise, 2, MADV_WIPEONFORK),
329*ba1276acSMatthew Dillon # endif
330*ba1276acSMatthew Dillon SC_DENY(__NR_madvise, EINVAL),
331*ba1276acSMatthew Dillon #endif
332*ba1276acSMatthew Dillon #ifdef __NR_mmap
333*ba1276acSMatthew Dillon SC_MMAP(__NR_mmap),
334*ba1276acSMatthew Dillon #endif
335*ba1276acSMatthew Dillon #ifdef __NR_mmap2
336*ba1276acSMatthew Dillon SC_MMAP(__NR_mmap2),
337*ba1276acSMatthew Dillon #endif
338*ba1276acSMatthew Dillon #ifdef __NR_mprotect
339*ba1276acSMatthew Dillon SC_ALLOW_ARG_MASK(__NR_mprotect, 2, PROT_READ|PROT_WRITE|PROT_NONE),
340*ba1276acSMatthew Dillon #endif
341*ba1276acSMatthew Dillon #ifdef __NR_mremap
342*ba1276acSMatthew Dillon SC_ALLOW(__NR_mremap),
343*ba1276acSMatthew Dillon #endif
344*ba1276acSMatthew Dillon #ifdef __NR_munmap
345*ba1276acSMatthew Dillon SC_ALLOW(__NR_munmap),
346*ba1276acSMatthew Dillon #endif
347*ba1276acSMatthew Dillon #ifdef __NR_nanosleep
348*ba1276acSMatthew Dillon SC_ALLOW(__NR_nanosleep),
349*ba1276acSMatthew Dillon #endif
350*ba1276acSMatthew Dillon #ifdef __NR_clock_nanosleep
351*ba1276acSMatthew Dillon SC_ALLOW(__NR_clock_nanosleep),
352*ba1276acSMatthew Dillon #endif
353*ba1276acSMatthew Dillon #ifdef __NR_clock_nanosleep_time64
354*ba1276acSMatthew Dillon SC_ALLOW(__NR_clock_nanosleep_time64),
355*ba1276acSMatthew Dillon #endif
356*ba1276acSMatthew Dillon #ifdef __NR_clock_gettime64
357*ba1276acSMatthew Dillon SC_ALLOW(__NR_clock_gettime64),
358*ba1276acSMatthew Dillon #endif
359*ba1276acSMatthew Dillon #ifdef __NR__newselect
360*ba1276acSMatthew Dillon SC_ALLOW(__NR__newselect),
361*ba1276acSMatthew Dillon #endif
362*ba1276acSMatthew Dillon #ifdef __NR_ppoll
363*ba1276acSMatthew Dillon SC_ALLOW(__NR_ppoll),
364*ba1276acSMatthew Dillon #endif
365*ba1276acSMatthew Dillon #ifdef __NR_ppoll_time64
366*ba1276acSMatthew Dillon SC_ALLOW(__NR_ppoll_time64),
367*ba1276acSMatthew Dillon #endif
368*ba1276acSMatthew Dillon #ifdef __NR_poll
369*ba1276acSMatthew Dillon SC_ALLOW(__NR_poll),
370*ba1276acSMatthew Dillon #endif
371*ba1276acSMatthew Dillon #ifdef __NR_pselect6
372*ba1276acSMatthew Dillon SC_ALLOW(__NR_pselect6),
373*ba1276acSMatthew Dillon #endif
374*ba1276acSMatthew Dillon #ifdef __NR_pselect6_time64
375*ba1276acSMatthew Dillon SC_ALLOW(__NR_pselect6_time64),
376*ba1276acSMatthew Dillon #endif
377*ba1276acSMatthew Dillon #ifdef __NR_read
378*ba1276acSMatthew Dillon SC_ALLOW(__NR_read),
379*ba1276acSMatthew Dillon #endif
380*ba1276acSMatthew Dillon #ifdef __NR_rt_sigprocmask
381*ba1276acSMatthew Dillon SC_ALLOW(__NR_rt_sigprocmask),
382*ba1276acSMatthew Dillon #endif
383*ba1276acSMatthew Dillon #ifdef __NR_select
384*ba1276acSMatthew Dillon SC_ALLOW(__NR_select),
385*ba1276acSMatthew Dillon #endif
386*ba1276acSMatthew Dillon #ifdef __NR_shutdown
387*ba1276acSMatthew Dillon SC_ALLOW(__NR_shutdown),
388*ba1276acSMatthew Dillon #endif
389*ba1276acSMatthew Dillon #ifdef __NR_sigprocmask
390*ba1276acSMatthew Dillon SC_ALLOW(__NR_sigprocmask),
391*ba1276acSMatthew Dillon #endif
392*ba1276acSMatthew Dillon #ifdef __NR_time
393*ba1276acSMatthew Dillon SC_ALLOW(__NR_time),
394*ba1276acSMatthew Dillon #endif
395*ba1276acSMatthew Dillon #ifdef __NR_write
396*ba1276acSMatthew Dillon SC_ALLOW(__NR_write),
397*ba1276acSMatthew Dillon #endif
398*ba1276acSMatthew Dillon #ifdef __NR_writev
399*ba1276acSMatthew Dillon SC_ALLOW(__NR_writev),
400*ba1276acSMatthew Dillon #endif
401*ba1276acSMatthew Dillon #ifdef __NR_socketcall
402*ba1276acSMatthew Dillon SC_ALLOW_ARG(__NR_socketcall, 0, SYS_SHUTDOWN),
403*ba1276acSMatthew Dillon SC_DENY(__NR_socketcall, EACCES),
404*ba1276acSMatthew Dillon #endif
405*ba1276acSMatthew Dillon #if defined(__NR_ioctl) && defined(__s390__)
406*ba1276acSMatthew Dillon /* Allow ioctls for ICA crypto card on s390 */
407*ba1276acSMatthew Dillon SC_ALLOW_ARG(__NR_ioctl, 1, Z90STAT_STATUS_MASK),
408*ba1276acSMatthew Dillon SC_ALLOW_ARG(__NR_ioctl, 1, ICARSAMODEXPO),
409*ba1276acSMatthew Dillon SC_ALLOW_ARG(__NR_ioctl, 1, ICARSACRT),
410*ba1276acSMatthew Dillon SC_ALLOW_ARG(__NR_ioctl, 1, ZSECSENDCPRB),
411*ba1276acSMatthew Dillon /* Allow ioctls for EP11 crypto card on s390 */
412*ba1276acSMatthew Dillon SC_ALLOW_ARG(__NR_ioctl, 1, ZSENDEP11CPRB),
413*ba1276acSMatthew Dillon #endif
414*ba1276acSMatthew Dillon #if defined(__x86_64__) && defined(__ILP32__) && defined(__X32_SYSCALL_BIT)
415*ba1276acSMatthew Dillon /*
416*ba1276acSMatthew Dillon * On Linux x32, the clock_gettime VDSO falls back to the
417*ba1276acSMatthew Dillon * x86-64 syscall under some circumstances, e.g.
418*ba1276acSMatthew Dillon * https://bugs.debian.org/849923
419*ba1276acSMatthew Dillon */
420*ba1276acSMatthew Dillon SC_ALLOW(__NR_clock_gettime & ~__X32_SYSCALL_BIT),
421*ba1276acSMatthew Dillon #endif
422*ba1276acSMatthew Dillon
423*ba1276acSMatthew Dillon /* Default deny */
424*ba1276acSMatthew Dillon BPF_STMT(BPF_RET+BPF_K, SECCOMP_FILTER_FAIL),
425*ba1276acSMatthew Dillon };
426*ba1276acSMatthew Dillon
427*ba1276acSMatthew Dillon static const struct sock_fprog preauth_program = {
428*ba1276acSMatthew Dillon .len = (unsigned short)(sizeof(preauth_insns)/sizeof(preauth_insns[0])),
429*ba1276acSMatthew Dillon .filter = (struct sock_filter *)preauth_insns,
430*ba1276acSMatthew Dillon };
431*ba1276acSMatthew Dillon
432*ba1276acSMatthew Dillon struct ssh_sandbox {
433*ba1276acSMatthew Dillon pid_t child_pid;
434*ba1276acSMatthew Dillon };
435*ba1276acSMatthew Dillon
436*ba1276acSMatthew Dillon struct ssh_sandbox *
ssh_sandbox_init(struct monitor * monitor)437*ba1276acSMatthew Dillon ssh_sandbox_init(struct monitor *monitor)
438*ba1276acSMatthew Dillon {
439*ba1276acSMatthew Dillon struct ssh_sandbox *box;
440*ba1276acSMatthew Dillon
441*ba1276acSMatthew Dillon /*
442*ba1276acSMatthew Dillon * Strictly, we don't need to maintain any state here but we need
443*ba1276acSMatthew Dillon * to return non-NULL to satisfy the API.
444*ba1276acSMatthew Dillon */
445*ba1276acSMatthew Dillon debug3("%s: preparing seccomp filter sandbox", __func__);
446*ba1276acSMatthew Dillon box = xcalloc(1, sizeof(*box));
447*ba1276acSMatthew Dillon box->child_pid = 0;
448*ba1276acSMatthew Dillon
449*ba1276acSMatthew Dillon return box;
450*ba1276acSMatthew Dillon }
451*ba1276acSMatthew Dillon
452*ba1276acSMatthew Dillon #ifdef SANDBOX_SECCOMP_FILTER_DEBUG
453*ba1276acSMatthew Dillon extern struct monitor *pmonitor;
454*ba1276acSMatthew Dillon void mm_log_handler(LogLevel level, int forced, const char *msg, void *ctx);
455*ba1276acSMatthew Dillon
456*ba1276acSMatthew Dillon static void
ssh_sandbox_violation(int signum,siginfo_t * info,void * void_context)457*ba1276acSMatthew Dillon ssh_sandbox_violation(int signum, siginfo_t *info, void *void_context)
458*ba1276acSMatthew Dillon {
459*ba1276acSMatthew Dillon char msg[256];
460*ba1276acSMatthew Dillon
461*ba1276acSMatthew Dillon snprintf(msg, sizeof(msg),
462*ba1276acSMatthew Dillon "%s: unexpected system call (arch:0x%x,syscall:%d @ %p)",
463*ba1276acSMatthew Dillon __func__, info->si_arch, info->si_syscall, info->si_call_addr);
464*ba1276acSMatthew Dillon mm_log_handler(SYSLOG_LEVEL_FATAL, 0, msg, pmonitor);
465*ba1276acSMatthew Dillon _exit(1);
466*ba1276acSMatthew Dillon }
467*ba1276acSMatthew Dillon
468*ba1276acSMatthew Dillon static void
ssh_sandbox_child_debugging(void)469*ba1276acSMatthew Dillon ssh_sandbox_child_debugging(void)
470*ba1276acSMatthew Dillon {
471*ba1276acSMatthew Dillon struct sigaction act;
472*ba1276acSMatthew Dillon sigset_t mask;
473*ba1276acSMatthew Dillon
474*ba1276acSMatthew Dillon debug3("%s: installing SIGSYS handler", __func__);
475*ba1276acSMatthew Dillon memset(&act, 0, sizeof(act));
476*ba1276acSMatthew Dillon sigemptyset(&mask);
477*ba1276acSMatthew Dillon sigaddset(&mask, SIGSYS);
478*ba1276acSMatthew Dillon
479*ba1276acSMatthew Dillon act.sa_sigaction = &ssh_sandbox_violation;
480*ba1276acSMatthew Dillon act.sa_flags = SA_SIGINFO;
481*ba1276acSMatthew Dillon if (sigaction(SIGSYS, &act, NULL) == -1)
482*ba1276acSMatthew Dillon fatal("%s: sigaction(SIGSYS): %s", __func__, strerror(errno));
483*ba1276acSMatthew Dillon if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
484*ba1276acSMatthew Dillon fatal("%s: sigprocmask(SIGSYS): %s",
485*ba1276acSMatthew Dillon __func__, strerror(errno));
486*ba1276acSMatthew Dillon }
487*ba1276acSMatthew Dillon #endif /* SANDBOX_SECCOMP_FILTER_DEBUG */
488*ba1276acSMatthew Dillon
489*ba1276acSMatthew Dillon void
ssh_sandbox_child(struct ssh_sandbox * box)490*ba1276acSMatthew Dillon ssh_sandbox_child(struct ssh_sandbox *box)
491*ba1276acSMatthew Dillon {
492*ba1276acSMatthew Dillon struct rlimit rl_zero, rl_one = {.rlim_cur = 1, .rlim_max = 1};
493*ba1276acSMatthew Dillon int nnp_failed = 0;
494*ba1276acSMatthew Dillon
495*ba1276acSMatthew Dillon /* Set rlimits for completeness if possible. */
496*ba1276acSMatthew Dillon rl_zero.rlim_cur = rl_zero.rlim_max = 0;
497*ba1276acSMatthew Dillon if (setrlimit(RLIMIT_FSIZE, &rl_zero) == -1)
498*ba1276acSMatthew Dillon fatal("%s: setrlimit(RLIMIT_FSIZE, { 0, 0 }): %s",
499*ba1276acSMatthew Dillon __func__, strerror(errno));
500*ba1276acSMatthew Dillon /*
501*ba1276acSMatthew Dillon * Cannot use zero for nfds, because poll(2) will fail with
502*ba1276acSMatthew Dillon * errno=EINVAL if npfds>RLIMIT_NOFILE.
503*ba1276acSMatthew Dillon */
504*ba1276acSMatthew Dillon if (setrlimit(RLIMIT_NOFILE, &rl_one) == -1)
505*ba1276acSMatthew Dillon fatal("%s: setrlimit(RLIMIT_NOFILE, { 0, 0 }): %s",
506*ba1276acSMatthew Dillon __func__, strerror(errno));
507*ba1276acSMatthew Dillon if (setrlimit(RLIMIT_NPROC, &rl_zero) == -1)
508*ba1276acSMatthew Dillon fatal("%s: setrlimit(RLIMIT_NPROC, { 0, 0 }): %s",
509*ba1276acSMatthew Dillon __func__, strerror(errno));
510*ba1276acSMatthew Dillon
511*ba1276acSMatthew Dillon #ifdef SANDBOX_SECCOMP_FILTER_DEBUG
512*ba1276acSMatthew Dillon ssh_sandbox_child_debugging();
513*ba1276acSMatthew Dillon #endif /* SANDBOX_SECCOMP_FILTER_DEBUG */
514*ba1276acSMatthew Dillon
515*ba1276acSMatthew Dillon debug3("%s: setting PR_SET_NO_NEW_PRIVS", __func__);
516*ba1276acSMatthew Dillon if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) {
517*ba1276acSMatthew Dillon debug("%s: prctl(PR_SET_NO_NEW_PRIVS): %s",
518*ba1276acSMatthew Dillon __func__, strerror(errno));
519*ba1276acSMatthew Dillon nnp_failed = 1;
520*ba1276acSMatthew Dillon }
521*ba1276acSMatthew Dillon debug3("%s: attaching seccomp filter program", __func__);
522*ba1276acSMatthew Dillon if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &preauth_program) == -1)
523*ba1276acSMatthew Dillon debug("%s: prctl(PR_SET_SECCOMP): %s",
524*ba1276acSMatthew Dillon __func__, strerror(errno));
525*ba1276acSMatthew Dillon else if (nnp_failed)
526*ba1276acSMatthew Dillon fatal("%s: SECCOMP_MODE_FILTER activated but "
527*ba1276acSMatthew Dillon "PR_SET_NO_NEW_PRIVS failed", __func__);
528*ba1276acSMatthew Dillon }
529*ba1276acSMatthew Dillon
530*ba1276acSMatthew Dillon void
ssh_sandbox_parent_finish(struct ssh_sandbox * box)531*ba1276acSMatthew Dillon ssh_sandbox_parent_finish(struct ssh_sandbox *box)
532*ba1276acSMatthew Dillon {
533*ba1276acSMatthew Dillon free(box);
534*ba1276acSMatthew Dillon debug3("%s: finished", __func__);
535*ba1276acSMatthew Dillon }
536*ba1276acSMatthew Dillon
537*ba1276acSMatthew Dillon void
ssh_sandbox_parent_preauth(struct ssh_sandbox * box,pid_t child_pid)538*ba1276acSMatthew Dillon ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid)
539*ba1276acSMatthew Dillon {
540*ba1276acSMatthew Dillon box->child_pid = child_pid;
541*ba1276acSMatthew Dillon }
542*ba1276acSMatthew Dillon
543*ba1276acSMatthew Dillon #endif /* SANDBOX_SECCOMP_FILTER */
544