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