]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/seccomp.c
Merge pull request #2377 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) {
423 ERROR("%s - Failed to turn off no-new-privs", strerror(-ret));
d58c6ad0
SH
424 seccomp_release(ctx);
425 return NULL;
426 }
04263914 427
127c5293 428#ifdef SCMP_FLTATR_ATL_TSKIP
04263914
CB
429 ret = seccomp_attr_set(ctx, SCMP_FLTATR_ATL_TSKIP, 1);
430 if (ret < 0)
431 WARN("%s - Failed to turn on seccomp nop-skip, continuing", strerror(-ret));
127c5293 432#endif
b5ed021b 433
adfee3a8
CB
434 ret = seccomp_arch_exist(ctx, arch);
435 if (ret < 0) {
436 if (ret != -EEXIST) {
437 ERROR("%s - Failed to determine whether arch %d is "
438 "already present in the main seccomp context",
04263914 439 strerror(-ret), (int)n_arch);
adfee3a8
CB
440 seccomp_release(ctx);
441 return NULL;
442 }
443
b5ed021b
CB
444 ret = seccomp_arch_add(ctx, arch);
445 if (ret != 0) {
adfee3a8
CB
446 ERROR("%s - Failed to add arch %d to main seccomp context",
447 strerror(-ret), (int)n_arch);
b5ed021b
CB
448 seccomp_release(ctx);
449 return NULL;
450 }
adfee3a8 451 TRACE("Added arch %d to main seccomp context", (int)n_arch);
b5ed021b 452
adfee3a8
CB
453 ret = seccomp_arch_remove(ctx, SCMP_ARCH_NATIVE);
454 if (ret != 0) {
455 ERROR("Failed to remove native arch from main seccomp context");
b5ed021b
CB
456 seccomp_release(ctx);
457 return NULL;
458 }
adfee3a8 459 TRACE("Removed native arch from main seccomp context");
eca6736e
CB
460
461 *needs_merge = true;
adfee3a8 462 } else {
eca6736e 463 *needs_merge = false;
adfee3a8 464 TRACE("Arch %d already present in main seccomp context", (int)n_arch);
d58c6ad0
SH
465 }
466
467 return ctx;
468}
469
470bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx,
ad9a5b72 471 struct seccomp_v2_rule *rule)
d58c6ad0 472{
ad9a5b72 473 int i, nr, ret;
3ee26d19
L
474 struct scmp_arg_cmp arg_cmp[6];
475
f06c6207
CB
476 ret = seccomp_arch_exist(ctx, arch);
477 if (arch && ret != 0) {
ad9a5b72 478 ERROR("%s - Seccomp: rule and context arch do not match (arch %d)", strerror(-ret), arch);
d58c6ad0
SH
479 return false;
480 }
6166fa6d 481
3ee26d19
L
482 /*get the syscall name*/
483 char *p = strchr(line, ' ');
484 if (p)
485 *p = '\0';
486
6166fa6d 487 if (strncmp(line, "reject_force_umount", 19) == 0) {
ad9a5b72
CB
488 ret = seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EACCES),
489 SCMP_SYS(umount2), 1,
490 SCMP_A1(SCMP_CMP_MASKED_EQ, MNT_FORCE, MNT_FORCE));
6166fa6d 491 if (ret < 0) {
ad9a5b72 492 ERROR("%s - Failed loading rule to reject force umount", strerror(-ret));
6166fa6d
SH
493 return false;
494 }
ad9a5b72
CB
495
496 INFO("Set seccomp rule to reject force umounts");
6166fa6d
SH
497 return true;
498 }
499
cd75548b 500 nr = seccomp_syscall_resolve_name(line);
d58c6ad0 501 if (nr == __NR_SCMP_ERROR) {
ad9a5b72 502 WARN("Failed to resolve syscall \"%s\"", line);
dfddc8aa 503 return false;
d58c6ad0 504 }
ad9a5b72 505
d58c6ad0 506 if (nr < 0) {
ad9a5b72 507 WARN("Got negative return value %d for syscall \"%s\"", nr, line);
dfddc8aa 508 return false;
d58c6ad0 509 }
3ee26d19 510
ad9a5b72 511 memset(&arg_cmp, 0, sizeof(arg_cmp));
3ee26d19 512 for (i = 0; i < rule->args_num; i++) {
ad9a5b72
CB
513 INFO("arg_cmp[%d]: SCMP_CMP(%u, %llu, %llu, %llu)", i,
514 rule->args_value[i].index,
515 (long long unsigned int)rule->args_value[i].op,
516 (long long unsigned int)rule->args_value[i].mask,
517 (long long unsigned int)rule->args_value[i].value);
3ee26d19
L
518
519 if (SCMP_CMP_MASKED_EQ == rule->args_value[i].op)
ad9a5b72
CB
520 arg_cmp[i] = SCMP_CMP(rule->args_value[i].index,
521 rule->args_value[i].op,
522 rule->args_value[i].mask,
523 rule->args_value[i].value);
3ee26d19 524 else
ad9a5b72
CB
525 arg_cmp[i] = SCMP_CMP(rule->args_value[i].index,
526 rule->args_value[i].op,
527 rule->args_value[i].value);
3ee26d19
L
528 }
529
ad9a5b72
CB
530 ret = seccomp_rule_add_exact_array(ctx, rule->action, nr,
531 rule->args_num, arg_cmp);
d58c6ad0 532 if (ret < 0) {
ad9a5b72
CB
533 ERROR("%s - Failed loading rule for %s (nr %d action %d (%s))",
534 strerror(-ret), line, nr, rule->action,
535 get_action_name(rule->action));
d58c6ad0
SH
536 return false;
537 }
ad9a5b72 538
d58c6ad0
SH
539 return true;
540}
541
50798138
SH
542/*
543 * v2 consists of
544 * [x86]
545 * open
546 * read
547 * write
548 * close
549 * # a comment
550 * [x86_64]
551 * open
552 * read
553 * write
554 * close
555 */
9dbd8ff3 556static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_conf *conf)
50798138 557{
50798138 558 int ret;
9c3798eb
CB
559 char *p;
560 enum lxc_hostarch_t cur_rule_arch, native_arch;
50798138 561 bool blacklist = false;
3ee26d19 562 uint32_t default_policy_action = -1, default_rule_action = -1;
3ee26d19 563 struct seccomp_v2_rule rule;
eca6736e
CB
564 struct scmp_ctx_info {
565 uint32_t architectures[3];
566 scmp_filter_ctx contexts[3];
567 bool needs_merge[3];
568 } ctx;
50798138
SH
569
570 if (strncmp(line, "blacklist", 9) == 0)
571 blacklist = true;
572 else if (strncmp(line, "whitelist", 9) != 0) {
9c3798eb 573 ERROR("Bad seccomp policy style \"%s\"", line);
50798138
SH
574 return -1;
575 }
576
9c3798eb
CB
577 p = strchr(line, ' ');
578 if (p) {
f06c6207 579 default_policy_action = get_v2_default_action(p + 1);
50798138
SH
580 if (default_policy_action == -2)
581 return -1;
582 }
583
584 /* for blacklist, allow any syscall which has no rule */
585 if (blacklist) {
586 if (default_policy_action == -1)
587 default_policy_action = SCMP_ACT_ALLOW;
9c3798eb 588
50798138
SH
589 if (default_rule_action == -1)
590 default_rule_action = SCMP_ACT_KILL;
591 } else {
592 if (default_policy_action == -1)
593 default_policy_action = SCMP_ACT_KILL;
9c3798eb 594
50798138
SH
595 if (default_rule_action == -1)
596 default_rule_action = SCMP_ACT_ALLOW;
597 }
598
eca6736e
CB
599 memset(&ctx, 0, sizeof(ctx));
600 ctx.architectures[0] = SCMP_ARCH_NATIVE;
601 ctx.architectures[1] = SCMP_ARCH_NATIVE;
602 ctx.architectures[2] = SCMP_ARCH_NATIVE;
9c3798eb
CB
603 native_arch = get_hostarch();
604 cur_rule_arch = native_arch;
d58c6ad0
SH
605 if (native_arch == lxc_seccomp_arch_amd64) {
606 cur_rule_arch = lxc_seccomp_arch_all;
eca6736e
CB
607
608 ctx.architectures[0] = SCMP_ARCH_X86;
609 ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_i386,
610 default_policy_action,
611 &ctx.needs_merge[0]);
612 if (!ctx.contexts[0])
613 goto bad;
614
615 ctx.architectures[1] = SCMP_ARCH_X32;
616 ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_x32,
617 default_policy_action,
618 &ctx.needs_merge[1]);
619 if (!ctx.contexts[1])
620 goto bad;
621
622 ctx.architectures[2] = SCMP_ARCH_X86_64;
623 ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_amd64,
624 default_policy_action,
625 &ctx.needs_merge[2]);
626 if (!ctx.contexts[2])
ab5e52f6 627 goto bad;
ca399594 628#ifdef SCMP_ARCH_PPC
7635139a
SH
629 } else if (native_arch == lxc_seccomp_arch_ppc64) {
630 cur_rule_arch = lxc_seccomp_arch_all;
eca6736e
CB
631
632 ctx.architectures[0] = SCMP_ARCH_PPC;
633 ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_ppc,
634 default_policy_action,
635 &ctx.needs_merge[0]);
636 if (!ctx.contexts[0])
637 goto bad;
638
639 ctx.architectures[2] = SCMP_ARCH_PPC64;
640 ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_ppc64,
641 default_policy_action,
642 &ctx.needs_merge[2]);
643 if (!ctx.contexts[2])
7635139a 644 goto bad;
ca399594
CB
645#endif
646#ifdef SCMP_ARCH_ARM
7635139a
SH
647 } else if (native_arch == lxc_seccomp_arch_arm64) {
648 cur_rule_arch = lxc_seccomp_arch_all;
eca6736e
CB
649
650 ctx.architectures[0] = SCMP_ARCH_ARM;
9c3798eb
CB
651 ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_arm,
652 default_policy_action,
653 &ctx.needs_merge[0]);
eca6736e
CB
654 if (!ctx.contexts[0])
655 goto bad;
656
b1c428f9 657#ifdef SCMP_ARCH_AARCH64
eca6736e 658 ctx.architectures[2] = SCMP_ARCH_AARCH64;
9c3798eb
CB
659 ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_arm64,
660 default_policy_action,
661 &ctx.needs_merge[2]);
eca6736e 662 if (!ctx.contexts[2])
2ccd9eda
JC
663 goto bad;
664#endif
b1c428f9 665#endif
2ccd9eda
JC
666#ifdef SCMP_ARCH_MIPS
667 } else if (native_arch == lxc_seccomp_arch_mips64) {
668 cur_rule_arch = lxc_seccomp_arch_all;
eca6736e
CB
669
670 ctx.architectures[0] = SCMP_ARCH_MIPS;
671 ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_mips,
672 default_policy_action,
673 &ctx.needs_merge[0]);
674 if (!ctx.contexts[0])
675 goto bad;
676
677 ctx.architectures[1] = SCMP_ARCH_MIPS64N32;
678 ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_mips64n32,
679 default_policy_action,
680 &ctx.needs_merge[1]);
681 if (!ctx.contexts[1])
682 goto bad;
683
684 ctx.architectures[2] = SCMP_ARCH_MIPS64;
685 ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_mips64,
686 default_policy_action,
687 &ctx.needs_merge[2]);
688 if (!ctx.contexts[2])
2ccd9eda
JC
689 goto bad;
690 } else if (native_arch == lxc_seccomp_arch_mipsel64) {
691 cur_rule_arch = lxc_seccomp_arch_all;
eca6736e
CB
692
693 ctx.architectures[0] = SCMP_ARCH_MIPSEL;
694 ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_mipsel,
695 default_policy_action,
696 &ctx.needs_merge[0]);
697 if (!ctx.contexts[0])
698 goto bad;
699
700 ctx.architectures[1] = SCMP_ARCH_MIPSEL64N32;
701 ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_mipsel64n32,
702 default_policy_action,
703 &ctx.needs_merge[1]);
704 if (!ctx.contexts[1])
705 goto bad;
706
707 ctx.architectures[2] = SCMP_ARCH_MIPSEL64;
708 ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_mipsel64,
709 default_policy_action,
710 &ctx.needs_merge[2]);
711 if (!ctx.contexts[2])
7635139a 712 goto bad;
be038e49 713#endif
d58c6ad0
SH
714 }
715
50798138
SH
716 if (default_policy_action != SCMP_ACT_KILL) {
717 ret = seccomp_reset(conf->seccomp_ctx, default_policy_action);
718 if (ret != 0) {
3ee26d19 719 ERROR("Error re-initializing Seccomp");
50798138
SH
720 return -1;
721 }
9c3798eb
CB
722
723 ret = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0);
724 if (ret < 0) {
725 ERROR("%s - Failed to turn off no-new-privs", strerror(-ret));
50798138
SH
726 return -1;
727 }
9c3798eb 728
127c5293 729#ifdef SCMP_FLTATR_ATL_TSKIP
9c3798eb
CB
730 ret = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1);
731 if (ret < 0)
732 WARN("%s - Failed to turn on seccomp nop-skip, continuing", strerror(-ret));
127c5293 733#endif
50798138
SH
734 }
735
9dbd8ff3 736 while (getline(&line, line_bufsz, f) != -1) {
50798138
SH
737 if (line[0] == '#')
738 continue;
9c3798eb
CB
739
740 if (line[0] == '\0')
50798138 741 continue;
9c3798eb 742
50798138 743 remove_trailing_newlines(line);
9c3798eb
CB
744
745 INFO("Processing \"%s\"", line);
50798138 746 if (line[0] == '[') {
1a0e70ac 747 /* Read the architecture for next set of rules. */
50798138 748 if (strcmp(line, "[x86]") == 0 ||
f06c6207 749 strcmp(line, "[X86]") == 0) {
d58c6ad0 750 if (native_arch != lxc_seccomp_arch_i386 &&
7e84441e 751 native_arch != lxc_seccomp_arch_amd64) {
d58c6ad0
SH
752 cur_rule_arch = lxc_seccomp_arch_unknown;
753 continue;
754 }
9c3798eb 755
d58c6ad0 756 cur_rule_arch = lxc_seccomp_arch_i386;
11de80d6
AB
757 } else if (strcmp(line, "[x32]") == 0 ||
758 strcmp(line, "[X32]") == 0) {
759 if (native_arch != lxc_seccomp_arch_amd64) {
760 cur_rule_arch = lxc_seccomp_arch_unknown;
761 continue;
762 }
9c3798eb 763
11de80d6 764 cur_rule_arch = lxc_seccomp_arch_x32;
d58c6ad0 765 } else if (strcmp(line, "[X86_64]") == 0 ||
f06c6207 766 strcmp(line, "[x86_64]") == 0) {
d58c6ad0
SH
767 if (native_arch != lxc_seccomp_arch_amd64) {
768 cur_rule_arch = lxc_seccomp_arch_unknown;
769 continue;
770 }
9c3798eb 771
d58c6ad0 772 cur_rule_arch = lxc_seccomp_arch_amd64;
d58c6ad0 773 } else if (strcmp(line, "[all]") == 0 ||
f06c6207 774 strcmp(line, "[ALL]") == 0) {
d58c6ad0 775 cur_rule_arch = lxc_seccomp_arch_all;
d58c6ad0 776 }
2b0ae718 777#ifdef SCMP_ARCH_ARM
50798138 778 else if (strcmp(line, "[arm]") == 0 ||
f06c6207 779 strcmp(line, "[ARM]") == 0) {
7635139a 780 if (native_arch != lxc_seccomp_arch_arm &&
7e84441e 781 native_arch != lxc_seccomp_arch_arm64) {
d58c6ad0
SH
782 cur_rule_arch = lxc_seccomp_arch_unknown;
783 continue;
784 }
9c3798eb 785
d58c6ad0 786 cur_rule_arch = lxc_seccomp_arch_arm;
d58c6ad0 787 }
b4067426 788#endif
9d291dd2
BP
789#ifdef SCMP_ARCH_AARCH64
790 else if (strcmp(line, "[arm64]") == 0 ||
f06c6207 791 strcmp(line, "[ARM64]") == 0) {
9d291dd2
BP
792 if (native_arch != lxc_seccomp_arch_arm64) {
793 cur_rule_arch = lxc_seccomp_arch_unknown;
794 continue;
795 }
9c3798eb 796
9d291dd2
BP
797 cur_rule_arch = lxc_seccomp_arch_arm64;
798 }
799#endif
b4067426
BP
800#ifdef SCMP_ARCH_PPC64LE
801 else if (strcmp(line, "[ppc64le]") == 0 ||
f06c6207 802 strcmp(line, "[PPC64LE]") == 0) {
b4067426
BP
803 if (native_arch != lxc_seccomp_arch_ppc64le) {
804 cur_rule_arch = lxc_seccomp_arch_unknown;
805 continue;
806 }
9c3798eb 807
b4067426
BP
808 cur_rule_arch = lxc_seccomp_arch_ppc64le;
809 }
810#endif
811#ifdef SCMP_ARCH_PPC64
812 else if (strcmp(line, "[ppc64]") == 0 ||
f06c6207 813 strcmp(line, "[PPC64]") == 0) {
b4067426
BP
814 if (native_arch != lxc_seccomp_arch_ppc64) {
815 cur_rule_arch = lxc_seccomp_arch_unknown;
816 continue;
817 }
9c3798eb 818
b4067426
BP
819 cur_rule_arch = lxc_seccomp_arch_ppc64;
820 }
821#endif
822#ifdef SCMP_ARCH_PPC
823 else if (strcmp(line, "[ppc]") == 0 ||
f06c6207 824 strcmp(line, "[PPC]") == 0) {
7635139a 825 if (native_arch != lxc_seccomp_arch_ppc &&
7e84441e 826 native_arch != lxc_seccomp_arch_ppc64) {
b4067426
BP
827 cur_rule_arch = lxc_seccomp_arch_unknown;
828 continue;
829 }
9c3798eb 830
b4067426
BP
831 cur_rule_arch = lxc_seccomp_arch_ppc;
832 }
2ccd9eda
JC
833#endif
834#ifdef SCMP_ARCH_MIPS
835 else if (strcmp(line, "[mips64]") == 0 ||
f06c6207 836 strcmp(line, "[MIPS64]") == 0) {
2ccd9eda
JC
837 if (native_arch != lxc_seccomp_arch_mips64) {
838 cur_rule_arch = lxc_seccomp_arch_unknown;
839 continue;
840 }
9c3798eb 841
2ccd9eda
JC
842 cur_rule_arch = lxc_seccomp_arch_mips64;
843 } else if (strcmp(line, "[mips64n32]") == 0 ||
f06c6207 844 strcmp(line, "[MIPS64N32]") == 0) {
2ccd9eda
JC
845 if (native_arch != lxc_seccomp_arch_mips64) {
846 cur_rule_arch = lxc_seccomp_arch_unknown;
847 continue;
848 }
9c3798eb 849
2ccd9eda
JC
850 cur_rule_arch = lxc_seccomp_arch_mips64n32;
851 } else if (strcmp(line, "[mips]") == 0 ||
f06c6207 852 strcmp(line, "[MIPS]") == 0) {
2ccd9eda 853 if (native_arch != lxc_seccomp_arch_mips &&
7e84441e 854 native_arch != lxc_seccomp_arch_mips64) {
2ccd9eda
JC
855 cur_rule_arch = lxc_seccomp_arch_unknown;
856 continue;
857 }
9c3798eb 858
2ccd9eda
JC
859 cur_rule_arch = lxc_seccomp_arch_mips;
860 } else if (strcmp(line, "[mipsel64]") == 0 ||
f06c6207 861 strcmp(line, "[MIPSEL64]") == 0) {
2ccd9eda
JC
862 if (native_arch != lxc_seccomp_arch_mipsel64) {
863 cur_rule_arch = lxc_seccomp_arch_unknown;
864 continue;
865 }
9c3798eb 866
2ccd9eda
JC
867 cur_rule_arch = lxc_seccomp_arch_mipsel64;
868 } else if (strcmp(line, "[mipsel64n32]") == 0 ||
f06c6207 869 strcmp(line, "[MIPSEL64N32]") == 0) {
2ccd9eda
JC
870 if (native_arch != lxc_seccomp_arch_mipsel64) {
871 cur_rule_arch = lxc_seccomp_arch_unknown;
872 continue;
873 }
9c3798eb 874
2ccd9eda
JC
875 cur_rule_arch = lxc_seccomp_arch_mipsel64n32;
876 } else if (strcmp(line, "[mipsel]") == 0 ||
f06c6207 877 strcmp(line, "[MIPSEL]") == 0) {
2ccd9eda 878 if (native_arch != lxc_seccomp_arch_mipsel &&
7e84441e 879 native_arch != lxc_seccomp_arch_mipsel64) {
2ccd9eda
JC
880 cur_rule_arch = lxc_seccomp_arch_unknown;
881 continue;
882 }
9c3798eb 883
2ccd9eda
JC
884 cur_rule_arch = lxc_seccomp_arch_mipsel;
885 }
be038e49
CB
886#endif
887#ifdef SCMP_ARCH_S390X
888 else if (strcmp(line, "[s390x]") == 0 ||
f06c6207 889 strcmp(line, "[S390X]") == 0) {
be038e49
CB
890 if (native_arch != lxc_seccomp_arch_s390x) {
891 cur_rule_arch = lxc_seccomp_arch_unknown;
892 continue;
893 }
9c3798eb 894
be038e49 895 cur_rule_arch = lxc_seccomp_arch_s390x;
2b0ae718 896#endif
9c3798eb 897 } else {
50798138 898 goto bad_arch;
9c3798eb 899 }
d58c6ad0 900
50798138
SH
901 continue;
902 }
903
d58c6ad0
SH
904 /* irrelevant arch - i.e. arm on i386 */
905 if (cur_rule_arch == lxc_seccomp_arch_unknown)
906 continue;
907
3ee26d19 908 memset(&rule, 0, sizeof(rule));
d58c6ad0 909 /* read optional action which follows the syscall */
3ee26d19
L
910 ret = parse_v2_rules(line, default_rule_action, &rule);
911 if (ret != 0) {
912 ERROR("Failed to interpret seccomp rule");
50798138
SH
913 goto bad_rule;
914 }
d58c6ad0 915
eca6736e
CB
916 if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line,
917 conf->seccomp_ctx, &rule))
918 goto bad_rule;
9c3798eb 919
eca6736e
CB
920 INFO("Added native rule for arch %d for %s action %d(%s)",
921 SCMP_ARCH_NATIVE, line, rule.action,
922 get_action_name(rule.action));
923
924 if (ctx.architectures[0] != SCMP_ARCH_NATIVE) {
925 if (!do_resolve_add_rule(ctx.architectures[0], line,
926 ctx.contexts[0], &rule))
d58c6ad0 927 goto bad_rule;
9c3798eb 928
eca6736e
CB
929 INFO("Added compat rule for arch %d for %s action %d(%s)",
930 ctx.architectures[0], line, rule.action,
3ee26d19 931 get_action_name(rule.action));
eca6736e 932 }
94d56054 933
eca6736e
CB
934 if (ctx.architectures[1] != SCMP_ARCH_NATIVE) {
935 if (!do_resolve_add_rule(ctx.architectures[1], line,
936 ctx.contexts[1], &rule))
d6417887 937 goto bad_rule;
9c3798eb 938
eca6736e
CB
939 INFO("Added compat rule for arch %d for %s action %d(%s)",
940 ctx.architectures[1], line, rule.action,
3ee26d19 941 get_action_name(rule.action));
eca6736e
CB
942 }
943
944 if (ctx.architectures[2] != SCMP_ARCH_NATIVE) {
945 if (!do_resolve_add_rule(ctx.architectures[2], line,
946 ctx.contexts[2], &rule))
d6417887 947 goto bad_rule;
9c3798eb 948
94d56054 949 INFO("Added native rule for arch %d for %s action %d(%s)",
eca6736e 950 ctx.architectures[2], line, rule.action,
3ee26d19 951 get_action_name(rule.action));
50798138
SH
952 }
953 }
d58c6ad0 954
d648e178 955 INFO("Merging compat seccomp contexts into main context");
eca6736e
CB
956 if (ctx.contexts[0]) {
957 if (ctx.needs_merge[0]) {
958 ret = seccomp_merge(conf->seccomp_ctx, ctx.contexts[0]);
b5ed021b 959 if (ret < 0) {
d648e178
CB
960 ERROR("Failed to merge first compat seccomp "
961 "context into main context");
b5ed021b
CB
962 goto bad;
963 }
9c3798eb 964
b5ed021b 965 TRACE("Merged first compat seccomp context into main context");
d648e178 966 } else {
eca6736e
CB
967 seccomp_release(ctx.contexts[0]);
968 ctx.contexts[0] = NULL;
b5ed021b 969 }
d648e178 970 }
b5ed021b 971
eca6736e
CB
972 if (ctx.contexts[1]) {
973 if (ctx.needs_merge[1]) {
974 ret = seccomp_merge(conf->seccomp_ctx, ctx.contexts[1]);
b5ed021b 975 if (ret < 0) {
d648e178
CB
976 ERROR("Failed to merge first compat seccomp "
977 "context into main context");
b5ed021b
CB
978 goto bad;
979 }
9c3798eb 980
b5ed021b 981 TRACE("Merged second compat seccomp context into main context");
d648e178 982 } else {
eca6736e
CB
983 seccomp_release(ctx.contexts[1]);
984 ctx.contexts[1] = NULL;
985 }
986 }
987
988 if (ctx.contexts[2]) {
989 if (ctx.needs_merge[2]) {
990 ret = seccomp_merge(conf->seccomp_ctx, ctx.contexts[2]);
991 if (ret < 0) {
992 ERROR("Failed to merge third compat seccomp "
993 "context into main context");
994 goto bad;
995 }
9c3798eb 996
eca6736e
CB
997 TRACE("Merged third compat seccomp context into main context");
998 } else {
999 seccomp_release(ctx.contexts[2]);
1000 ctx.contexts[2] = NULL;
50798138
SH
1001 }
1002 }
6166fa6d 1003
9dbd8ff3 1004 free(line);
50798138
SH
1005 return 0;
1006
1007bad_arch:
9c3798eb
CB
1008 ERROR("Unsupported architecture \"%s\"", line);
1009
50798138 1010bad_rule:
d58c6ad0 1011bad:
eca6736e
CB
1012 if (ctx.contexts[0])
1013 seccomp_release(ctx.contexts[0]);
9c3798eb 1014
eca6736e
CB
1015 if (ctx.contexts[1])
1016 seccomp_release(ctx.contexts[1]);
9c3798eb 1017
eca6736e
CB
1018 if (ctx.contexts[2])
1019 seccomp_release(ctx.contexts[2]);
1020
9dbd8ff3 1021 free(line);
9c3798eb 1022
50798138 1023 return -1;
d58c6ad0
SH
1024}
1025#else /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
1026static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
1027{
50798138 1028 return -1;
50798138 1029}
d58c6ad0 1030#endif /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
50798138 1031
8f2c3a70
SH
1032/*
1033 * The first line of the config file has a policy language version
1034 * the second line has some directives
1035 * then comes policy subject to the directives
998cd2f4 1036 * right now version must be '1' or '2'
1037 * the directives must include 'whitelist'(version == 1 or 2) or 'blacklist'
1038 * (version == 2) and can include 'debug' (though debug is not yet supported).
8f2c3a70
SH
1039 */
1040static int parse_config(FILE *f, struct lxc_conf *conf)
1041{
9dbd8ff3
WB
1042 char *line = NULL;
1043 size_t line_bufsz = 0;
8f2c3a70
SH
1044 int ret, version;
1045
1046 ret = fscanf(f, "%d\n", &version);
50798138 1047 if (ret != 1 || (version != 1 && version != 2)) {
3ee26d19 1048 ERROR("Invalid version");
8f2c3a70
SH
1049 return -1;
1050 }
6ca8172d 1051
9dbd8ff3 1052 if (getline(&line, &line_bufsz, f) == -1) {
3ee26d19 1053 ERROR("Invalid config file");
9dbd8ff3 1054 goto bad_line;
8f2c3a70 1055 }
6ca8172d 1056
50798138 1057 if (version == 1 && !strstr(line, "whitelist")) {
3ee26d19 1058 ERROR("Only whitelist policy is supported");
9dbd8ff3 1059 goto bad_line;
8f2c3a70 1060 }
50798138 1061
8f2c3a70 1062 if (strstr(line, "debug")) {
3ee26d19 1063 ERROR("Debug not yet implemented");
9dbd8ff3 1064 goto bad_line;
8f2c3a70 1065 }
50798138
SH
1066
1067 if (version == 1)
9dbd8ff3 1068 return parse_config_v1(f, line, &line_bufsz, conf);
6ca8172d 1069
9dbd8ff3
WB
1070 return parse_config_v2(f, line, &line_bufsz, conf);
1071
1072bad_line:
1073 free(line);
1074 return -1;
8f2c3a70
SH
1075}
1076
cd75548b
SH
1077/*
1078 * use_seccomp: return true if we should try and apply a seccomp policy
1079 * if defined for the container.
1080 * This will return false if
1081 * 1. seccomp is not enabled in the kernel
1082 * 2. a seccomp policy is already enabled for this task
1083 */
1084static bool use_seccomp(void)
d58c6ad0 1085{
d58c6ad0 1086 int ret, v;
6ca8172d
CB
1087 FILE *f;
1088 size_t line_bufsz = 0;
1089 char *line = NULL;
1090 bool already_enabled = false, found = false;
d58c6ad0 1091
6ca8172d 1092 f = fopen("/proc/self/status", "r");
d58c6ad0 1093 if (!f)
cd75548b 1094 return true;
d58c6ad0 1095
6ca8172d 1096 while (getline(&line, &line_bufsz, f) != -1) {
d58c6ad0 1097 if (strncmp(line, "Seccomp:", 8) == 0) {
cd75548b 1098 found = true;
6ca8172d 1099
f06c6207 1100 ret = sscanf(line + 8, "%d", &v);
cd75548b
SH
1101 if (ret == 1 && v != 0)
1102 already_enabled = true;
6ca8172d 1103
cd75548b 1104 break;
d58c6ad0
SH
1105 }
1106 }
6ca8172d 1107 free(line);
d58c6ad0 1108 fclose(f);
6ca8172d
CB
1109
1110 if (!found) {
3ee26d19 1111 INFO("Seccomp is not enabled in the kernel");
cd75548b
SH
1112 return false;
1113 }
6ca8172d
CB
1114
1115 if (already_enabled) {
3ee26d19 1116 INFO("Already seccomp-confined, not loading new policy");
cd75548b
SH
1117 return false;
1118 }
6ca8172d 1119
cd75548b 1120 return true;
d58c6ad0
SH
1121}
1122
8f2c3a70
SH
1123int lxc_read_seccomp_config(struct lxc_conf *conf)
1124{
cf6624c1 1125 int ret;
8f2c3a70 1126 FILE *f;
8f2c3a70 1127
769872f9
SH
1128 if (!conf->seccomp)
1129 return 0;
1130
cd75548b 1131 if (!use_seccomp())
d58c6ad0 1132 return 0;
47f6d547 1133
769872f9
SH
1134#if HAVE_SCMP_FILTER_CTX
1135 /* XXX for debug, pass in SCMP_ACT_TRAP */
50798138 1136 conf->seccomp_ctx = seccomp_init(SCMP_ACT_KILL);
769872f9
SH
1137 ret = !conf->seccomp_ctx;
1138#else
50798138 1139 ret = seccomp_init(SCMP_ACT_KILL) < 0;
769872f9
SH
1140#endif
1141 if (ret) {
3ee26d19 1142 ERROR("Failed initializing seccomp");
8f2c3a70
SH
1143 return -1;
1144 }
8f2c3a70 1145
47f6d547 1146/* turn off no-new-privs. We don't want it in lxc, and it breaks
f06c6207 1147 * with apparmor */
769872f9 1148#if HAVE_SCMP_FILTER_CTX
cf6624c1 1149 ret = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0);
727c3073 1150#else
cf6624c1 1151 ret = seccomp_attr_set(SCMP_FLTATR_CTL_NNP, 0);
769872f9 1152#endif
cf6624c1
CB
1153 if (ret < 0) {
1154 ERROR("%s - Failed to turn off no-new-privs", strerror(-ret));
8f2c3a70
SH
1155 return -1;
1156 }
127c5293 1157#ifdef SCMP_FLTATR_ATL_TSKIP
cf6624c1
CB
1158 ret = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1);
1159 if (ret < 0)
47f6d547 1160 WARN("%s - Failed to turn on seccomp nop-skip, continuing",
cf6624c1 1161 strerror(-ret));
127c5293 1162#endif
8f2c3a70
SH
1163
1164 f = fopen(conf->seccomp, "r");
1165 if (!f) {
3ee26d19 1166 SYSERROR("Failed to open seccomp policy file %s", conf->seccomp);
8f2c3a70
SH
1167 return -1;
1168 }
47f6d547 1169
8f2c3a70
SH
1170 ret = parse_config(f, conf);
1171 fclose(f);
47f6d547 1172
8f2c3a70
SH
1173 return ret;
1174}
1175
1176int lxc_seccomp_load(struct lxc_conf *conf)
1177{
1178 int ret;
47f6d547 1179
8f2c3a70
SH
1180 if (!conf->seccomp)
1181 return 0;
47f6d547 1182
cd75548b 1183 if (!use_seccomp())
d58c6ad0 1184 return 0;
47f6d547 1185
769872f9 1186#if HAVE_SCMP_FILTER_CTX
47f6d547
CB
1187 ret = seccomp_load(conf->seccomp_ctx);
1188#else
1189 ret = seccomp_load();
769872f9 1190#endif
8f2c3a70 1191 if (ret < 0) {
47f6d547 1192 ERROR("%s- Error loading the seccomp policy", strerror(-ret));
8f2c3a70
SH
1193 return -1;
1194 }
5107af32 1195
1196/* After load seccomp filter into the kernel successfully, export the current seccomp
1197 * filter to log file */
1198#if HAVE_SCMP_FILTER_CTX
47f6d547
CB
1199 if ((lxc_log_get_level() <= LXC_LOG_LEVEL_TRACE ||
1200 conf->loglevel <= LXC_LOG_LEVEL_TRACE) &&
5107af32 1201 lxc_log_fd >= 0) {
1202 ret = seccomp_export_pfc(conf->seccomp_ctx, lxc_log_fd);
1203 /* Just give an warning when export error */
1204 if (ret < 0)
47f6d547 1205 WARN("%s - Failed to export seccomp filter to log file", strerror(-ret));
5107af32 1206 }
1207#endif
47f6d547 1208
8f2c3a70
SH
1209 return 0;
1210}
769872f9 1211
f06c6207
CB
1212void lxc_seccomp_free(struct lxc_conf *conf)
1213{
f10fad2f
ME
1214 free(conf->seccomp);
1215 conf->seccomp = NULL;
47f6d547 1216
769872f9
SH
1217#if HAVE_SCMP_FILTER_CTX
1218 if (conf->seccomp_ctx) {
1219 seccomp_release(conf->seccomp_ctx);
1220 conf->seccomp_ctx = NULL;
1221 }
1222#endif
1223}