Blame view

kernel/seccomp.c 23.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
  /*
   * linux/kernel/seccomp.c
   *
   * Copyright 2004-2005  Andrea Arcangeli <andrea@cpushare.com>
   *
e2cfabdfd   Will Drewry   seccomp: add syst...
6
7
8
9
10
11
12
13
   * 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
14
   */
e2cfabdfd   Will Drewry   seccomp: add syst...
15
  #include <linux/atomic.h>
85e7bac33   Eric Paris   seccomp: audit ab...
16
  #include <linux/audit.h>
5b1017404   Roland McGrath   x86-64: seccomp: ...
17
  #include <linux/compat.h>
e2cfabdfd   Will Drewry   seccomp: add syst...
18
19
  #include <linux/sched.h>
  #include <linux/seccomp.h>
c8bee430d   Kees Cook   seccomp: split fi...
20
  #include <linux/slab.h>
48dc92b9f   Kees Cook   seccomp: add "sec...
21
  #include <linux/syscalls.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22

a4412fc94   Andy Lutomirski   seccomp,x86,arm,m...
23
  #ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
e2cfabdfd   Will Drewry   seccomp: add syst...
24
  #include <asm/syscall.h>
a4412fc94   Andy Lutomirski   seccomp,x86,arm,m...
25
  #endif
e2cfabdfd   Will Drewry   seccomp: add syst...
26
27
  
  #ifdef CONFIG_SECCOMP_FILTER
e2cfabdfd   Will Drewry   seccomp: add syst...
28
  #include <linux/filter.h>
c2e1f2e30   Kees Cook   seccomp: implemen...
29
  #include <linux/pid.h>
fb0fadf9b   Will Drewry   ptrace,seccomp: A...
30
  #include <linux/ptrace.h>
e2cfabdfd   Will Drewry   seccomp: add syst...
31
  #include <linux/security.h>
e2cfabdfd   Will Drewry   seccomp: add syst...
32
33
34
35
36
37
38
39
40
41
42
43
  #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.
   * @prev: points to a previously installed, or inherited, filter
   * @len: the number of instructions in the program
119ce5c8b   Fabian Frederick   kernel/seccomp.c:...
44
   * @insnsi: the BPF program instructions to evaluate
e2cfabdfd   Will Drewry   seccomp: add syst...
45
46
47
48
49
50
51
52
53
54
55
56
57
58
   *
   * 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 {
  	atomic_t usage;
  	struct seccomp_filter *prev;
7ae457c1e   Alexei Starovoitov   net: filter: spli...
59
  	struct bpf_prog *prog;
e2cfabdfd   Will Drewry   seccomp: add syst...
60
61
62
63
  };
  
  /* 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...
64
  /*
e2cfabdfd   Will Drewry   seccomp: add syst...
65
66
67
   * Endianness is explicitly ignored and left for BPF program authors to manage
   * as per the specific architecture.
   */
bd4cf0ed3   Alexei Starovoitov   net: filter: rewo...
68
  static void populate_seccomp_data(struct seccomp_data *sd)
e2cfabdfd   Will Drewry   seccomp: add syst...
69
  {
bd4cf0ed3   Alexei Starovoitov   net: filter: rewo...
70
71
  	struct task_struct *task = current;
  	struct pt_regs *regs = task_pt_regs(task);
2eac76483   Daniel Borkmann   seccomp: fix popu...
72
  	unsigned long args[6];
e2cfabdfd   Will Drewry   seccomp: add syst...
73

bd4cf0ed3   Alexei Starovoitov   net: filter: rewo...
74
  	sd->nr = syscall_get_nr(task, regs);
0b747172d   Linus Torvalds   Merge git://git.i...
75
  	sd->arch = syscall_get_arch();
2eac76483   Daniel Borkmann   seccomp: fix popu...
76
77
78
79
80
81
82
  	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...
83
  	sd->instruction_pointer = KSTK_EIP(task);
e2cfabdfd   Will Drewry   seccomp: add syst...
84
85
86
87
88
89
90
  }
  
  /**
   *	seccomp_check_filter - verify seccomp filter code
   *	@filter: filter to verify
   *	@flen: length of filter
   *
4df95ff48   Alexei Starovoitov   net: filter: rena...
91
   * Takes a previously checked filter (by bpf_check_classic) and
e2cfabdfd   Will Drewry   seccomp: add syst...
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
   * 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 ...
107
  		case BPF_LD | BPF_W | BPF_ABS:
bd4cf0ed3   Alexei Starovoitov   net: filter: rewo...
108
  			ftest->code = BPF_LDX | BPF_W | BPF_ABS;
e2cfabdfd   Will Drewry   seccomp: add syst...
109
110
111
112
  			/* 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 ...
113
  		case BPF_LD | BPF_W | BPF_LEN:
bd4cf0ed3   Alexei Starovoitov   net: filter: rewo...
114
  			ftest->code = BPF_LD | BPF_IMM;
e2cfabdfd   Will Drewry   seccomp: add syst...
115
116
  			ftest->k = sizeof(struct seccomp_data);
  			continue;
348059313   Daniel Borkmann   net: filter: get ...
117
  		case BPF_LDX | BPF_W | BPF_LEN:
bd4cf0ed3   Alexei Starovoitov   net: filter: rewo...
118
  			ftest->code = BPF_LDX | BPF_IMM;
e2cfabdfd   Will Drewry   seccomp: add syst...
119
120
121
  			ftest->k = sizeof(struct seccomp_data);
  			continue;
  		/* Explicitly include allowed calls. */
348059313   Daniel Borkmann   net: filter: get ...
122
123
124
125
126
127
128
129
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
  		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...
160
161
162
163
164
165
166
167
168
169
170
171
172
173
  			continue;
  		default:
  			return -EINVAL;
  		}
  	}
  	return 0;
  }
  
  /**
   * seccomp_run_filters - evaluates all seccomp filters against @syscall
   * @syscall: number of the current system call
   *
   * Returns valid seccomp BPF response codes.
   */
8112c4f14   Kees Cook   seccomp: remove 2...
174
  static u32 seccomp_run_filters(const struct seccomp_data *sd)
e2cfabdfd   Will Drewry   seccomp: add syst...
175
  {
d39bd00de   Andy Lutomirski   seccomp: Allow ar...
176
  	struct seccomp_data sd_local;
acf3b2c71   Will Drewry   seccomp: add SECC...
177
  	u32 ret = SECCOMP_RET_ALLOW;
8225d3853   Pranith Kumar   seccomp: Replace ...
178
179
180
  	/* Make sure cross-thread synced filter points somewhere sane. */
  	struct seccomp_filter *f =
  			lockless_dereference(current->seccomp.filter);
acf3b2c71   Will Drewry   seccomp: add SECC...
181
182
  
  	/* Ensure unexpected behavior doesn't result in failing open. */
3ba2530cc   Kees Cook   seccomp: allow mo...
183
  	if (unlikely(WARN_ON(f == NULL)))
acf3b2c71   Will Drewry   seccomp: add SECC...
184
  		return SECCOMP_RET_KILL;
d39bd00de   Andy Lutomirski   seccomp: Allow ar...
185
186
187
188
  	if (!sd) {
  		populate_seccomp_data(&sd_local);
  		sd = &sd_local;
  	}
bd4cf0ed3   Alexei Starovoitov   net: filter: rewo...
189

e2cfabdfd   Will Drewry   seccomp: add syst...
190
191
  	/*
  	 * All filters in the list are evaluated and the lowest BPF return
acf3b2c71   Will Drewry   seccomp: add SECC...
192
  	 * value always takes priority (ignoring the DATA).
e2cfabdfd   Will Drewry   seccomp: add syst...
193
  	 */
3ba2530cc   Kees Cook   seccomp: allow mo...
194
  	for (; f; f = f->prev) {
d39bd00de   Andy Lutomirski   seccomp: Allow ar...
195
  		u32 cur_ret = BPF_PROG_RUN(f->prog, (void *)sd);
8f577cadf   Alexei Starovoitov   seccomp: JIT comp...
196

acf3b2c71   Will Drewry   seccomp: add SECC...
197
198
  		if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION))
  			ret = cur_ret;
e2cfabdfd   Will Drewry   seccomp: add syst...
199
200
201
  	}
  	return ret;
  }
1f41b4504   Kees Cook   seccomp: extract ...
202
  #endif /* CONFIG_SECCOMP_FILTER */
e2cfabdfd   Will Drewry   seccomp: add syst...
203

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

1f41b4504   Kees Cook   seccomp: extract ...
208
209
210
211
212
  	if (current->seccomp.mode && current->seccomp.mode != seccomp_mode)
  		return false;
  
  	return true;
  }
3ba2530cc   Kees Cook   seccomp: allow mo...
213
214
  static inline void seccomp_assign_mode(struct task_struct *task,
  				       unsigned long seccomp_mode)
1f41b4504   Kees Cook   seccomp: extract ...
215
  {
69f6a34bd   Guenter Roeck   seccomp: Replace ...
216
  	assert_spin_locked(&task->sighand->siglock);
dbd952127   Kees Cook   seccomp: introduc...
217

3ba2530cc   Kees Cook   seccomp: allow mo...
218
219
220
221
222
223
224
  	task->seccomp.mode = seccomp_mode;
  	/*
  	 * Make sure TIF_SECCOMP cannot be set before the mode (and
  	 * filter) is set.
  	 */
  	smp_mb__before_atomic();
  	set_tsk_thread_flag(task, TIF_SECCOMP);
1f41b4504   Kees Cook   seccomp: extract ...
225
226
227
  }
  
  #ifdef CONFIG_SECCOMP_FILTER
c2e1f2e30   Kees Cook   seccomp: implemen...
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
  /* 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 ...
255
  	assert_spin_locked(&current->sighand->siglock);
c2e1f2e30   Kees Cook   seccomp: implemen...
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
  
  	/* 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.
   *
   */
  static inline void seccomp_sync_threads(void)
  {
  	struct task_struct *thread, *caller;
  
  	BUG_ON(!mutex_is_locked(&current->signal->cred_guard_mutex));
69f6a34bd   Guenter Roeck   seccomp: Replace ...
296
  	assert_spin_locked(&current->sighand->siglock);
c2e1f2e30   Kees Cook   seccomp: implemen...
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
  
  	/* 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...
315
316
317
318
319
320
321
322
323
  
  		/*
  		 * 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...
324
325
326
327
328
329
  		/*
  		 * 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...
330
  		if (thread->seccomp.mode == SECCOMP_MODE_DISABLED)
c2e1f2e30   Kees Cook   seccomp: implemen...
331
  			seccomp_assign_mode(thread, SECCOMP_MODE_FILTER);
c2e1f2e30   Kees Cook   seccomp: implemen...
332
333
  	}
  }
e2cfabdfd   Will Drewry   seccomp: add syst...
334
  /**
c8bee430d   Kees Cook   seccomp: split fi...
335
   * seccomp_prepare_filter: Prepares a seccomp filter for use.
e2cfabdfd   Will Drewry   seccomp: add syst...
336
337
   * @fprog: BPF program to install
   *
c8bee430d   Kees Cook   seccomp: split fi...
338
   * Returns filter on success or an ERR_PTR on failure.
e2cfabdfd   Will Drewry   seccomp: add syst...
339
   */
c8bee430d   Kees Cook   seccomp: split fi...
340
  static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
e2cfabdfd   Will Drewry   seccomp: add syst...
341
  {
ac67eb2c5   Daniel Borkmann   seccomp, filter: ...
342
343
  	struct seccomp_filter *sfilter;
  	int ret;
97f2645f3   Masahiro Yamada   tree-wide: replac...
344
  	const bool save_orig = IS_ENABLED(CONFIG_CHECKPOINT_RESTORE);
e2cfabdfd   Will Drewry   seccomp: add syst...
345
346
  
  	if (fprog->len == 0 || fprog->len > BPF_MAXINSNS)
c8bee430d   Kees Cook   seccomp: split fi...
347
  		return ERR_PTR(-EINVAL);
d9e12f42e   Nicolas Schichan   seccomp: simplify...
348

c8bee430d   Kees Cook   seccomp: split fi...
349
  	BUG_ON(INT_MAX / fprog->len < sizeof(struct sock_filter));
e2cfabdfd   Will Drewry   seccomp: add syst...
350
351
  
  	/*
119ce5c8b   Fabian Frederick   kernel/seccomp.c:...
352
  	 * Installing a seccomp filter requires that the task has
e2cfabdfd   Will Drewry   seccomp: add syst...
353
354
355
356
  	 * 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...
357
  	if (!task_no_new_privs(current) &&
e2cfabdfd   Will Drewry   seccomp: add syst...
358
359
  	    security_capable_noaudit(current_cred(), current_user_ns(),
  				     CAP_SYS_ADMIN) != 0)
c8bee430d   Kees Cook   seccomp: split fi...
360
  		return ERR_PTR(-EACCES);
e2cfabdfd   Will Drewry   seccomp: add syst...
361

bd4cf0ed3   Alexei Starovoitov   net: filter: rewo...
362
  	/* Allocate a new seccomp_filter */
ac67eb2c5   Daniel Borkmann   seccomp, filter: ...
363
364
  	sfilter = kzalloc(sizeof(*sfilter), GFP_KERNEL | __GFP_NOWARN);
  	if (!sfilter)
d9e12f42e   Nicolas Schichan   seccomp: simplify...
365
  		return ERR_PTR(-ENOMEM);
ac67eb2c5   Daniel Borkmann   seccomp, filter: ...
366
367
  
  	ret = bpf_prog_create_from_user(&sfilter->prog, fprog,
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
368
  					seccomp_check_filter, save_orig);
ac67eb2c5   Daniel Borkmann   seccomp, filter: ...
369
370
371
  	if (ret < 0) {
  		kfree(sfilter);
  		return ERR_PTR(ret);
d9e12f42e   Nicolas Schichan   seccomp: simplify...
372
  	}
bd4cf0ed3   Alexei Starovoitov   net: filter: rewo...
373

ac67eb2c5   Daniel Borkmann   seccomp, filter: ...
374
  	atomic_set(&sfilter->usage, 1);
e2cfabdfd   Will Drewry   seccomp: add syst...
375

ac67eb2c5   Daniel Borkmann   seccomp, filter: ...
376
  	return sfilter;
e2cfabdfd   Will Drewry   seccomp: add syst...
377
378
379
  }
  
  /**
c8bee430d   Kees Cook   seccomp: split fi...
380
   * seccomp_prepare_user_filter - prepares a user-supplied sock_fprog
e2cfabdfd   Will Drewry   seccomp: add syst...
381
382
383
384
   * @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...
385
386
  static struct seccomp_filter *
  seccomp_prepare_user_filter(const char __user *user_filter)
e2cfabdfd   Will Drewry   seccomp: add syst...
387
388
  {
  	struct sock_fprog fprog;
c8bee430d   Kees Cook   seccomp: split fi...
389
  	struct seccomp_filter *filter = ERR_PTR(-EFAULT);
e2cfabdfd   Will Drewry   seccomp: add syst...
390
391
  
  #ifdef CONFIG_COMPAT
5c38065e0   Andy Lutomirski   seccomp: check in...
392
  	if (in_compat_syscall()) {
e2cfabdfd   Will Drewry   seccomp: add syst...
393
394
395
396
397
398
399
400
401
  		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...
402
  	filter = seccomp_prepare_filter(&fprog);
e2cfabdfd   Will Drewry   seccomp: add syst...
403
  out:
c8bee430d   Kees Cook   seccomp: split fi...
404
405
406
407
408
409
410
411
  	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...
412
413
   * Caller must be holding current->sighand->siglock lock.
   *
c8bee430d   Kees Cook   seccomp: split fi...
414
415
416
417
418
419
420
   * 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 ...
421
  	assert_spin_locked(&current->sighand->siglock);
dbd952127   Kees Cook   seccomp: introduc...
422

c8bee430d   Kees Cook   seccomp: split fi...
423
424
425
426
427
428
  	/* 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...
429
430
431
432
433
434
435
436
  	/* 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;
  	}
c8bee430d   Kees Cook   seccomp: split fi...
437
438
439
440
441
442
  	/*
  	 * 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...
443
444
445
  	/* Now that the new filter is in place, synchronize to all threads. */
  	if (flags & SECCOMP_FILTER_FLAG_TSYNC)
  		seccomp_sync_threads();
c8bee430d   Kees Cook   seccomp: split fi...
446
  	return 0;
e2cfabdfd   Will Drewry   seccomp: add syst...
447
448
449
450
451
452
453
454
455
456
457
  }
  
  /* 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;
  	/* Reference count is bounded by the number of total processes. */
  	atomic_inc(&orig->usage);
  }
c8bee430d   Kees Cook   seccomp: split fi...
458
459
460
  static inline void seccomp_filter_free(struct seccomp_filter *filter)
  {
  	if (filter) {
bab189918   Daniel Borkmann   bpf, seccomp: pre...
461
  		bpf_prog_destroy(filter->prog);
c8bee430d   Kees Cook   seccomp: split fi...
462
463
464
  		kfree(filter);
  	}
  }
e2cfabdfd   Will Drewry   seccomp: add syst...
465
466
467
468
469
470
471
472
  /* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */
  void put_seccomp_filter(struct task_struct *tsk)
  {
  	struct seccomp_filter *orig = tsk->seccomp.filter;
  	/* Clean up single-reference branches iteratively. */
  	while (orig && atomic_dec_and_test(&orig->usage)) {
  		struct seccomp_filter *freeme = orig;
  		orig = orig->prev;
c8bee430d   Kees Cook   seccomp: split fi...
473
  		seccomp_filter_free(freeme);
e2cfabdfd   Will Drewry   seccomp: add syst...
474
475
  	}
  }
bb6ea4301   Will Drewry   seccomp: Add SECC...
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
  
  /**
   * 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;
  	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;
5e937a9ae   Eric Paris   syscall_get_arch:...
492
  	info.si_arch = syscall_get_arch();
bb6ea4301   Will Drewry   seccomp: Add SECC...
493
494
495
  	info.si_syscall = syscall;
  	force_sig_info(SIGSYS, &info, current);
  }
e2cfabdfd   Will Drewry   seccomp: add syst...
496
  #endif	/* CONFIG_SECCOMP_FILTER */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
499
500
501
502
  
  /*
   * 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 ...
503
  static const int mode1_syscalls[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
505
506
  	__NR_seccomp_read, __NR_seccomp_write, __NR_seccomp_exit, __NR_seccomp_sigreturn,
  	0, /* null terminated */
  };
a4412fc94   Andy Lutomirski   seccomp,x86,arm,m...
507
  static void __secure_computing_strict(int this_syscall)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
  {
cb4253aa0   Matt Redfearn   secomp: Constify ...
509
  	const int *syscall_whitelist = mode1_syscalls;
a4412fc94   Andy Lutomirski   seccomp,x86,arm,m...
510
  #ifdef CONFIG_COMPAT
5c38065e0   Andy Lutomirski   seccomp: check in...
511
  	if (in_compat_syscall())
c983f0e86   Matt Redfearn   seccomp: Get comp...
512
  		syscall_whitelist = get_compat_mode1_syscalls();
a4412fc94   Andy Lutomirski   seccomp,x86,arm,m...
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
  #endif
  	do {
  		if (*syscall_whitelist == this_syscall)
  			return;
  	} while (*++syscall_whitelist);
  
  #ifdef SECCOMP_DEBUG
  	dump_stack();
  #endif
  	audit_seccomp(this_syscall, SIGKILL, SECCOMP_RET_KILL);
  	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...
530
  	if (IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) &&
13c4a9011   Tycho Andersen   seccomp: add ptra...
531
532
  	    unlikely(current->ptrace & PT_SUSPEND_SECCOMP))
  		return;
221272f97   Kees Cook   seccomp: swap har...
533
  	if (mode == SECCOMP_MODE_DISABLED)
a4412fc94   Andy Lutomirski   seccomp,x86,arm,m...
534
535
536
537
538
539
540
  		return;
  	else if (mode == SECCOMP_MODE_STRICT)
  		__secure_computing_strict(this_syscall);
  	else
  		BUG();
  }
  #else
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
541
542
  
  #ifdef CONFIG_SECCOMP_FILTER
ce6526e8a   Kees Cook   seccomp: recheck ...
543
544
  static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd,
  			    const bool recheck_after_trace)
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
545
546
547
  {
  	u32 filter_ret, action;
  	int data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548

3ba2530cc   Kees Cook   seccomp: allow mo...
549
550
551
552
553
  	/*
  	 * Make sure that any changes to mode from another thread have
  	 * been seen after TIF_SECCOMP was seen.
  	 */
  	rmb();
d39bd00de   Andy Lutomirski   seccomp: Allow ar...
554
  	filter_ret = seccomp_run_filters(sd);
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
555
556
557
558
559
  	data = filter_ret & SECCOMP_RET_DATA;
  	action = filter_ret & SECCOMP_RET_ACTION;
  
  	switch (action) {
  	case SECCOMP_RET_ERRNO:
580c57f10   Kees Cook   seccomp: cap SECC...
560
561
562
  		/* Set low-order bits as an errno, capped at MAX_ERRNO. */
  		if (data > MAX_ERRNO)
  			data = MAX_ERRNO;
d39bd00de   Andy Lutomirski   seccomp: Allow ar...
563
  		syscall_set_return_value(current, task_pt_regs(current),
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
564
565
566
567
568
  					 -data, 0);
  		goto skip;
  
  	case SECCOMP_RET_TRAP:
  		/* Show the handler the original registers. */
d39bd00de   Andy Lutomirski   seccomp: Allow ar...
569
  		syscall_rollback(current, task_pt_regs(current));
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
570
571
572
573
574
  		/* 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 ...
575
576
577
  		/* We've been put in this state by the ptracer already. */
  		if (recheck_after_trace)
  			return 0;
8112c4f14   Kees Cook   seccomp: remove 2...
578
579
580
581
582
583
584
585
586
587
588
589
  		/* 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...
590
591
592
593
594
595
596
  		 * 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...
597
598
  		 */
  		if (fatal_signal_pending(current))
485a252a5   Kees Cook   seccomp: Fix trac...
599
  			goto skip;
8112c4f14   Kees Cook   seccomp: remove 2...
600
601
602
603
  		/* 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 ...
604
605
606
607
608
609
610
611
  		/*
  		 * 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...
612
  		return 0;
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
613
614
  
  	case SECCOMP_RET_ALLOW:
8112c4f14   Kees Cook   seccomp: remove 2...
615
  		return 0;
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
616
617
618
619
620
621
622
623
624
625
626
  
  	case SECCOMP_RET_KILL:
  	default:
  		audit_seccomp(this_syscall, SIGSYS, action);
  		do_exit(SIGSYS);
  	}
  
  	unreachable();
  
  skip:
  	audit_seccomp(this_syscall, 0, action);
8112c4f14   Kees Cook   seccomp: remove 2...
627
628
629
  	return -1;
  }
  #else
ce6526e8a   Kees Cook   seccomp: recheck ...
630
631
  static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd,
  			    const bool recheck_after_trace)
8112c4f14   Kees Cook   seccomp: remove 2...
632
633
  {
  	BUG();
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
634
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
  #endif
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
636

8112c4f14   Kees Cook   seccomp: remove 2...
637
  int __secure_computing(const struct seccomp_data *sd)
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
638
639
  {
  	int mode = current->seccomp.mode;
8112c4f14   Kees Cook   seccomp: remove 2...
640
  	int this_syscall;
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
641

97f2645f3   Masahiro Yamada   tree-wide: replac...
642
  	if (IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) &&
13c4a9011   Tycho Andersen   seccomp: add ptra...
643
  	    unlikely(current->ptrace & PT_SUSPEND_SECCOMP))
8112c4f14   Kees Cook   seccomp: remove 2...
644
645
646
647
  		return 0;
  
  	this_syscall = sd ? sd->nr :
  		syscall_get_nr(current, task_pt_regs(current));
13c4a9011   Tycho Andersen   seccomp: add ptra...
648

13aa72f0f   Andy Lutomirski   seccomp: Refactor...
649
  	switch (mode) {
e2cfabdfd   Will Drewry   seccomp: add syst...
650
  	case SECCOMP_MODE_STRICT:
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
651
  		__secure_computing_strict(this_syscall);  /* may call do_exit */
8112c4f14   Kees Cook   seccomp: remove 2...
652
  		return 0;
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
653
  	case SECCOMP_MODE_FILTER:
ce6526e8a   Kees Cook   seccomp: recheck ...
654
  		return __seccomp_filter(this_syscall, sd, false);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655
656
657
  	default:
  		BUG();
  	}
13aa72f0f   Andy Lutomirski   seccomp: Refactor...
658
  }
a4412fc94   Andy Lutomirski   seccomp,x86,arm,m...
659
  #endif /* CONFIG_HAVE_ARCH_SECCOMP_FILTER */
1d9d02fee   Andrea Arcangeli   move seccomp from...
660
661
662
663
664
  
  long prctl_get_seccomp(void)
  {
  	return current->seccomp.mode;
  }
e2cfabdfd   Will Drewry   seccomp: add syst...
665
  /**
3b23dd128   Kees Cook   seccomp: split mo...
666
   * seccomp_set_mode_strict: internal function for setting strict seccomp
e2cfabdfd   Will Drewry   seccomp: add syst...
667
668
669
670
671
   *
   * 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...
672
  static long seccomp_set_mode_strict(void)
1d9d02fee   Andrea Arcangeli   move seccomp from...
673
  {
3b23dd128   Kees Cook   seccomp: split mo...
674
  	const unsigned long seccomp_mode = SECCOMP_MODE_STRICT;
e2cfabdfd   Will Drewry   seccomp: add syst...
675
  	long ret = -EINVAL;
1d9d02fee   Andrea Arcangeli   move seccomp from...
676

dbd952127   Kees Cook   seccomp: introduc...
677
  	spin_lock_irq(&current->sighand->siglock);
1f41b4504   Kees Cook   seccomp: extract ...
678
  	if (!seccomp_may_assign_mode(seccomp_mode))
1d9d02fee   Andrea Arcangeli   move seccomp from...
679
  		goto out;
cf99abace   Andrea Arcangeli   make seccomp zero...
680
  #ifdef TIF_NOTSC
3b23dd128   Kees Cook   seccomp: split mo...
681
  	disable_TSC();
cf99abace   Andrea Arcangeli   make seccomp zero...
682
  #endif
3ba2530cc   Kees Cook   seccomp: allow mo...
683
  	seccomp_assign_mode(current, seccomp_mode);
3b23dd128   Kees Cook   seccomp: split mo...
684
685
686
  	ret = 0;
  
  out:
dbd952127   Kees Cook   seccomp: introduc...
687
  	spin_unlock_irq(&current->sighand->siglock);
3b23dd128   Kees Cook   seccomp: split mo...
688
689
690
  
  	return ret;
  }
e2cfabdfd   Will Drewry   seccomp: add syst...
691
  #ifdef CONFIG_SECCOMP_FILTER
3b23dd128   Kees Cook   seccomp: split mo...
692
693
  /**
   * seccomp_set_mode_filter: internal function for setting seccomp filter
48dc92b9f   Kees Cook   seccomp: add "sec...
694
   * @flags:  flags to change filter behavior
3b23dd128   Kees Cook   seccomp: split mo...
695
696
697
698
699
700
701
702
703
704
   * @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...
705
706
  static long seccomp_set_mode_filter(unsigned int flags,
  				    const char __user *filter)
3b23dd128   Kees Cook   seccomp: split mo...
707
708
  {
  	const unsigned long seccomp_mode = SECCOMP_MODE_FILTER;
c8bee430d   Kees Cook   seccomp: split fi...
709
  	struct seccomp_filter *prepared = NULL;
3b23dd128   Kees Cook   seccomp: split mo...
710
  	long ret = -EINVAL;
48dc92b9f   Kees Cook   seccomp: add "sec...
711
  	/* Validate flags. */
c2e1f2e30   Kees Cook   seccomp: implemen...
712
  	if (flags & ~SECCOMP_FILTER_FLAG_MASK)
dbd952127   Kees Cook   seccomp: introduc...
713
  		return -EINVAL;
48dc92b9f   Kees Cook   seccomp: add "sec...
714

c8bee430d   Kees Cook   seccomp: split fi...
715
716
717
718
  	/* 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...
719
720
721
722
723
724
725
  	/*
  	 * 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...
726
  	spin_lock_irq(&current->sighand->siglock);
3b23dd128   Kees Cook   seccomp: split mo...
727
728
  	if (!seccomp_may_assign_mode(seccomp_mode))
  		goto out;
c8bee430d   Kees Cook   seccomp: split fi...
729
  	ret = seccomp_attach_filter(flags, prepared);
3b23dd128   Kees Cook   seccomp: split mo...
730
  	if (ret)
e2cfabdfd   Will Drewry   seccomp: add syst...
731
  		goto out;
c8bee430d   Kees Cook   seccomp: split fi...
732
733
  	/* Do not free the successfully attached filter. */
  	prepared = NULL;
1d9d02fee   Andrea Arcangeli   move seccomp from...
734

3ba2530cc   Kees Cook   seccomp: allow mo...
735
  	seccomp_assign_mode(current, seccomp_mode);
e2cfabdfd   Will Drewry   seccomp: add syst...
736
  out:
dbd952127   Kees Cook   seccomp: introduc...
737
  	spin_unlock_irq(&current->sighand->siglock);
c2e1f2e30   Kees Cook   seccomp: implemen...
738
739
740
  	if (flags & SECCOMP_FILTER_FLAG_TSYNC)
  		mutex_unlock(&current->signal->cred_guard_mutex);
  out_free:
c8bee430d   Kees Cook   seccomp: split fi...
741
  	seccomp_filter_free(prepared);
1d9d02fee   Andrea Arcangeli   move seccomp from...
742
743
  	return ret;
  }
3b23dd128   Kees Cook   seccomp: split mo...
744
  #else
48dc92b9f   Kees Cook   seccomp: add "sec...
745
746
  static inline long seccomp_set_mode_filter(unsigned int flags,
  					   const char __user *filter)
3b23dd128   Kees Cook   seccomp: split mo...
747
748
749
750
  {
  	return -EINVAL;
  }
  #endif
d78ab02c2   Kees Cook   seccomp: create i...
751

48dc92b9f   Kees Cook   seccomp: add "sec...
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
  /* 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);
  	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...
773
774
775
776
777
778
779
780
781
  /**
   * 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...
782
783
  	unsigned int op;
  	char __user *uargs;
3b23dd128   Kees Cook   seccomp: split mo...
784
785
  	switch (seccomp_mode) {
  	case SECCOMP_MODE_STRICT:
48dc92b9f   Kees Cook   seccomp: add "sec...
786
787
788
789
790
791
792
793
  		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...
794
  	case SECCOMP_MODE_FILTER:
48dc92b9f   Kees Cook   seccomp: add "sec...
795
796
797
  		op = SECCOMP_SET_MODE_FILTER;
  		uargs = filter;
  		break;
3b23dd128   Kees Cook   seccomp: split mo...
798
799
800
  	default:
  		return -EINVAL;
  	}
48dc92b9f   Kees Cook   seccomp: add "sec...
801
802
803
  
  	/* prctl interface doesn't have flags, so they are always zero. */
  	return do_seccomp(op, 0, uargs);
d78ab02c2   Kees Cook   seccomp: create i...
804
  }
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
  
  #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...
852
  		/* This must be a new non-cBPF filter, since we save
f8e529ed9   Tycho Andersen   seccomp, ptrace: ...
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
  		 * every cBPF filter's orig_prog above when
  		 * CONFIG_CHECKPOINT_RESTORE is enabled.
  		 */
  		ret = -EMEDIUMTYPE;
  		goto out;
  	}
  
  	ret = fprog->len;
  	if (!data)
  		goto out;
  
  	get_seccomp_filter(task);
  	spin_unlock_irq(&task->sighand->siglock);
  
  	if (copy_to_user(data, fprog->filter, bpf_classic_proglen(fprog)))
  		ret = -EFAULT;
  
  	put_seccomp_filter(task);
  	return ret;
  
  out:
  	spin_unlock_irq(&task->sighand->siglock);
  	return ret;
  }
  #endif