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