]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/seccomp.c
Merge pull request #2445 from 2xsec/bugfix
[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>
ccf8d128 26#include <seccomp.h>
8f2c3a70
SH
27#include <stdio.h>
28#include <stdlib.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"
eacebcc3 35#include "utils.h"
8f2c3a70 36
0b5c590d
CB
37#ifdef __MIPSEL__
38#define MIPS_ARCH_O32 lxc_seccomp_arch_mipsel
39#define MIPS_ARCH_N64 lxc_seccomp_arch_mipsel64
40#else
41#define MIPS_ARCH_O32 lxc_seccomp_arch_mips
42#define MIPS_ARCH_N64 lxc_seccomp_arch_mips64
43#endif
44
8f2c3a70
SH
45lxc_log_define(lxc_seccomp, lxc);
46
9dbd8ff3 47static int parse_config_v1(FILE *f, char *line, size_t *line_bufsz, struct lxc_conf *conf)
50798138 48{
ccf8d128 49 int ret = 0;
50798138 50
9dbd8ff3 51 while (getline(&line, line_bufsz, f) != -1) {
50798138 52 int nr;
ccf8d128 53
50798138 54 ret = sscanf(line, "%d", &nr);
97a9b258
WB
55 if (ret != 1) {
56 ret = -1;
57 break;
58 }
ccf8d128 59
50798138 60#if HAVE_SCMP_FILTER_CTX
ccf8d128
CB
61 ret = seccomp_rule_add(conf->seccomp_ctx, SCMP_ACT_ALLOW, nr, 0);
62#else
63 ret = seccomp_rule_add(SCMP_ACT_ALLOW, nr, 0);
50798138 64#endif
50798138 65 if (ret < 0) {
3ee26d19 66 ERROR("Failed loading allow rule for %d", nr);
ccf8d128 67 break;
50798138
SH
68 }
69 }
ccf8d128
CB
70 free(line);
71
72 return ret;
50798138
SH
73}
74
2b0ae718 75#if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
1ab6b4a1
CB
76static const char *get_action_name(uint32_t action)
77{
78 /* The upper 16 bits indicate the type of the seccomp action. */
79 switch (action & 0xffff0000) {
80 case SCMP_ACT_KILL:
81 return "kill";
82 case SCMP_ACT_ALLOW:
83 return "allow";
84 case SCMP_ACT_TRAP:
85 return "trap";
86 case SCMP_ACT_ERRNO(0):
87 return "errno";
88 }
89
90 return "invalid action";
91}
92
50798138
SH
93static uint32_t get_v2_default_action(char *line)
94{
95 uint32_t ret_action = -1;
96
f06c6207
CB
97 while (*line == ' ')
98 line++;
30448a13 99
1a0e70ac 100 /* After 'whitelist' or 'blacklist' comes default behavior. */
30448a13 101 if (strncmp(line, "kill", 4) == 0) {
50798138 102 ret_action = SCMP_ACT_KILL;
30448a13
CB
103 } else if (strncmp(line, "errno", 5) == 0) {
104 int e, ret;
105
106 ret = sscanf(line + 5, "%d", &e);
107 if (ret != 1) {
108 ERROR("Failed to parse errno value from %s", line);
50798138
SH
109 return -2;
110 }
30448a13 111
50798138 112 ret_action = SCMP_ACT_ERRNO(e);
30448a13 113 } else if (strncmp(line, "allow", 5) == 0) {
50798138 114 ret_action = SCMP_ACT_ALLOW;
30448a13 115 } else if (strncmp(line, "trap", 4) == 0) {
50798138 116 ret_action = SCMP_ACT_TRAP;
7474b5b3 117 } else if (line[0]) {
54a051c1 118 ERROR("Unrecognized seccomp action \"%s\"", line);
7474b5b3 119 return -2;
30448a13
CB
120 }
121
50798138
SH
122 return ret_action;
123}
124
3ee26d19 125static uint32_t get_v2_action(char *line, uint32_t def_action)
50798138 126{
1ab6b4a1 127 char *p;
50798138
SH
128 uint32_t ret;
129
1ab6b4a1 130 p = strchr(line, ' ');
50798138
SH
131 if (!p)
132 return def_action;
50798138 133 p++;
1ab6b4a1 134
50798138
SH
135 while (*p == ' ')
136 p++;
1ab6b4a1 137
50798138
SH
138 if (!*p || *p == '#')
139 return def_action;
1ab6b4a1 140
50798138 141 ret = get_v2_default_action(p);
1ab6b4a1
CB
142 switch (ret) {
143 case -2:
144 return -1;
145 case -1:
146 return def_action;
50798138 147 }
1ab6b4a1
CB
148
149 return ret;
50798138 150}
3ee26d19 151
63a49b03 152struct seccomp_v2_rule_args {
3ee26d19
L
153 uint32_t index;
154 uint64_t value;
155 uint64_t mask;
156 enum scmp_compare op;
157};
158
159struct seccomp_v2_rule {
160 uint32_t action;
161 uint32_t args_num;
63a49b03 162 struct seccomp_v2_rule_args args_value[6];
3ee26d19
L
163};
164
165static enum scmp_compare parse_v2_rule_op(char *s)
166{
3ee26d19 167 if (strcmp(s, "SCMP_CMP_NE") == 0 || strcmp(s, "!=") == 0)
29cb2617 168 return SCMP_CMP_NE;
3ee26d19 169 else if (strcmp(s, "SCMP_CMP_LT") == 0 || strcmp(s, "<") == 0)
29cb2617 170 return SCMP_CMP_LT;
3ee26d19 171 else if (strcmp(s, "SCMP_CMP_LE") == 0 || strcmp(s, "<=") == 0)
29cb2617 172 return SCMP_CMP_LE;
3ee26d19 173 else if (strcmp(s, "SCMP_CMP_EQ") == 0 || strcmp(s, "==") == 0)
29cb2617 174 return SCMP_CMP_EQ;
3ee26d19 175 else if (strcmp(s, "SCMP_CMP_GE") == 0 || strcmp(s, ">=") == 0)
29cb2617 176 return SCMP_CMP_GE;
3ee26d19 177 else if (strcmp(s, "SCMP_CMP_GT") == 0 || strcmp(s, ">") == 0)
29cb2617 178 return SCMP_CMP_GT;
3ee26d19 179 else if (strcmp(s, "SCMP_CMP_MASKED_EQ") == 0 || strcmp(s, "&=") == 0)
29cb2617 180 return SCMP_CMP_MASKED_EQ;
3ee26d19 181
29cb2617 182 return _SCMP_CMP_MAX;
3ee26d19
L
183}
184
63a49b03
CB
185/*
186 * This function is used to parse the args string into the structure.
73e3cb9a 187 * args string format:[index,value,op,mask] or [index,value,op]
3ee26d19
L
188 * index: the index for syscall arguments (type uint)
189 * value: the value for syscall arguments (type uint64)
190 * op: the operator for syscall arguments(string),
191 a valid list of constants as of libseccomp v2.3.2 is
192 SCMP_CMP_NE,SCMP_CMP_LE,SCMP_CMP_LE, SCMP_CMP_EQ, SCMP_CMP_GE,
193 SCMP_CMP_GT, SCMP_CMP_MASKED_EQ, or !=,<=,==,>=,>,&=
73e3cb9a 194 * mask: the mask to apply on "value" for SCMP_CMP_MASKED_EQ (type uint64, optional)
3ee26d19
L
195 * Returns 0 on success, < 0 otherwise.
196 */
63a49b03 197static int get_seccomp_arg_value(char *key, struct seccomp_v2_rule_args *rule_args)
3ee26d19
L
198{
199 int ret = 0;
3ee26d19 200 uint32_t index = 0;
63a49b03
CB
201 uint64_t mask = 0, value = 0;
202 enum scmp_compare op = 0;
3ee26d19 203 char *tmp = NULL;
f42183e6 204 char s[31] = {0}, v[24] = {0}, m[24] = {'0'};
3ee26d19 205
3ee26d19
L
206 tmp = strchr(key, '[');
207 if (!tmp) {
208 ERROR("Failed to interpret args");
209 return -1;
210 }
63a49b03 211
eacebcc3 212 ret = sscanf(tmp, "[%i,%23[^,],%30[^0-9^,],%23[^,]", &index, v, s, m);
3ee26d19
L
213 if ((ret != 3 && ret != 4) || index >= 6) {
214 ERROR("Failed to interpret args value");
215 return -1;
216 }
217
573ad77f 218 ret = lxc_safe_uint64(v, &value, 0);
eacebcc3
FA
219 if (ret < 0) {
220 ERROR("Invalid argument value");
221 return -1;
222 }
223
573ad77f 224 ret = lxc_safe_uint64(m, &mask, 0);
eacebcc3
FA
225 if (ret < 0) {
226 ERROR("Invalid argument mask");
227 return -1;
228 }
229
3ee26d19
L
230 op = parse_v2_rule_op(s);
231 if (op == _SCMP_CMP_MAX) {
232 ERROR("Failed to interpret args operator value");
233 return -1;
234 }
235
236 rule_args->index = index;
237 rule_args->value = value;
238 rule_args->mask = mask;
239 rule_args->op = op;
240 return 0;
241}
242
243/* This function is used to parse the seccomp rule entry.
244 * @line : seccomp rule entry string.
245 * @def_action : default action used in the case if the 'line' contain non valid action.
246 * @rules : output struct.
247 * Returns 0 on success, < 0 otherwise.
248 */
f67c94d0
CB
249static int parse_v2_rules(char *line, uint32_t def_action,
250 struct seccomp_v2_rule *rules)
3ee26d19 251{
f67c94d0
CB
252 int i = 0, ret = -1;
253 char *key = NULL, *saveptr = NULL, *tmp = NULL;
3ee26d19
L
254
255 tmp = strdup(line);
256 if (!tmp)
257 return -1;
258
259 /* read optional action which follows the syscall */
260 rules->action = get_v2_action(tmp, def_action);
f858dd50
WB
261 if (rules->action == -1) {
262 ERROR("Failed to interpret action");
263 ret = -1;
54a051c1 264 goto on_error;
f858dd50 265 }
3ee26d19 266
f67c94d0 267 ret = 0;
3ee26d19 268 rules->args_num = 0;
f67c94d0 269 if (!strchr(tmp, '['))
54a051c1 270 goto on_error;
3ee26d19 271
f67c94d0
CB
272 ret = -1;
273 for ((key = strtok_r(tmp, "]", &saveptr)), i = 0; key && i < 6;
274 (key = strtok_r(NULL, "]", &saveptr)), i++) {
3ee26d19 275 ret = get_seccomp_arg_value(key, &rules->args_value[i]);
f67c94d0 276 if (ret < 0)
54a051c1 277 goto on_error;
f67c94d0 278
3ee26d19
L
279 rules->args_num++;
280 }
281
282 ret = 0;
f67c94d0 283
54a051c1 284on_error:
3ee26d19 285 free(tmp);
f67c94d0 286
3ee26d19
L
287 return ret;
288}
2b0ae718 289#endif
50798138 290
d58c6ad0
SH
291#if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
292enum lxc_hostarch_t {
293 lxc_seccomp_arch_all = 0,
294 lxc_seccomp_arch_native,
295 lxc_seccomp_arch_i386,
11de80d6 296 lxc_seccomp_arch_x32,
d58c6ad0
SH
297 lxc_seccomp_arch_amd64,
298 lxc_seccomp_arch_arm,
9d291dd2 299 lxc_seccomp_arch_arm64,
b4067426
BP
300 lxc_seccomp_arch_ppc64,
301 lxc_seccomp_arch_ppc64le,
302 lxc_seccomp_arch_ppc,
2ccd9eda
JC
303 lxc_seccomp_arch_mips,
304 lxc_seccomp_arch_mips64,
305 lxc_seccomp_arch_mips64n32,
306 lxc_seccomp_arch_mipsel,
307 lxc_seccomp_arch_mipsel64,
308 lxc_seccomp_arch_mipsel64n32,
be038e49 309 lxc_seccomp_arch_s390x,
d58c6ad0
SH
310 lxc_seccomp_arch_unknown = 999,
311};
312
313int get_hostarch(void)
314{
315 struct utsname uts;
316 if (uname(&uts) < 0) {
3ee26d19 317 SYSERROR("Failed to read host arch");
d58c6ad0
SH
318 return -1;
319 }
0197fe2e 320
d58c6ad0
SH
321 if (strcmp(uts.machine, "i686") == 0)
322 return lxc_seccomp_arch_i386;
1a0e70ac 323 /* no x32 kernels */
d58c6ad0
SH
324 else if (strcmp(uts.machine, "x86_64") == 0)
325 return lxc_seccomp_arch_amd64;
326 else if (strncmp(uts.machine, "armv7", 5) == 0)
327 return lxc_seccomp_arch_arm;
9d291dd2
BP
328 else if (strncmp(uts.machine, "aarch64", 7) == 0)
329 return lxc_seccomp_arch_arm64;
b4067426
BP
330 else if (strncmp(uts.machine, "ppc64le", 7) == 0)
331 return lxc_seccomp_arch_ppc64le;
332 else if (strncmp(uts.machine, "ppc64", 5) == 0)
333 return lxc_seccomp_arch_ppc64;
334 else if (strncmp(uts.machine, "ppc", 3) == 0)
335 return lxc_seccomp_arch_ppc;
2ccd9eda
JC
336 else if (strncmp(uts.machine, "mips64", 6) == 0)
337 return MIPS_ARCH_N64;
338 else if (strncmp(uts.machine, "mips", 4) == 0)
339 return MIPS_ARCH_O32;
be038e49
CB
340 else if (strncmp(uts.machine, "s390x", 5) == 0)
341 return lxc_seccomp_arch_s390x;
0197fe2e 342
d58c6ad0
SH
343 return lxc_seccomp_arch_unknown;
344}
345
04263914
CB
346scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch,
347 uint32_t default_policy_action, bool *needs_merge)
d58c6ad0 348{
d58c6ad0
SH
349 int ret;
350 uint32_t arch;
04263914 351 scmp_filter_ctx ctx;
d58c6ad0 352
04263914
CB
353 switch (n_arch) {
354 case lxc_seccomp_arch_i386:
355 arch = SCMP_ARCH_X86;
356 break;
357 case lxc_seccomp_arch_x32:
358 arch = SCMP_ARCH_X32;
359 break;
360 case lxc_seccomp_arch_amd64:
361 arch = SCMP_ARCH_X86_64;
362 break;
363 case lxc_seccomp_arch_arm:
364 arch = SCMP_ARCH_ARM;
365 break;
9d291dd2 366#ifdef SCMP_ARCH_AARCH64
04263914
CB
367 case lxc_seccomp_arch_arm64:
368 arch = SCMP_ARCH_AARCH64;
369 break;
9d291dd2 370#endif
b4067426 371#ifdef SCMP_ARCH_PPC64LE
04263914
CB
372 case lxc_seccomp_arch_ppc64le:
373 arch = SCMP_ARCH_PPC64LE;
374 break;
b4067426
BP
375#endif
376#ifdef SCMP_ARCH_PPC64
04263914
CB
377 case lxc_seccomp_arch_ppc64:
378 arch = SCMP_ARCH_PPC64;
379 break;
b4067426
BP
380#endif
381#ifdef SCMP_ARCH_PPC
04263914
CB
382 case lxc_seccomp_arch_ppc:
383 arch = SCMP_ARCH_PPC;
384 break;
2ccd9eda
JC
385#endif
386#ifdef SCMP_ARCH_MIPS
04263914
CB
387 case lxc_seccomp_arch_mips:
388 arch = SCMP_ARCH_MIPS;
389 break;
390 case lxc_seccomp_arch_mips64:
391 arch = SCMP_ARCH_MIPS64;
392 break;
393 case lxc_seccomp_arch_mips64n32:
394 arch = SCMP_ARCH_MIPS64N32;
395 break;
396 case lxc_seccomp_arch_mipsel:
397 arch = SCMP_ARCH_MIPSEL;
398 break;
399 case lxc_seccomp_arch_mipsel64:
400 arch = SCMP_ARCH_MIPSEL64;
401 break;
402 case lxc_seccomp_arch_mipsel64n32:
403 arch = SCMP_ARCH_MIPSEL64N32;
404 break;
be038e49
CB
405#endif
406#ifdef SCMP_ARCH_S390X
04263914
CB
407 case lxc_seccomp_arch_s390x:
408 arch = SCMP_ARCH_S390X;
409 break;
b4067426 410#endif
04263914
CB
411 default:
412 return NULL;
d58c6ad0
SH
413 }
414
04263914
CB
415 ctx = seccomp_init(default_policy_action);
416 if (!ctx) {
3ee26d19 417 ERROR("Error initializing seccomp context");
d58c6ad0
SH
418 return NULL;
419 }
04263914
CB
420
421 ret = seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0);
422 if (ret < 0) {
6d1400b5 423 errno = -ret;
424 SYSERROR("Failed to turn off no-new-privs");
d58c6ad0
SH
425 seccomp_release(ctx);
426 return NULL;
427 }
04263914 428
127c5293 429#ifdef SCMP_FLTATR_ATL_TSKIP
04263914 430 ret = seccomp_attr_set(ctx, SCMP_FLTATR_ATL_TSKIP, 1);
a24c5678 431 if (ret < 0) {
432 errno = -ret;
433 SYSWARN("Failed to turn on seccomp nop-skip, continuing");
434 }
127c5293 435#endif
b5ed021b 436
adfee3a8
CB
437 ret = seccomp_arch_exist(ctx, arch);
438 if (ret < 0) {
439 if (ret != -EEXIST) {
6d1400b5 440 errno = -ret;
441 SYSERROR("Failed to determine whether arch %d is "
442 "already present in the main seccomp context",
443 (int)n_arch);
adfee3a8
CB
444 seccomp_release(ctx);
445 return NULL;
446 }
447
b5ed021b
CB
448 ret = seccomp_arch_add(ctx, arch);
449 if (ret != 0) {
6d1400b5 450 errno = -ret;
451 SYSERROR("Failed to add arch %d to main seccomp context",
452 (int)n_arch);
b5ed021b
CB
453 seccomp_release(ctx);
454 return NULL;
455 }
adfee3a8 456 TRACE("Added arch %d to main seccomp context", (int)n_arch);
b5ed021b 457
adfee3a8
CB
458 ret = seccomp_arch_remove(ctx, SCMP_ARCH_NATIVE);
459 if (ret != 0) {
460 ERROR("Failed to remove native arch from main seccomp context");
b5ed021b
CB
461 seccomp_release(ctx);
462 return NULL;
463 }
adfee3a8 464 TRACE("Removed native arch from main seccomp context");
eca6736e
CB
465
466 *needs_merge = true;
adfee3a8 467 } else {
eca6736e 468 *needs_merge = false;
adfee3a8 469 TRACE("Arch %d already present in main seccomp context", (int)n_arch);
d58c6ad0
SH
470 }
471
472 return ctx;
473}
474
475bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx,
ad9a5b72 476 struct seccomp_v2_rule *rule)
d58c6ad0 477{
ad9a5b72 478 int i, nr, ret;
3ee26d19
L
479 struct scmp_arg_cmp arg_cmp[6];
480
f06c6207
CB
481 ret = seccomp_arch_exist(ctx, arch);
482 if (arch && ret != 0) {
6d1400b5 483 errno = -ret;
484 SYSERROR("Seccomp: rule and context arch do not match (arch %d)", arch);
d58c6ad0
SH
485 return false;
486 }
6166fa6d 487
3ee26d19
L
488 /*get the syscall name*/
489 char *p = strchr(line, ' ');
490 if (p)
491 *p = '\0';
492
6166fa6d 493 if (strncmp(line, "reject_force_umount", 19) == 0) {
ad9a5b72
CB
494 ret = seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EACCES),
495 SCMP_SYS(umount2), 1,
496 SCMP_A1(SCMP_CMP_MASKED_EQ, MNT_FORCE, MNT_FORCE));
6166fa6d 497 if (ret < 0) {
6d1400b5 498 errno = -ret;
499 SYSERROR("Failed loading rule to reject force umount");
6166fa6d
SH
500 return false;
501 }
ad9a5b72
CB
502
503 INFO("Set seccomp rule to reject force umounts");
6166fa6d
SH
504 return true;
505 }
506
cd75548b 507 nr = seccomp_syscall_resolve_name(line);
d58c6ad0 508 if (nr == __NR_SCMP_ERROR) {
ad9a5b72 509 WARN("Failed to resolve syscall \"%s\"", line);
8c26014b 510 WARN("This syscall will NOT be handled by seccomp");
24b9874f 511 return true;
d58c6ad0 512 }
ad9a5b72 513
d58c6ad0 514 if (nr < 0) {
ad9a5b72 515 WARN("Got negative return value %d for syscall \"%s\"", nr, line);
8c26014b 516 WARN("This syscall will NOT be handled by seccomp");
24b9874f 517 return true;
d58c6ad0 518 }
3ee26d19 519
ad9a5b72 520 memset(&arg_cmp, 0, sizeof(arg_cmp));
3ee26d19 521 for (i = 0; i < rule->args_num; i++) {
ad9a5b72
CB
522 INFO("arg_cmp[%d]: SCMP_CMP(%u, %llu, %llu, %llu)", i,
523 rule->args_value[i].index,
524 (long long unsigned int)rule->args_value[i].op,
525 (long long unsigned int)rule->args_value[i].mask,
526 (long long unsigned int)rule->args_value[i].value);
3ee26d19
L
527
528 if (SCMP_CMP_MASKED_EQ == rule->args_value[i].op)
ad9a5b72
CB
529 arg_cmp[i] = SCMP_CMP(rule->args_value[i].index,
530 rule->args_value[i].op,
531 rule->args_value[i].mask,
532 rule->args_value[i].value);
3ee26d19 533 else
ad9a5b72
CB
534 arg_cmp[i] = SCMP_CMP(rule->args_value[i].index,
535 rule->args_value[i].op,
536 rule->args_value[i].value);
3ee26d19
L
537 }
538
ad9a5b72
CB
539 ret = seccomp_rule_add_exact_array(ctx, rule->action, nr,
540 rule->args_num, arg_cmp);
d58c6ad0 541 if (ret < 0) {
6d1400b5 542 errno = -ret;
543 SYSERROR("Failed loading rule for %s (nr %d action %d (%s))",
544 line, nr, rule->action, get_action_name(rule->action));
d58c6ad0
SH
545 return false;
546 }
ad9a5b72 547
d58c6ad0
SH
548 return true;
549}
550
50798138
SH
551/*
552 * v2 consists of
553 * [x86]
554 * open
555 * read
556 * write
557 * close
558 * # a comment
559 * [x86_64]
560 * open
561 * read
562 * write
563 * close
564 */
9dbd8ff3 565static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_conf *conf)
50798138 566{
50798138 567 int ret;
9c3798eb
CB
568 char *p;
569 enum lxc_hostarch_t cur_rule_arch, native_arch;
50798138 570 bool blacklist = false;
3ee26d19 571 uint32_t default_policy_action = -1, default_rule_action = -1;
3ee26d19 572 struct seccomp_v2_rule rule;
eca6736e
CB
573 struct scmp_ctx_info {
574 uint32_t architectures[3];
575 scmp_filter_ctx contexts[3];
576 bool needs_merge[3];
577 } ctx;
50798138
SH
578
579 if (strncmp(line, "blacklist", 9) == 0)
580 blacklist = true;
581 else if (strncmp(line, "whitelist", 9) != 0) {
9c3798eb 582 ERROR("Bad seccomp policy style \"%s\"", line);
50798138
SH
583 return -1;
584 }
585
9c3798eb
CB
586 p = strchr(line, ' ');
587 if (p) {
f06c6207 588 default_policy_action = get_v2_default_action(p + 1);
50798138
SH
589 if (default_policy_action == -2)
590 return -1;
591 }
592
593 /* for blacklist, allow any syscall which has no rule */
594 if (blacklist) {
595 if (default_policy_action == -1)
596 default_policy_action = SCMP_ACT_ALLOW;
9c3798eb 597
50798138
SH
598 if (default_rule_action == -1)
599 default_rule_action = SCMP_ACT_KILL;
600 } else {
601 if (default_policy_action == -1)
602 default_policy_action = SCMP_ACT_KILL;
9c3798eb 603
50798138
SH
604 if (default_rule_action == -1)
605 default_rule_action = SCMP_ACT_ALLOW;
606 }
607
eca6736e
CB
608 memset(&ctx, 0, sizeof(ctx));
609 ctx.architectures[0] = SCMP_ARCH_NATIVE;
610 ctx.architectures[1] = SCMP_ARCH_NATIVE;
611 ctx.architectures[2] = SCMP_ARCH_NATIVE;
9c3798eb
CB
612 native_arch = get_hostarch();
613 cur_rule_arch = native_arch;
d58c6ad0
SH
614 if (native_arch == lxc_seccomp_arch_amd64) {
615 cur_rule_arch = lxc_seccomp_arch_all;
eca6736e
CB
616
617 ctx.architectures[0] = SCMP_ARCH_X86;
618 ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_i386,
619 default_policy_action,
620 &ctx.needs_merge[0]);
621 if (!ctx.contexts[0])
622 goto bad;
623
624 ctx.architectures[1] = SCMP_ARCH_X32;
625 ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_x32,
626 default_policy_action,
627 &ctx.needs_merge[1]);
628 if (!ctx.contexts[1])
629 goto bad;
630
631 ctx.architectures[2] = SCMP_ARCH_X86_64;
632 ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_amd64,
633 default_policy_action,
634 &ctx.needs_merge[2]);
635 if (!ctx.contexts[2])
ab5e52f6 636 goto bad;
ca399594 637#ifdef SCMP_ARCH_PPC
7635139a
SH
638 } else if (native_arch == lxc_seccomp_arch_ppc64) {
639 cur_rule_arch = lxc_seccomp_arch_all;
eca6736e
CB
640
641 ctx.architectures[0] = SCMP_ARCH_PPC;
642 ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_ppc,
643 default_policy_action,
644 &ctx.needs_merge[0]);
645 if (!ctx.contexts[0])
646 goto bad;
647
648 ctx.architectures[2] = SCMP_ARCH_PPC64;
649 ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_ppc64,
650 default_policy_action,
651 &ctx.needs_merge[2]);
652 if (!ctx.contexts[2])
7635139a 653 goto bad;
ca399594
CB
654#endif
655#ifdef SCMP_ARCH_ARM
7635139a
SH
656 } else if (native_arch == lxc_seccomp_arch_arm64) {
657 cur_rule_arch = lxc_seccomp_arch_all;
eca6736e
CB
658
659 ctx.architectures[0] = SCMP_ARCH_ARM;
9c3798eb
CB
660 ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_arm,
661 default_policy_action,
662 &ctx.needs_merge[0]);
eca6736e
CB
663 if (!ctx.contexts[0])
664 goto bad;
665
b1c428f9 666#ifdef SCMP_ARCH_AARCH64
eca6736e 667 ctx.architectures[2] = SCMP_ARCH_AARCH64;
9c3798eb
CB
668 ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_arm64,
669 default_policy_action,
670 &ctx.needs_merge[2]);
eca6736e 671 if (!ctx.contexts[2])
2ccd9eda
JC
672 goto bad;
673#endif
b1c428f9 674#endif
2ccd9eda
JC
675#ifdef SCMP_ARCH_MIPS
676 } else if (native_arch == lxc_seccomp_arch_mips64) {
677 cur_rule_arch = lxc_seccomp_arch_all;
eca6736e
CB
678
679 ctx.architectures[0] = SCMP_ARCH_MIPS;
680 ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_mips,
681 default_policy_action,
682 &ctx.needs_merge[0]);
683 if (!ctx.contexts[0])
684 goto bad;
685
686 ctx.architectures[1] = SCMP_ARCH_MIPS64N32;
687 ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_mips64n32,
688 default_policy_action,
689 &ctx.needs_merge[1]);
690 if (!ctx.contexts[1])
691 goto bad;
692
693 ctx.architectures[2] = SCMP_ARCH_MIPS64;
694 ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_mips64,
695 default_policy_action,
696 &ctx.needs_merge[2]);
697 if (!ctx.contexts[2])
2ccd9eda
JC
698 goto bad;
699 } else if (native_arch == lxc_seccomp_arch_mipsel64) {
700 cur_rule_arch = lxc_seccomp_arch_all;
eca6736e
CB
701
702 ctx.architectures[0] = SCMP_ARCH_MIPSEL;
703 ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_mipsel,
704 default_policy_action,
705 &ctx.needs_merge[0]);
706 if (!ctx.contexts[0])
707 goto bad;
708
709 ctx.architectures[1] = SCMP_ARCH_MIPSEL64N32;
710 ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_mipsel64n32,
711 default_policy_action,
712 &ctx.needs_merge[1]);
713 if (!ctx.contexts[1])
714 goto bad;
715
716 ctx.architectures[2] = SCMP_ARCH_MIPSEL64;
717 ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_mipsel64,
718 default_policy_action,
719 &ctx.needs_merge[2]);
720 if (!ctx.contexts[2])
7635139a 721 goto bad;
be038e49 722#endif
d58c6ad0
SH
723 }
724
50798138
SH
725 if (default_policy_action != SCMP_ACT_KILL) {
726 ret = seccomp_reset(conf->seccomp_ctx, default_policy_action);
727 if (ret != 0) {
3ee26d19 728 ERROR("Error re-initializing Seccomp");
50798138
SH
729 return -1;
730 }
9c3798eb
CB
731
732 ret = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0);
733 if (ret < 0) {
6d1400b5 734 errno = -ret;
735 SYSERROR("Failed to turn off no-new-privs");
50798138
SH
736 return -1;
737 }
9c3798eb 738
127c5293 739#ifdef SCMP_FLTATR_ATL_TSKIP
9c3798eb 740 ret = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1);
a24c5678 741 if (ret < 0) {
742 errno = -ret;
743 SYSWARN("Failed to turn on seccomp nop-skip, continuing");
744 }
127c5293 745#endif
50798138
SH
746 }
747
9dbd8ff3 748 while (getline(&line, line_bufsz, f) != -1) {
50798138
SH
749 if (line[0] == '#')
750 continue;
9c3798eb
CB
751
752 if (line[0] == '\0')
50798138 753 continue;
9c3798eb 754
50798138 755 remove_trailing_newlines(line);
9c3798eb
CB
756
757 INFO("Processing \"%s\"", line);
50798138 758 if (line[0] == '[') {
1a0e70ac 759 /* Read the architecture for next set of rules. */
50798138 760 if (strcmp(line, "[x86]") == 0 ||
f06c6207 761 strcmp(line, "[X86]") == 0) {
d58c6ad0 762 if (native_arch != lxc_seccomp_arch_i386 &&
7e84441e 763 native_arch != lxc_seccomp_arch_amd64) {
d58c6ad0
SH
764 cur_rule_arch = lxc_seccomp_arch_unknown;
765 continue;
766 }
9c3798eb 767
d58c6ad0 768 cur_rule_arch = lxc_seccomp_arch_i386;
11de80d6
AB
769 } else if (strcmp(line, "[x32]") == 0 ||
770 strcmp(line, "[X32]") == 0) {
771 if (native_arch != lxc_seccomp_arch_amd64) {
772 cur_rule_arch = lxc_seccomp_arch_unknown;
773 continue;
774 }
9c3798eb 775
11de80d6 776 cur_rule_arch = lxc_seccomp_arch_x32;
d58c6ad0 777 } else if (strcmp(line, "[X86_64]") == 0 ||
f06c6207 778 strcmp(line, "[x86_64]") == 0) {
d58c6ad0
SH
779 if (native_arch != lxc_seccomp_arch_amd64) {
780 cur_rule_arch = lxc_seccomp_arch_unknown;
781 continue;
782 }
9c3798eb 783
d58c6ad0 784 cur_rule_arch = lxc_seccomp_arch_amd64;
d58c6ad0 785 } else if (strcmp(line, "[all]") == 0 ||
f06c6207 786 strcmp(line, "[ALL]") == 0) {
d58c6ad0 787 cur_rule_arch = lxc_seccomp_arch_all;
d58c6ad0 788 }
2b0ae718 789#ifdef SCMP_ARCH_ARM
50798138 790 else if (strcmp(line, "[arm]") == 0 ||
f06c6207 791 strcmp(line, "[ARM]") == 0) {
7635139a 792 if (native_arch != lxc_seccomp_arch_arm &&
7e84441e 793 native_arch != lxc_seccomp_arch_arm64) {
d58c6ad0
SH
794 cur_rule_arch = lxc_seccomp_arch_unknown;
795 continue;
796 }
9c3798eb 797
d58c6ad0 798 cur_rule_arch = lxc_seccomp_arch_arm;
d58c6ad0 799 }
b4067426 800#endif
9d291dd2
BP
801#ifdef SCMP_ARCH_AARCH64
802 else if (strcmp(line, "[arm64]") == 0 ||
f06c6207 803 strcmp(line, "[ARM64]") == 0) {
9d291dd2
BP
804 if (native_arch != lxc_seccomp_arch_arm64) {
805 cur_rule_arch = lxc_seccomp_arch_unknown;
806 continue;
807 }
9c3798eb 808
9d291dd2
BP
809 cur_rule_arch = lxc_seccomp_arch_arm64;
810 }
811#endif
b4067426
BP
812#ifdef SCMP_ARCH_PPC64LE
813 else if (strcmp(line, "[ppc64le]") == 0 ||
f06c6207 814 strcmp(line, "[PPC64LE]") == 0) {
b4067426
BP
815 if (native_arch != lxc_seccomp_arch_ppc64le) {
816 cur_rule_arch = lxc_seccomp_arch_unknown;
817 continue;
818 }
9c3798eb 819
b4067426
BP
820 cur_rule_arch = lxc_seccomp_arch_ppc64le;
821 }
822#endif
823#ifdef SCMP_ARCH_PPC64
824 else if (strcmp(line, "[ppc64]") == 0 ||
f06c6207 825 strcmp(line, "[PPC64]") == 0) {
b4067426
BP
826 if (native_arch != lxc_seccomp_arch_ppc64) {
827 cur_rule_arch = lxc_seccomp_arch_unknown;
828 continue;
829 }
9c3798eb 830
b4067426
BP
831 cur_rule_arch = lxc_seccomp_arch_ppc64;
832 }
833#endif
834#ifdef SCMP_ARCH_PPC
835 else if (strcmp(line, "[ppc]") == 0 ||
f06c6207 836 strcmp(line, "[PPC]") == 0) {
7635139a 837 if (native_arch != lxc_seccomp_arch_ppc &&
7e84441e 838 native_arch != lxc_seccomp_arch_ppc64) {
b4067426
BP
839 cur_rule_arch = lxc_seccomp_arch_unknown;
840 continue;
841 }
9c3798eb 842
b4067426
BP
843 cur_rule_arch = lxc_seccomp_arch_ppc;
844 }
2ccd9eda
JC
845#endif
846#ifdef SCMP_ARCH_MIPS
847 else if (strcmp(line, "[mips64]") == 0 ||
f06c6207 848 strcmp(line, "[MIPS64]") == 0) {
2ccd9eda
JC
849 if (native_arch != lxc_seccomp_arch_mips64) {
850 cur_rule_arch = lxc_seccomp_arch_unknown;
851 continue;
852 }
9c3798eb 853
2ccd9eda
JC
854 cur_rule_arch = lxc_seccomp_arch_mips64;
855 } else if (strcmp(line, "[mips64n32]") == 0 ||
f06c6207 856 strcmp(line, "[MIPS64N32]") == 0) {
2ccd9eda
JC
857 if (native_arch != lxc_seccomp_arch_mips64) {
858 cur_rule_arch = lxc_seccomp_arch_unknown;
859 continue;
860 }
9c3798eb 861
2ccd9eda
JC
862 cur_rule_arch = lxc_seccomp_arch_mips64n32;
863 } else if (strcmp(line, "[mips]") == 0 ||
f06c6207 864 strcmp(line, "[MIPS]") == 0) {
2ccd9eda 865 if (native_arch != lxc_seccomp_arch_mips &&
7e84441e 866 native_arch != lxc_seccomp_arch_mips64) {
2ccd9eda
JC
867 cur_rule_arch = lxc_seccomp_arch_unknown;
868 continue;
869 }
9c3798eb 870
2ccd9eda
JC
871 cur_rule_arch = lxc_seccomp_arch_mips;
872 } else if (strcmp(line, "[mipsel64]") == 0 ||
f06c6207 873 strcmp(line, "[MIPSEL64]") == 0) {
2ccd9eda
JC
874 if (native_arch != lxc_seccomp_arch_mipsel64) {
875 cur_rule_arch = lxc_seccomp_arch_unknown;
876 continue;
877 }
9c3798eb 878
2ccd9eda
JC
879 cur_rule_arch = lxc_seccomp_arch_mipsel64;
880 } else if (strcmp(line, "[mipsel64n32]") == 0 ||
f06c6207 881 strcmp(line, "[MIPSEL64N32]") == 0) {
2ccd9eda
JC
882 if (native_arch != lxc_seccomp_arch_mipsel64) {
883 cur_rule_arch = lxc_seccomp_arch_unknown;
884 continue;
885 }
9c3798eb 886
2ccd9eda
JC
887 cur_rule_arch = lxc_seccomp_arch_mipsel64n32;
888 } else if (strcmp(line, "[mipsel]") == 0 ||
f06c6207 889 strcmp(line, "[MIPSEL]") == 0) {
2ccd9eda 890 if (native_arch != lxc_seccomp_arch_mipsel &&
7e84441e 891 native_arch != lxc_seccomp_arch_mipsel64) {
2ccd9eda
JC
892 cur_rule_arch = lxc_seccomp_arch_unknown;
893 continue;
894 }
9c3798eb 895
2ccd9eda
JC
896 cur_rule_arch = lxc_seccomp_arch_mipsel;
897 }
be038e49
CB
898#endif
899#ifdef SCMP_ARCH_S390X
900 else if (strcmp(line, "[s390x]") == 0 ||
f06c6207 901 strcmp(line, "[S390X]") == 0) {
be038e49
CB
902 if (native_arch != lxc_seccomp_arch_s390x) {
903 cur_rule_arch = lxc_seccomp_arch_unknown;
904 continue;
905 }
9c3798eb 906
be038e49 907 cur_rule_arch = lxc_seccomp_arch_s390x;
2b0ae718 908#endif
9c3798eb 909 } else {
50798138 910 goto bad_arch;
9c3798eb 911 }
d58c6ad0 912
50798138
SH
913 continue;
914 }
915
d58c6ad0
SH
916 /* irrelevant arch - i.e. arm on i386 */
917 if (cur_rule_arch == lxc_seccomp_arch_unknown)
918 continue;
919
3ee26d19 920 memset(&rule, 0, sizeof(rule));
d58c6ad0 921 /* read optional action which follows the syscall */
3ee26d19
L
922 ret = parse_v2_rules(line, default_rule_action, &rule);
923 if (ret != 0) {
924 ERROR("Failed to interpret seccomp rule");
50798138
SH
925 goto bad_rule;
926 }
d58c6ad0 927
eca6736e
CB
928 if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line,
929 conf->seccomp_ctx, &rule))
930 goto bad_rule;
9c3798eb 931
eca6736e
CB
932 INFO("Added native rule for arch %d for %s action %d(%s)",
933 SCMP_ARCH_NATIVE, line, rule.action,
934 get_action_name(rule.action));
935
936 if (ctx.architectures[0] != SCMP_ARCH_NATIVE) {
937 if (!do_resolve_add_rule(ctx.architectures[0], line,
938 ctx.contexts[0], &rule))
d58c6ad0 939 goto bad_rule;
9c3798eb 940
eca6736e
CB
941 INFO("Added compat rule for arch %d for %s action %d(%s)",
942 ctx.architectures[0], line, rule.action,
3ee26d19 943 get_action_name(rule.action));
eca6736e 944 }
94d56054 945
eca6736e
CB
946 if (ctx.architectures[1] != SCMP_ARCH_NATIVE) {
947 if (!do_resolve_add_rule(ctx.architectures[1], line,
948 ctx.contexts[1], &rule))
d6417887 949 goto bad_rule;
9c3798eb 950
eca6736e
CB
951 INFO("Added compat rule for arch %d for %s action %d(%s)",
952 ctx.architectures[1], line, rule.action,
3ee26d19 953 get_action_name(rule.action));
eca6736e
CB
954 }
955
956 if (ctx.architectures[2] != SCMP_ARCH_NATIVE) {
957 if (!do_resolve_add_rule(ctx.architectures[2], line,
958 ctx.contexts[2], &rule))
d6417887 959 goto bad_rule;
9c3798eb 960
94d56054 961 INFO("Added native rule for arch %d for %s action %d(%s)",
eca6736e 962 ctx.architectures[2], line, rule.action,
3ee26d19 963 get_action_name(rule.action));
50798138
SH
964 }
965 }
d58c6ad0 966
d648e178 967 INFO("Merging compat seccomp contexts into main context");
eca6736e
CB
968 if (ctx.contexts[0]) {
969 if (ctx.needs_merge[0]) {
970 ret = seccomp_merge(conf->seccomp_ctx, ctx.contexts[0]);
b5ed021b 971 if (ret < 0) {
d648e178
CB
972 ERROR("Failed to merge first compat seccomp "
973 "context into main context");
b5ed021b
CB
974 goto bad;
975 }
9c3798eb 976
b5ed021b 977 TRACE("Merged first compat seccomp context into main context");
d648e178 978 } else {
eca6736e
CB
979 seccomp_release(ctx.contexts[0]);
980 ctx.contexts[0] = NULL;
b5ed021b 981 }
d648e178 982 }
b5ed021b 983
eca6736e
CB
984 if (ctx.contexts[1]) {
985 if (ctx.needs_merge[1]) {
986 ret = seccomp_merge(conf->seccomp_ctx, ctx.contexts[1]);
b5ed021b 987 if (ret < 0) {
d648e178
CB
988 ERROR("Failed to merge first compat seccomp "
989 "context into main context");
b5ed021b
CB
990 goto bad;
991 }
9c3798eb 992
b5ed021b 993 TRACE("Merged second compat seccomp context into main context");
d648e178 994 } else {
eca6736e
CB
995 seccomp_release(ctx.contexts[1]);
996 ctx.contexts[1] = NULL;
997 }
998 }
999
1000 if (ctx.contexts[2]) {
1001 if (ctx.needs_merge[2]) {
1002 ret = seccomp_merge(conf->seccomp_ctx, ctx.contexts[2]);
1003 if (ret < 0) {
1004 ERROR("Failed to merge third compat seccomp "
1005 "context into main context");
1006 goto bad;
1007 }
9c3798eb 1008
eca6736e
CB
1009 TRACE("Merged third compat seccomp context into main context");
1010 } else {
1011 seccomp_release(ctx.contexts[2]);
1012 ctx.contexts[2] = NULL;
50798138
SH
1013 }
1014 }
6166fa6d 1015
9dbd8ff3 1016 free(line);
50798138
SH
1017 return 0;
1018
1019bad_arch:
9c3798eb
CB
1020 ERROR("Unsupported architecture \"%s\"", line);
1021
50798138 1022bad_rule:
d58c6ad0 1023bad:
eca6736e
CB
1024 if (ctx.contexts[0])
1025 seccomp_release(ctx.contexts[0]);
9c3798eb 1026
eca6736e
CB
1027 if (ctx.contexts[1])
1028 seccomp_release(ctx.contexts[1]);
9c3798eb 1029
eca6736e
CB
1030 if (ctx.contexts[2])
1031 seccomp_release(ctx.contexts[2]);
1032
9dbd8ff3 1033 free(line);
9c3798eb 1034
50798138 1035 return -1;
d58c6ad0
SH
1036}
1037#else /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
1038static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
1039{
50798138 1040 return -1;
50798138 1041}
d58c6ad0 1042#endif /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
50798138 1043
8f2c3a70
SH
1044/*
1045 * The first line of the config file has a policy language version
1046 * the second line has some directives
1047 * then comes policy subject to the directives
998cd2f4 1048 * right now version must be '1' or '2'
1049 * the directives must include 'whitelist'(version == 1 or 2) or 'blacklist'
1050 * (version == 2) and can include 'debug' (though debug is not yet supported).
8f2c3a70
SH
1051 */
1052static int parse_config(FILE *f, struct lxc_conf *conf)
1053{
9dbd8ff3
WB
1054 char *line = NULL;
1055 size_t line_bufsz = 0;
8f2c3a70
SH
1056 int ret, version;
1057
1058 ret = fscanf(f, "%d\n", &version);
50798138 1059 if (ret != 1 || (version != 1 && version != 2)) {
3ee26d19 1060 ERROR("Invalid version");
8f2c3a70
SH
1061 return -1;
1062 }
6ca8172d 1063
9dbd8ff3 1064 if (getline(&line, &line_bufsz, f) == -1) {
3ee26d19 1065 ERROR("Invalid config file");
9dbd8ff3 1066 goto bad_line;
8f2c3a70 1067 }
6ca8172d 1068
50798138 1069 if (version == 1 && !strstr(line, "whitelist")) {
3ee26d19 1070 ERROR("Only whitelist policy is supported");
9dbd8ff3 1071 goto bad_line;
8f2c3a70 1072 }
50798138 1073
8f2c3a70 1074 if (strstr(line, "debug")) {
3ee26d19 1075 ERROR("Debug not yet implemented");
9dbd8ff3 1076 goto bad_line;
8f2c3a70 1077 }
50798138
SH
1078
1079 if (version == 1)
9dbd8ff3 1080 return parse_config_v1(f, line, &line_bufsz, conf);
6ca8172d 1081
9dbd8ff3
WB
1082 return parse_config_v2(f, line, &line_bufsz, conf);
1083
1084bad_line:
1085 free(line);
1086 return -1;
8f2c3a70
SH
1087}
1088
cd75548b
SH
1089/*
1090 * use_seccomp: return true if we should try and apply a seccomp policy
1091 * if defined for the container.
1092 * This will return false if
1093 * 1. seccomp is not enabled in the kernel
1094 * 2. a seccomp policy is already enabled for this task
1095 */
1096static bool use_seccomp(void)
d58c6ad0 1097{
d58c6ad0 1098 int ret, v;
6ca8172d
CB
1099 FILE *f;
1100 size_t line_bufsz = 0;
1101 char *line = NULL;
1102 bool already_enabled = false, found = false;
d58c6ad0 1103
6ca8172d 1104 f = fopen("/proc/self/status", "r");
d58c6ad0 1105 if (!f)
cd75548b 1106 return true;
d58c6ad0 1107
6ca8172d 1108 while (getline(&line, &line_bufsz, f) != -1) {
d58c6ad0 1109 if (strncmp(line, "Seccomp:", 8) == 0) {
cd75548b 1110 found = true;
6ca8172d 1111
f06c6207 1112 ret = sscanf(line + 8, "%d", &v);
cd75548b
SH
1113 if (ret == 1 && v != 0)
1114 already_enabled = true;
6ca8172d 1115
cd75548b 1116 break;
d58c6ad0
SH
1117 }
1118 }
6ca8172d 1119 free(line);
d58c6ad0 1120 fclose(f);
6ca8172d
CB
1121
1122 if (!found) {
3ee26d19 1123 INFO("Seccomp is not enabled in the kernel");
cd75548b
SH
1124 return false;
1125 }
6ca8172d
CB
1126
1127 if (already_enabled) {
3ee26d19 1128 INFO("Already seccomp-confined, not loading new policy");
cd75548b
SH
1129 return false;
1130 }
6ca8172d 1131
cd75548b 1132 return true;
d58c6ad0
SH
1133}
1134
8f2c3a70
SH
1135int lxc_read_seccomp_config(struct lxc_conf *conf)
1136{
cf6624c1 1137 int ret;
8f2c3a70 1138 FILE *f;
8f2c3a70 1139
769872f9
SH
1140 if (!conf->seccomp)
1141 return 0;
1142
cd75548b 1143 if (!use_seccomp())
d58c6ad0 1144 return 0;
47f6d547 1145
769872f9
SH
1146#if HAVE_SCMP_FILTER_CTX
1147 /* XXX for debug, pass in SCMP_ACT_TRAP */
50798138 1148 conf->seccomp_ctx = seccomp_init(SCMP_ACT_KILL);
769872f9
SH
1149 ret = !conf->seccomp_ctx;
1150#else
50798138 1151 ret = seccomp_init(SCMP_ACT_KILL) < 0;
769872f9
SH
1152#endif
1153 if (ret) {
3ee26d19 1154 ERROR("Failed initializing seccomp");
8f2c3a70
SH
1155 return -1;
1156 }
8f2c3a70 1157
47f6d547 1158/* turn off no-new-privs. We don't want it in lxc, and it breaks
f06c6207 1159 * with apparmor */
769872f9 1160#if HAVE_SCMP_FILTER_CTX
cf6624c1 1161 ret = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0);
727c3073 1162#else
cf6624c1 1163 ret = seccomp_attr_set(SCMP_FLTATR_CTL_NNP, 0);
769872f9 1164#endif
cf6624c1 1165 if (ret < 0) {
6d1400b5 1166 errno = -ret;
1167 SYSERROR("Failed to turn off no-new-privs");
8f2c3a70
SH
1168 return -1;
1169 }
a24c5678 1170
127c5293 1171#ifdef SCMP_FLTATR_ATL_TSKIP
cf6624c1 1172 ret = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1);
a24c5678 1173 if (ret < 0) {
1174 errno = -ret;
1175 SYSWARN("Failed to turn on seccomp nop-skip, continuing");
1176 }
127c5293 1177#endif
8f2c3a70
SH
1178
1179 f = fopen(conf->seccomp, "r");
1180 if (!f) {
3ee26d19 1181 SYSERROR("Failed to open seccomp policy file %s", conf->seccomp);
8f2c3a70
SH
1182 return -1;
1183 }
47f6d547 1184
8f2c3a70
SH
1185 ret = parse_config(f, conf);
1186 fclose(f);
47f6d547 1187
8f2c3a70
SH
1188 return ret;
1189}
1190
1191int lxc_seccomp_load(struct lxc_conf *conf)
1192{
1193 int ret;
47f6d547 1194
8f2c3a70
SH
1195 if (!conf->seccomp)
1196 return 0;
47f6d547 1197
cd75548b 1198 if (!use_seccomp())
d58c6ad0 1199 return 0;
47f6d547 1200
769872f9 1201#if HAVE_SCMP_FILTER_CTX
47f6d547
CB
1202 ret = seccomp_load(conf->seccomp_ctx);
1203#else
1204 ret = seccomp_load();
769872f9 1205#endif
8f2c3a70 1206 if (ret < 0) {
6d1400b5 1207 errno = -ret;
1208 SYSERROR("Error loading the seccomp policy");
8f2c3a70
SH
1209 return -1;
1210 }
5107af32 1211
1212/* After load seccomp filter into the kernel successfully, export the current seccomp
1213 * filter to log file */
1214#if HAVE_SCMP_FILTER_CTX
47f6d547
CB
1215 if ((lxc_log_get_level() <= LXC_LOG_LEVEL_TRACE ||
1216 conf->loglevel <= LXC_LOG_LEVEL_TRACE) &&
5107af32 1217 lxc_log_fd >= 0) {
1218 ret = seccomp_export_pfc(conf->seccomp_ctx, lxc_log_fd);
1219 /* Just give an warning when export error */
a24c5678 1220 if (ret < 0) {
1221 errno = -ret;
1222 SYSWARN("Failed to export seccomp filter to log file");
1223 }
5107af32 1224 }
1225#endif
47f6d547 1226
8f2c3a70
SH
1227 return 0;
1228}
769872f9 1229
f06c6207
CB
1230void lxc_seccomp_free(struct lxc_conf *conf)
1231{
f10fad2f
ME
1232 free(conf->seccomp);
1233 conf->seccomp = NULL;
47f6d547 1234
769872f9
SH
1235#if HAVE_SCMP_FILTER_CTX
1236 if (conf->seccomp_ctx) {
1237 seccomp_release(conf->seccomp_ctx);
1238 conf->seccomp_ctx = NULL;
1239 }
1240#endif
1241}