Blame view

kernel/seccomp.c 34.3 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>
5c3070890   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 =
506458efa   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;
  }
8bf37d8c0   Thomas Gleixner   seccomp: Move spe...
229
  void __weak arch_seccomp_spec_mitigate(struct task_struct *task) { }
5c3070890   Kees Cook   seccomp: Enable s...
230

3ba2530cc   Kees Cook   seccomp: allow mo...
231
  static inline void seccomp_assign_mode(struct task_struct *task,
00a02d0c5   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();
00a02d0c5   Kees Cook   seccomp: Add filt...
243
244
  	/* Assume default seccomp processes want spec flaw mitigation. */
  	if ((flags & SECCOMP_FILTER_FLAG_SPEC_ALLOW) == 0)
8bf37d8c0   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.
   *
   */
00a02d0c5   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)
00a02d0c5   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)
00a02d0c5   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
  static void seccomp_init_siginfo(siginfo_t *info, int syscall, int reason)
  {
3b10db2b0   Eric W. Biederman   signal: Replace m...
512
  	clear_siginfo(info);
b25e67161   Mike Frysinger   seccomp: dump cor...
513
514
515
516
517
518
519
  	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
  	}
  
  	/*
326bee028   Tyler Hicks   seccomp: Don't sp...
580
581
582
583
  	 * Emit an audit message when the action is RET_KILL_*, RET_LOG, or the
  	 * FILTER_FLAG_LOG bit was set. The admin has the ability to silence
  	 * any action from being logged by removing the action name from the
  	 * seccomp_actions_logged sysctl.
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
584
  	 */
326bee028   Tyler Hicks   seccomp: Don't sp...
585
586
  	if (!log)
  		return;
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
587

326bee028   Tyler Hicks   seccomp: Don't sp...
588
  	audit_seccomp(syscall, signr, action);
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
589
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
591
592
593
594
  /*
   * 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 ...
595
  static const int mode1_syscalls[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596
597
598
  	__NR_seccomp_read, __NR_seccomp_write, __NR_seccomp_exit, __NR_seccomp_sigreturn,
  	0, /* null terminated */
  };
a4412fc94   Andy Lutomirski   seccomp,x86,arm,m...
599
  static void __secure_computing_strict(int this_syscall)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
  {
cb4253aa0   Matt Redfearn   secomp: Constify ...
601
  	const int *syscall_whitelist = mode1_syscalls;
a4412fc94   Andy Lutomirski   seccomp,x86,arm,m...
602
  #ifdef CONFIG_COMPAT
5c38065e0   Andy Lutomirski   seccomp: check in...
603
  	if (in_compat_syscall())
c983f0e86   Matt Redfearn   seccomp: Get comp...
604
  		syscall_whitelist = get_compat_mode1_syscalls();
a4412fc94   Andy Lutomirski   seccomp,x86,arm,m...
605
606
607
608
609
610
611
612
613
  #endif
  	do {
  		if (*syscall_whitelist == this_syscall)
  			return;
  	} while (*++syscall_whitelist);
  
  #ifdef SECCOMP_DEBUG
  	dump_stack();
  #endif
fd76875ca   Kees Cook   seccomp: Rename S...
614
  	seccomp_log(this_syscall, SIGKILL, SECCOMP_RET_KILL_THREAD, true);
a4412fc94   Andy Lutomirski   seccomp,x86,arm,m...
615
616
617
618
619
620
621
  	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...
622
  	if (IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) &&
13c4a9011   Tycho Andersen   seccomp: add ptra...
623
624
  	    unlikely(current->ptrace & PT_SUSPEND_SECCOMP))
  		return;
221272f97   Kees Cook   seccomp: swap har...
625
  	if (mode == SECCOMP_MODE_DISABLED)
a4412fc94   Andy Lutomirski   seccomp,x86,arm,m...
626
627
628
629
630
631
632
  		return;
  	else if (mode == SECCOMP_MODE_STRICT)
  		__secure_computing_strict(this_syscall);
  	else
  		BUG();
  }
  #else
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
633
634
  
  #ifdef CONFIG_SECCOMP_FILTER
ce6526e8a   Kees Cook   seccomp: recheck ...
635
636
  static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd,
  			    const bool recheck_after_trace)
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
637
638
  {
  	u32 filter_ret, action;
deb4de8b3   Kees Cook   seccomp: Provide ...
639
  	struct seccomp_filter *match = NULL;
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
640
  	int data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641

3ba2530cc   Kees Cook   seccomp: allow mo...
642
643
644
645
646
  	/*
  	 * Make sure that any changes to mode from another thread have
  	 * been seen after TIF_SECCOMP was seen.
  	 */
  	rmb();
deb4de8b3   Kees Cook   seccomp: Provide ...
647
  	filter_ret = seccomp_run_filters(sd, &match);
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
648
  	data = filter_ret & SECCOMP_RET_DATA;
0466bdb99   Kees Cook   seccomp: Implemen...
649
  	action = filter_ret & SECCOMP_RET_ACTION_FULL;
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
650
651
652
  
  	switch (action) {
  	case SECCOMP_RET_ERRNO:
580c57f10   Kees Cook   seccomp: cap SECC...
653
654
655
  		/* Set low-order bits as an errno, capped at MAX_ERRNO. */
  		if (data > MAX_ERRNO)
  			data = MAX_ERRNO;
d39bd00de   Andy Lutomirski   seccomp: Allow ar...
656
  		syscall_set_return_value(current, task_pt_regs(current),
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
657
658
659
660
661
  					 -data, 0);
  		goto skip;
  
  	case SECCOMP_RET_TRAP:
  		/* Show the handler the original registers. */
d39bd00de   Andy Lutomirski   seccomp: Allow ar...
662
  		syscall_rollback(current, task_pt_regs(current));
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
663
664
665
666
667
  		/* 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 ...
668
669
670
  		/* We've been put in this state by the ptracer already. */
  		if (recheck_after_trace)
  			return 0;
8112c4f14   Kees Cook   seccomp: remove 2...
671
672
673
674
675
676
677
678
679
680
681
682
  		/* 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...
683
684
685
686
687
688
689
  		 * 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...
690
691
  		 */
  		if (fatal_signal_pending(current))
485a252a5   Kees Cook   seccomp: Fix trac...
692
  			goto skip;
8112c4f14   Kees Cook   seccomp: remove 2...
693
694
695
696
  		/* 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 ...
697
698
699
700
701
702
703
704
  		/*
  		 * 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...
705
  		return 0;
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
706

59f5cf44a   Tyler Hicks   seccomp: Action t...
707
708
709
  	case SECCOMP_RET_LOG:
  		seccomp_log(this_syscall, 0, action, true);
  		return 0;
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
710
  	case SECCOMP_RET_ALLOW:
deb4de8b3   Kees Cook   seccomp: Provide ...
711
712
713
714
715
  		/*
  		 * 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...
716
  		return 0;
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
717

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

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

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

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

dbd952127   Kees Cook   seccomp: introduc...
792
  	spin_lock_irq(&current->sighand->siglock);
1f41b4504   Kees Cook   seccomp: extract ...
793
  	if (!seccomp_may_assign_mode(seccomp_mode))
1d9d02fee   Andrea Arcangeli   move seccomp from...
794
  		goto out;
cf99abace   Andrea Arcangeli   make seccomp zero...
795
  #ifdef TIF_NOTSC
3b23dd128   Kees Cook   seccomp: split mo...
796
  	disable_TSC();
cf99abace   Andrea Arcangeli   make seccomp zero...
797
  #endif
00a02d0c5   Kees Cook   seccomp: Add filt...
798
  	seccomp_assign_mode(current, seccomp_mode, 0);
3b23dd128   Kees Cook   seccomp: split mo...
799
800
801
  	ret = 0;
  
  out:
dbd952127   Kees Cook   seccomp: introduc...
802
  	spin_unlock_irq(&current->sighand->siglock);
3b23dd128   Kees Cook   seccomp: split mo...
803
804
805
  
  	return ret;
  }
e2cfabdfd   Will Drewry   seccomp: add syst...
806
  #ifdef CONFIG_SECCOMP_FILTER
3b23dd128   Kees Cook   seccomp: split mo...
807
808
  /**
   * seccomp_set_mode_filter: internal function for setting seccomp filter
48dc92b9f   Kees Cook   seccomp: add "sec...
809
   * @flags:  flags to change filter behavior
3b23dd128   Kees Cook   seccomp: split mo...
810
811
812
813
814
815
816
817
818
819
   * @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...
820
821
  static long seccomp_set_mode_filter(unsigned int flags,
  				    const char __user *filter)
3b23dd128   Kees Cook   seccomp: split mo...
822
823
  {
  	const unsigned long seccomp_mode = SECCOMP_MODE_FILTER;
c8bee430d   Kees Cook   seccomp: split fi...
824
  	struct seccomp_filter *prepared = NULL;
3b23dd128   Kees Cook   seccomp: split mo...
825
  	long ret = -EINVAL;
48dc92b9f   Kees Cook   seccomp: add "sec...
826
  	/* Validate flags. */
c2e1f2e30   Kees Cook   seccomp: implemen...
827
  	if (flags & ~SECCOMP_FILTER_FLAG_MASK)
dbd952127   Kees Cook   seccomp: introduc...
828
  		return -EINVAL;
48dc92b9f   Kees Cook   seccomp: add "sec...
829

c8bee430d   Kees Cook   seccomp: split fi...
830
831
832
833
  	/* 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...
834
835
836
837
838
839
840
  	/*
  	 * 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...
841
  	spin_lock_irq(&current->sighand->siglock);
3b23dd128   Kees Cook   seccomp: split mo...
842
843
  	if (!seccomp_may_assign_mode(seccomp_mode))
  		goto out;
c8bee430d   Kees Cook   seccomp: split fi...
844
  	ret = seccomp_attach_filter(flags, prepared);
3b23dd128   Kees Cook   seccomp: split mo...
845
  	if (ret)
e2cfabdfd   Will Drewry   seccomp: add syst...
846
  		goto out;
c8bee430d   Kees Cook   seccomp: split fi...
847
848
  	/* Do not free the successfully attached filter. */
  	prepared = NULL;
1d9d02fee   Andrea Arcangeli   move seccomp from...
849

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

d612b1fd8   Tyler Hicks   seccomp: Operatio...
867
868
869
870
871
872
873
874
  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...
875
  	case SECCOMP_RET_KILL_PROCESS:
fd76875ca   Kees Cook   seccomp: Rename S...
876
  	case SECCOMP_RET_KILL_THREAD:
d612b1fd8   Tyler Hicks   seccomp: Operatio...
877
878
879
  	case SECCOMP_RET_TRAP:
  	case SECCOMP_RET_ERRNO:
  	case SECCOMP_RET_TRACE:
59f5cf44a   Tyler Hicks   seccomp: Action t...
880
  	case SECCOMP_RET_LOG:
d612b1fd8   Tyler Hicks   seccomp: Operatio...
881
882
883
884
885
886
887
888
  	case SECCOMP_RET_ALLOW:
  		break;
  	default:
  		return -EOPNOTSUPP;
  	}
  
  	return 0;
  }
48dc92b9f   Kees Cook   seccomp: add "sec...
889
890
891
892
893
894
895
896
897
898
899
  /* 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...
900
901
902
903
904
  	case SECCOMP_GET_ACTION_AVAIL:
  		if (flags != 0)
  			return -EINVAL;
  
  		return seccomp_get_action_avail(uargs);
48dc92b9f   Kees Cook   seccomp: add "sec...
905
906
907
908
909
910
911
912
913
914
  	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...
915
916
917
918
919
920
921
922
923
  /**
   * 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...
924
925
  	unsigned int op;
  	char __user *uargs;
3b23dd128   Kees Cook   seccomp: split mo...
926
927
  	switch (seccomp_mode) {
  	case SECCOMP_MODE_STRICT:
48dc92b9f   Kees Cook   seccomp: add "sec...
928
929
930
931
932
933
934
935
  		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...
936
  	case SECCOMP_MODE_FILTER:
48dc92b9f   Kees Cook   seccomp: add "sec...
937
938
939
  		op = SECCOMP_SET_MODE_FILTER;
  		uargs = filter;
  		break;
3b23dd128   Kees Cook   seccomp: split mo...
940
941
942
  	default:
  		return -EINVAL;
  	}
48dc92b9f   Kees Cook   seccomp: add "sec...
943
944
945
  
  	/* prctl interface doesn't have flags, so they are always zero. */
  	return do_seccomp(op, 0, uargs);
d78ab02c2   Kees Cook   seccomp: create i...
946
  }
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
947
948
  
  #if defined(CONFIG_SECCOMP_FILTER) && defined(CONFIG_CHECKPOINT_RESTORE)
f06eae831   Tycho Andersen   seccomp: hoist ou...
949
950
  static struct seccomp_filter *get_nth_filter(struct task_struct *task,
  					     unsigned long filter_off)
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
951
  {
f06eae831   Tycho Andersen   seccomp: hoist ou...
952
953
  	struct seccomp_filter *orig, *filter;
  	unsigned long count;
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
954

f06eae831   Tycho Andersen   seccomp: hoist ou...
955
956
957
958
  	/*
  	 * Note: this is only correct because the caller should be the (ptrace)
  	 * tracer of the task, otherwise lock_task_sighand is needed.
  	 */
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
959
  	spin_lock_irq(&task->sighand->siglock);
f06eae831   Tycho Andersen   seccomp: hoist ou...
960

f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
961
  	if (task->seccomp.mode != SECCOMP_MODE_FILTER) {
f06eae831   Tycho Andersen   seccomp: hoist ou...
962
963
  		spin_unlock_irq(&task->sighand->siglock);
  		return ERR_PTR(-EINVAL);
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
964
  	}
f06eae831   Tycho Andersen   seccomp: hoist ou...
965
966
967
968
969
970
  	orig = task->seccomp.filter;
  	__get_seccomp_filter(orig);
  	spin_unlock_irq(&task->sighand->siglock);
  
  	count = 0;
  	for (filter = orig; filter; filter = filter->prev)
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
971
  		count++;
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
972
973
  
  	if (filter_off >= count) {
f06eae831   Tycho Andersen   seccomp: hoist ou...
974
  		filter = ERR_PTR(-ENOENT);
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
975
976
  		goto out;
  	}
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
977

f06eae831   Tycho Andersen   seccomp: hoist ou...
978
979
  	count -= filter_off;
  	for (filter = orig; filter && count > 1; filter = filter->prev)
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
980
  		count--;
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
981
982
  
  	if (WARN_ON(count != 1 || !filter)) {
f06eae831   Tycho Andersen   seccomp: hoist ou...
983
  		filter = ERR_PTR(-ENOENT);
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
984
985
  		goto out;
  	}
f06eae831   Tycho Andersen   seccomp: hoist ou...
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
  	__get_seccomp_filter(filter);
  
  out:
  	__put_seccomp_filter(orig);
  	return filter;
  }
  
  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;
  
  	if (!capable(CAP_SYS_ADMIN) ||
  	    current->seccomp.mode != SECCOMP_MODE_DISABLED) {
  		return -EACCES;
  	}
  
  	filter = get_nth_filter(task, filter_off);
  	if (IS_ERR(filter))
  		return PTR_ERR(filter);
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
1008
1009
  	fprog = filter->prog->orig_prog;
  	if (!fprog) {
470bf1f27   Mickaël Salaün   seccomp: Fix comm...
1010
  		/* This must be a new non-cBPF filter, since we save
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
  		 * every cBPF filter's orig_prog above when
  		 * CONFIG_CHECKPOINT_RESTORE is enabled.
  		 */
  		ret = -EMEDIUMTYPE;
  		goto out;
  	}
  
  	ret = fprog->len;
  	if (!data)
  		goto out;
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
1021
1022
  	if (copy_to_user(data, fprog->filter, bpf_classic_proglen(fprog)))
  		ret = -EFAULT;
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
1023
  out:
66a733ea6   Oleg Nesterov   seccomp: fix the ...
1024
  	__put_seccomp_filter(filter);
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
1025
  	return ret;
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
1026
  }
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
1027

26500475a   Tycho Andersen   ptrace, seccomp: ...
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
  long seccomp_get_metadata(struct task_struct *task,
  			  unsigned long size, void __user *data)
  {
  	long ret;
  	struct seccomp_filter *filter;
  	struct seccomp_metadata kmd = {};
  
  	if (!capable(CAP_SYS_ADMIN) ||
  	    current->seccomp.mode != SECCOMP_MODE_DISABLED) {
  		return -EACCES;
  	}
  
  	size = min_t(unsigned long, size, sizeof(kmd));
63bb0045b   Tycho Andersen   ptrace, seccomp: ...
1041
1042
1043
1044
  	if (size < sizeof(kmd.filter_off))
  		return -EINVAL;
  
  	if (copy_from_user(&kmd.filter_off, data, sizeof(kmd.filter_off)))
26500475a   Tycho Andersen   ptrace, seccomp: ...
1045
1046
1047
1048
1049
  		return -EFAULT;
  
  	filter = get_nth_filter(task, kmd.filter_off);
  	if (IS_ERR(filter))
  		return PTR_ERR(filter);
26500475a   Tycho Andersen   ptrace, seccomp: ...
1050
1051
1052
1053
1054
1055
1056
1057
  	if (filter->log)
  		kmd.flags |= SECCOMP_FILTER_FLAG_LOG;
  
  	ret = size;
  	if (copy_to_user(data, &kmd, size))
  		ret = -EFAULT;
  
  	__put_seccomp_filter(filter);
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
1058
1059
1060
  	return ret;
  }
  #endif
8e5f1ad11   Tyler Hicks   seccomp: Sysctl t...
1061
1062
1063
1064
  
  #ifdef CONFIG_SYSCTL
  
  /* Human readable action names for friendly sysctl interaction */
0466bdb99   Kees Cook   seccomp: Implemen...
1065
  #define SECCOMP_RET_KILL_PROCESS_NAME	"kill_process"
fd76875ca   Kees Cook   seccomp: Rename S...
1066
  #define SECCOMP_RET_KILL_THREAD_NAME	"kill_thread"
8e5f1ad11   Tyler Hicks   seccomp: Sysctl t...
1067
1068
1069
  #define SECCOMP_RET_TRAP_NAME		"trap"
  #define SECCOMP_RET_ERRNO_NAME		"errno"
  #define SECCOMP_RET_TRACE_NAME		"trace"
59f5cf44a   Tyler Hicks   seccomp: Action t...
1070
  #define SECCOMP_RET_LOG_NAME		"log"
8e5f1ad11   Tyler Hicks   seccomp: Sysctl t...
1071
  #define SECCOMP_RET_ALLOW_NAME		"allow"
fd76875ca   Kees Cook   seccomp: Rename S...
1072
  static const char seccomp_actions_avail[] =
0466bdb99   Kees Cook   seccomp: Implemen...
1073
  				SECCOMP_RET_KILL_PROCESS_NAME	" "
fd76875ca   Kees Cook   seccomp: Rename S...
1074
1075
1076
1077
1078
1079
  				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...
1080

0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
1081
1082
1083
1084
1085
1086
  struct seccomp_log_name {
  	u32		log;
  	const char	*name;
  };
  
  static const struct seccomp_log_name seccomp_log_names[] = {
0466bdb99   Kees Cook   seccomp: Implemen...
1087
  	{ SECCOMP_LOG_KILL_PROCESS, SECCOMP_RET_KILL_PROCESS_NAME },
fd76875ca   Kees Cook   seccomp: Rename S...
1088
  	{ SECCOMP_LOG_KILL_THREAD, SECCOMP_RET_KILL_THREAD_NAME },
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
1089
1090
1091
  	{ 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...
1092
  	{ SECCOMP_LOG_LOG, SECCOMP_RET_LOG_NAME },
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
1093
1094
1095
1096
1097
  	{ SECCOMP_LOG_ALLOW, SECCOMP_RET_ALLOW_NAME },
  	{ }
  };
  
  static bool seccomp_names_from_actions_logged(char *names, size_t size,
beb44acaf   Tyler Hicks   seccomp: Configur...
1098
1099
  					      u32 actions_logged,
  					      const char *sep)
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
1100
1101
  {
  	const struct seccomp_log_name *cur;
beb44acaf   Tyler Hicks   seccomp: Configur...
1102
  	bool append_sep = false;
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
1103
1104
1105
1106
1107
1108
  
  	for (cur = seccomp_log_names; cur->name && size; cur++) {
  		ssize_t ret;
  
  		if (!(actions_logged & cur->log))
  			continue;
beb44acaf   Tyler Hicks   seccomp: Configur...
1109
1110
  		if (append_sep) {
  			ret = strscpy(names, sep, size);
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
1111
1112
1113
1114
1115
1116
  			if (ret < 0)
  				return false;
  
  			names += ret;
  			size -= ret;
  		} else
beb44acaf   Tyler Hicks   seccomp: Configur...
1117
  			append_sep = true;
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
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
  
  		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;
  }
d013db029   Tyler Hicks   seccomp: Separate...
1161
1162
  static int read_actions_logged(struct ctl_table *ro_table, void __user *buffer,
  			       size_t *lenp, loff_t *ppos)
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
1163
1164
1165
  {
  	char names[sizeof(seccomp_actions_avail)];
  	struct ctl_table table;
d013db029   Tyler Hicks   seccomp: Separate...
1166
1167
1168
1169
  
  	memset(names, 0, sizeof(names));
  
  	if (!seccomp_names_from_actions_logged(names, sizeof(names),
beb44acaf   Tyler Hicks   seccomp: Configur...
1170
  					       seccomp_actions_logged, " "))
d013db029   Tyler Hicks   seccomp: Separate...
1171
1172
1173
1174
1175
1176
1177
1178
1179
  		return -EINVAL;
  
  	table = *ro_table;
  	table.data = names;
  	table.maxlen = sizeof(names);
  	return proc_dostring(&table, 0, buffer, lenp, ppos);
  }
  
  static int write_actions_logged(struct ctl_table *ro_table, void __user *buffer,
ea6eca778   Tyler Hicks   seccomp: Audit at...
1180
  				size_t *lenp, loff_t *ppos, u32 *actions_logged)
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
1181
1182
1183
1184
  {
  	char names[sizeof(seccomp_actions_avail)];
  	struct ctl_table table;
  	int ret;
d013db029   Tyler Hicks   seccomp: Separate...
1185
  	if (!capable(CAP_SYS_ADMIN))
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
1186
1187
1188
  		return -EPERM;
  
  	memset(names, 0, sizeof(names));
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
1189
1190
1191
  	table = *ro_table;
  	table.data = names;
  	table.maxlen = sizeof(names);
d013db029   Tyler Hicks   seccomp: Separate...
1192
  	ret = proc_dostring(&table, 1, buffer, lenp, ppos);
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
1193
1194
  	if (ret)
  		return ret;
ea6eca778   Tyler Hicks   seccomp: Audit at...
1195
  	if (!seccomp_actions_logged_from_names(actions_logged, table.data))
d013db029   Tyler Hicks   seccomp: Separate...
1196
  		return -EINVAL;
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
1197

ea6eca778   Tyler Hicks   seccomp: Audit at...
1198
  	if (*actions_logged & SECCOMP_LOG_ALLOW)
d013db029   Tyler Hicks   seccomp: Separate...
1199
  		return -EINVAL;
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
1200

ea6eca778   Tyler Hicks   seccomp: Audit at...
1201
  	seccomp_actions_logged = *actions_logged;
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
1202
1203
  	return 0;
  }
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
1204

ea6eca778   Tyler Hicks   seccomp: Audit at...
1205
1206
1207
1208
1209
1210
1211
  static void audit_actions_logged(u32 actions_logged, u32 old_actions_logged,
  				 int ret)
  {
  	char names[sizeof(seccomp_actions_avail)];
  	char old_names[sizeof(seccomp_actions_avail)];
  	const char *new = names;
  	const char *old = old_names;
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
1212

ea6eca778   Tyler Hicks   seccomp: Audit at...
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
  	if (!audit_enabled)
  		return;
  
  	memset(names, 0, sizeof(names));
  	memset(old_names, 0, sizeof(old_names));
  
  	if (ret)
  		new = "?";
  	else if (!actions_logged)
  		new = "(none)";
  	else if (!seccomp_names_from_actions_logged(names, sizeof(names),
  						    actions_logged, ","))
  		new = "?";
  
  	if (!old_actions_logged)
  		old = "(none)";
  	else if (!seccomp_names_from_actions_logged(old_names,
  						    sizeof(old_names),
  						    old_actions_logged, ","))
  		old = "?";
  
  	return audit_seccomp_actions_logged(new, old, !ret);
  }
d013db029   Tyler Hicks   seccomp: Separate...
1236
1237
1238
1239
  static int seccomp_actions_logged_handler(struct ctl_table *ro_table, int write,
  					  void __user *buffer, size_t *lenp,
  					  loff_t *ppos)
  {
ea6eca778   Tyler Hicks   seccomp: Audit at...
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
  	int ret;
  
  	if (write) {
  		u32 actions_logged = 0;
  		u32 old_actions_logged = seccomp_actions_logged;
  
  		ret = write_actions_logged(ro_table, buffer, lenp, ppos,
  					   &actions_logged);
  		audit_actions_logged(actions_logged, old_actions_logged, ret);
  	} else
  		ret = read_actions_logged(ro_table, buffer, lenp, ppos);
  
  	return ret;
0ddec0fc8   Tyler Hicks   seccomp: Sysctl t...
1253
  }
8e5f1ad11   Tyler Hicks   seccomp: Sysctl t...
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
  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...
1268
1269
1270
1271
1272
  	{
  		.procname	= "actions_logged",
  		.mode		= 0644,
  		.proc_handler	= seccomp_actions_logged_handler,
  	},
8e5f1ad11   Tyler Hicks   seccomp: Sysctl t...
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
  	{ }
  };
  
  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 */