ksgi

Форк
0
/
sandbox-seccomp-filter.c 
350 строк · 9.1 Кб
1
/*	$Id$ */
2
/*
3
 * Copyright (c) 2015 Kristaps Dzonsons <kristaps@bsd.lv>
4
 *
5
 * Permission to use, copy, modify, and distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
17
#include "config.h"
18

19
#if HAVE_SECCOMP_FILTER
20

21
/*
22
 * Copyright (c) 2012 Will Drewry <wad@dataspill.org>
23
 *
24
 * Permission to use, copy, modify, and distribute this software for any
25
 * purpose with or without fee is hereby granted, provided that the above
26
 * copyright notice and this permission notice appear in all copies.
27
 *
28
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
29
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
30
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
31
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
32
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
33
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
34
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
35
 */
36

37
#include <sys/types.h>
38
#include <sys/resource.h>
39
#include <sys/prctl.h>
40

41
#include <linux/audit.h>
42
#include <linux/filter.h>
43
#include <linux/seccomp.h>
44
#include <elf.h>
45

46
#ifdef AUDIT_ARCH_AARCH64
47
#define __ARCH_WANT_SYSCALL_NO_AT
48
#define __ARCH_WANT_SYSCALL_DEPRECATED
49
#endif
50
#include <asm/unistd.h>
51

52
#include <errno.h>
53
#include <signal.h>
54
#include <stdarg.h>
55
#include <stddef.h>  /* for offsetof */
56
#include <stdio.h>
57
#include <stdlib.h>
58
#include <string.h>
59
#include <unistd.h>
60

61
#include "kcgi.h"
62
#include "extern.h"
63

64
/* Linux seccomp_filter sandbox */
65
#ifdef SANDBOX_SECCOMP_DEBUG
66
# define SECCOMP_FILTER_FAIL SECCOMP_RET_TRAP
67
#else
68
# define SECCOMP_FILTER_FAIL SECCOMP_RET_KILL
69
#endif
70

71
/* Simple helpers to avoid manual errors (but larger BPF programs). */
72
#define SC_DENY(_nr, _errno) \
73
	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_ ## _nr, 0, 1), \
74
	BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO|(_errno))
75
#define SC_ALLOW(_nr) \
76
	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_ ## _nr, 0, 1), \
77
	BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
78

79
static const struct sock_filter preauth_ctrl[] = {
80
	/* Ensure the syscall arch convention is as expected. */
81
	BPF_STMT(BPF_LD+BPF_W+BPF_ABS,
82
		offsetof(struct seccomp_data, arch)),
83
	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SECCOMP_AUDIT_ARCH, 1, 0),
84
	BPF_STMT(BPF_RET+BPF_K, SECCOMP_FILTER_FAIL),
85
	/* Load the syscall number for checking. */
86
	BPF_STMT(BPF_LD+BPF_W+BPF_ABS,
87
		offsetof(struct seccomp_data, nr)),
88
#ifdef __NR_open /* not defined on aarch64 */
89
	SC_DENY(open, EACCES),
90
#endif
91
#ifdef __NR_openat
92
	SC_DENY(openat, EACCES),
93
#endif
94
	SC_ALLOW(getpid),
95
#ifdef __NR_getrandom
96
	SC_ALLOW(getrandom),
97
#endif
98
	SC_ALLOW(gettimeofday),
99
	SC_ALLOW(clock_gettime),
100
#ifdef __NR_time /* not defined on EABI ARM */
101
	SC_ALLOW(time),
102
#endif
103
#ifdef __NR_accept /* not defined for __i386__ (linux) */
104
	SC_ALLOW(accept),
105
#endif
106
#ifdef __NR_socketcall /* used for accept on __i386__ (linux) */
107
	SC_ALLOW(socketcall),
108
#endif
109
	SC_ALLOW(fcntl),
110
#ifdef __NR_fcntl64 /* only noted on arm */
111
	SC_ALLOW(fcntl64),
112
#endif
113
#ifdef __NR_sendmsg /* not defined for __i386__ (linux) */
114
	SC_ALLOW(sendmsg),
115
#endif
116
#ifdef __NR_recvmsg /* XXX: untested: mirroring __NR_sendmsg */
117
	SC_ALLOW(recvmsg),
118
#endif
119
	SC_ALLOW(read),
120
	SC_ALLOW(readv),
121
	SC_ALLOW(write),
122
	SC_ALLOW(writev),
123
	SC_ALLOW(close),
124
#ifdef __NR_shutdown /* not defined on archs that go via socketcall(2) */
125
	SC_ALLOW(shutdown),
126
#endif
127
	SC_ALLOW(brk),
128
#ifdef __NR_ppoll
129
	SC_ALLOW(ppoll),
130
#endif
131
#ifdef __NR_poll /* not defined on aarch64 */
132
	SC_ALLOW(poll),
133
#endif
134
#ifdef __NR__newselect
135
	SC_ALLOW(_newselect),
136
#endif
137
#ifdef __NR_select
138
	SC_ALLOW(select),
139
#endif
140
#ifdef __NR_pselect6
141
	SC_ALLOW(pselect6),
142
#endif
143
	SC_ALLOW(madvise),
144
#ifdef __NR_mmap2 /* EABI ARM only has mmap2() */
145
	SC_ALLOW(mmap2),
146
#endif
147
#ifdef __NR_mmap
148
	SC_ALLOW(mmap),
149
#endif
150
	SC_ALLOW(munmap),
151
	SC_ALLOW(exit_group),
152
#ifdef __NR_rt_sigprocmask
153
	SC_ALLOW(rt_sigprocmask),
154
#else
155
	SC_ALLOW(sigprocmask),
156
#endif
157
#ifdef __NR_rt_sigaction
158
	SC_ALLOW(rt_sigaction),
159
#else
160
	SC_ALLOW(sigaction),
161
#endif
162
	BPF_STMT(BPF_RET+BPF_K, SECCOMP_FILTER_FAIL),
163
};
164

165
/* Syscall filtering set for preauth. */
166
static const struct sock_filter preauth_work[] = {
167
	/* Ensure the syscall arch convention is as expected. */
168
	BPF_STMT(BPF_LD+BPF_W+BPF_ABS,
169
		offsetof(struct seccomp_data, arch)),
170
	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SECCOMP_AUDIT_ARCH, 1, 0),
171
	BPF_STMT(BPF_RET+BPF_K, SECCOMP_FILTER_FAIL),
172
	/* Load the syscall number for checking. */
173
	BPF_STMT(BPF_LD+BPF_W+BPF_ABS,
174
		offsetof(struct seccomp_data, nr)),
175
#ifdef __NR_open /* not defined on aarch64 */
176
	SC_DENY(open, EACCES),
177
#endif
178
#ifdef __NR_openat
179
	SC_DENY(openat, EACCES),
180
#endif
181
	SC_ALLOW(getpid),
182
#ifdef __NR_getrandom
183
	SC_ALLOW(getrandom),
184
#endif
185
	SC_ALLOW(gettimeofday),
186
	SC_ALLOW(clock_gettime),
187
#ifdef __NR_time /* not defined on EABI ARM */
188
	SC_ALLOW(time),
189
#endif
190
	SC_ALLOW(read),
191
	SC_ALLOW(readv),
192
	SC_ALLOW(lseek), /* for kutil_openlog logging */
193
	SC_ALLOW(fstat), /* for kutil_openlog logging */
194
#ifdef __NR_newfstatat
195
	SC_ALLOW(newfstatat), /* for kutil_openlog logging */
196
#endif
197
#ifdef __NR_statx
198
	SC_ALLOW(statx), /* for kutil_openlog logging */
199
#endif
200
	SC_ALLOW(write),
201
	SC_ALLOW(writev),
202
	SC_ALLOW(close),
203
#ifdef __NR_fcntl64 /* only noted on arm */
204
	SC_ALLOW(fcntl64),
205
#endif
206
#ifdef __NR_shutdown /* not defined on archs that go via socketcall(2) */
207
	SC_ALLOW(shutdown),
208
#endif
209
	SC_ALLOW(brk),
210
#ifdef __NR_ppoll
211
	SC_ALLOW(ppoll),
212
#endif
213
#ifdef __NR_poll /* not defined on aarch64 */
214
	SC_ALLOW(poll),
215
#endif
216
#ifdef __NR__newselect
217
	SC_ALLOW(_newselect),
218
#endif
219
#ifdef __NR_select
220
	SC_ALLOW(select),
221
#endif
222
#ifdef __NR_pselect6
223
	SC_ALLOW(pselect6),
224
#endif
225
	SC_ALLOW(madvise),
226
#ifdef __NR_mmap2 /* EABI ARM only has mmap2() */
227
	SC_ALLOW(mmap2),
228
#endif
229
#ifdef __NR_mmap
230
	SC_ALLOW(mmap),
231
#endif
232
	SC_ALLOW(mremap),
233
	SC_ALLOW(munmap),
234
	SC_ALLOW(exit_group),
235
#ifdef __NR_rt_sigprocmask
236
	SC_ALLOW(rt_sigprocmask),
237
#else
238
	SC_ALLOW(sigprocmask),
239
#endif
240
	BPF_STMT(BPF_RET+BPF_K, SECCOMP_FILTER_FAIL),
241
};
242

243
static const struct sock_fprog preauth_prog_work = {
244
	.len = (unsigned short)(sizeof(preauth_work)/sizeof(preauth_work[0])),
245
	.filter = (struct sock_filter *)preauth_work,
246
};
247

248
static const struct sock_fprog preauth_prog_ctrl = {
249
	.len = (unsigned short)(sizeof(preauth_ctrl)/sizeof(preauth_ctrl[0])),
250
	.filter = (struct sock_filter *)preauth_ctrl,
251
};
252

253
#ifdef SANDBOX_SECCOMP_DEBUG
254
static void
255
ssh_sandbox_violation_control(int signum, 
256
	siginfo_t *info, void *void_context)
257
{
258

259
	fprintf(stderr, 
260
		"%s: unexpected system call (control) "
261
		"(arch:0x%x,syscall:%d @ %p)\n",
262
		__func__, info->si_arch, 
263
		info->si_syscall, info->si_call_addr);
264
	exit(1);
265
}
266

267
static void
268
ssh_sandbox_violation_worker(int signum, 
269
	siginfo_t *info, void *void_context)
270
{
271

272
	fprintf(stderr, 
273
		"%s: unexpected system call (worker) "
274
		"(arch:0x%x,syscall:%d @ %p)\n",
275
		__func__, info->si_arch, 
276
		info->si_syscall, info->si_call_addr);
277
	exit(1);
278
}
279

280
static void
281
ssh_sandbox_child_debugging(enum sandtype type)
282
{
283
	struct sigaction act;
284
	sigset_t mask;
285

286
	memset(&act, 0, sizeof(act));
287
	sigemptyset(&mask);
288
	sigaddset(&mask, SIGSYS);
289

290
	act.sa_sigaction = SAND_WORKER == type ?
291
		&ssh_sandbox_violation_worker :
292
		&ssh_sandbox_violation_control;
293
	act.sa_flags = SA_SIGINFO;
294
	if (sigaction(SIGSYS, &act, NULL) == -1)
295
		fprintf(stderr, "%s: sigaction(SIGSYS): %s\n", 
296
			__func__, strerror(errno));
297
	if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
298
		fprintf(stderr, "%s: sigprocmask(SIGSYS): %s\n",
299
			__func__, strerror(errno));
300
}
301
#endif /* SANDBOX_SECCOMP_DEBUG */
302

303
int
304
ksandbox_seccomp_init_child(enum sandtype type)
305
{
306
	struct rlimit	rl_zero;
307
	int 		nnp_failed = 0;
308

309
	rl_zero.rlim_cur = rl_zero.rlim_max = 0;
310
#if 0
311
	/*
312
	 * Don't do this: we might write into a kutil_openlog(3).
313
	 */
314
	if (setrlimit(RLIMIT_FSIZE, &rl_zero) == -1)
315
		kutil_warn(NULL, NULL, "setrlimit");
316

317
	/*
318
	 * Don't do like OpenSSH: we need to pass stuff back and forth
319
	 * over pipes, and this will prevent that from happening.
320
	 */
321
	if (setrlimit(RLIMIT_NOFILE, &rl_zero) == -1)
322
		kutil_warn(NULL, NULL, "setrlimit");
323
#endif
324

325
	if (setrlimit(RLIMIT_NPROC, &rl_zero) == -1)
326
		kutil_warn(NULL, NULL, "setrlimit");
327

328
#ifdef SANDBOX_SECCOMP_DEBUG
329
	ssh_sandbox_child_debugging(type);
330
#endif 
331

332
	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) {
333
		kutil_warn(NULL, NULL, "prctl");
334
		nnp_failed = 1;
335
	}
336

337
	if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, 
338
	    SAND_WORKER != type ?
339
	    &preauth_prog_ctrl : &preauth_prog_work) == -1)
340
		kutil_warn(NULL, NULL, "prctl");
341
	else if (nnp_failed) {
342
		kutil_warnx(NULL, NULL, "SECCOMP_MODE_FILTER "
343
		    "activated but PR_SET_NO_NEW_PRIVS failed");
344
		_exit(EXIT_FAILURE);
345
	}
346

347
	return 1;
348
}
349

350
#endif
351

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.