]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/seccomp.c
tools: document -d/--daemonize for lxc-execute
[mirror_lxc.git] / src / lxc / seccomp.c
CommitLineData
8f2c3a70
SH
1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright Canonical, Inc. 2012
5 *
6 * Authors:
7 * Serge Hallyn <serge.hallyn@canonical.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
250b1eec 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
8f2c3a70
SH
22 */
23
24#define _GNU_SOURCE
567b2049 25#include <errno.h>
8f2c3a70
SH
26#include <stdio.h>
27#include <stdlib.h>
28#include <seccomp.h>
6166fa6d 29#include <sys/mount.h>
567b2049 30#include <sys/utsname.h>
f2363e38 31
769872f9 32#include "config.h"
8f2c3a70 33#include "log.h"
567b2049 34#include "lxcseccomp.h"
8f2c3a70
SH
35
36lxc_log_define(lxc_seccomp, lxc);
37
50798138
SH
38static int parse_config_v1(FILE *f, struct lxc_conf *conf)
39{
40 char line[1024];
41 int ret;
42
43 while (fgets(line, 1024, f)) {
44 int nr;
45 ret = sscanf(line, "%d", &nr);
46 if (ret != 1)
47 return -1;
48 ret = seccomp_rule_add(
49#if HAVE_SCMP_FILTER_CTX
f06c6207 50 conf->seccomp_ctx,
50798138 51#endif
f06c6207 52 SCMP_ACT_ALLOW, nr, 0);
50798138 53 if (ret < 0) {
3ee26d19 54 ERROR("Failed loading allow rule for %d", nr);
50798138
SH
55 return ret;
56 }
57 }
58 return 0;
59}
60
2b0ae718 61#if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
50798138
SH
62static void remove_trailing_newlines(char *l)
63{
64 char *p = l;
65
66 while (*p)
67 p++;
68 while (--p >= l && *p == '\n')
69 *p = '\0';
70}
71
72static uint32_t get_v2_default_action(char *line)
73{
74 uint32_t ret_action = -1;
75
f06c6207
CB
76 while (*line == ' ')
77 line++;
1a0e70ac 78 /* After 'whitelist' or 'blacklist' comes default behavior. */
50798138
SH
79 if (strncmp(line, "kill", 4) == 0)
80 ret_action = SCMP_ACT_KILL;
81 else if (strncmp(line, "errno", 5) == 0) {
82 int e;
f06c6207 83 if (sscanf(line + 5, "%d", &e) != 1) {
3ee26d19 84 ERROR("Bad errno value in %s", line);
50798138
SH
85 return -2;
86 }
87 ret_action = SCMP_ACT_ERRNO(e);
88 } else if (strncmp(line, "allow", 5) == 0)
89 ret_action = SCMP_ACT_ALLOW;
90 else if (strncmp(line, "trap", 4) == 0)
91 ret_action = SCMP_ACT_TRAP;
92 return ret_action;
93}
94
4836330b 95static const char *get_action_name(uint32_t action)
96{
1a0e70ac 97 /* The upper 16 bits indicate the type of the seccomp action. */
4836330b 98 switch(action & 0xffff0000){
99 case SCMP_ACT_KILL:
100 return "kill";
101 case SCMP_ACT_ALLOW:
102 return "allow";
103 case SCMP_ACT_TRAP:
104 return "trap";
105 case SCMP_ACT_ERRNO(0):
106 return "errno";
107 default:
108 return "invalid action";
109 }
110}
111
3ee26d19 112static uint32_t get_v2_action(char *line, uint32_t def_action)
50798138
SH
113{
114 char *p = strchr(line, ' ');
115 uint32_t ret;
116
117 if (!p)
118 return def_action;
50798138
SH
119 p++;
120 while (*p == ' ')
121 p++;
122 if (!*p || *p == '#')
123 return def_action;
124 ret = get_v2_default_action(p);
125 switch(ret) {
126 case -2: return -1;
127 case -1: return def_action;
128 default: return ret;
129 }
130}
3ee26d19
L
131
132struct v2_rule_args {
133 uint32_t index;
134 uint64_t value;
135 uint64_t mask;
136 enum scmp_compare op;
137};
138
139struct seccomp_v2_rule {
140 uint32_t action;
141 uint32_t args_num;
142 struct v2_rule_args args_value[6];
143};
144
145static enum scmp_compare parse_v2_rule_op(char *s)
146{
3ee26d19 147 if (strcmp(s, "SCMP_CMP_NE") == 0 || strcmp(s, "!=") == 0)
29cb2617 148 return SCMP_CMP_NE;
3ee26d19 149 else if (strcmp(s, "SCMP_CMP_LT") == 0 || strcmp(s, "<") == 0)
29cb2617 150 return SCMP_CMP_LT;
3ee26d19 151 else if (strcmp(s, "SCMP_CMP_LE") == 0 || strcmp(s, "<=") == 0)
29cb2617 152 return SCMP_CMP_LE;
3ee26d19 153 else if (strcmp(s, "SCMP_CMP_EQ") == 0 || strcmp(s, "==") == 0)
29cb2617 154 return SCMP_CMP_EQ;
3ee26d19 155 else if (strcmp(s, "SCMP_CMP_GE") == 0 || strcmp(s, ">=") == 0)
29cb2617 156 return SCMP_CMP_GE;
3ee26d19 157 else if (strcmp(s, "SCMP_CMP_GT") == 0 || strcmp(s, ">") == 0)
29cb2617 158 return SCMP_CMP_GT;
3ee26d19 159 else if (strcmp(s, "SCMP_CMP_MASKED_EQ") == 0 || strcmp(s, "&=") == 0)
29cb2617 160 return SCMP_CMP_MASKED_EQ;
3ee26d19 161
29cb2617 162 return _SCMP_CMP_MAX;
3ee26d19
L
163}
164
165/* This function is used to parse the args string into the structure.
166 * args string format:[index,value,op,valueTwo] or [index,value,op]
167 * For one arguments, [index,value,valueTwo,op]
168 * index: the index for syscall arguments (type uint)
169 * value: the value for syscall arguments (type uint64)
170 * op: the operator for syscall arguments(string),
171 a valid list of constants as of libseccomp v2.3.2 is
172 SCMP_CMP_NE,SCMP_CMP_LE,SCMP_CMP_LE, SCMP_CMP_EQ, SCMP_CMP_GE,
173 SCMP_CMP_GT, SCMP_CMP_MASKED_EQ, or !=,<=,==,>=,>,&=
174 * valueTwo: the value for syscall arguments only used for mask eq (type uint64, optional)
175 * Returns 0 on success, < 0 otherwise.
176 */
177static int get_seccomp_arg_value(char *key, struct v2_rule_args *rule_args)
178{
179 int ret = 0;
180 uint64_t value = 0;
181 uint64_t mask = 0;
182 enum scmp_compare op = 0;
183 uint32_t index = 0;
184 char s[30] = {0};
185 char *tmp = NULL;
186
187 memset(s, 0, sizeof(s));
188 tmp = strchr(key, '[');
189 if (!tmp) {
190 ERROR("Failed to interpret args");
191 return -1;
192 }
193 ret = sscanf(tmp, "[%i,%lli,%30[^0-9^,],%lli", &index, (long long unsigned int *)&value, s, (long long unsigned int *)&mask);
194 if ((ret != 3 && ret != 4) || index >= 6) {
195 ERROR("Failed to interpret args value");
196 return -1;
197 }
198
199 op = parse_v2_rule_op(s);
200 if (op == _SCMP_CMP_MAX) {
201 ERROR("Failed to interpret args operator value");
202 return -1;
203 }
204
205 rule_args->index = index;
206 rule_args->value = value;
207 rule_args->mask = mask;
208 rule_args->op = op;
209 return 0;
210}
211
212/* This function is used to parse the seccomp rule entry.
213 * @line : seccomp rule entry string.
214 * @def_action : default action used in the case if the 'line' contain non valid action.
215 * @rules : output struct.
216 * Returns 0 on success, < 0 otherwise.
217 */
218static int parse_v2_rules(char *line, uint32_t def_action, struct seccomp_v2_rule *rules)
219{
220 int ret = 0 ;
221 int i = 0;
222 char *tmp = NULL;
223 char *key = NULL;
224 char *saveptr = NULL;
225
226 tmp = strdup(line);
227 if (!tmp)
228 return -1;
229
230 /* read optional action which follows the syscall */
231 rules->action = get_v2_action(tmp, def_action);
232 if (rules->action == -1) {
233 ERROR("Failed to interpret action");
234 ret = -1;
235 goto out;
236 }
237
238 rules->args_num = 0;
239 if (!strchr(tmp, '[')) {
240 ret = 0;
241 goto out;
242 }
243
244 for ((key = strtok_r(tmp, "]", &saveptr)), i = 0; key && i < 6; (key = strtok_r(NULL, "]", &saveptr)), i++) {
245 ret = get_seccomp_arg_value(key, &rules->args_value[i]);
246 if (ret < 0) {
247 ret = -1;
248 goto out;
249 }
250 rules->args_num++;
251 }
252
253 ret = 0;
254out:
255 free(tmp);
256 return ret;
257}
258
2b0ae718 259#endif
50798138 260
d58c6ad0
SH
261#if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
262enum lxc_hostarch_t {
263 lxc_seccomp_arch_all = 0,
264 lxc_seccomp_arch_native,
265 lxc_seccomp_arch_i386,
11de80d6 266 lxc_seccomp_arch_x32,
d58c6ad0
SH
267 lxc_seccomp_arch_amd64,
268 lxc_seccomp_arch_arm,
9d291dd2 269 lxc_seccomp_arch_arm64,
b4067426
BP
270 lxc_seccomp_arch_ppc64,
271 lxc_seccomp_arch_ppc64le,
272 lxc_seccomp_arch_ppc,
2ccd9eda
JC
273 lxc_seccomp_arch_mips,
274 lxc_seccomp_arch_mips64,
275 lxc_seccomp_arch_mips64n32,
276 lxc_seccomp_arch_mipsel,
277 lxc_seccomp_arch_mipsel64,
278 lxc_seccomp_arch_mipsel64n32,
be038e49 279 lxc_seccomp_arch_s390x,
d58c6ad0
SH
280 lxc_seccomp_arch_unknown = 999,
281};
282
2ccd9eda
JC
283#ifdef __MIPSEL__
284# define MIPS_ARCH_O32 lxc_seccomp_arch_mipsel
285# define MIPS_ARCH_N64 lxc_seccomp_arch_mipsel64
286#else
287# define MIPS_ARCH_O32 lxc_seccomp_arch_mips
288# define MIPS_ARCH_N64 lxc_seccomp_arch_mips64
289#endif
290
d58c6ad0
SH
291int get_hostarch(void)
292{
293 struct utsname uts;
294 if (uname(&uts) < 0) {
3ee26d19 295 SYSERROR("Failed to read host arch");
d58c6ad0
SH
296 return -1;
297 }
298 if (strcmp(uts.machine, "i686") == 0)
299 return lxc_seccomp_arch_i386;
1a0e70ac 300 /* no x32 kernels */
d58c6ad0
SH
301 else if (strcmp(uts.machine, "x86_64") == 0)
302 return lxc_seccomp_arch_amd64;
303 else if (strncmp(uts.machine, "armv7", 5) == 0)
304 return lxc_seccomp_arch_arm;
9d291dd2
BP
305 else if (strncmp(uts.machine, "aarch64", 7) == 0)
306 return lxc_seccomp_arch_arm64;
b4067426
BP
307 else if (strncmp(uts.machine, "ppc64le", 7) == 0)
308 return lxc_seccomp_arch_ppc64le;
309 else if (strncmp(uts.machine, "ppc64", 5) == 0)
310 return lxc_seccomp_arch_ppc64;
311 else if (strncmp(uts.machine, "ppc", 3) == 0)
312 return lxc_seccomp_arch_ppc;
2ccd9eda
JC
313 else if (strncmp(uts.machine, "mips64", 6) == 0)
314 return MIPS_ARCH_N64;
315 else if (strncmp(uts.machine, "mips", 4) == 0)
316 return MIPS_ARCH_O32;
be038e49
CB
317 else if (strncmp(uts.machine, "s390x", 5) == 0)
318 return lxc_seccomp_arch_s390x;
d58c6ad0
SH
319 return lxc_seccomp_arch_unknown;
320}
321
322scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_policy_action)
323{
324 scmp_filter_ctx ctx;
325 int ret;
326 uint32_t arch;
327
328 switch(n_arch) {
329 case lxc_seccomp_arch_i386: arch = SCMP_ARCH_X86; break;
11de80d6 330 case lxc_seccomp_arch_x32: arch = SCMP_ARCH_X32; break;
d58c6ad0
SH
331 case lxc_seccomp_arch_amd64: arch = SCMP_ARCH_X86_64; break;
332 case lxc_seccomp_arch_arm: arch = SCMP_ARCH_ARM; break;
9d291dd2
BP
333#ifdef SCMP_ARCH_AARCH64
334 case lxc_seccomp_arch_arm64: arch = SCMP_ARCH_AARCH64; break;
335#endif
b4067426
BP
336#ifdef SCMP_ARCH_PPC64LE
337 case lxc_seccomp_arch_ppc64le: arch = SCMP_ARCH_PPC64LE; break;
338#endif
339#ifdef SCMP_ARCH_PPC64
340 case lxc_seccomp_arch_ppc64: arch = SCMP_ARCH_PPC64; break;
341#endif
342#ifdef SCMP_ARCH_PPC
343 case lxc_seccomp_arch_ppc: arch = SCMP_ARCH_PPC; break;
2ccd9eda
JC
344#endif
345#ifdef SCMP_ARCH_MIPS
346 case lxc_seccomp_arch_mips: arch = SCMP_ARCH_MIPS; break;
347 case lxc_seccomp_arch_mips64: arch = SCMP_ARCH_MIPS64; break;
348 case lxc_seccomp_arch_mips64n32: arch = SCMP_ARCH_MIPS64N32; break;
349 case lxc_seccomp_arch_mipsel: arch = SCMP_ARCH_MIPSEL; break;
350 case lxc_seccomp_arch_mipsel64: arch = SCMP_ARCH_MIPSEL64; break;
351 case lxc_seccomp_arch_mipsel64n32: arch = SCMP_ARCH_MIPSEL64N32; break;
be038e49
CB
352#endif
353#ifdef SCMP_ARCH_S390X
354 case lxc_seccomp_arch_s390x: arch = SCMP_ARCH_S390X; break;
b4067426 355#endif
d58c6ad0
SH
356 default: return NULL;
357 }
358
359 if ((ctx = seccomp_init(default_policy_action)) == NULL) {
3ee26d19 360 ERROR("Error initializing seccomp context");
d58c6ad0
SH
361 return NULL;
362 }
363 if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0)) {
3ee26d19 364 ERROR("Failed to turn off no-new-privs");
d58c6ad0
SH
365 seccomp_release(ctx);
366 return NULL;
367 }
127c5293
SH
368#ifdef SCMP_FLTATR_ATL_TSKIP
369 if (seccomp_attr_set(ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
370 WARN("Failed to turn on seccomp nop-skip, continuing");
371 }
372#endif
b5ed021b 373
adfee3a8
CB
374 ret = seccomp_arch_exist(ctx, arch);
375 if (ret < 0) {
376 if (ret != -EEXIST) {
377 ERROR("%s - Failed to determine whether arch %d is "
378 "already present in the main seccomp context",
379 strerror(-ret), (int)n_arch);
380 seccomp_release(ctx);
381 return NULL;
382 }
383
b5ed021b
CB
384 ret = seccomp_arch_add(ctx, arch);
385 if (ret != 0) {
adfee3a8
CB
386 ERROR("%s - Failed to add arch %d to main seccomp context",
387 strerror(-ret), (int)n_arch);
b5ed021b
CB
388 seccomp_release(ctx);
389 return NULL;
390 }
adfee3a8 391 TRACE("Added arch %d to main seccomp context", (int)n_arch);
b5ed021b 392
adfee3a8
CB
393 ret = seccomp_arch_remove(ctx, SCMP_ARCH_NATIVE);
394 if (ret != 0) {
395 ERROR("Failed to remove native arch from main seccomp context");
b5ed021b
CB
396 seccomp_release(ctx);
397 return NULL;
398 }
adfee3a8
CB
399 TRACE("Removed native arch from main seccomp context");
400 } else {
401 TRACE("Arch %d already present in main seccomp context", (int)n_arch);
d58c6ad0
SH
402 }
403
404 return ctx;
405}
406
407bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx,
3ee26d19 408 struct seccomp_v2_rule *rule)
d58c6ad0 409{
3ee26d19
L
410 int nr, ret, i;
411 struct scmp_arg_cmp arg_cmp[6];
412
413 memset(arg_cmp, 0 ,sizeof(arg_cmp));
d58c6ad0 414
f06c6207
CB
415 ret = seccomp_arch_exist(ctx, arch);
416 if (arch && ret != 0) {
417 ERROR("BUG: Seccomp: rule and context arch do not match (arch "
3ee26d19 418 "%d): %s",
f06c6207 419 arch, strerror(-ret));
d58c6ad0
SH
420 return false;
421 }
6166fa6d 422
3ee26d19
L
423 /*get the syscall name*/
424 char *p = strchr(line, ' ');
425 if (p)
426 *p = '\0';
427
6166fa6d 428 if (strncmp(line, "reject_force_umount", 19) == 0) {
3ee26d19 429 INFO("Setting Seccomp rule to reject force umounts");
6166fa6d
SH
430 ret = seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(umount2),
431 1, SCMP_A1(SCMP_CMP_MASKED_EQ , MNT_FORCE , MNT_FORCE ));
432 if (ret < 0) {
f06c6207 433 ERROR("Failed (%d) loading rule to reject force "
3ee26d19 434 "umount: %s",
f06c6207 435 ret, strerror(-ret));
6166fa6d
SH
436 return false;
437 }
438 return true;
439 }
440
cd75548b 441 nr = seccomp_syscall_resolve_name(line);
d58c6ad0 442 if (nr == __NR_SCMP_ERROR) {
3ee26d19
L
443 WARN("Seccomp: failed to resolve syscall: %s", line);
444 WARN("This syscall will NOT be blacklisted");
d58c6ad0
SH
445 return true;
446 }
447 if (nr < 0) {
3ee26d19
L
448 WARN("Seccomp: got negative for syscall: %d: %s", nr, line);
449 WARN("This syscall will NOT be blacklisted");
d58c6ad0
SH
450 return true;
451 }
3ee26d19
L
452
453 for (i = 0; i < rule->args_num; i++) {
454 INFO("arg_cmp[%d]:SCMP_CMP(%u, %llu, %llu, %llu)", i,
455 rule->args_value[i].index,
456 (long long unsigned int)rule->args_value[i].op,
457 (long long unsigned int)rule->args_value[i].mask,
458 (long long unsigned int)rule->args_value[i].value);
459
460 if (SCMP_CMP_MASKED_EQ == rule->args_value[i].op)
461 arg_cmp[i] = SCMP_CMP(rule->args_value[i].index, rule->args_value[i].op, rule->args_value[i].mask, rule->args_value[i].value);
462 else
463 arg_cmp[i] = SCMP_CMP(rule->args_value[i].index, rule->args_value[i].op, rule->args_value[i].value);
464 }
465
466 ret = seccomp_rule_add_exact_array(ctx, rule->action, nr, rule->args_num, arg_cmp);
d58c6ad0 467 if (ret < 0) {
3ee26d19
L
468 ERROR("Failed (%d) loading rule for %s (nr %d action %d(%s)): %s",
469 ret, line, nr, rule->action, get_action_name(rule->action), strerror(-ret));
d58c6ad0
SH
470 return false;
471 }
472 return true;
473}
474
50798138
SH
475/*
476 * v2 consists of
477 * [x86]
478 * open
479 * read
480 * write
481 * close
482 * # a comment
483 * [x86_64]
484 * open
485 * read
486 * write
487 * close
488 */
489static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
490{
50798138
SH
491 char *p;
492 int ret;
f06c6207 493 scmp_filter_ctx compat_ctx[2] = {NULL, NULL};
50798138 494 bool blacklist = false;
3ee26d19 495 uint32_t default_policy_action = -1, default_rule_action = -1;
d58c6ad0
SH
496 enum lxc_hostarch_t native_arch = get_hostarch(),
497 cur_rule_arch = native_arch;
f06c6207 498 uint32_t compat_arch[2] = {SCMP_ARCH_NATIVE, SCMP_ARCH_NATIVE};
3ee26d19 499 struct seccomp_v2_rule rule;
50798138
SH
500
501 if (strncmp(line, "blacklist", 9) == 0)
502 blacklist = true;
503 else if (strncmp(line, "whitelist", 9) != 0) {
3ee26d19 504 ERROR("Bad seccomp policy style: %s", line);
50798138
SH
505 return -1;
506 }
507
508 if ((p = strchr(line, ' '))) {
f06c6207 509 default_policy_action = get_v2_default_action(p + 1);
50798138
SH
510 if (default_policy_action == -2)
511 return -1;
512 }
513
514 /* for blacklist, allow any syscall which has no rule */
515 if (blacklist) {
516 if (default_policy_action == -1)
517 default_policy_action = SCMP_ACT_ALLOW;
518 if (default_rule_action == -1)
519 default_rule_action = SCMP_ACT_KILL;
520 } else {
521 if (default_policy_action == -1)
522 default_policy_action = SCMP_ACT_KILL;
523 if (default_rule_action == -1)
524 default_rule_action = SCMP_ACT_ALLOW;
525 }
526
d58c6ad0
SH
527 if (native_arch == lxc_seccomp_arch_amd64) {
528 cur_rule_arch = lxc_seccomp_arch_all;
2ccd9eda
JC
529 compat_arch[0] = SCMP_ARCH_X86;
530 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_i386,
ab5e52f6 531 default_policy_action);
11de80d6
AB
532 compat_arch[1] = SCMP_ARCH_X32;
533 compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_x32,
534 default_policy_action);
535 if (!compat_ctx[0] || !compat_ctx[1])
ab5e52f6 536 goto bad;
ca399594 537#ifdef SCMP_ARCH_PPC
7635139a
SH
538 } else if (native_arch == lxc_seccomp_arch_ppc64) {
539 cur_rule_arch = lxc_seccomp_arch_all;
2ccd9eda
JC
540 compat_arch[0] = SCMP_ARCH_PPC;
541 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_ppc,
7635139a 542 default_policy_action);
2ccd9eda 543 if (!compat_ctx[0])
7635139a 544 goto bad;
ca399594
CB
545#endif
546#ifdef SCMP_ARCH_ARM
7635139a
SH
547 } else if (native_arch == lxc_seccomp_arch_arm64) {
548 cur_rule_arch = lxc_seccomp_arch_all;
2ccd9eda
JC
549 compat_arch[0] = SCMP_ARCH_ARM;
550 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_arm,
7635139a 551 default_policy_action);
2ccd9eda
JC
552 if (!compat_ctx[0])
553 goto bad;
554#endif
555#ifdef SCMP_ARCH_MIPS
556 } else if (native_arch == lxc_seccomp_arch_mips64) {
557 cur_rule_arch = lxc_seccomp_arch_all;
558 compat_arch[0] = SCMP_ARCH_MIPS;
559 compat_arch[1] = SCMP_ARCH_MIPS64N32;
560 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_mips,
561 default_policy_action);
562 compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_mips64n32,
563 default_policy_action);
564 if (!compat_ctx[0] || !compat_ctx[1])
565 goto bad;
566 } else if (native_arch == lxc_seccomp_arch_mipsel64) {
567 cur_rule_arch = lxc_seccomp_arch_all;
568 compat_arch[0] = SCMP_ARCH_MIPSEL;
569 compat_arch[1] = SCMP_ARCH_MIPSEL64N32;
570 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_mipsel,
571 default_policy_action);
572 compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_mipsel64n32,
573 default_policy_action);
574 if (!compat_ctx[0] || !compat_ctx[1])
7635139a 575 goto bad;
be038e49 576#endif
d58c6ad0
SH
577 }
578
50798138
SH
579 if (default_policy_action != SCMP_ACT_KILL) {
580 ret = seccomp_reset(conf->seccomp_ctx, default_policy_action);
581 if (ret != 0) {
3ee26d19 582 ERROR("Error re-initializing Seccomp");
50798138
SH
583 return -1;
584 }
585 if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0)) {
3ee26d19 586 ERROR("Failed to turn off no-new-privs");
50798138
SH
587 return -1;
588 }
127c5293
SH
589#ifdef SCMP_FLTATR_ATL_TSKIP
590 if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
591 WARN("Failed to turn on seccomp nop-skip, continuing");
592 }
593#endif
50798138
SH
594 }
595
596 while (fgets(line, 1024, f)) {
50798138
SH
597
598 if (line[0] == '#')
599 continue;
600 if (strlen(line) == 0)
601 continue;
602 remove_trailing_newlines(line);
3ee26d19 603 INFO("processing: .%s", line);
50798138 604 if (line[0] == '[') {
1a0e70ac 605 /* Read the architecture for next set of rules. */
50798138 606 if (strcmp(line, "[x86]") == 0 ||
f06c6207 607 strcmp(line, "[X86]") == 0) {
d58c6ad0 608 if (native_arch != lxc_seccomp_arch_i386 &&
7635139a 609 native_arch != lxc_seccomp_arch_amd64) {
d58c6ad0
SH
610 cur_rule_arch = lxc_seccomp_arch_unknown;
611 continue;
612 }
613 cur_rule_arch = lxc_seccomp_arch_i386;
11de80d6
AB
614 } else if (strcmp(line, "[x32]") == 0 ||
615 strcmp(line, "[X32]") == 0) {
616 if (native_arch != lxc_seccomp_arch_amd64) {
617 cur_rule_arch = lxc_seccomp_arch_unknown;
618 continue;
619 }
620 cur_rule_arch = lxc_seccomp_arch_x32;
d58c6ad0 621 } else if (strcmp(line, "[X86_64]") == 0 ||
f06c6207 622 strcmp(line, "[x86_64]") == 0) {
d58c6ad0
SH
623 if (native_arch != lxc_seccomp_arch_amd64) {
624 cur_rule_arch = lxc_seccomp_arch_unknown;
625 continue;
626 }
627 cur_rule_arch = lxc_seccomp_arch_amd64;
d58c6ad0 628 } else if (strcmp(line, "[all]") == 0 ||
f06c6207 629 strcmp(line, "[ALL]") == 0) {
d58c6ad0 630 cur_rule_arch = lxc_seccomp_arch_all;
d58c6ad0 631 }
2b0ae718 632#ifdef SCMP_ARCH_ARM
50798138 633 else if (strcmp(line, "[arm]") == 0 ||
f06c6207 634 strcmp(line, "[ARM]") == 0) {
7635139a
SH
635 if (native_arch != lxc_seccomp_arch_arm &&
636 native_arch != lxc_seccomp_arch_arm64) {
d58c6ad0
SH
637 cur_rule_arch = lxc_seccomp_arch_unknown;
638 continue;
639 }
640 cur_rule_arch = lxc_seccomp_arch_arm;
d58c6ad0 641 }
b4067426 642#endif
9d291dd2
BP
643#ifdef SCMP_ARCH_AARCH64
644 else if (strcmp(line, "[arm64]") == 0 ||
f06c6207 645 strcmp(line, "[ARM64]") == 0) {
9d291dd2
BP
646 if (native_arch != lxc_seccomp_arch_arm64) {
647 cur_rule_arch = lxc_seccomp_arch_unknown;
648 continue;
649 }
650 cur_rule_arch = lxc_seccomp_arch_arm64;
651 }
652#endif
b4067426
BP
653#ifdef SCMP_ARCH_PPC64LE
654 else if (strcmp(line, "[ppc64le]") == 0 ||
f06c6207 655 strcmp(line, "[PPC64LE]") == 0) {
b4067426
BP
656 if (native_arch != lxc_seccomp_arch_ppc64le) {
657 cur_rule_arch = lxc_seccomp_arch_unknown;
658 continue;
659 }
660 cur_rule_arch = lxc_seccomp_arch_ppc64le;
661 }
662#endif
663#ifdef SCMP_ARCH_PPC64
664 else if (strcmp(line, "[ppc64]") == 0 ||
f06c6207 665 strcmp(line, "[PPC64]") == 0) {
b4067426
BP
666 if (native_arch != lxc_seccomp_arch_ppc64) {
667 cur_rule_arch = lxc_seccomp_arch_unknown;
668 continue;
669 }
670 cur_rule_arch = lxc_seccomp_arch_ppc64;
671 }
672#endif
673#ifdef SCMP_ARCH_PPC
674 else if (strcmp(line, "[ppc]") == 0 ||
f06c6207 675 strcmp(line, "[PPC]") == 0) {
7635139a
SH
676 if (native_arch != lxc_seccomp_arch_ppc &&
677 native_arch != lxc_seccomp_arch_ppc64) {
b4067426
BP
678 cur_rule_arch = lxc_seccomp_arch_unknown;
679 continue;
680 }
681 cur_rule_arch = lxc_seccomp_arch_ppc;
682 }
2ccd9eda
JC
683#endif
684#ifdef SCMP_ARCH_MIPS
685 else if (strcmp(line, "[mips64]") == 0 ||
f06c6207 686 strcmp(line, "[MIPS64]") == 0) {
2ccd9eda
JC
687 if (native_arch != lxc_seccomp_arch_mips64) {
688 cur_rule_arch = lxc_seccomp_arch_unknown;
689 continue;
690 }
691 cur_rule_arch = lxc_seccomp_arch_mips64;
692 } else if (strcmp(line, "[mips64n32]") == 0 ||
f06c6207 693 strcmp(line, "[MIPS64N32]") == 0) {
2ccd9eda
JC
694 if (native_arch != lxc_seccomp_arch_mips64) {
695 cur_rule_arch = lxc_seccomp_arch_unknown;
696 continue;
697 }
698 cur_rule_arch = lxc_seccomp_arch_mips64n32;
699 } else if (strcmp(line, "[mips]") == 0 ||
f06c6207 700 strcmp(line, "[MIPS]") == 0) {
2ccd9eda
JC
701 if (native_arch != lxc_seccomp_arch_mips &&
702 native_arch != lxc_seccomp_arch_mips64) {
703 cur_rule_arch = lxc_seccomp_arch_unknown;
704 continue;
705 }
706 cur_rule_arch = lxc_seccomp_arch_mips;
707 } else if (strcmp(line, "[mipsel64]") == 0 ||
f06c6207 708 strcmp(line, "[MIPSEL64]") == 0) {
2ccd9eda
JC
709 if (native_arch != lxc_seccomp_arch_mipsel64) {
710 cur_rule_arch = lxc_seccomp_arch_unknown;
711 continue;
712 }
713 cur_rule_arch = lxc_seccomp_arch_mipsel64;
714 } else if (strcmp(line, "[mipsel64n32]") == 0 ||
f06c6207 715 strcmp(line, "[MIPSEL64N32]") == 0) {
2ccd9eda
JC
716 if (native_arch != lxc_seccomp_arch_mipsel64) {
717 cur_rule_arch = lxc_seccomp_arch_unknown;
718 continue;
719 }
720 cur_rule_arch = lxc_seccomp_arch_mipsel64n32;
721 } else if (strcmp(line, "[mipsel]") == 0 ||
f06c6207 722 strcmp(line, "[MIPSEL]") == 0) {
2ccd9eda
JC
723 if (native_arch != lxc_seccomp_arch_mipsel &&
724 native_arch != lxc_seccomp_arch_mipsel64) {
725 cur_rule_arch = lxc_seccomp_arch_unknown;
726 continue;
727 }
728 cur_rule_arch = lxc_seccomp_arch_mipsel;
729 }
be038e49
CB
730#endif
731#ifdef SCMP_ARCH_S390X
732 else if (strcmp(line, "[s390x]") == 0 ||
f06c6207 733 strcmp(line, "[S390X]") == 0) {
be038e49
CB
734 if (native_arch != lxc_seccomp_arch_s390x) {
735 cur_rule_arch = lxc_seccomp_arch_unknown;
736 continue;
737 }
738 cur_rule_arch = lxc_seccomp_arch_s390x;
739 }
2b0ae718 740#endif
50798138
SH
741 else
742 goto bad_arch;
d58c6ad0 743
50798138
SH
744 continue;
745 }
746
d58c6ad0
SH
747 /* irrelevant arch - i.e. arm on i386 */
748 if (cur_rule_arch == lxc_seccomp_arch_unknown)
749 continue;
750
3ee26d19 751 memset(&rule, 0, sizeof(rule));
d58c6ad0 752 /* read optional action which follows the syscall */
3ee26d19
L
753 ret = parse_v2_rules(line, default_rule_action, &rule);
754 if (ret != 0) {
755 ERROR("Failed to interpret seccomp rule");
50798138
SH
756 goto bad_rule;
757 }
d58c6ad0 758
d6417887
WB
759 if (cur_rule_arch == native_arch ||
760 cur_rule_arch == lxc_seccomp_arch_native ||
2ccd9eda 761 compat_arch[0] == SCMP_ARCH_NATIVE) {
3ee26d19 762 if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, &rule))
d58c6ad0 763 goto bad_rule;
94d56054
CB
764 INFO("Added native rule for arch %d for %s action %d(%s)",
765 SCMP_ARCH_NATIVE, line, rule.action,
3ee26d19 766 get_action_name(rule.action));
94d56054
CB
767 } else if (cur_rule_arch != lxc_seccomp_arch_all) {
768 int arch_index = 0;
769
770 if ((cur_rule_arch == lxc_seccomp_arch_mips64n32) ||
771 (cur_rule_arch == lxc_seccomp_arch_mipsel64n32))
772 arch_index = 1;
773
3ee26d19 774 if (!do_resolve_add_rule(compat_arch[arch_index], line, compat_ctx[arch_index], &rule))
d6417887 775 goto bad_rule;
94d56054
CB
776 INFO("Added compat-only rule for arch %d for %s action %d(%s)",
777 compat_arch[arch_index], line, rule.action,
3ee26d19 778 get_action_name(rule.action));
94d56054 779 } else {
3ee26d19 780 if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, &rule))
d6417887 781 goto bad_rule;
94d56054
CB
782 INFO("Added native rule for arch %d for %s action %d(%s)",
783 SCMP_ARCH_NATIVE, line, rule.action,
3ee26d19 784 get_action_name(rule.action));
94d56054
CB
785
786 if (compat_arch[0] != SCMP_ARCH_NATIVE) {
787 if (!do_resolve_add_rule(compat_arch[0], line, compat_ctx[0], &rule))
788 goto bad_rule;
789 INFO("Added compat rule for arch %d for %s "
790 "action %d(%s)", compat_arch[0], line,
791 rule.action, get_action_name(rule.action));
792 }
793
794 if (compat_arch[1] != SCMP_ARCH_NATIVE) {
795 if (!do_resolve_add_rule(compat_arch[1], line, compat_ctx[1], &rule))
796 goto bad_rule;
797 INFO("Added compat rule for arch %d for %s "
798 "action %d(%s)", compat_arch[1], line,
799 rule.action, get_action_name(rule.action));
800 }
50798138
SH
801 }
802 }
d58c6ad0 803
d648e178 804 INFO("Merging compat seccomp contexts into main context");
2ccd9eda 805 if (compat_ctx[0]) {
d648e178
CB
806 if ((compat_arch[0] != native_arch) &&
807 (compat_arch[0] != seccomp_arch_native())) {
b5ed021b
CB
808 ret = seccomp_merge(conf->seccomp_ctx, compat_ctx[0]);
809 if (ret < 0) {
d648e178
CB
810 ERROR("Failed to merge first compat seccomp "
811 "context into main context");
b5ed021b
CB
812 goto bad;
813 }
814 TRACE("Merged first compat seccomp context into main context");
d648e178
CB
815 } else {
816 seccomp_release(compat_ctx[0]);
817 compat_ctx[0] = NULL;
b5ed021b 818 }
d648e178 819 }
b5ed021b 820
d648e178
CB
821 if (compat_ctx[1]) {
822 if ((compat_arch[1] != native_arch) &&
823 (compat_arch[1] != seccomp_arch_native())) {
b5ed021b
CB
824 ret = seccomp_merge(conf->seccomp_ctx, compat_ctx[1]);
825 if (ret < 0) {
d648e178
CB
826 ERROR("Failed to merge first compat seccomp "
827 "context into main context");
b5ed021b
CB
828 goto bad;
829 }
830 TRACE("Merged second compat seccomp context into main context");
d648e178
CB
831 } else {
832 seccomp_release(compat_ctx[1]);
833 compat_ctx[1] = NULL;
50798138
SH
834 }
835 }
6166fa6d 836
50798138
SH
837 return 0;
838
839bad_arch:
f06c6207 840 ERROR("Unsupported arch: %s.", line);
50798138 841bad_rule:
d58c6ad0 842bad:
2ccd9eda
JC
843 if (compat_ctx[0])
844 seccomp_release(compat_ctx[0]);
845 if (compat_ctx[1])
846 seccomp_release(compat_ctx[1]);
50798138 847 return -1;
d58c6ad0
SH
848}
849#else /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
850static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
851{
50798138 852 return -1;
50798138 853}
d58c6ad0 854#endif /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
50798138 855
8f2c3a70
SH
856/*
857 * The first line of the config file has a policy language version
858 * the second line has some directives
859 * then comes policy subject to the directives
998cd2f4 860 * right now version must be '1' or '2'
861 * the directives must include 'whitelist'(version == 1 or 2) or 'blacklist'
862 * (version == 2) and can include 'debug' (though debug is not yet supported).
8f2c3a70
SH
863 */
864static int parse_config(FILE *f, struct lxc_conf *conf)
865{
866 char line[1024];
867 int ret, version;
868
869 ret = fscanf(f, "%d\n", &version);
50798138 870 if (ret != 1 || (version != 1 && version != 2)) {
3ee26d19 871 ERROR("Invalid version");
8f2c3a70
SH
872 return -1;
873 }
874 if (!fgets(line, 1024, f)) {
3ee26d19 875 ERROR("Invalid config file");
8f2c3a70
SH
876 return -1;
877 }
50798138 878 if (version == 1 && !strstr(line, "whitelist")) {
3ee26d19 879 ERROR("Only whitelist policy is supported");
8f2c3a70
SH
880 return -1;
881 }
50798138 882
8f2c3a70 883 if (strstr(line, "debug")) {
3ee26d19 884 ERROR("Debug not yet implemented");
8f2c3a70
SH
885 return -1;
886 }
50798138
SH
887
888 if (version == 1)
889 return parse_config_v1(f, conf);
890 return parse_config_v2(f, line, conf);
8f2c3a70
SH
891}
892
cd75548b
SH
893/*
894 * use_seccomp: return true if we should try and apply a seccomp policy
895 * if defined for the container.
896 * This will return false if
897 * 1. seccomp is not enabled in the kernel
898 * 2. a seccomp policy is already enabled for this task
899 */
900static bool use_seccomp(void)
d58c6ad0
SH
901{
902 FILE *f = fopen("/proc/self/status", "r");
903 char line[1024];
cd75548b
SH
904 bool already_enabled = false;
905 bool found = false;
d58c6ad0
SH
906 int ret, v;
907
908 if (!f)
cd75548b 909 return true;
d58c6ad0
SH
910
911 while (fgets(line, 1024, f)) {
912 if (strncmp(line, "Seccomp:", 8) == 0) {
cd75548b 913 found = true;
f06c6207 914 ret = sscanf(line + 8, "%d", &v);
cd75548b
SH
915 if (ret == 1 && v != 0)
916 already_enabled = true;
917 break;
d58c6ad0
SH
918 }
919 }
920
d58c6ad0 921 fclose(f);
f06c6207 922 if (!found) { /* no Seccomp line, no seccomp in kernel */
3ee26d19 923 INFO("Seccomp is not enabled in the kernel");
cd75548b
SH
924 return false;
925 }
f06c6207 926 if (already_enabled) { /* already seccomp-confined */
3ee26d19 927 INFO("Already seccomp-confined, not loading new policy");
cd75548b
SH
928 return false;
929 }
930 return true;
d58c6ad0
SH
931}
932
8f2c3a70
SH
933int lxc_read_seccomp_config(struct lxc_conf *conf)
934{
935 FILE *f;
936 int ret;
727c3073 937 int check_seccomp_attr_set;
8f2c3a70 938
769872f9
SH
939 if (!conf->seccomp)
940 return 0;
941
cd75548b 942 if (!use_seccomp())
d58c6ad0 943 return 0;
769872f9
SH
944#if HAVE_SCMP_FILTER_CTX
945 /* XXX for debug, pass in SCMP_ACT_TRAP */
50798138 946 conf->seccomp_ctx = seccomp_init(SCMP_ACT_KILL);
769872f9
SH
947 ret = !conf->seccomp_ctx;
948#else
50798138 949 ret = seccomp_init(SCMP_ACT_KILL) < 0;
769872f9
SH
950#endif
951 if (ret) {
3ee26d19 952 ERROR("Failed initializing seccomp");
8f2c3a70
SH
953 return -1;
954 }
8f2c3a70 955
127c5293 956/* turn off no-new-privs. We don't want it in lxc, and it breaks
f06c6207 957 * with apparmor */
769872f9 958#if HAVE_SCMP_FILTER_CTX
f06c6207 959 check_seccomp_attr_set = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0);
727c3073 960#else
f06c6207 961 check_seccomp_attr_set = seccomp_attr_set(SCMP_FLTATR_CTL_NNP, 0);
769872f9 962#endif
727c3073 963 if (check_seccomp_attr_set) {
3ee26d19 964 ERROR("Failed to turn off no-new-privs");
8f2c3a70
SH
965 return -1;
966 }
127c5293
SH
967#ifdef SCMP_FLTATR_ATL_TSKIP
968 if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
969 WARN("Failed to turn on seccomp nop-skip, continuing");
970 }
971#endif
8f2c3a70
SH
972
973 f = fopen(conf->seccomp, "r");
974 if (!f) {
3ee26d19 975 SYSERROR("Failed to open seccomp policy file %s", conf->seccomp);
8f2c3a70
SH
976 return -1;
977 }
978 ret = parse_config(f, conf);
979 fclose(f);
980 return ret;
981}
982
983int lxc_seccomp_load(struct lxc_conf *conf)
984{
985 int ret;
986 if (!conf->seccomp)
987 return 0;
cd75548b 988 if (!use_seccomp())
d58c6ad0 989 return 0;
769872f9
SH
990 ret = seccomp_load(
991#if HAVE_SCMP_FILTER_CTX
f06c6207 992 conf->seccomp_ctx
769872f9 993#endif
f06c6207 994 );
8f2c3a70 995 if (ret < 0) {
3ee26d19 996 ERROR("Error loading the seccomp policy: %s", strerror(-ret));
8f2c3a70
SH
997 return -1;
998 }
5107af32 999
1000/* After load seccomp filter into the kernel successfully, export the current seccomp
1001 * filter to log file */
1002#if HAVE_SCMP_FILTER_CTX
4b73005c 1003 if ((lxc_log_get_level() <= LXC_LOG_LEVEL_TRACE || conf->loglevel <= LXC_LOG_LEVEL_TRACE) &&
5107af32 1004 lxc_log_fd >= 0) {
1005 ret = seccomp_export_pfc(conf->seccomp_ctx, lxc_log_fd);
1006 /* Just give an warning when export error */
1007 if (ret < 0)
3ee26d19 1008 WARN("Failed to export seccomp filter to log file: %s", strerror(-ret));
5107af32 1009 }
1010#endif
8f2c3a70
SH
1011 return 0;
1012}
769872f9 1013
f06c6207
CB
1014void lxc_seccomp_free(struct lxc_conf *conf)
1015{
f10fad2f
ME
1016 free(conf->seccomp);
1017 conf->seccomp = NULL;
769872f9
SH
1018#if HAVE_SCMP_FILTER_CTX
1019 if (conf->seccomp_ctx) {
1020 seccomp_release(conf->seccomp_ctx);
1021 conf->seccomp_ctx = NULL;
1022 }
1023#endif
1024}