Blame view

kernel/seccomp.c 31.8 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
  /*
   * linux/kernel/seccomp.c
   *
   * Copyright 2004-2005  Andrea Arcangeli <andrea@cpushare.com>
   *
e2cfabdfd   Will Drewry   seccomp: add syst...
7
8
9
10
11
12
13
14
   * Copyright (C) 2012 Google, Inc.
   * Will Drewry <wad@chromium.org>
   *
   * This defines a simple but solid secure-computing facility.
   *
   * Mode 1 uses a fixed list of allowed system calls.
   * Mode 2 allows user-defined system call filters in the form
   *        of Berkeley Packet Filters/Linux Socket Filters.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
   */
0b5fa2290   Kees Cook   seccomp: Switch f...
16
  #include <linux/refcount.h>
85e7bac33   Eric Paris   seccomp: audit ab...
17
  #include <linux/audit.h>
5b1017404   Roland McGrath   x86-64: seccomp: ...
18
  #include <linux/compat.h>
b25e67161   Mike Frysinger   seccomp: dump cor...
19
  #include <linux/coredump.h>
8e5f1ad11   Tyler Hicks   seccomp: Sysctl t...
20
  #include <linux/kmemleak.h>
87895ae1e   Kees Cook   seccomp: Enable s...
21
22
  #include <linux/nospec.h>
  #include <linux/prctl.h>
e2cfabdfd   Will Drewry   seccomp: add syst...
23
  #include <linux/sched.h>
68db0cf10   Ingo Molnar   sched/headers: Pr...
24
  #include <linux/sched/task_stack.h>
e2cfabdfd   Will Drewry   seccomp: add syst...
25
  #include <linux/seccomp.h>
c8bee430d   Kees Cook   seccomp: split fi...
26
  #include <linux/slab.h>
48dc92b9f   Kees Cook   seccomp: add "sec...
27
  #include <linux/syscalls.h>
8e5f1ad11   Tyler Hicks   seccomp: Sysctl t...
28
  #include <linux/sysctl.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29

a4412fc94   Andy Lutomirski   seccomp,x86,arm,m...
30
  #ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
e2cfabdfd   Will Drewry   seccomp: add syst...
31
  #include <asm/syscall.h>
a4412fc94   Andy Lutomirski   seccomp,x86,arm,m...
32
  #endif
e2cfabdfd   Will Drewry   seccomp: add syst...
33
34
  
  #ifdef CONFIG_SECCOMP_FILTER
e2cfabdfd   Will Drewry   seccomp: add syst...
35
  #include <linux/filter.h>
c2e1f2e30   Kees Cook   seccomp: implemen...
36
  #include <linux/pid.h>
fb0fadf9b   Will Drewry   ptrace,seccomp: A...
37
  #include <linux/ptrace.h>
e2cfabdfd   Will Drewry   seccomp: add syst...
38
  #include <linux/security.h>
e2cfabdfd   Will Drewry   seccomp: add syst...
39
40
41
42
43
44
45
46
47
48
  #include <linux/tracehook.h>
  #include <linux/uaccess.h>
  
  /**
   * struct seccomp_filter - container for seccomp BPF programs
   *
   * @usage: reference count to manage the object lifetime.
   *         get/put helpers should be used when accessing an instance
   *         outside of a lifetime-guarded section.  In general, this
   *         is only needed for handling filters shared across tasks.
e66a39977   Tyler Hicks   seccomp: Filter f...
49
   * @log: true if all actions except for SECCOMP_RET_ALLOW should be logged
e2cfabdfd   Will Drewry   seccomp: add syst...
50
   * @prev: points to a previously installed, or inherited, filter
285fdfc5d   Mickaël Salaün   seccomp: Fix docu...
51
   * @prog: the BPF program to evaluate
e2cfabdfd   Will Drewry   seccomp: add syst...
52
53
54
55
56
57
58
59
60
61
62
63
   *
   * seccomp_filter objects are organized in a tree linked via the @prev
   * pointer.  For any task, it appears to be a singly-linked list starting
   * with current->seccomp.filter, the most recently attached or inherited filter.
   * However, multiple filters may share a @prev node, by way of fork(), which
   * results in a unidirectional tree existing in memory.  This is similar to
   * how namespaces work.
   *
   * seccomp_filter objects should never be modified after being attached
   * to a task_struct (other than @usage).
   */
  struct seccomp_filter {
0b5fa2290   Kees Cook   seccomp: Switch f...
64
  	refcount_t usage;
e66a39977   Tyler Hicks   seccomp: Filter f...
65
  	bool log;
e2cfabdfd   Will Drewry   seccomp: add syst...
66
  	struct seccomp_filter *prev;
7ae457c1e   Alexei Starovoitov   net: filter: spli...
67
  	struct bpf_prog *prog;
e2cfabdfd   Will Drewry   seccomp: add syst...
68
69
70
71
  };
  
  /* Limit any path through the tree to 256KB worth of instructions. */
  #define MAX_INSNS_PER_PATH ((1 << 18) / sizeof(struct sock_filter))
bd4cf0ed3   Alexei Starovoitov   net: filter: rewo...
72
  /*
e2cfabdfd   Will Drewry   seccomp: add syst...
73
74
75
   * Endianness is explicitly ignored and left for BPF program authors to manage
   * as per the specific architecture.
   */
bd4cf0ed3   Alexei Starovoitov   net: filter: rewo...
76
  static void populate_seccomp_data(struct seccomp_data *sd)
e2cfabdfd   Will Drewry   seccomp: add syst...
77
  {
bd4cf0ed3   Alexei Starovoitov   net: filter: rewo...
78
79
  	struct task_struct *task = current;
  	struct pt_regs *regs = task_pt_regs(task);
2eac76483   Daniel Borkmann   seccomp: fix popu...
80
  	unsigned long args[6];
e2cfabdfd   Will Drewry   seccomp: add syst...
81

bd4cf0ed3   Alexei Starovoitov   net: filter: rewo...
82
  	sd->nr = syscall_get_nr(task, regs);
0b747172d   Linus Torvalds   Merge git://git.i...
83
  	sd->arch = syscall_get_arch();
2eac76483   Daniel Borkmann   seccomp: fix popu...
84
85
86
87
88
89
90
  	syscall_get_arguments(task, regs, 0, 6, args);
  	sd->args[0] = args[0];
  	sd->args[1] = args[1];
  	sd->args[2] = args[2];
  	sd->args[3] = args[3];
  	sd->args[4] = args[4];
  	sd->args[5] = args[5];
bd4cf0ed3   Alexei Starovoitov   net: filter: rewo...
91
  	sd->instruction_pointer = KSTK_EIP(task);
e2cfabdfd   Will Drewry   seccomp: add syst...
92
93
94
95
96
97
98
  }
  
  /**
   *	seccomp_check_filter - verify seccomp filter code
   *	@filter: filter to verify
   *	@flen: length of filter
   *
4df95ff48   Alexei Starovoitov   net: filter: rena...
99
   * Takes a previously checked filter (by bpf_check_classic) and
e2cfabdfd   Will Drewry   seccomp: add syst...
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
   * redirects all filter code that loads struct sk_buff data
   * and related data through seccomp_bpf_load.  It also
   * enforces length and alignment checking of those loads.
   *
   * Returns 0 if the rule set is legal or -EINVAL if not.
   */
  static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen)
  {
  	int pc;
  	for (pc = 0; pc < flen; pc++) {
  		struct sock_filter *ftest = &filter[pc];
  		u16 code = ftest->code;
  		u32 k = ftest->k;
  
  		switch (code) {
348059313   Daniel Borkmann   net: filter: get ...
115
  		case BPF_LD | BPF_W | BPF_ABS:
bd4cf0ed3   Alexei Starovoitov   net: filter: rewo...
116
  			ftest->code = BPF_LDX | BPF_W | BPF_ABS;
e2cfabdfd   Will Drewry   seccomp: add syst...
117
118
119
120
  			/* 32-bit aligned and not out of bounds. */
  			if (k >= sizeof(struct seccomp_data) || k & 3)
  				return -EINVAL;
  			continue;
348059313   Daniel Borkmann   net: filter: get ...
121
  		case BPF_LD | BPF_W | BPF_LEN:
bd4cf0ed3   Alexei Starovoitov   net: filter: rewo...
122
  			ftest->code = BPF_LD | BPF_IMM;
e2cfabdfd   Will Drewry   seccomp: add syst...
123
124
  			ftest->k = sizeof(struct seccomp_data);
  			continue;
348059313   Daniel Borkmann   net: filter: get ...
125
  		case BPF_LDX | BPF_W | BPF_LEN:
bd4cf0ed3   Alexei Starovoitov   net: filter: rewo...
126
  			ftest->code = BPF_LDX | BPF_IMM;
e2cfabdfd   Will Drewry   seccomp: add syst...
127
128
129
  			ftest->k = sizeof(struct seccomp_data);
  			continue;
  		/* Explicitly include allowed calls. */
348059313   Daniel Borkmann   net: filter: get ...
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  		case BPF_RET | BPF_K:
  		case BPF_RET | BPF_A:
  		case BPF_ALU | BPF_ADD | BPF_K:
  		case BPF_ALU | BPF_ADD | BPF_X:
  		case BPF_ALU | BPF_SUB | BPF_K:
  		case BPF_ALU | BPF_SUB | BPF_X:
  		case BPF_ALU | BPF_MUL | BPF_K:
  		case BPF_ALU | BPF_MUL | BPF_X:
  		case BPF_ALU | BPF_DIV | BPF_K:
  		case BPF_ALU | BPF_DIV | BPF_X:
  		case BPF_ALU | BPF_AND | BPF_K:
  		case BPF_ALU | BPF_AND | BPF_X:
  		case BPF_ALU | BPF_OR | BPF_K:
  		case BPF_ALU | BPF_OR | BPF_X:
  		case BPF_ALU | BPF_XOR | BPF_K:
  		case BPF_ALU | BPF_XOR | BPF_X:
  		case BPF_ALU | BPF_LSH | BPF_K:
  		case BPF_ALU | BPF_LSH | BPF_X:
  		case BPF_ALU | BPF_RSH | BPF_K:
  		case BPF_ALU | BPF_RSH | BPF_X:
  		case BPF_ALU | BPF_NEG:
  		case BPF_LD | BPF_IMM:
  		case BPF_LDX | BPF_IMM:
  		case BPF_MISC | BPF_TAX:
  		case BPF_MISC | BPF_TXA:
  		case BPF_LD | BPF_MEM:
  		case BPF_LDX | BPF_MEM:
  		case BPF_ST:
  		case BPF_STX:
  		case BPF_JMP | BPF_JA:
  		case BPF_JMP | BPF_JEQ | BPF_K:
  		case BPF_JMP | BPF_JEQ | BPF_X:
  		case BPF_JMP | BPF_JGE | BPF_K:
  		case BPF_JMP | BPF_JGE | BPF_X:
  		case BPF_JMP | BPF_JGT | BPF_K:
  		case BPF_JMP | BPF_JGT | BPF_X:
  		case BPF_JMP | BPF_JSET | BPF_K:
  		case BPF_JMP | BPF_JSET | BPF_X:
e2cfabdfd   Will Drewry   seccomp: add syst...
168
169
170
171
172
173
174
175
176
  			continue;
  		default:
  			return -EINVAL;
  		}
  	}
  	return 0;
  }
  
  /**
285fdfc5d   Mickaël Salaün   seccomp: Fix docu...
177
178
   * seccomp_run_filters - evaluates all seccomp filters against @sd
   * @sd: optional seccomp data to be passed to filters
deb4de8b3   Kees Cook   seccomp: Provide ...
179
180
181
   * @match: stores struct seccomp_filter that resulted in the return value,
   *         unless filter returned SECCOMP_RET_ALLOW, in which case it will
   *         be unchanged.
e2cfabdfd   Will Drewry   seccomp: add syst...
182
183
184
   *
   * Returns valid seccomp BPF response codes.
   */
0466bdb99   Kees Cook   seccomp: Implemen...
185
  #define ACTION_ONLY(ret) ((s32)((ret) & (SECCOMP_RET_ACTION_FULL)))
deb4de8b3   Kees Cook   seccomp: Provide ...
186
187
  static u32 seccomp_run_filters(const struct seccomp_data *sd,
  			       struct seccomp_filter **match)
e2cfabdfd   Will Drewry   seccomp: add syst...
188
  {
d39bd00de   Andy Lutomirski   seccomp: Allow ar...
189
  	struct seccomp_data sd_local;
acf3b2c71   Will Drewry   seccomp: add SECC...
190
  	u32 ret = SECCOMP_RET_ALLOW;
8225d3853   Pranith Kumar   seccomp: Replace ...
191
192
  	/* Make sure cross-thread synced filter points somewhere sane. */
  	struct seccomp_filter *f =
5383f45db   Will Deacon   locking/barriers:...
193
  			READ_ONCE(current->seccomp.filter);
acf3b2c71   Will Drewry   seccomp: add SECC...
194
195
  
  	/* Ensure unexpected behavior doesn't result in failing open. */
3ba2530cc   Kees Cook   seccomp: allow mo...
196
  	if (unlikely(WARN_ON(f == NULL)))
4d3b0b05a   Kees Cook   seccomp: Introduc...
197
  		return SECCOMP_RET_KILL_PROCESS;
acf3b2c71   Will Drewry   seccomp: add SECC...
198

d39bd00de   Andy Lutomirski   seccomp: Allow ar...
199
200
201
202
  	if (!sd) {
  		populate_seccomp_data(&sd_local);
  		sd = &sd_local;
  	}
bd4cf0ed3   Alexei Starovoitov   net: filter: rewo...
203

e2cfabdfd   Will Drewry   seccomp: add syst...
204
205
  	/*
  	 * All filters in the list are evaluated and the lowest BPF return
acf3b2c71   Will Drewry   seccomp: add SECC...
206
  	 * value always takes priority (ignoring the DATA).
e2cfabdfd   Will Drewry   seccomp: add syst...
207
  	 */
3ba2530cc   Kees Cook   seccomp: allow mo...
208
  	for (; f; f = f->prev) {
88575199c   Daniel Borkmann   bpf: drop unneces...
209
  		u32 cur_ret = BPF_PROG_RUN(f->prog, sd);
8f577cadf   Alexei Starovoitov   seccomp: JIT comp...
210

0466bdb99   Kees Cook   seccomp: Implemen...
211
  		if (ACTION_ONLY(cur_ret) < ACTION_ONLY(ret)) {
acf3b2c71   Will Drewry   seccomp: add SECC...
212
  			ret = cur_ret;
deb4de8b3   Kees Cook   seccomp: Provide ...
213
214
  			*match = f;
  		}
e2cfabdfd   Will Drewry   seccomp: add syst...
215
216
217
  	}
  	return ret;
  }
1f41b4504   Kees Cook   seccomp: extract ...
218
  #endif /* CONFIG_SECCOMP_FILTER */
e2cfabdfd   Will Drewry   seccomp: add syst...
219

1f41b4504   Kees Cook   seccomp: extract ...
220
221
  static inline bool seccomp_may_assign_mode(unsigned long seccomp_mode)
  {
69f6a34bd   Guenter Roeck   seccomp: Replace ...
222
  	assert_spin_locked(&current->sighand->siglock);
dbd952127   Kees Cook   seccomp: introduc...
223

1f41b4504   Kees Cook   seccomp: extract ...
224
225
226
227
228
  	if (current->seccomp.mode && current->seccomp.mode != seccomp_mode)
  		return false;
  
  	return true;
  }
61dfdc12f   Thomas Gleixner   seccomp: Move spe...
229
  void __weak arch_seccomp_spec_mitigate(struct task_struct *task) { }
87895ae1e   Kees Cook   seccomp: Enable s...
230

3ba2530cc   Kees Cook   seccomp: allow mo...
231
  static inline void seccomp_assign_mode(struct task_struct *task,
9939db75c   Kees Cook   seccomp: Add filt...
232
233
  				       unsigned long seccomp_mode,
  				       unsigned long flags)
1f41b4504   Kees Cook   seccomp: extract ...
234
  {
69f6a34bd   Guenter Roeck   seccomp: Replace ...
235
  	assert_spin_locked(&task->sighand->siglock);
dbd952127   Kees Cook   seccomp: introduc...
236

3ba2530cc   Kees Cook   seccomp: allow mo...
237
238
239
240
241
242
  	task->seccomp.mode = seccomp_mode;
  	/*
  	 * Make sure TIF_SECCOMP cannot be set before the mode (and
  	 * filter) is set.
  	 */
  	smp_mb__before_atomic();
9939db75c   Kees Cook   seccomp: Add filt...
243
244
  	/* Assume default seccomp processes want spec flaw mitigation. */
  	if ((flags & SECCOMP_FILTER_FLAG_SPEC_ALLOW) == 0)
61dfdc12f   Thomas Gleixner   seccomp: Move spe...
245
  		arch_seccomp_spec_mitigate(task);
3ba2530cc   Kees Cook   seccomp: allow mo...
246
  	set_tsk_thread_flag(task, TIF_SECCOMP);
1f41b4504   Kees Cook   seccomp: extract ...
247
248
249
  }
  
  #ifdef CONFIG_SECCOMP_FILTER
c2e1f2e30   Kees Cook   seccomp: implemen...
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
  /* Returns 1 if the parent is an ancestor of the child. */
  static int is_ancestor(struct seccomp_filter *parent,
  		       struct seccomp_filter *child)
  {
  	/* NULL is the root ancestor. */
  	if (parent == NULL)
  		return 1;
  	for (; child; child = child->prev)
  		if (child == parent)
  			return 1;
  	return 0;
  }
  
  /**
   * seccomp_can_sync_threads: checks if all threads can be synchronized
   *
   * Expects sighand and cred_guard_mutex locks to be held.
   *
   * Returns 0 on success, -ve on error, or the pid of a thread which was
   * either not in the correct seccomp mode or it did not have an ancestral
   * seccomp filter.
   */
  static inline pid_t seccomp_can_sync_threads(void)
  {
  	struct task_struct *thread, *caller;
  
  	BUG_ON(!mutex_is_locked(&current->signal->cred_guard_mutex));
69f6a34bd   Guenter Roeck   seccomp: Replace ...
277
  	assert_spin_locked(&current->sighand->siglock);
c2e1f2e30   Kees Cook   seccomp: implemen...
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
  
  	/* Validate all threads being eligible for synchronization. */
  	caller = current;
  	for_each_thread(caller, thread) {
  		pid_t failed;
  
  		/* Skip current, since it is initiating the sync. */
  		if (thread == caller)
  			continue;
  
  		if (thread->seccomp.mode == SECCOMP_MODE_DISABLED ||
  		    (thread->seccomp.mode == SECCOMP_MODE_FILTER &&
  		     is_ancestor(thread->seccomp.filter,
  				 caller->seccomp.filter)))
  			continue;
  
  		/* Return the first thread that cannot be synchronized. */
  		failed = task_pid_vnr(thread);
  		/* If the pid cannot be resolved, then return -ESRCH */
  		if (unlikely(WARN_ON(failed == 0)))
  			failed = -ESRCH;
  		return failed;
  	}
  
  	return 0;
  }
  
  /**
   * seccomp_sync_threads: sets all threads to use current's filter
   *
   * Expects sighand and cred_guard_mutex locks to be held, and for
   * seccomp_can_sync_threads() to have returned success already
   * without dropping the locks.
   *
   */
9939db75c   Kees Cook   seccomp: Add filt...
313
  static inline void seccomp_sync_threads(unsigned long flags)
c2e1f2e30   Kees Cook   seccomp: implemen...
314
315
316
317
  {
  	struct task_struct *thread, *caller;
  
  	BUG_ON(!mutex_is_locked(&current->signal->cred_guard_mutex));
69f6a34bd   Guenter Roeck   seccomp: Replace ...
318
  	assert_spin_locked(&current->sighand->siglock);
c2e1f2e30   Kees Cook   seccomp: implemen...
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
  
  	/* Synchronize all threads. */
  	caller = current;
  	for_each_thread(caller, thread) {
  		/* Skip current, since it needs no changes. */
  		if (thread == caller)
  			continue;
  
  		/* Get a task reference for the new leaf node. */
  		get_seccomp_filter(caller);
  		/*
  		 * Drop the task reference to the shared ancestor since
  		 * current's path will hold a reference.  (This also
  		 * allows a put before the assignment.)
  		 */
  		put_seccomp_filter(thread);
  		smp_store_release(&thread->seccomp.filter,
  				  caller->seccomp.filter);
103502a35   Jann Horn   seccomp: always p...
337
338
339
340
341
342
343
344
345
  
  		/*
  		 * Don't let an unprivileged task work around
  		 * the no_new_privs restriction by creating
  		 * a thread that sets it up, enters seccomp,
  		 * then dies.
  		 */
  		if (task_no_new_privs(caller))
  			task_set_no_new_privs(thread);
c2e1f2e30   Kees Cook   seccomp: implemen...
346
347
348
349
350
351
  		/*
  		 * Opt the other thread into seccomp if needed.
  		 * As threads are considered to be trust-realm
  		 * equivalent (see ptrace_may_access), it is safe to
  		 * allow one thread to transition the other.
  		 */
103502a35   Jann Horn   seccomp: always p...
352
  		if (thread->seccomp.mode == SECCOMP_MODE_DISABLED)
9939db75c   Kees Cook   seccomp: Add filt...
353
354
  			seccomp_assign_mode(thread, SECCOMP_MODE_FILTER,
  					    flags);
c2e1f2e30   Kees Cook   seccomp: implemen...
355
356
  	}
  }
e2cfabdfd   Will Drewry   seccomp: add syst...
357
  /**
c8bee430d   Kees Cook   seccomp: split fi...
358
   * seccomp_prepare_filter: Prepares a seccomp filter for use.
e2cfabdfd   Will Drewry   seccomp: add syst...
359
360
   * @fprog: BPF program to install
   *
c8bee430d   Kees Cook   seccomp: split fi...
361
   * Returns filter on success or an ERR_PTR on failure.
e2cfabdfd   Will Drewry   seccomp: add syst...
362
   */
c8bee430d   Kees Cook   seccomp: split fi...
363
  static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
e2cfabdfd   Will Drewry   seccomp: add syst...
364
  {
ac67eb2c5   Daniel Borkmann   seccomp, filter: ...
365
366
  	struct seccomp_filter *sfilter;
  	int ret;
97f2645f3   Masahiro Yamada   tree-wide: replac...
367
  	const bool save_orig = IS_ENABLED(CONFIG_CHECKPOINT_RESTORE);
e2cfabdfd   Will Drewry   seccomp: add syst...
368
369
  
  	if (fprog->len == 0 || fprog->len > BPF_MAXINSNS)
c8bee430d   Kees Cook   seccomp: split fi...
370
  		return ERR_PTR(-EINVAL);
d9e12f42e   Nicolas Schichan   seccomp: simplify...
371

c8bee430d   Kees Cook   seccomp: split fi...
372
  	BUG_ON(INT_MAX / fprog->len < sizeof(struct sock_filter));
e2cfabdfd   Will Drewry   seccomp: add syst...
373
374
  
  	/*
119ce5c8b   Fabian Frederick   kernel/seccomp.c:...
375
  	 * Installing a seccomp filter requires that the task has
e2cfabdfd   Will Drewry   seccomp: add syst...
376
377
378
379
  	 * CAP_SYS_ADMIN in its namespace or be running with no_new_privs.
  	 * This avoids scenarios where unprivileged tasks can affect the
  	 * behavior of privileged children.
  	 */
1d4457f99   Kees Cook   sched: move no_ne...
380
  	if (!task_no_new_privs(current) &&
e2cfabdfd   Will Drewry   seccomp: add syst...
381
382
  	    security_capable_noaudit(current_cred(), current_user_ns(),
  				     CAP_SYS_ADMIN) != 0)
c8bee430d   Kees Cook   seccomp: split fi...
383
  		return ERR_PTR(-EACCES);
e2cfabdfd   Will Drewry   seccomp: add syst...
384

bd4cf0ed3   Alexei Starovoitov   net: filter: rewo...
385
  	/* Allocate a new seccomp_filter */
ac67eb2c5   Daniel Borkmann   seccomp, filter: ...
386
387
  	sfilter = kzalloc(sizeof(*sfilter), GFP_KERNEL | __GFP_NOWARN);
  	if (!sfilter)
d9e12f42e   Nicolas Schichan   seccomp: simplify...
388
  		return ERR_PTR(-ENOMEM);
ac67eb2c5   Daniel Borkmann   seccomp, filter: ...
389
390
  
  	ret = bpf_prog_create_from_user(&sfilter->prog, fprog,
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
391
  					seccomp_check_filter, save_orig);
ac67eb2c5   Daniel Borkmann   seccomp, filter: ...
392
393
394
  	if (ret < 0) {
  		kfree(sfilter);
  		return ERR_PTR(ret);
d9e12f42e   Nicolas Schichan   seccomp: simplify...
395
  	}
bd4cf0ed3   Alexei Starovoitov   net: filter: rewo...
396

0b5fa2290   Kees Cook   seccomp: Switch f...
397
  	refcount_set(&sfilter->usage, 1);
e2cfabdfd   Will Drewry   seccomp: add syst...
398

ac67eb2c5   Daniel Borkmann   seccomp, filter: ...
399
  	return sfilter;
e2cfabdfd   Will Drewry   seccomp: add syst...
400
401
402
  }
  
  /**
c8bee430d   Kees Cook   seccomp: split fi...
403
   * seccomp_prepare_user_filter - prepares a user-supplied sock_fprog
e2cfabdfd   Will Drewry   seccomp: add syst...
404
405
406
407
   * @user_filter: pointer to the user data containing a sock_fprog.
   *
   * Returns 0 on success and non-zero otherwise.
   */
c8bee430d   Kees Cook   seccomp: split fi...
408
409
  static struct seccomp_filter *
  seccomp_prepare_user_filter(const char __user *user_filter)
e2cfabdfd   Will Drewry   seccomp: add syst...
410
411
  {
  	struct sock_fprog fprog;
c8bee430d   Kees Cook   seccomp: split fi...
412
  	struct seccomp_filter *filter = ERR_PTR(-EFAULT);
e2cfabdfd   Will Drewry   seccomp: add syst...
413
414
  
  #ifdef CONFIG_COMPAT
5c38065e0   Andy Lutomirski   seccomp: check in...
415
  	if (in_compat_syscall()) {
e2cfabdfd   Will Drewry   seccomp: add syst...
416
417
418
419
420
421
422
423
424
  		struct compat_sock_fprog fprog32;
  		if (copy_from_user(&fprog32, user_filter, sizeof(fprog32)))
  			goto out;
  		fprog.len = fprog32.len;
  		fprog.filter = compat_ptr(fprog32.filter);
  	} else /* falls through to the if below. */
  #endif
  	if (copy_from_user(&fprog, user_filter, sizeof(fprog)))
  		goto out;
c8bee430d   Kees Cook   seccomp: split fi...
425
  	filter = seccomp_prepare_filter(&fprog);
e2cfabdfd   Will Drewry   seccomp: add syst...
426
  out:
c8bee430d   Kees Cook   seccomp: split fi...
427
428
429
430
431
432
433
434
  	return filter;
  }
  
  /**
   * seccomp_attach_filter: validate and attach filter
   * @flags:  flags to change filter behavior
   * @filter: seccomp filter to add to the current process
   *
dbd952127   Kees Cook   seccomp: introduc...
435
436
   * Caller must be holding current->sighand->siglock lock.
   *
c8bee430d   Kees Cook   seccomp: split fi...
437
438
439
440
441
442
443
   * Returns 0 on success, -ve on error.
   */
  static long seccomp_attach_filter(unsigned int flags,
  				  struct seccomp_filter *filter)
  {
  	unsigned long total_insns;
  	struct seccomp_filter *walker;
69f6a34bd   Guenter Roeck   seccomp: Replace ...
444
  	assert_spin_locked(&current->sighand->siglock);
dbd952127   Kees Cook   seccomp: introduc...
445

c8bee430d   Kees Cook   seccomp: split fi...
446
447
448
449
450
451
  	/* Validate resulting filter length. */
  	total_insns = filter->prog->len;
  	for (walker = current->seccomp.filter; walker; walker = walker->prev)
  		total_insns += walker->prog->len + 4;  /* 4 instr penalty */
  	if (total_insns > MAX_INSNS_PER_PATH)
  		return -ENOMEM;
c2e1f2e30   Kees Cook   seccomp: implemen...
452
453
454
455
456
457
458
459
  	/* If thread sync has been requested, check that it is possible. */
  	if (flags & SECCOMP_FILTER_FLAG_TSYNC) {
  		int ret;
  
  		ret = seccomp_can_sync_threads();
  		if (ret)
  			return ret;
  	}
e66a39977   Tyler Hicks   seccomp: Filter f...
460
461
462
  	/* Set log flag, if present. */
  	if (flags & SECCOMP_FILTER_FLAG_LOG)
  		filter->log = true;
c8bee430d   Kees Cook   seccomp: split fi...
463
464
465
466
467
468
  	/*
  	 * If there is an existing filter, make it the prev and don't drop its
  	 * task reference.
  	 */
  	filter->prev = current->seccomp.filter;
  	current->seccomp.filter = filter;
c2e1f2e30   Kees Cook   seccomp: implemen...
469
470
  	/* Now that the new filter is in place, synchronize to all threads. */
  	if (flags & SECCOMP_FILTER_FLAG_TSYNC)
9939db75c   Kees Cook   seccomp: Add filt...
471
  		seccomp_sync_threads(flags);
c2e1f2e30   Kees Cook   seccomp: implemen...
472

c8bee430d   Kees Cook   seccomp: split fi...
473
  	return 0;
e2cfabdfd   Will Drewry   seccomp: add syst...
474
  }
084f5601c   Colin Ian King   seccomp: make fun...
475
  static void __get_seccomp_filter(struct seccomp_filter *filter)
66a733ea6   Oleg Nesterov   seccomp: fix the ...
476
477
478
479
  {
  	/* Reference count is bounded by the number of total processes. */
  	refcount_inc(&filter->usage);
  }
e2cfabdfd   Will Drewry   seccomp: add syst...
480
481
482
483
484
485
  /* get_seccomp_filter - increments the reference count of the filter on @tsk */
  void get_seccomp_filter(struct task_struct *tsk)
  {
  	struct seccomp_filter *orig = tsk->seccomp.filter;
  	if (!orig)
  		return;
66a733ea6   Oleg Nesterov   seccomp: fix the ...
486
  	__get_seccomp_filter(orig);
e2cfabdfd   Will Drewry   seccomp: add syst...
487
  }
c8bee430d   Kees Cook   seccomp: split fi...
488
489
490
  static inline void seccomp_filter_free(struct seccomp_filter *filter)
  {
  	if (filter) {
bab189918   Daniel Borkmann   bpf, seccomp: pre...
491
  		bpf_prog_destroy(filter->prog);
c8bee430d   Kees Cook   seccomp: split fi...
492
493
494
  		kfree(filter);
  	}
  }
66a733ea6   Oleg Nesterov   seccomp: fix the ...
495
  static void __put_seccomp_filter(struct seccomp_filter *orig)
e2cfabdfd   Will Drewry   seccomp: add syst...
496
  {
e2cfabdfd   Will Drewry   seccomp: add syst...
497
  	/* Clean up single-reference branches iteratively. */
0b5fa2290   Kees Cook   seccomp: Switch f...
498
  	while (orig && refcount_dec_and_test(&orig->usage)) {
e2cfabdfd   Will Drewry   seccomp: add syst...
499
500
  		struct seccomp_filter *freeme = orig;
  		orig = orig->prev;
c8bee430d   Kees Cook   seccomp: split fi...
501
  		seccomp_filter_free(freeme);
e2cfabdfd   Will Drewry   seccomp: add syst...
502
503
  	}
  }
bb6ea4301   Will Drewry   seccomp: Add SECC...
504

66a733ea6   Oleg Nesterov   seccomp: fix the ...
505
506
507
508
509
  /* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */
  void put_seccomp_filter(struct task_struct *tsk)
  {
  	__put_seccomp_filter(tsk->seccomp.filter);
  }
b25e67161   Mike Frysinger   seccomp: dump cor...
510
511
512
513
514
515
516
517
518
519
  static void seccomp_init_siginfo(siginfo_t *info, int syscall, int reason)
  {
  	memset(info, 0, sizeof(*info));
  	info->si_signo = SIGSYS;
  	info->si_code = SYS_SECCOMP;
  	info->si_call_addr = (void __user *)KSTK_EIP(current);
  	info->si_errno = reason;
  	info->si_arch = syscall_get_arch();
  	info->si_syscall = syscall;
  }
bb6ea4301   Will Drewry   seccomp: Add SECC...
520
521
522
523
524
525
526
527
528
529
  /**
   * seccomp_send_sigsys - signals the task to allow in-process syscall emulation
   * @syscall: syscall number to send to userland
   * @reason: filter-supplied reason code to send to userland (via si_errno)
   *
   * Forces a SIGSYS with a code of SYS_SECCOMP and related sigsys info.
   */
  static void seccomp_send_sigsys(int syscall, int reason)
  {
  	struct siginfo info;
b25e67161   Mike Frysinger   seccomp: dump cor...
530
  	seccomp_init_siginfo(&info, syscall, reason);
bb6ea4301   Will Drewry   seccomp: Add SECC...
531
532
  	force_sig_info(SIGSYS, &info, current);
  }
e2cfabdfd   Will Drewry   seccomp: add syst...
533
  #endif	/* CONFIG_SECCOMP_FILTER */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534

0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
535
  /* For use with seccomp_actions_logged */
4d3b0b05a   Kees Cook   seccomp: Introduc...
536
537
  #define SECCOMP_LOG_KILL_PROCESS	(1 << 0)
  #define SECCOMP_LOG_KILL_THREAD		(1 << 1)
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
538
539
540
  #define SECCOMP_LOG_TRAP		(1 << 2)
  #define SECCOMP_LOG_ERRNO		(1 << 3)
  #define SECCOMP_LOG_TRACE		(1 << 4)
59f5cf44a   Tyler Hicks   seccomp: Action t...
541
542
  #define SECCOMP_LOG_LOG			(1 << 5)
  #define SECCOMP_LOG_ALLOW		(1 << 6)
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
543

4d3b0b05a   Kees Cook   seccomp: Introduc...
544
545
  static u32 seccomp_actions_logged = SECCOMP_LOG_KILL_PROCESS |
  				    SECCOMP_LOG_KILL_THREAD  |
fd76875ca   Kees Cook   seccomp: Rename S...
546
547
548
  				    SECCOMP_LOG_TRAP  |
  				    SECCOMP_LOG_ERRNO |
  				    SECCOMP_LOG_TRACE |
59f5cf44a   Tyler Hicks   seccomp: Action t...
549
  				    SECCOMP_LOG_LOG;
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
550

e66a39977   Tyler Hicks   seccomp: Filter f...
551
552
  static inline void seccomp_log(unsigned long syscall, long signr, u32 action,
  			       bool requested)
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
553
554
555
556
557
  {
  	bool log = false;
  
  	switch (action) {
  	case SECCOMP_RET_ALLOW:
e66a39977   Tyler Hicks   seccomp: Filter f...
558
  		break;
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
559
  	case SECCOMP_RET_TRAP:
e66a39977   Tyler Hicks   seccomp: Filter f...
560
561
  		log = requested && seccomp_actions_logged & SECCOMP_LOG_TRAP;
  		break;
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
562
  	case SECCOMP_RET_ERRNO:
e66a39977   Tyler Hicks   seccomp: Filter f...
563
564
  		log = requested && seccomp_actions_logged & SECCOMP_LOG_ERRNO;
  		break;
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
565
  	case SECCOMP_RET_TRACE:
e66a39977   Tyler Hicks   seccomp: Filter f...
566
  		log = requested && seccomp_actions_logged & SECCOMP_LOG_TRACE;
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
567
  		break;
59f5cf44a   Tyler Hicks   seccomp: Action t...
568
569
570
  	case SECCOMP_RET_LOG:
  		log = seccomp_actions_logged & SECCOMP_LOG_LOG;
  		break;
fd76875ca   Kees Cook   seccomp: Rename S...
571
  	case SECCOMP_RET_KILL_THREAD:
fd76875ca   Kees Cook   seccomp: Rename S...
572
  		log = seccomp_actions_logged & SECCOMP_LOG_KILL_THREAD;
4d3b0b05a   Kees Cook   seccomp: Introduc...
573
574
575
576
  		break;
  	case SECCOMP_RET_KILL_PROCESS:
  	default:
  		log = seccomp_actions_logged & SECCOMP_LOG_KILL_PROCESS;
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
577
578
579
  	}
  
  	/*
fd76875ca   Kees Cook   seccomp: Rename S...
580
  	 * Force an audit message to be emitted when the action is RET_KILL_*,
59f5cf44a   Tyler Hicks   seccomp: Action t...
581
582
  	 * RET_LOG, or the FILTER_FLAG_LOG bit was set and the action is
  	 * allowed to be logged by the admin.
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
583
584
585
586
587
588
589
590
591
592
  	 */
  	if (log)
  		return __audit_seccomp(syscall, signr, action);
  
  	/*
  	 * Let the audit subsystem decide if the action should be audited based
  	 * on whether the current task itself is being audited.
  	 */
  	return audit_seccomp(syscall, signr, action);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
594
595
596
597
  /*
   * Secure computing mode 1 allows only read/write/exit/sigreturn.
   * To be fully secure this must be combined with rlimit
   * to limit the stack allocations too.
   */
cb4253aa0   Matt Redfearn   secomp: Constify ...
598
  static const int mode1_syscalls[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
600
601
  	__NR_seccomp_read, __NR_seccomp_write, __NR_seccomp_exit, __NR_seccomp_sigreturn,
  	0, /* null terminated */
  };
a4412fc94   Andy Lutomirski   seccomp,x86,arm,m...
602
  static void __secure_computing_strict(int this_syscall)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
  {
cb4253aa0   Matt Redfearn   secomp: Constify ...
604
  	const int *syscall_whitelist = mode1_syscalls;
a4412fc94   Andy Lutomirski   seccomp,x86,arm,m...
605
  #ifdef CONFIG_COMPAT
5c38065e0   Andy Lutomirski   seccomp: check in...
606
  	if (in_compat_syscall())
c983f0e86   Matt Redfearn   seccomp: Get comp...
607
  		syscall_whitelist = get_compat_mode1_syscalls();
a4412fc94   Andy Lutomirski   seccomp,x86,arm,m...
608
609
610
611
612
613
614
615
616
  #endif
  	do {
  		if (*syscall_whitelist == this_syscall)
  			return;
  	} while (*++syscall_whitelist);
  
  #ifdef SECCOMP_DEBUG
  	dump_stack();
  #endif
fd76875ca   Kees Cook   seccomp: Rename S...
617
  	seccomp_log(this_syscall, SIGKILL, SECCOMP_RET_KILL_THREAD, true);
a4412fc94   Andy Lutomirski   seccomp,x86,arm,m...
618
619
620
621
622
623
624
  	do_exit(SIGKILL);
  }
  
  #ifndef CONFIG_HAVE_ARCH_SECCOMP_FILTER
  void secure_computing_strict(int this_syscall)
  {
  	int mode = current->seccomp.mode;
97f2645f3   Masahiro Yamada   tree-wide: replac...
625
  	if (IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) &&
13c4a9011   Tycho Andersen   seccomp: add ptra...
626
627
  	    unlikely(current->ptrace & PT_SUSPEND_SECCOMP))
  		return;
221272f97   Kees Cook   seccomp: swap har...
628
  	if (mode == SECCOMP_MODE_DISABLED)
a4412fc94   Andy Lutomirski   seccomp,x86,arm,m...
629
630
631
632
633
634
635
  		return;
  	else if (mode == SECCOMP_MODE_STRICT)
  		__secure_computing_strict(this_syscall);
  	else
  		BUG();
  }
  #else
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
636
637
  
  #ifdef CONFIG_SECCOMP_FILTER
ce6526e8a   Kees Cook   seccomp: recheck ...
638
639
  static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd,
  			    const bool recheck_after_trace)
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
640
641
  {
  	u32 filter_ret, action;
deb4de8b3   Kees Cook   seccomp: Provide ...
642
  	struct seccomp_filter *match = NULL;
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
643
  	int data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644

3ba2530cc   Kees Cook   seccomp: allow mo...
645
646
647
648
649
  	/*
  	 * Make sure that any changes to mode from another thread have
  	 * been seen after TIF_SECCOMP was seen.
  	 */
  	rmb();
deb4de8b3   Kees Cook   seccomp: Provide ...
650
  	filter_ret = seccomp_run_filters(sd, &match);
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
651
  	data = filter_ret & SECCOMP_RET_DATA;
0466bdb99   Kees Cook   seccomp: Implemen...
652
  	action = filter_ret & SECCOMP_RET_ACTION_FULL;
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
653
654
655
  
  	switch (action) {
  	case SECCOMP_RET_ERRNO:
580c57f10   Kees Cook   seccomp: cap SECC...
656
657
658
  		/* Set low-order bits as an errno, capped at MAX_ERRNO. */
  		if (data > MAX_ERRNO)
  			data = MAX_ERRNO;
d39bd00de   Andy Lutomirski   seccomp: Allow ar...
659
  		syscall_set_return_value(current, task_pt_regs(current),
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
660
661
662
663
664
  					 -data, 0);
  		goto skip;
  
  	case SECCOMP_RET_TRAP:
  		/* Show the handler the original registers. */
d39bd00de   Andy Lutomirski   seccomp: Allow ar...
665
  		syscall_rollback(current, task_pt_regs(current));
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
666
667
668
669
670
  		/* Let the filter pass back 16 bits of data. */
  		seccomp_send_sigsys(this_syscall, data);
  		goto skip;
  
  	case SECCOMP_RET_TRACE:
ce6526e8a   Kees Cook   seccomp: recheck ...
671
672
673
  		/* We've been put in this state by the ptracer already. */
  		if (recheck_after_trace)
  			return 0;
8112c4f14   Kees Cook   seccomp: remove 2...
674
675
676
677
678
679
680
681
682
683
684
685
  		/* ENOSYS these calls if there is no tracer attached. */
  		if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) {
  			syscall_set_return_value(current,
  						 task_pt_regs(current),
  						 -ENOSYS, 0);
  			goto skip;
  		}
  
  		/* Allow the BPF to provide the event message */
  		ptrace_event(PTRACE_EVENT_SECCOMP, data);
  		/*
  		 * The delivery of a fatal signal during event
485a252a5   Kees Cook   seccomp: Fix trac...
686
687
688
689
690
691
692
  		 * notification may silently skip tracer notification,
  		 * which could leave us with a potentially unmodified
  		 * syscall that the tracer would have liked to have
  		 * changed. Since the process is about to die, we just
  		 * force the syscall to be skipped and let the signal
  		 * kill the process and correctly handle any tracer exit
  		 * notifications.
8112c4f14   Kees Cook   seccomp: remove 2...
693
694
  		 */
  		if (fatal_signal_pending(current))
485a252a5   Kees Cook   seccomp: Fix trac...
695
  			goto skip;
8112c4f14   Kees Cook   seccomp: remove 2...
696
697
698
699
  		/* Check if the tracer forced the syscall to be skipped. */
  		this_syscall = syscall_get_nr(current, task_pt_regs(current));
  		if (this_syscall < 0)
  			goto skip;
ce6526e8a   Kees Cook   seccomp: recheck ...
700
701
702
703
704
705
706
707
  		/*
  		 * Recheck the syscall, since it may have changed. This
  		 * intentionally uses a NULL struct seccomp_data to force
  		 * a reload of all registers. This does not goto skip since
  		 * a skip would have already been reported.
  		 */
  		if (__seccomp_filter(this_syscall, NULL, true))
  			return -1;
8112c4f14   Kees Cook   seccomp: remove 2...
708
  		return 0;
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
709

59f5cf44a   Tyler Hicks   seccomp: Action t...
710
711
712
  	case SECCOMP_RET_LOG:
  		seccomp_log(this_syscall, 0, action, true);
  		return 0;
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
713
  	case SECCOMP_RET_ALLOW:
deb4de8b3   Kees Cook   seccomp: Provide ...
714
715
716
717
718
  		/*
  		 * Note that the "match" filter will always be NULL for
  		 * this action since SECCOMP_RET_ALLOW is the starting
  		 * state in seccomp_run_filters().
  		 */
8112c4f14   Kees Cook   seccomp: remove 2...
719
  		return 0;
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
720

fd76875ca   Kees Cook   seccomp: Rename S...
721
  	case SECCOMP_RET_KILL_THREAD:
4d3b0b05a   Kees Cook   seccomp: Introduc...
722
  	case SECCOMP_RET_KILL_PROCESS:
131b63515   Kees Cook   seccomp: Clean up...
723
  	default:
e66a39977   Tyler Hicks   seccomp: Filter f...
724
  		seccomp_log(this_syscall, SIGSYS, action, true);
d7276e321   Kees Cook   seccomp: Only dum...
725
  		/* Dump core only if this is the last remaining thread. */
4d3b0b05a   Kees Cook   seccomp: Introduc...
726
727
  		if (action == SECCOMP_RET_KILL_PROCESS ||
  		    get_nr_threads(current) == 1) {
131b63515   Kees Cook   seccomp: Clean up...
728
  			siginfo_t info;
d7276e321   Kees Cook   seccomp: Only dum...
729
730
731
732
733
734
  			/* Show the original registers in the dump. */
  			syscall_rollback(current, task_pt_regs(current));
  			/* Trigger a manual coredump since do_exit skips it. */
  			seccomp_init_siginfo(&info, this_syscall, data);
  			do_coredump(&info);
  		}
4d3b0b05a   Kees Cook   seccomp: Introduc...
735
736
737
738
  		if (action == SECCOMP_RET_KILL_PROCESS)
  			do_group_exit(SIGSYS);
  		else
  			do_exit(SIGSYS);
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
739
740
741
742
743
  	}
  
  	unreachable();
  
  skip:
e66a39977   Tyler Hicks   seccomp: Filter f...
744
  	seccomp_log(this_syscall, 0, action, match ? match->log : false);
8112c4f14   Kees Cook   seccomp: remove 2...
745
746
747
  	return -1;
  }
  #else
ce6526e8a   Kees Cook   seccomp: recheck ...
748
749
  static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd,
  			    const bool recheck_after_trace)
8112c4f14   Kees Cook   seccomp: remove 2...
750
751
  {
  	BUG();
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
752
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
  #endif
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
754

8112c4f14   Kees Cook   seccomp: remove 2...
755
  int __secure_computing(const struct seccomp_data *sd)
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
756
757
  {
  	int mode = current->seccomp.mode;
8112c4f14   Kees Cook   seccomp: remove 2...
758
  	int this_syscall;
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
759

97f2645f3   Masahiro Yamada   tree-wide: replac...
760
  	if (IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) &&
13c4a9011   Tycho Andersen   seccomp: add ptra...
761
  	    unlikely(current->ptrace & PT_SUSPEND_SECCOMP))
8112c4f14   Kees Cook   seccomp: remove 2...
762
763
764
765
  		return 0;
  
  	this_syscall = sd ? sd->nr :
  		syscall_get_nr(current, task_pt_regs(current));
13c4a9011   Tycho Andersen   seccomp: add ptra...
766

13aa72f0f   Andy Lutomirski   seccomp: Refactor...
767
  	switch (mode) {
e2cfabdfd   Will Drewry   seccomp: add syst...
768
  	case SECCOMP_MODE_STRICT:
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
769
  		__secure_computing_strict(this_syscall);  /* may call do_exit */
8112c4f14   Kees Cook   seccomp: remove 2...
770
  		return 0;
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
771
  	case SECCOMP_MODE_FILTER:
ce6526e8a   Kees Cook   seccomp: recheck ...
772
  		return __seccomp_filter(this_syscall, sd, false);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
774
775
  	default:
  		BUG();
  	}
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
776
  }
a4412fc94   Andy Lutomirski   seccomp,x86,arm,m...
777
  #endif /* CONFIG_HAVE_ARCH_SECCOMP_FILTER */
1d9d02fee   Andrea Arcangeli   move seccomp from...
778
779
780
781
782
  
  long prctl_get_seccomp(void)
  {
  	return current->seccomp.mode;
  }
e2cfabdfd   Will Drewry   seccomp: add syst...
783
  /**
3b23dd128   Kees Cook   seccomp: split mo...
784
   * seccomp_set_mode_strict: internal function for setting strict seccomp
e2cfabdfd   Will Drewry   seccomp: add syst...
785
786
787
788
789
   *
   * Once current->seccomp.mode is non-zero, it may not be changed.
   *
   * Returns 0 on success or -EINVAL on failure.
   */
3b23dd128   Kees Cook   seccomp: split mo...
790
  static long seccomp_set_mode_strict(void)
1d9d02fee   Andrea Arcangeli   move seccomp from...
791
  {
3b23dd128   Kees Cook   seccomp: split mo...
792
  	const unsigned long seccomp_mode = SECCOMP_MODE_STRICT;
e2cfabdfd   Will Drewry   seccomp: add syst...
793
  	long ret = -EINVAL;
1d9d02fee   Andrea Arcangeli   move seccomp from...
794

dbd952127   Kees Cook   seccomp: introduc...
795
  	spin_lock_irq(&current->sighand->siglock);
1f41b4504   Kees Cook   seccomp: extract ...
796
  	if (!seccomp_may_assign_mode(seccomp_mode))
1d9d02fee   Andrea Arcangeli   move seccomp from...
797
  		goto out;
cf99abace   Andrea Arcangeli   make seccomp zero...
798
  #ifdef TIF_NOTSC
3b23dd128   Kees Cook   seccomp: split mo...
799
  	disable_TSC();
cf99abace   Andrea Arcangeli   make seccomp zero...
800
  #endif
9939db75c   Kees Cook   seccomp: Add filt...
801
  	seccomp_assign_mode(current, seccomp_mode, 0);
3b23dd128   Kees Cook   seccomp: split mo...
802
803
804
  	ret = 0;
  
  out:
dbd952127   Kees Cook   seccomp: introduc...
805
  	spin_unlock_irq(&current->sighand->siglock);
3b23dd128   Kees Cook   seccomp: split mo...
806
807
808
  
  	return ret;
  }
e2cfabdfd   Will Drewry   seccomp: add syst...
809
  #ifdef CONFIG_SECCOMP_FILTER
3b23dd128   Kees Cook   seccomp: split mo...
810
811
  /**
   * seccomp_set_mode_filter: internal function for setting seccomp filter
48dc92b9f   Kees Cook   seccomp: add "sec...
812
   * @flags:  flags to change filter behavior
3b23dd128   Kees Cook   seccomp: split mo...
813
814
815
816
817
818
819
820
821
822
   * @filter: struct sock_fprog containing filter
   *
   * This function may be called repeatedly to install additional filters.
   * Every filter successfully installed will be evaluated (in reverse order)
   * for each system call the task makes.
   *
   * Once current->seccomp.mode is non-zero, it may not be changed.
   *
   * Returns 0 on success or -EINVAL on failure.
   */
48dc92b9f   Kees Cook   seccomp: add "sec...
823
824
  static long seccomp_set_mode_filter(unsigned int flags,
  				    const char __user *filter)
3b23dd128   Kees Cook   seccomp: split mo...
825
826
  {
  	const unsigned long seccomp_mode = SECCOMP_MODE_FILTER;
c8bee430d   Kees Cook   seccomp: split fi...
827
  	struct seccomp_filter *prepared = NULL;
3b23dd128   Kees Cook   seccomp: split mo...
828
  	long ret = -EINVAL;
48dc92b9f   Kees Cook   seccomp: add "sec...
829
  	/* Validate flags. */
c2e1f2e30   Kees Cook   seccomp: implemen...
830
  	if (flags & ~SECCOMP_FILTER_FLAG_MASK)
dbd952127   Kees Cook   seccomp: introduc...
831
  		return -EINVAL;
48dc92b9f   Kees Cook   seccomp: add "sec...
832

c8bee430d   Kees Cook   seccomp: split fi...
833
834
835
836
  	/* Prepare the new filter before holding any locks. */
  	prepared = seccomp_prepare_user_filter(filter);
  	if (IS_ERR(prepared))
  		return PTR_ERR(prepared);
c2e1f2e30   Kees Cook   seccomp: implemen...
837
838
839
840
841
842
843
  	/*
  	 * Make sure we cannot change seccomp or nnp state via TSYNC
  	 * while another thread is in the middle of calling exec.
  	 */
  	if (flags & SECCOMP_FILTER_FLAG_TSYNC &&
  	    mutex_lock_killable(&current->signal->cred_guard_mutex))
  		goto out_free;
dbd952127   Kees Cook   seccomp: introduc...
844
  	spin_lock_irq(&current->sighand->siglock);
3b23dd128   Kees Cook   seccomp: split mo...
845
846
  	if (!seccomp_may_assign_mode(seccomp_mode))
  		goto out;
c8bee430d   Kees Cook   seccomp: split fi...
847
  	ret = seccomp_attach_filter(flags, prepared);
3b23dd128   Kees Cook   seccomp: split mo...
848
  	if (ret)
e2cfabdfd   Will Drewry   seccomp: add syst...
849
  		goto out;
c8bee430d   Kees Cook   seccomp: split fi...
850
851
  	/* Do not free the successfully attached filter. */
  	prepared = NULL;
1d9d02fee   Andrea Arcangeli   move seccomp from...
852

9939db75c   Kees Cook   seccomp: Add filt...
853
  	seccomp_assign_mode(current, seccomp_mode, flags);
e2cfabdfd   Will Drewry   seccomp: add syst...
854
  out:
dbd952127   Kees Cook   seccomp: introduc...
855
  	spin_unlock_irq(&current->sighand->siglock);
c2e1f2e30   Kees Cook   seccomp: implemen...
856
857
858
  	if (flags & SECCOMP_FILTER_FLAG_TSYNC)
  		mutex_unlock(&current->signal->cred_guard_mutex);
  out_free:
c8bee430d   Kees Cook   seccomp: split fi...
859
  	seccomp_filter_free(prepared);
1d9d02fee   Andrea Arcangeli   move seccomp from...
860
861
  	return ret;
  }
3b23dd128   Kees Cook   seccomp: split mo...
862
  #else
48dc92b9f   Kees Cook   seccomp: add "sec...
863
864
  static inline long seccomp_set_mode_filter(unsigned int flags,
  					   const char __user *filter)
3b23dd128   Kees Cook   seccomp: split mo...
865
866
867
868
  {
  	return -EINVAL;
  }
  #endif
d78ab02c2   Kees Cook   seccomp: create i...
869

d612b1fd8   Tyler Hicks   seccomp: Operatio...
870
871
872
873
874
875
876
877
  static long seccomp_get_action_avail(const char __user *uaction)
  {
  	u32 action;
  
  	if (copy_from_user(&action, uaction, sizeof(action)))
  		return -EFAULT;
  
  	switch (action) {
0466bdb99   Kees Cook   seccomp: Implemen...
878
  	case SECCOMP_RET_KILL_PROCESS:
fd76875ca   Kees Cook   seccomp: Rename S...
879
  	case SECCOMP_RET_KILL_THREAD:
d612b1fd8   Tyler Hicks   seccomp: Operatio...
880
881
882
  	case SECCOMP_RET_TRAP:
  	case SECCOMP_RET_ERRNO:
  	case SECCOMP_RET_TRACE:
59f5cf44a   Tyler Hicks   seccomp: Action t...
883
  	case SECCOMP_RET_LOG:
d612b1fd8   Tyler Hicks   seccomp: Operatio...
884
885
886
887
888
889
890
891
  	case SECCOMP_RET_ALLOW:
  		break;
  	default:
  		return -EOPNOTSUPP;
  	}
  
  	return 0;
  }
48dc92b9f   Kees Cook   seccomp: add "sec...
892
893
894
895
896
897
898
899
900
901
902
  /* Common entry point for both prctl and syscall. */
  static long do_seccomp(unsigned int op, unsigned int flags,
  		       const char __user *uargs)
  {
  	switch (op) {
  	case SECCOMP_SET_MODE_STRICT:
  		if (flags != 0 || uargs != NULL)
  			return -EINVAL;
  		return seccomp_set_mode_strict();
  	case SECCOMP_SET_MODE_FILTER:
  		return seccomp_set_mode_filter(flags, uargs);
d612b1fd8   Tyler Hicks   seccomp: Operatio...
903
904
905
906
907
  	case SECCOMP_GET_ACTION_AVAIL:
  		if (flags != 0)
  			return -EINVAL;
  
  		return seccomp_get_action_avail(uargs);
48dc92b9f   Kees Cook   seccomp: add "sec...
908
909
910
911
912
913
914
915
916
917
  	default:
  		return -EINVAL;
  	}
  }
  
  SYSCALL_DEFINE3(seccomp, unsigned int, op, unsigned int, flags,
  			 const char __user *, uargs)
  {
  	return do_seccomp(op, flags, uargs);
  }
d78ab02c2   Kees Cook   seccomp: create i...
918
919
920
921
922
923
924
925
926
  /**
   * prctl_set_seccomp: configures current->seccomp.mode
   * @seccomp_mode: requested mode to use
   * @filter: optional struct sock_fprog for use with SECCOMP_MODE_FILTER
   *
   * Returns 0 on success or -EINVAL on failure.
   */
  long prctl_set_seccomp(unsigned long seccomp_mode, char __user *filter)
  {
48dc92b9f   Kees Cook   seccomp: add "sec...
927
928
  	unsigned int op;
  	char __user *uargs;
3b23dd128   Kees Cook   seccomp: split mo...
929
930
  	switch (seccomp_mode) {
  	case SECCOMP_MODE_STRICT:
48dc92b9f   Kees Cook   seccomp: add "sec...
931
932
933
934
935
936
937
938
  		op = SECCOMP_SET_MODE_STRICT;
  		/*
  		 * Setting strict mode through prctl always ignored filter,
  		 * so make sure it is always NULL here to pass the internal
  		 * check in do_seccomp().
  		 */
  		uargs = NULL;
  		break;
3b23dd128   Kees Cook   seccomp: split mo...
939
  	case SECCOMP_MODE_FILTER:
48dc92b9f   Kees Cook   seccomp: add "sec...
940
941
942
  		op = SECCOMP_SET_MODE_FILTER;
  		uargs = filter;
  		break;
3b23dd128   Kees Cook   seccomp: split mo...
943
944
945
  	default:
  		return -EINVAL;
  	}
48dc92b9f   Kees Cook   seccomp: add "sec...
946
947
948
  
  	/* prctl interface doesn't have flags, so they are always zero. */
  	return do_seccomp(op, 0, uargs);
d78ab02c2   Kees Cook   seccomp: create i...
949
  }
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
  
  #if defined(CONFIG_SECCOMP_FILTER) && defined(CONFIG_CHECKPOINT_RESTORE)
  long seccomp_get_filter(struct task_struct *task, unsigned long filter_off,
  			void __user *data)
  {
  	struct seccomp_filter *filter;
  	struct sock_fprog_kern *fprog;
  	long ret;
  	unsigned long count = 0;
  
  	if (!capable(CAP_SYS_ADMIN) ||
  	    current->seccomp.mode != SECCOMP_MODE_DISABLED) {
  		return -EACCES;
  	}
  
  	spin_lock_irq(&task->sighand->siglock);
  	if (task->seccomp.mode != SECCOMP_MODE_FILTER) {
  		ret = -EINVAL;
  		goto out;
  	}
  
  	filter = task->seccomp.filter;
  	while (filter) {
  		filter = filter->prev;
  		count++;
  	}
  
  	if (filter_off >= count) {
  		ret = -ENOENT;
  		goto out;
  	}
  	count -= filter_off;
  
  	filter = task->seccomp.filter;
  	while (filter && count > 1) {
  		filter = filter->prev;
  		count--;
  	}
  
  	if (WARN_ON(count != 1 || !filter)) {
  		/* The filter tree shouldn't shrink while we're using it. */
  		ret = -ENOENT;
  		goto out;
  	}
  
  	fprog = filter->prog->orig_prog;
  	if (!fprog) {
470bf1f27   Mickaël Salaün   seccomp: Fix comm...
997
  		/* This must be a new non-cBPF filter, since we save
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
998
999
1000
1001
1002
1003
1004
1005
1006
1007
  		 * every cBPF filter's orig_prog above when
  		 * CONFIG_CHECKPOINT_RESTORE is enabled.
  		 */
  		ret = -EMEDIUMTYPE;
  		goto out;
  	}
  
  	ret = fprog->len;
  	if (!data)
  		goto out;
66a733ea6   Oleg Nesterov   seccomp: fix the ...
1008
  	__get_seccomp_filter(filter);
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
1009
1010
1011
1012
  	spin_unlock_irq(&task->sighand->siglock);
  
  	if (copy_to_user(data, fprog->filter, bpf_classic_proglen(fprog)))
  		ret = -EFAULT;
66a733ea6   Oleg Nesterov   seccomp: fix the ...
1013
  	__put_seccomp_filter(filter);
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
1014
1015
1016
1017
1018
1019
1020
  	return ret;
  
  out:
  	spin_unlock_irq(&task->sighand->siglock);
  	return ret;
  }
  #endif
8e5f1ad11   Tyler Hicks   seccomp: Sysctl t...
1021
1022
1023
1024
  
  #ifdef CONFIG_SYSCTL
  
  /* Human readable action names for friendly sysctl interaction */
0466bdb99   Kees Cook   seccomp: Implemen...
1025
  #define SECCOMP_RET_KILL_PROCESS_NAME	"kill_process"
fd76875ca   Kees Cook   seccomp: Rename S...
1026
  #define SECCOMP_RET_KILL_THREAD_NAME	"kill_thread"
8e5f1ad11   Tyler Hicks   seccomp: Sysctl t...
1027
1028
1029
  #define SECCOMP_RET_TRAP_NAME		"trap"
  #define SECCOMP_RET_ERRNO_NAME		"errno"
  #define SECCOMP_RET_TRACE_NAME		"trace"
59f5cf44a   Tyler Hicks   seccomp: Action t...
1030
  #define SECCOMP_RET_LOG_NAME		"log"
8e5f1ad11   Tyler Hicks   seccomp: Sysctl t...
1031
  #define SECCOMP_RET_ALLOW_NAME		"allow"
fd76875ca   Kees Cook   seccomp: Rename S...
1032
  static const char seccomp_actions_avail[] =
0466bdb99   Kees Cook   seccomp: Implemen...
1033
  				SECCOMP_RET_KILL_PROCESS_NAME	" "
fd76875ca   Kees Cook   seccomp: Rename S...
1034
1035
1036
1037
1038
1039
  				SECCOMP_RET_KILL_THREAD_NAME	" "
  				SECCOMP_RET_TRAP_NAME		" "
  				SECCOMP_RET_ERRNO_NAME		" "
  				SECCOMP_RET_TRACE_NAME		" "
  				SECCOMP_RET_LOG_NAME		" "
  				SECCOMP_RET_ALLOW_NAME;
8e5f1ad11   Tyler Hicks   seccomp: Sysctl t...
1040

0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
1041
1042
1043
1044
1045
1046
  struct seccomp_log_name {
  	u32		log;
  	const char	*name;
  };
  
  static const struct seccomp_log_name seccomp_log_names[] = {
0466bdb99   Kees Cook   seccomp: Implemen...
1047
  	{ SECCOMP_LOG_KILL_PROCESS, SECCOMP_RET_KILL_PROCESS_NAME },
fd76875ca   Kees Cook   seccomp: Rename S...
1048
  	{ SECCOMP_LOG_KILL_THREAD, SECCOMP_RET_KILL_THREAD_NAME },
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
1049
1050
1051
  	{ SECCOMP_LOG_TRAP, SECCOMP_RET_TRAP_NAME },
  	{ SECCOMP_LOG_ERRNO, SECCOMP_RET_ERRNO_NAME },
  	{ SECCOMP_LOG_TRACE, SECCOMP_RET_TRACE_NAME },
59f5cf44a   Tyler Hicks   seccomp: Action t...
1052
  	{ SECCOMP_LOG_LOG, SECCOMP_RET_LOG_NAME },
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
  	{ SECCOMP_LOG_ALLOW, SECCOMP_RET_ALLOW_NAME },
  	{ }
  };
  
  static bool seccomp_names_from_actions_logged(char *names, size_t size,
  					      u32 actions_logged)
  {
  	const struct seccomp_log_name *cur;
  	bool append_space = false;
  
  	for (cur = seccomp_log_names; cur->name && size; cur++) {
  		ssize_t ret;
  
  		if (!(actions_logged & cur->log))
  			continue;
  
  		if (append_space) {
  			ret = strscpy(names, " ", size);
  			if (ret < 0)
  				return false;
  
  			names += ret;
  			size -= ret;
  		} else
  			append_space = true;
  
  		ret = strscpy(names, cur->name, size);
  		if (ret < 0)
  			return false;
  
  		names += ret;
  		size -= ret;
  	}
  
  	return true;
  }
  
  static bool seccomp_action_logged_from_name(u32 *action_logged,
  					    const char *name)
  {
  	const struct seccomp_log_name *cur;
  
  	for (cur = seccomp_log_names; cur->name; cur++) {
  		if (!strcmp(cur->name, name)) {
  			*action_logged = cur->log;
  			return true;
  		}
  	}
  
  	return false;
  }
  
  static bool seccomp_actions_logged_from_names(u32 *actions_logged, char *names)
  {
  	char *name;
  
  	*actions_logged = 0;
  	while ((name = strsep(&names, " ")) && *name) {
  		u32 action_logged = 0;
  
  		if (!seccomp_action_logged_from_name(&action_logged, name))
  			return false;
  
  		*actions_logged |= action_logged;
  	}
  
  	return true;
  }
  
  static int seccomp_actions_logged_handler(struct ctl_table *ro_table, int write,
  					  void __user *buffer, size_t *lenp,
  					  loff_t *ppos)
  {
  	char names[sizeof(seccomp_actions_avail)];
  	struct ctl_table table;
  	int ret;
  
  	if (write && !capable(CAP_SYS_ADMIN))
  		return -EPERM;
  
  	memset(names, 0, sizeof(names));
  
  	if (!write) {
  		if (!seccomp_names_from_actions_logged(names, sizeof(names),
  						       seccomp_actions_logged))
  			return -EINVAL;
  	}
  
  	table = *ro_table;
  	table.data = names;
  	table.maxlen = sizeof(names);
  	ret = proc_dostring(&table, write, buffer, lenp, ppos);
  	if (ret)
  		return ret;
  
  	if (write) {
  		u32 actions_logged;
  
  		if (!seccomp_actions_logged_from_names(&actions_logged,
  						       table.data))
  			return -EINVAL;
  
  		if (actions_logged & SECCOMP_LOG_ALLOW)
  			return -EINVAL;
  
  		seccomp_actions_logged = actions_logged;
  	}
  
  	return 0;
  }
8e5f1ad11   Tyler Hicks   seccomp: Sysctl t...
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
  static struct ctl_path seccomp_sysctl_path[] = {
  	{ .procname = "kernel", },
  	{ .procname = "seccomp", },
  	{ }
  };
  
  static struct ctl_table seccomp_sysctl_table[] = {
  	{
  		.procname	= "actions_avail",
  		.data		= (void *) &seccomp_actions_avail,
  		.maxlen		= sizeof(seccomp_actions_avail),
  		.mode		= 0444,
  		.proc_handler	= proc_dostring,
  	},
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
1177
1178
1179
1180
1181
  	{
  		.procname	= "actions_logged",
  		.mode		= 0644,
  		.proc_handler	= seccomp_actions_logged_handler,
  	},
8e5f1ad11   Tyler Hicks   seccomp: Sysctl t...
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
  	{ }
  };
  
  static int __init seccomp_sysctl_init(void)
  {
  	struct ctl_table_header *hdr;
  
  	hdr = register_sysctl_paths(seccomp_sysctl_path, seccomp_sysctl_table);
  	if (!hdr)
  		pr_warn("seccomp: sysctl registration failed
  ");
  	else
  		kmemleak_not_leak(hdr);
  
  	return 0;
  }
  
  device_initcall(seccomp_sysctl_init)
  
  #endif /* CONFIG_SYSCTL */