]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/seccomp.c
tree-wide: fix lxc header inclusion
[mirror_lxc.git] / src / lxc / seccomp.c
CommitLineData
cc73685d 1/* SPDX-License-Identifier: LGPL-2.1+ */
8f2c3a70 2
d38dd64a
CB
3#ifndef _GNU_SOURCE
4#define _GNU_SOURCE 1
5#endif
567b2049 6#include <errno.h>
ccf8d128 7#include <seccomp.h>
8f2c3a70
SH
8#include <stdio.h>
9#include <stdlib.h>
e4353a7f 10#include <sys/epoll.h>
6166fa6d 11#include <sys/mount.h>
567b2049 12#include <sys/utsname.h>
f2363e38 13
12ae2a33
CB
14#include "lxc.h"
15
e35b7bf8 16#include "af_unix.h"
c3e3c21a 17#include "commands.h"
769872f9 18#include "config.h"
8f2c3a70 19#include "log.h"
567b2049 20#include "lxcseccomp.h"
c3e3c21a 21#include "mainloop.h"
cdb2a47f 22#include "memory_utils.h"
eacebcc3 23#include "utils.h"
8f2c3a70 24
0b5c590d
CB
25#ifdef __MIPSEL__
26#define MIPS_ARCH_O32 lxc_seccomp_arch_mipsel
27#define MIPS_ARCH_N64 lxc_seccomp_arch_mipsel64
28#else
29#define MIPS_ARCH_O32 lxc_seccomp_arch_mips
30#define MIPS_ARCH_N64 lxc_seccomp_arch_mips64
31#endif
32
4a094eec
WB
33#ifndef SECCOMP_GET_NOTIF_SIZES
34#define SECCOMP_GET_NOTIF_SIZES 3
35#endif
36
ac2cecc4 37lxc_log_define(seccomp, lxc);
8f2c3a70 38
4a094eec
WB
39#if HAVE_DECL_SECCOMP_NOTIFY_FD
40static inline int __seccomp(unsigned int operation, unsigned int flags,
41 void *args)
42{
4a094eec 43 return syscall(__NR_seccomp, operation, flags, args);
4a094eec
WB
44}
45#endif
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
c3e3c21a 61 ret = seccomp_rule_add(conf->seccomp.seccomp_ctx, SCMP_ACT_ALLOW, nr, 0);
ccf8d128
CB
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";
d7d2d2d9 88#if HAVE_DECL_SECCOMP_NOTIFY_FD
02ca9d75 89 case SCMP_ACT_NOTIFY:
cdb2a47f
CB
90 return "notify";
91#endif
1ab6b4a1
CB
92 }
93
94 return "invalid action";
95}
96
14551c8c 97static int32_t get_v2_default_action(char *line)
50798138 98{
14551c8c 99 int32_t ret_action = -1;
50798138 100
f06c6207
CB
101 while (*line == ' ')
102 line++;
30448a13 103
78522aa9 104 /* After 'allowlist' or 'denylist' comes default behavior. */
becc8d20 105 if (strnequal(line, "kill", 4)) {
50798138 106 ret_action = SCMP_ACT_KILL;
becc8d20 107 } else if (strnequal(line, "errno", 5)) {
30448a13
CB
108 int e, ret;
109
110 ret = sscanf(line + 5, "%d", &e);
111 if (ret != 1) {
112 ERROR("Failed to parse errno value from %s", line);
50798138
SH
113 return -2;
114 }
30448a13 115
50798138 116 ret_action = SCMP_ACT_ERRNO(e);
becc8d20 117 } else if (strnequal(line, "allow", 5)) {
50798138 118 ret_action = SCMP_ACT_ALLOW;
becc8d20 119 } else if (strnequal(line, "trap", 4)) {
50798138 120 ret_action = SCMP_ACT_TRAP;
d7d2d2d9 121#if HAVE_DECL_SECCOMP_NOTIFY_FD
becc8d20 122 } else if (strnequal(line, "notify", 6)) {
02ca9d75 123 ret_action = SCMP_ACT_NOTIFY;
cdb2a47f 124#endif
7474b5b3 125 } else if (line[0]) {
54a051c1 126 ERROR("Unrecognized seccomp action \"%s\"", line);
7474b5b3 127 return -2;
30448a13
CB
128 }
129
50798138
SH
130 return ret_action;
131}
132
14551c8c 133static int32_t get_v2_action(char *line, uint32_t def_action)
50798138 134{
1ab6b4a1 135 char *p;
50798138
SH
136 uint32_t ret;
137
1ab6b4a1 138 p = strchr(line, ' ');
50798138
SH
139 if (!p)
140 return def_action;
50798138 141 p++;
1ab6b4a1 142
50798138
SH
143 while (*p == ' ')
144 p++;
1ab6b4a1 145
50798138
SH
146 if (!*p || *p == '#')
147 return def_action;
1ab6b4a1 148
50798138 149 ret = get_v2_default_action(p);
1ab6b4a1
CB
150 switch (ret) {
151 case -2:
152 return -1;
153 case -1:
154 return def_action;
50798138 155 }
1ab6b4a1
CB
156
157 return ret;
50798138 158}
3ee26d19 159
63a49b03 160struct seccomp_v2_rule_args {
3ee26d19
L
161 uint32_t index;
162 uint64_t value;
163 uint64_t mask;
164 enum scmp_compare op;
165};
166
167struct seccomp_v2_rule {
168 uint32_t action;
169 uint32_t args_num;
63a49b03 170 struct seccomp_v2_rule_args args_value[6];
3ee26d19
L
171};
172
173static enum scmp_compare parse_v2_rule_op(char *s)
174{
dc2c2622 175 if (strequal(s, "SCMP_CMP_NE") || strequal(s, "!="))
29cb2617 176 return SCMP_CMP_NE;
dc2c2622 177 else if (strequal(s, "SCMP_CMP_LT") || strequal(s, "<"))
29cb2617 178 return SCMP_CMP_LT;
dc2c2622 179 else if (strequal(s, "SCMP_CMP_LE") || strequal(s, "<="))
29cb2617 180 return SCMP_CMP_LE;
dc2c2622 181 else if (strequal(s, "SCMP_CMP_EQ") || strequal(s, "=="))
29cb2617 182 return SCMP_CMP_EQ;
dc2c2622 183 else if (strequal(s, "SCMP_CMP_GE") || strequal(s, ">="))
29cb2617 184 return SCMP_CMP_GE;
dc2c2622 185 else if (strequal(s, "SCMP_CMP_GT") || strequal(s, ">"))
29cb2617 186 return SCMP_CMP_GT;
dc2c2622 187 else if (strequal(s, "SCMP_CMP_MASKED_EQ") || strequal(s, "&="))
29cb2617 188 return SCMP_CMP_MASKED_EQ;
3ee26d19 189
29cb2617 190 return _SCMP_CMP_MAX;
3ee26d19
L
191}
192
63a49b03
CB
193/*
194 * This function is used to parse the args string into the structure.
73e3cb9a 195 * args string format:[index,value,op,mask] or [index,value,op]
3ee26d19
L
196 * index: the index for syscall arguments (type uint)
197 * value: the value for syscall arguments (type uint64)
198 * op: the operator for syscall arguments(string),
199 a valid list of constants as of libseccomp v2.3.2 is
200 SCMP_CMP_NE,SCMP_CMP_LE,SCMP_CMP_LE, SCMP_CMP_EQ, SCMP_CMP_GE,
201 SCMP_CMP_GT, SCMP_CMP_MASKED_EQ, or !=,<=,==,>=,>,&=
73e3cb9a 202 * mask: the mask to apply on "value" for SCMP_CMP_MASKED_EQ (type uint64, optional)
3ee26d19
L
203 * Returns 0 on success, < 0 otherwise.
204 */
63a49b03 205static int get_seccomp_arg_value(char *key, struct seccomp_v2_rule_args *rule_args)
3ee26d19
L
206{
207 int ret = 0;
3ee26d19 208 uint32_t index = 0;
63a49b03
CB
209 uint64_t mask = 0, value = 0;
210 enum scmp_compare op = 0;
3ee26d19 211 char *tmp = NULL;
f42183e6 212 char s[31] = {0}, v[24] = {0}, m[24] = {'0'};
3ee26d19 213
3ee26d19
L
214 tmp = strchr(key, '[');
215 if (!tmp) {
216 ERROR("Failed to interpret args");
217 return -1;
218 }
63a49b03 219
eacebcc3 220 ret = sscanf(tmp, "[%i,%23[^,],%30[^0-9^,],%23[^,]", &index, v, s, m);
3ee26d19
L
221 if ((ret != 3 && ret != 4) || index >= 6) {
222 ERROR("Failed to interpret args value");
223 return -1;
224 }
225
573ad77f 226 ret = lxc_safe_uint64(v, &value, 0);
eacebcc3
FA
227 if (ret < 0) {
228 ERROR("Invalid argument value");
229 return -1;
230 }
231
573ad77f 232 ret = lxc_safe_uint64(m, &mask, 0);
eacebcc3
FA
233 if (ret < 0) {
234 ERROR("Invalid argument mask");
235 return -1;
236 }
237
3ee26d19
L
238 op = parse_v2_rule_op(s);
239 if (op == _SCMP_CMP_MAX) {
240 ERROR("Failed to interpret args operator value");
241 return -1;
242 }
243
244 rule_args->index = index;
245 rule_args->value = value;
246 rule_args->mask = mask;
247 rule_args->op = op;
248 return 0;
249}
250
251/* This function is used to parse the seccomp rule entry.
252 * @line : seccomp rule entry string.
253 * @def_action : default action used in the case if the 'line' contain non valid action.
254 * @rules : output struct.
255 * Returns 0 on success, < 0 otherwise.
256 */
f67c94d0
CB
257static int parse_v2_rules(char *line, uint32_t def_action,
258 struct seccomp_v2_rule *rules)
3ee26d19 259{
f67c94d0
CB
260 int i = 0, ret = -1;
261 char *key = NULL, *saveptr = NULL, *tmp = NULL;
3ee26d19
L
262
263 tmp = strdup(line);
264 if (!tmp)
265 return -1;
266
267 /* read optional action which follows the syscall */
14551c8c
CB
268 ret = get_v2_action(tmp, def_action);
269 if (ret == -1) {
f858dd50 270 ERROR("Failed to interpret action");
54a051c1 271 goto on_error;
f858dd50 272 }
3ee26d19 273
14551c8c
CB
274 rules->action = ret;
275
f67c94d0 276 ret = 0;
3ee26d19 277 rules->args_num = 0;
f67c94d0 278 if (!strchr(tmp, '['))
54a051c1 279 goto on_error;
3ee26d19 280
f67c94d0
CB
281 ret = -1;
282 for ((key = strtok_r(tmp, "]", &saveptr)), i = 0; key && i < 6;
283 (key = strtok_r(NULL, "]", &saveptr)), i++) {
3ee26d19 284 ret = get_seccomp_arg_value(key, &rules->args_value[i]);
f67c94d0 285 if (ret < 0)
54a051c1 286 goto on_error;
f67c94d0 287
3ee26d19
L
288 rules->args_num++;
289 }
290
291 ret = 0;
f67c94d0 292
54a051c1 293on_error:
3ee26d19 294 free(tmp);
f67c94d0 295
3ee26d19
L
296 return ret;
297}
2b0ae718 298#endif
50798138 299
d58c6ad0 300#if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
3e9671a1 301enum lxc_hostarch_t {
d58c6ad0
SH
302 lxc_seccomp_arch_all = 0,
303 lxc_seccomp_arch_native,
304 lxc_seccomp_arch_i386,
11de80d6 305 lxc_seccomp_arch_x32,
d58c6ad0
SH
306 lxc_seccomp_arch_amd64,
307 lxc_seccomp_arch_arm,
9d291dd2 308 lxc_seccomp_arch_arm64,
b4067426
BP
309 lxc_seccomp_arch_ppc64,
310 lxc_seccomp_arch_ppc64le,
311 lxc_seccomp_arch_ppc,
2ccd9eda
JC
312 lxc_seccomp_arch_mips,
313 lxc_seccomp_arch_mips64,
314 lxc_seccomp_arch_mips64n32,
315 lxc_seccomp_arch_mipsel,
316 lxc_seccomp_arch_mipsel64,
317 lxc_seccomp_arch_mipsel64n32,
be038e49 318 lxc_seccomp_arch_s390x,
3c3fab00 319 lxc_seccomp_arch_s390,
d58c6ad0
SH
320 lxc_seccomp_arch_unknown = 999,
321};
322
59eac805 323static int get_hostarch(void)
d58c6ad0
SH
324{
325 struct utsname uts;
326 if (uname(&uts) < 0) {
3ee26d19 327 SYSERROR("Failed to read host arch");
d58c6ad0
SH
328 return -1;
329 }
0197fe2e 330
dc2c2622 331 if (strequal(uts.machine, "i686"))
d58c6ad0 332 return lxc_seccomp_arch_i386;
1a0e70ac 333 /* no x32 kernels */
dc2c2622 334 else if (strequal(uts.machine, "x86_64"))
d58c6ad0 335 return lxc_seccomp_arch_amd64;
becc8d20 336 else if (strnequal(uts.machine, "armv7", 5))
d58c6ad0 337 return lxc_seccomp_arch_arm;
becc8d20 338 else if (strnequal(uts.machine, "aarch64", 7))
9d291dd2 339 return lxc_seccomp_arch_arm64;
becc8d20 340 else if (strnequal(uts.machine, "ppc64le", 7))
b4067426 341 return lxc_seccomp_arch_ppc64le;
becc8d20 342 else if (strnequal(uts.machine, "ppc64", 5))
b4067426 343 return lxc_seccomp_arch_ppc64;
becc8d20 344 else if (strnequal(uts.machine, "ppc", 3))
b4067426 345 return lxc_seccomp_arch_ppc;
becc8d20 346 else if (strnequal(uts.machine, "mips64", 6))
2ccd9eda 347 return MIPS_ARCH_N64;
becc8d20 348 else if (strnequal(uts.machine, "mips", 4))
2ccd9eda 349 return MIPS_ARCH_O32;
becc8d20 350 else if (strnequal(uts.machine, "s390x", 5))
be038e49 351 return lxc_seccomp_arch_s390x;
becc8d20 352 else if (strnequal(uts.machine, "s390", 4))
3c3fab00 353 return lxc_seccomp_arch_s390;
d58c6ad0
SH
354 return lxc_seccomp_arch_unknown;
355}
356
59eac805
CB
357static scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_policy_action,
358 bool *needs_merge)
d58c6ad0 359{
d58c6ad0
SH
360 int ret;
361 uint32_t arch;
04263914 362 scmp_filter_ctx ctx;
d58c6ad0 363
04263914
CB
364 switch (n_arch) {
365 case lxc_seccomp_arch_i386:
366 arch = SCMP_ARCH_X86;
367 break;
368 case lxc_seccomp_arch_x32:
369 arch = SCMP_ARCH_X32;
370 break;
371 case lxc_seccomp_arch_amd64:
372 arch = SCMP_ARCH_X86_64;
373 break;
374 case lxc_seccomp_arch_arm:
375 arch = SCMP_ARCH_ARM;
376 break;
9d291dd2 377#ifdef SCMP_ARCH_AARCH64
04263914
CB
378 case lxc_seccomp_arch_arm64:
379 arch = SCMP_ARCH_AARCH64;
380 break;
9d291dd2 381#endif
b4067426 382#ifdef SCMP_ARCH_PPC64LE
04263914
CB
383 case lxc_seccomp_arch_ppc64le:
384 arch = SCMP_ARCH_PPC64LE;
385 break;
b4067426
BP
386#endif
387#ifdef SCMP_ARCH_PPC64
04263914
CB
388 case lxc_seccomp_arch_ppc64:
389 arch = SCMP_ARCH_PPC64;
390 break;
b4067426
BP
391#endif
392#ifdef SCMP_ARCH_PPC
04263914
CB
393 case lxc_seccomp_arch_ppc:
394 arch = SCMP_ARCH_PPC;
395 break;
2ccd9eda
JC
396#endif
397#ifdef SCMP_ARCH_MIPS
04263914
CB
398 case lxc_seccomp_arch_mips:
399 arch = SCMP_ARCH_MIPS;
400 break;
401 case lxc_seccomp_arch_mips64:
402 arch = SCMP_ARCH_MIPS64;
403 break;
404 case lxc_seccomp_arch_mips64n32:
405 arch = SCMP_ARCH_MIPS64N32;
406 break;
407 case lxc_seccomp_arch_mipsel:
408 arch = SCMP_ARCH_MIPSEL;
409 break;
410 case lxc_seccomp_arch_mipsel64:
411 arch = SCMP_ARCH_MIPSEL64;
412 break;
413 case lxc_seccomp_arch_mipsel64n32:
414 arch = SCMP_ARCH_MIPSEL64N32;
415 break;
be038e49
CB
416#endif
417#ifdef SCMP_ARCH_S390X
04263914
CB
418 case lxc_seccomp_arch_s390x:
419 arch = SCMP_ARCH_S390X;
420 break;
3c3fab00 421#endif
422#ifdef SCMP_ARCH_S390
423 case lxc_seccomp_arch_s390:
424 arch = SCMP_ARCH_S390;
425 break;
b4067426 426#endif
04263914
CB
427 default:
428 return NULL;
d58c6ad0
SH
429 }
430
04263914
CB
431 ctx = seccomp_init(default_policy_action);
432 if (!ctx) {
3ee26d19 433 ERROR("Error initializing seccomp context");
d58c6ad0
SH
434 return NULL;
435 }
04263914
CB
436
437 ret = seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0);
438 if (ret < 0) {
6d1400b5 439 errno = -ret;
440 SYSERROR("Failed to turn off no-new-privs");
d58c6ad0
SH
441 seccomp_release(ctx);
442 return NULL;
443 }
04263914 444
127c5293 445#ifdef SCMP_FLTATR_ATL_TSKIP
04263914 446 ret = seccomp_attr_set(ctx, SCMP_FLTATR_ATL_TSKIP, 1);
a24c5678 447 if (ret < 0) {
448 errno = -ret;
449 SYSWARN("Failed to turn on seccomp nop-skip, continuing");
450 }
127c5293 451#endif
b5ed021b 452
adfee3a8
CB
453 ret = seccomp_arch_exist(ctx, arch);
454 if (ret < 0) {
455 if (ret != -EEXIST) {
6d1400b5 456 errno = -ret;
457 SYSERROR("Failed to determine whether arch %d is "
458 "already present in the main seccomp context",
459 (int)n_arch);
adfee3a8
CB
460 seccomp_release(ctx);
461 return NULL;
462 }
463
b5ed021b
CB
464 ret = seccomp_arch_add(ctx, arch);
465 if (ret != 0) {
6d1400b5 466 errno = -ret;
467 SYSERROR("Failed to add arch %d to main seccomp context",
468 (int)n_arch);
b5ed021b
CB
469 seccomp_release(ctx);
470 return NULL;
471 }
adfee3a8 472 TRACE("Added arch %d to main seccomp context", (int)n_arch);
b5ed021b 473
adfee3a8
CB
474 ret = seccomp_arch_remove(ctx, SCMP_ARCH_NATIVE);
475 if (ret != 0) {
476 ERROR("Failed to remove native arch from main seccomp context");
b5ed021b
CB
477 seccomp_release(ctx);
478 return NULL;
479 }
adfee3a8 480 TRACE("Removed native arch from main seccomp context");
3e9671a1
CB
481
482 *needs_merge = true;
adfee3a8 483 } else {
3e9671a1 484 *needs_merge = false;
adfee3a8 485 TRACE("Arch %d already present in main seccomp context", (int)n_arch);
d58c6ad0
SH
486 }
487
488 return ctx;
489}
490
0ff0d23e
RJ
491enum lxc_seccomp_rule_status_t {
492 lxc_seccomp_rule_added = 0,
493 lxc_seccomp_rule_err,
494 lxc_seccomp_rule_undefined_syscall,
495 lxc_seccomp_rule_unsupported_arch,
496};
497
498static enum lxc_seccomp_rule_status_t do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx,
59eac805 499 struct seccomp_v2_rule *rule)
d58c6ad0 500{
14551c8c 501 int nr, ret;
3ee26d19
L
502 struct scmp_arg_cmp arg_cmp[6];
503
f06c6207
CB
504 ret = seccomp_arch_exist(ctx, arch);
505 if (arch && ret != 0) {
6d1400b5 506 errno = -ret;
507 SYSERROR("Seccomp: rule and context arch do not match (arch %d)", arch);
0ff0d23e 508 return lxc_seccomp_rule_err;
d58c6ad0 509 }
6166fa6d 510
3ee26d19
L
511 /*get the syscall name*/
512 char *p = strchr(line, ' ');
513 if (p)
514 *p = '\0';
515
becc8d20 516 if (strnequal(line, "reject_force_umount", 19)) {
ad9a5b72
CB
517 ret = seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EACCES),
518 SCMP_SYS(umount2), 1,
519 SCMP_A1(SCMP_CMP_MASKED_EQ, MNT_FORCE, MNT_FORCE));
6166fa6d 520 if (ret < 0) {
6d1400b5 521 errno = -ret;
522 SYSERROR("Failed loading rule to reject force umount");
0ff0d23e 523 return lxc_seccomp_rule_err;
6166fa6d 524 }
ad9a5b72
CB
525
526 INFO("Set seccomp rule to reject force umounts");
0ff0d23e 527 return lxc_seccomp_rule_added;
6166fa6d
SH
528 }
529
cd75548b 530 nr = seccomp_syscall_resolve_name(line);
d58c6ad0 531 if (nr == __NR_SCMP_ERROR) {
0ff0d23e
RJ
532 INFO("The syscall[%s] is is undefined on host native arch", line);
533 return lxc_seccomp_rule_undefined_syscall;
d58c6ad0 534 }
ad9a5b72 535
0ff0d23e
RJ
536 // The syscall resolves to a pseudo syscall and may be available on compat archs.
537 if (nr < 0 && arch == SCMP_ARCH_NATIVE) {
538 DEBUG("The syscall[%d:%s] is a pseudo syscall and not available on host native arch.", nr, line);
539 return lxc_seccomp_rule_unsupported_arch;
d58c6ad0 540 }
3ee26d19 541
fbec5f83 542 if (arch != SCMP_ARCH_NATIVE && seccomp_syscall_resolve_name_arch(arch, line) < 0) {
0ff0d23e
RJ
543 DEBUG("The syscall[%d:%s] is not supported on compat arch[%u]", nr, line, arch);
544 return lxc_seccomp_rule_unsupported_arch;
fbec5f83
RJ
545 }
546
ad9a5b72 547 memset(&arg_cmp, 0, sizeof(arg_cmp));
14551c8c
CB
548 for (size_t i = 0; i < rule->args_num; i++) {
549 INFO("arg_cmp[%zu]: SCMP_CMP(%u, %llu, %llu, %llu)", i,
ad9a5b72
CB
550 rule->args_value[i].index,
551 (long long unsigned int)rule->args_value[i].op,
552 (long long unsigned int)rule->args_value[i].mask,
553 (long long unsigned int)rule->args_value[i].value);
3ee26d19
L
554
555 if (SCMP_CMP_MASKED_EQ == rule->args_value[i].op)
ad9a5b72
CB
556 arg_cmp[i] = SCMP_CMP(rule->args_value[i].index,
557 rule->args_value[i].op,
558 rule->args_value[i].mask,
559 rule->args_value[i].value);
3ee26d19 560 else
ad9a5b72
CB
561 arg_cmp[i] = SCMP_CMP(rule->args_value[i].index,
562 rule->args_value[i].op,
563 rule->args_value[i].value);
3ee26d19
L
564 }
565
0ff0d23e
RJ
566 INFO("Adding %s rule for syscall[%d:%s] action[%d:%s] arch[%u]",
567 (arch == SCMP_ARCH_NATIVE) ? "native" : "compat",
568 nr, line, rule->action, get_action_name(rule->action), arch);
569
ad9a5b72
CB
570 ret = seccomp_rule_add_exact_array(ctx, rule->action, nr,
571 rule->args_num, arg_cmp);
d58c6ad0 572 if (ret < 0) {
6d1400b5 573 errno = -ret;
0ff0d23e
RJ
574 SYSERROR("Failed to add rule for syscall[%d:%s] action[%d:%s] arch[%u]",
575 nr, line, rule->action, get_action_name(rule->action), arch);
576 return lxc_seccomp_rule_err;
d58c6ad0 577 }
ad9a5b72 578
0ff0d23e 579 return lxc_seccomp_rule_added;
d58c6ad0
SH
580}
581
78522aa9
CB
582/*
583 * It is unfortunate, but we can't simply remove those terms since this would
584 * break way too many users.
585 */
586#define BACKWARDCOMPAT_TERMINOLOGY_DENYLIST "blacklist"
587#define BACKWARDCOMPAT_TERMINOLOGY_ALLOWLIST "whitelist"
588
589static inline bool is_denylist(const char *type)
590{
591 return strnequal(type, "denylist", STRLITERALLEN("denylist")) ||
592 strnequal(type, BACKWARDCOMPAT_TERMINOLOGY_DENYLIST,
593 STRLITERALLEN(BACKWARDCOMPAT_TERMINOLOGY_DENYLIST));
594}
595
596static inline bool is_allowlist(const char *type)
597{
598 return strnequal(type, "allowlist", STRLITERALLEN("allowlist")) ||
599 strnequal(type, BACKWARDCOMPAT_TERMINOLOGY_ALLOWLIST,
600 STRLITERALLEN(BACKWARDCOMPAT_TERMINOLOGY_ALLOWLIST));
601}
602
50798138
SH
603/*
604 * v2 consists of
605 * [x86]
606 * open
607 * read
608 * write
609 * close
610 * # a comment
611 * [x86_64]
612 * open
613 * read
614 * write
615 * close
616 */
9dbd8ff3 617static int parse_config_v2(FILE *f, char *line, size_t *line_bufsz, struct lxc_conf *conf)
50798138 618{
50798138 619 int ret;
9c3798eb 620 char *p;
3e9671a1 621 enum lxc_hostarch_t cur_rule_arch, native_arch;
78522aa9 622 bool denylist = false;
14551c8c 623 int32_t default_policy_action = -1, default_rule_action = -1;
3ee26d19 624 struct seccomp_v2_rule rule;
3e9671a1
CB
625 struct scmp_ctx_info {
626 uint32_t architectures[3];
627 scmp_filter_ctx contexts[3];
628 bool needs_merge[3];
629 } ctx;
50798138 630
78522aa9
CB
631 if (is_denylist(line))
632 denylist = true;
633 else if (!is_allowlist(line))
634 return log_error(-EINVAL, "Bad seccomp policy style \"%s\"", line);
50798138 635
9c3798eb
CB
636 p = strchr(line, ' ');
637 if (p) {
f06c6207 638 default_policy_action = get_v2_default_action(p + 1);
50798138
SH
639 if (default_policy_action == -2)
640 return -1;
641 }
642
78522aa9
CB
643 /* for denylist, allow any syscall which has no rule */
644 if (denylist) {
50798138
SH
645 if (default_policy_action == -1)
646 default_policy_action = SCMP_ACT_ALLOW;
9c3798eb 647
50798138
SH
648 if (default_rule_action == -1)
649 default_rule_action = SCMP_ACT_KILL;
650 } else {
651 if (default_policy_action == -1)
652 default_policy_action = SCMP_ACT_KILL;
9c3798eb 653
50798138
SH
654 if (default_rule_action == -1)
655 default_rule_action = SCMP_ACT_ALLOW;
656 }
657
15044cd1
RJ
658 DEBUG("Host native arch is [%u]", seccomp_arch_native());
659
eca6736e
CB
660 memset(&ctx, 0, sizeof(ctx));
661 ctx.architectures[0] = SCMP_ARCH_NATIVE;
662 ctx.architectures[1] = SCMP_ARCH_NATIVE;
663 ctx.architectures[2] = SCMP_ARCH_NATIVE;
9c3798eb
CB
664 native_arch = get_hostarch();
665 cur_rule_arch = native_arch;
d58c6ad0
SH
666 if (native_arch == lxc_seccomp_arch_amd64) {
667 cur_rule_arch = lxc_seccomp_arch_all;
eca6736e
CB
668
669 ctx.architectures[0] = SCMP_ARCH_X86;
670 ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_i386,
3e9671a1
CB
671 default_policy_action,
672 &ctx.needs_merge[0]);
eca6736e
CB
673 if (!ctx.contexts[0])
674 goto bad;
675
676 ctx.architectures[1] = SCMP_ARCH_X32;
677 ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_x32,
3e9671a1
CB
678 default_policy_action,
679 &ctx.needs_merge[1]);
eca6736e
CB
680 if (!ctx.contexts[1])
681 goto bad;
682
683 ctx.architectures[2] = SCMP_ARCH_X86_64;
684 ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_amd64,
3e9671a1
CB
685 default_policy_action,
686 &ctx.needs_merge[2]);
eca6736e 687 if (!ctx.contexts[2])
ab5e52f6 688 goto bad;
ca399594 689#ifdef SCMP_ARCH_PPC
7635139a
SH
690 } else if (native_arch == lxc_seccomp_arch_ppc64) {
691 cur_rule_arch = lxc_seccomp_arch_all;
eca6736e
CB
692
693 ctx.architectures[0] = SCMP_ARCH_PPC;
694 ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_ppc,
3e9671a1
CB
695 default_policy_action,
696 &ctx.needs_merge[0]);
eca6736e
CB
697 if (!ctx.contexts[0])
698 goto bad;
699
3e9671a1
CB
700 ctx.architectures[2] = SCMP_ARCH_PPC64;
701 ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_ppc64,
702 default_policy_action,
703 &ctx.needs_merge[2]);
704 if (!ctx.contexts[2])
7635139a 705 goto bad;
ca399594
CB
706#endif
707#ifdef SCMP_ARCH_ARM
7635139a
SH
708 } else if (native_arch == lxc_seccomp_arch_arm64) {
709 cur_rule_arch = lxc_seccomp_arch_all;
eca6736e
CB
710
711 ctx.architectures[0] = SCMP_ARCH_ARM;
9c3798eb 712 ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_arm,
3e9671a1
CB
713 default_policy_action,
714 &ctx.needs_merge[0]);
eca6736e
CB
715 if (!ctx.contexts[0])
716 goto bad;
717
b1c428f9 718#ifdef SCMP_ARCH_AARCH64
3e9671a1
CB
719 ctx.architectures[2] = SCMP_ARCH_AARCH64;
720 ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_arm64,
721 default_policy_action,
722 &ctx.needs_merge[2]);
723 if (!ctx.contexts[2])
2ccd9eda
JC
724 goto bad;
725#endif
b1c428f9 726#endif
2ccd9eda
JC
727#ifdef SCMP_ARCH_MIPS
728 } else if (native_arch == lxc_seccomp_arch_mips64) {
729 cur_rule_arch = lxc_seccomp_arch_all;
eca6736e
CB
730
731 ctx.architectures[0] = SCMP_ARCH_MIPS;
732 ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_mips,
3e9671a1
CB
733 default_policy_action,
734 &ctx.needs_merge[0]);
eca6736e
CB
735 if (!ctx.contexts[0])
736 goto bad;
737
738 ctx.architectures[1] = SCMP_ARCH_MIPS64N32;
739 ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_mips64n32,
3e9671a1
CB
740 default_policy_action,
741 &ctx.needs_merge[1]);
eca6736e
CB
742 if (!ctx.contexts[1])
743 goto bad;
744
745 ctx.architectures[2] = SCMP_ARCH_MIPS64;
746 ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_mips64,
3e9671a1
CB
747 default_policy_action,
748 &ctx.needs_merge[2]);
eca6736e 749 if (!ctx.contexts[2])
2ccd9eda
JC
750 goto bad;
751 } else if (native_arch == lxc_seccomp_arch_mipsel64) {
752 cur_rule_arch = lxc_seccomp_arch_all;
eca6736e
CB
753
754 ctx.architectures[0] = SCMP_ARCH_MIPSEL;
755 ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_mipsel,
3e9671a1
CB
756 default_policy_action,
757 &ctx.needs_merge[0]);
eca6736e
CB
758 if (!ctx.contexts[0])
759 goto bad;
760
761 ctx.architectures[1] = SCMP_ARCH_MIPSEL64N32;
762 ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_mipsel64n32,
3e9671a1
CB
763 default_policy_action,
764 &ctx.needs_merge[1]);
eca6736e
CB
765 if (!ctx.contexts[1])
766 goto bad;
767
768 ctx.architectures[2] = SCMP_ARCH_MIPSEL64;
769 ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_mipsel64,
3e9671a1
CB
770 default_policy_action,
771 &ctx.needs_merge[2]);
eca6736e 772 if (!ctx.contexts[2])
7635139a 773 goto bad;
be038e49 774#endif
d58c6ad0
SH
775 }
776
50798138 777 if (default_policy_action != SCMP_ACT_KILL) {
c3e3c21a 778 ret = seccomp_reset(conf->seccomp.seccomp_ctx, default_policy_action);
50798138 779 if (ret != 0) {
3ee26d19 780 ERROR("Error re-initializing Seccomp");
50798138
SH
781 return -1;
782 }
9c3798eb 783
c3e3c21a 784 ret = seccomp_attr_set(conf->seccomp.seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0);
9c3798eb 785 if (ret < 0) {
6d1400b5 786 errno = -ret;
787 SYSERROR("Failed to turn off no-new-privs");
50798138
SH
788 return -1;
789 }
9c3798eb 790
127c5293 791#ifdef SCMP_FLTATR_ATL_TSKIP
c3e3c21a 792 ret = seccomp_attr_set(conf->seccomp.seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1);
a24c5678 793 if (ret < 0) {
794 errno = -ret;
795 SYSWARN("Failed to turn on seccomp nop-skip, continuing");
796 }
127c5293 797#endif
50798138
SH
798 }
799
9dbd8ff3 800 while (getline(&line, line_bufsz, f) != -1) {
50798138
SH
801 if (line[0] == '#')
802 continue;
9c3798eb
CB
803
804 if (line[0] == '\0')
50798138 805 continue;
9c3798eb 806
50798138 807 remove_trailing_newlines(line);
9c3798eb
CB
808
809 INFO("Processing \"%s\"", line);
50798138 810 if (line[0] == '[') {
1a0e70ac 811 /* Read the architecture for next set of rules. */
dc2c2622
CB
812 if (strequal(line, "[x86]") ||
813 strequal(line, "[X86]")) {
d58c6ad0 814 if (native_arch != lxc_seccomp_arch_i386 &&
7e84441e 815 native_arch != lxc_seccomp_arch_amd64) {
d58c6ad0
SH
816 cur_rule_arch = lxc_seccomp_arch_unknown;
817 continue;
818 }
9c3798eb 819
d58c6ad0 820 cur_rule_arch = lxc_seccomp_arch_i386;
dc2c2622
CB
821 } else if (strequal(line, "[x32]") ||
822 strequal(line, "[X32]")) {
11de80d6
AB
823 if (native_arch != lxc_seccomp_arch_amd64) {
824 cur_rule_arch = lxc_seccomp_arch_unknown;
825 continue;
826 }
9c3798eb 827
11de80d6 828 cur_rule_arch = lxc_seccomp_arch_x32;
dc2c2622
CB
829 } else if (strequal(line, "[X86_64]") ||
830 strequal(line, "[x86_64]")) {
d58c6ad0
SH
831 if (native_arch != lxc_seccomp_arch_amd64) {
832 cur_rule_arch = lxc_seccomp_arch_unknown;
833 continue;
834 }
9c3798eb 835
d58c6ad0 836 cur_rule_arch = lxc_seccomp_arch_amd64;
dc2c2622
CB
837 } else if (strequal(line, "[all]") ||
838 strequal(line, "[ALL]")) {
d58c6ad0 839 cur_rule_arch = lxc_seccomp_arch_all;
d58c6ad0 840 }
2b0ae718 841#ifdef SCMP_ARCH_ARM
dc2c2622
CB
842 else if (strequal(line, "[arm]") ||
843 strequal(line, "[ARM]")) {
7635139a 844 if (native_arch != lxc_seccomp_arch_arm &&
7e84441e 845 native_arch != lxc_seccomp_arch_arm64) {
d58c6ad0
SH
846 cur_rule_arch = lxc_seccomp_arch_unknown;
847 continue;
848 }
9c3798eb 849
d58c6ad0 850 cur_rule_arch = lxc_seccomp_arch_arm;
d58c6ad0 851 }
b4067426 852#endif
9d291dd2 853#ifdef SCMP_ARCH_AARCH64
dc2c2622
CB
854 else if (strequal(line, "[arm64]") ||
855 strequal(line, "[ARM64]")) {
9d291dd2
BP
856 if (native_arch != lxc_seccomp_arch_arm64) {
857 cur_rule_arch = lxc_seccomp_arch_unknown;
858 continue;
859 }
9c3798eb 860
9d291dd2
BP
861 cur_rule_arch = lxc_seccomp_arch_arm64;
862 }
863#endif
b4067426 864#ifdef SCMP_ARCH_PPC64LE
dc2c2622
CB
865 else if (strequal(line, "[ppc64le]") ||
866 strequal(line, "[PPC64LE]")) {
b4067426
BP
867 if (native_arch != lxc_seccomp_arch_ppc64le) {
868 cur_rule_arch = lxc_seccomp_arch_unknown;
869 continue;
870 }
9c3798eb 871
b4067426
BP
872 cur_rule_arch = lxc_seccomp_arch_ppc64le;
873 }
874#endif
875#ifdef SCMP_ARCH_PPC64
dc2c2622
CB
876 else if (strequal(line, "[ppc64]") ||
877 strequal(line, "[PPC64]")) {
b4067426
BP
878 if (native_arch != lxc_seccomp_arch_ppc64) {
879 cur_rule_arch = lxc_seccomp_arch_unknown;
880 continue;
881 }
9c3798eb 882
b4067426
BP
883 cur_rule_arch = lxc_seccomp_arch_ppc64;
884 }
885#endif
886#ifdef SCMP_ARCH_PPC
dc2c2622
CB
887 else if (strequal(line, "[ppc]") ||
888 strequal(line, "[PPC]")) {
7635139a 889 if (native_arch != lxc_seccomp_arch_ppc &&
7e84441e 890 native_arch != lxc_seccomp_arch_ppc64) {
b4067426
BP
891 cur_rule_arch = lxc_seccomp_arch_unknown;
892 continue;
893 }
9c3798eb 894
b4067426
BP
895 cur_rule_arch = lxc_seccomp_arch_ppc;
896 }
2ccd9eda
JC
897#endif
898#ifdef SCMP_ARCH_MIPS
dc2c2622
CB
899 else if (strequal(line, "[mips64]") ||
900 strequal(line, "[MIPS64]")) {
2ccd9eda
JC
901 if (native_arch != lxc_seccomp_arch_mips64) {
902 cur_rule_arch = lxc_seccomp_arch_unknown;
903 continue;
904 }
9c3798eb 905
2ccd9eda 906 cur_rule_arch = lxc_seccomp_arch_mips64;
dc2c2622
CB
907 } else if (strequal(line, "[mips64n32]") ||
908 strequal(line, "[MIPS64N32]")) {
2ccd9eda
JC
909 if (native_arch != lxc_seccomp_arch_mips64) {
910 cur_rule_arch = lxc_seccomp_arch_unknown;
911 continue;
912 }
9c3798eb 913
2ccd9eda 914 cur_rule_arch = lxc_seccomp_arch_mips64n32;
dc2c2622
CB
915 } else if (strequal(line, "[mips]") ||
916 strequal(line, "[MIPS]")) {
2ccd9eda 917 if (native_arch != lxc_seccomp_arch_mips &&
7e84441e 918 native_arch != lxc_seccomp_arch_mips64) {
2ccd9eda
JC
919 cur_rule_arch = lxc_seccomp_arch_unknown;
920 continue;
921 }
9c3798eb 922
2ccd9eda 923 cur_rule_arch = lxc_seccomp_arch_mips;
dc2c2622
CB
924 } else if (strequal(line, "[mipsel64]") ||
925 strequal(line, "[MIPSEL64]")) {
2ccd9eda
JC
926 if (native_arch != lxc_seccomp_arch_mipsel64) {
927 cur_rule_arch = lxc_seccomp_arch_unknown;
928 continue;
929 }
9c3798eb 930
2ccd9eda 931 cur_rule_arch = lxc_seccomp_arch_mipsel64;
dc2c2622
CB
932 } else if (strequal(line, "[mipsel64n32]") ||
933 strequal(line, "[MIPSEL64N32]")) {
2ccd9eda
JC
934 if (native_arch != lxc_seccomp_arch_mipsel64) {
935 cur_rule_arch = lxc_seccomp_arch_unknown;
936 continue;
937 }
9c3798eb 938
2ccd9eda 939 cur_rule_arch = lxc_seccomp_arch_mipsel64n32;
dc2c2622
CB
940 } else if (strequal(line, "[mipsel]") ||
941 strequal(line, "[MIPSEL]")) {
2ccd9eda 942 if (native_arch != lxc_seccomp_arch_mipsel &&
7e84441e 943 native_arch != lxc_seccomp_arch_mipsel64) {
2ccd9eda
JC
944 cur_rule_arch = lxc_seccomp_arch_unknown;
945 continue;
946 }
9c3798eb 947
2ccd9eda
JC
948 cur_rule_arch = lxc_seccomp_arch_mipsel;
949 }
be038e49
CB
950#endif
951#ifdef SCMP_ARCH_S390X
dc2c2622
CB
952 else if (strequal(line, "[s390x]") ||
953 strequal(line, "[S390X]")) {
be038e49
CB
954 if (native_arch != lxc_seccomp_arch_s390x) {
955 cur_rule_arch = lxc_seccomp_arch_unknown;
956 continue;
957 }
9c3798eb 958
be038e49 959 cur_rule_arch = lxc_seccomp_arch_s390x;
b8bcbe9b 960 }
3c3fab00 961#endif
962#ifdef SCMP_ARCH_S390
dc2c2622
CB
963 else if (strequal(line, "[s390]") ||
964 strequal(line, "[S390]")) {
3c3fab00 965 if (native_arch != lxc_seccomp_arch_s390) {
966 cur_rule_arch = lxc_seccomp_arch_unknown;
967 continue;
968 }
969
970 cur_rule_arch = lxc_seccomp_arch_s390;
971 }
2b0ae718 972#endif
b8bcbe9b 973 else {
50798138 974 goto bad_arch;
9c3798eb 975 }
d58c6ad0 976
50798138
SH
977 continue;
978 }
979
d58c6ad0
SH
980 /* irrelevant arch - i.e. arm on i386 */
981 if (cur_rule_arch == lxc_seccomp_arch_unknown)
982 continue;
983
3ee26d19 984 memset(&rule, 0, sizeof(rule));
d58c6ad0 985 /* read optional action which follows the syscall */
3ee26d19
L
986 ret = parse_v2_rules(line, default_rule_action, &rule);
987 if (ret != 0) {
988 ERROR("Failed to interpret seccomp rule");
50798138
SH
989 goto bad_rule;
990 }
d58c6ad0 991
d7d2d2d9 992#if HAVE_DECL_SECCOMP_NOTIFY_FD
02ca9d75 993 if ((rule.action == SCMP_ACT_NOTIFY) &&
c3e3c21a 994 !conf->seccomp.notifier.wants_supervision) {
c3e3c21a 995 conf->seccomp.notifier.wants_supervision = true;
2e5bcac3 996 TRACE("Set SECCOMP_FILTER_FLAG_NEW_LISTENER attribute");
cdb2a47f
CB
997 }
998#endif
999
9c3798eb 1000
0ff0d23e
RJ
1001 ret = do_resolve_add_rule(SCMP_ARCH_NATIVE, line,
1002 conf->seccomp.seccomp_ctx, &rule);
1003 if (ret == lxc_seccomp_rule_err)
1004 goto bad_rule;
1005 if (ret == lxc_seccomp_rule_undefined_syscall)
1006 continue;
94d56054 1007
15044cd1
RJ
1008 for (int i = 0; i < 3; i++ ) {
1009 uint32_t arch = ctx.architectures[i];
1010 if (arch != SCMP_ARCH_NATIVE && arch != seccomp_arch_native()) {
1011 if (lxc_seccomp_rule_err == do_resolve_add_rule(arch, line,
1012 ctx.contexts[i], &rule))
1013 goto bad_rule;
1014 }
3e9671a1 1015 }
f1bcfc79 1016
50798138 1017 }
d58c6ad0 1018
d648e178 1019 INFO("Merging compat seccomp contexts into main context");
eca6736e
CB
1020 if (ctx.contexts[0]) {
1021 if (ctx.needs_merge[0]) {
c3e3c21a 1022 ret = seccomp_merge(conf->seccomp.seccomp_ctx, ctx.contexts[0]);
b5ed021b 1023 if (ret < 0) {
3e9671a1
CB
1024 ERROR("Failed to merge first compat seccomp "
1025 "context into main context");
b5ed021b
CB
1026 goto bad;
1027 }
9c3798eb 1028
b5ed021b 1029 TRACE("Merged first compat seccomp context into main context");
d648e178 1030 } else {
eca6736e
CB
1031 seccomp_release(ctx.contexts[0]);
1032 ctx.contexts[0] = NULL;
b5ed021b 1033 }
d648e178 1034 }
b5ed021b 1035
eca6736e
CB
1036 if (ctx.contexts[1]) {
1037 if (ctx.needs_merge[1]) {
c3e3c21a 1038 ret = seccomp_merge(conf->seccomp.seccomp_ctx, ctx.contexts[1]);
b5ed021b 1039 if (ret < 0) {
3e9671a1
CB
1040 ERROR("Failed to merge first compat seccomp "
1041 "context into main context");
b5ed021b
CB
1042 goto bad;
1043 }
9c3798eb 1044
b5ed021b 1045 TRACE("Merged second compat seccomp context into main context");
d648e178 1046 } else {
eca6736e
CB
1047 seccomp_release(ctx.contexts[1]);
1048 ctx.contexts[1] = NULL;
1049 }
1050 }
1051
1052 if (ctx.contexts[2]) {
1053 if (ctx.needs_merge[2]) {
c3e3c21a 1054 ret = seccomp_merge(conf->seccomp.seccomp_ctx, ctx.contexts[2]);
eca6736e 1055 if (ret < 0) {
3e9671a1
CB
1056 ERROR("Failed to merge third compat seccomp "
1057 "context into main context");
eca6736e
CB
1058 goto bad;
1059 }
9c3798eb 1060
eca6736e
CB
1061 TRACE("Merged third compat seccomp context into main context");
1062 } else {
1063 seccomp_release(ctx.contexts[2]);
1064 ctx.contexts[2] = NULL;
50798138
SH
1065 }
1066 }
6166fa6d 1067
9dbd8ff3 1068 free(line);
50798138
SH
1069 return 0;
1070
1071bad_arch:
9c3798eb
CB
1072 ERROR("Unsupported architecture \"%s\"", line);
1073
50798138 1074bad_rule:
d58c6ad0 1075bad:
eca6736e
CB
1076 if (ctx.contexts[0])
1077 seccomp_release(ctx.contexts[0]);
9c3798eb 1078
eca6736e
CB
1079 if (ctx.contexts[1])
1080 seccomp_release(ctx.contexts[1]);
9c3798eb 1081
eca6736e
CB
1082 if (ctx.contexts[2])
1083 seccomp_release(ctx.contexts[2]);
1084
9dbd8ff3 1085 free(line);
9c3798eb 1086
50798138 1087 return -1;
d58c6ad0
SH
1088}
1089#else /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
1090static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
1091{
50798138 1092 return -1;
50798138 1093}
d58c6ad0 1094#endif /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
50798138 1095
8f2c3a70
SH
1096/*
1097 * The first line of the config file has a policy language version
1098 * the second line has some directives
1099 * then comes policy subject to the directives
998cd2f4 1100 * right now version must be '1' or '2'
78522aa9 1101 * the directives must include 'allowlist'(version == 1 or 2) or 'denylist'
998cd2f4 1102 * (version == 2) and can include 'debug' (though debug is not yet supported).
8f2c3a70
SH
1103 */
1104static int parse_config(FILE *f, struct lxc_conf *conf)
1105{
9dbd8ff3
WB
1106 char *line = NULL;
1107 size_t line_bufsz = 0;
8f2c3a70
SH
1108 int ret, version;
1109
1110 ret = fscanf(f, "%d\n", &version);
50798138 1111 if (ret != 1 || (version != 1 && version != 2)) {
3ee26d19 1112 ERROR("Invalid version");
8f2c3a70
SH
1113 return -1;
1114 }
6ca8172d 1115
9dbd8ff3 1116 if (getline(&line, &line_bufsz, f) == -1) {
3ee26d19 1117 ERROR("Invalid config file");
9dbd8ff3 1118 goto bad_line;
8f2c3a70 1119 }
6ca8172d 1120
78522aa9
CB
1121 if (version == 1 && !strstr(line, "allowlist")) {
1122 ERROR("Only allowlist policy is supported");
9dbd8ff3 1123 goto bad_line;
8f2c3a70 1124 }
50798138 1125
8f2c3a70 1126 if (strstr(line, "debug")) {
3ee26d19 1127 ERROR("Debug not yet implemented");
9dbd8ff3 1128 goto bad_line;
8f2c3a70 1129 }
50798138
SH
1130
1131 if (version == 1)
9dbd8ff3 1132 return parse_config_v1(f, line, &line_bufsz, conf);
6ca8172d 1133
9dbd8ff3
WB
1134 return parse_config_v2(f, line, &line_bufsz, conf);
1135
1136bad_line:
1137 free(line);
1138 return -1;
8f2c3a70
SH
1139}
1140
cd75548b
SH
1141/*
1142 * use_seccomp: return true if we should try and apply a seccomp policy
1143 * if defined for the container.
1144 * This will return false if
1145 * 1. seccomp is not enabled in the kernel
1146 * 2. a seccomp policy is already enabled for this task
1147 */
50d86993 1148static bool use_seccomp(const struct lxc_conf *conf)
d58c6ad0 1149{
4110345b
CB
1150 __do_free char *line = NULL;
1151 __do_fclose FILE *f = NULL;
d58c6ad0 1152 int ret, v;
6ca8172d 1153 size_t line_bufsz = 0;
6ca8172d 1154 bool already_enabled = false, found = false;
d58c6ad0 1155
c3e3c21a 1156 if (conf->seccomp.allow_nesting > 0)
50d86993
CB
1157 return true;
1158
4110345b 1159 f = fopen("/proc/self/status", "re");
d58c6ad0 1160 if (!f)
cd75548b 1161 return true;
d58c6ad0 1162
6ca8172d 1163 while (getline(&line, &line_bufsz, f) != -1) {
becc8d20 1164 if (strnequal(line, "Seccomp:", 8)) {
cd75548b 1165 found = true;
6ca8172d 1166
f06c6207 1167 ret = sscanf(line + 8, "%d", &v);
cd75548b
SH
1168 if (ret == 1 && v != 0)
1169 already_enabled = true;
6ca8172d 1170
cd75548b 1171 break;
d58c6ad0
SH
1172 }
1173 }
6ca8172d
CB
1174
1175 if (!found) {
3ee26d19 1176 INFO("Seccomp is not enabled in the kernel");
cd75548b
SH
1177 return false;
1178 }
6ca8172d
CB
1179
1180 if (already_enabled) {
3ee26d19 1181 INFO("Already seccomp-confined, not loading new policy");
cd75548b
SH
1182 return false;
1183 }
6ca8172d 1184
cd75548b 1185 return true;
d58c6ad0
SH
1186}
1187
8f2c3a70
SH
1188int lxc_read_seccomp_config(struct lxc_conf *conf)
1189{
4110345b 1190 __do_fclose FILE *f = NULL;
cf6624c1 1191 int ret;
8f2c3a70 1192
c3e3c21a 1193 if (!conf->seccomp.seccomp)
769872f9
SH
1194 return 0;
1195
50d86993 1196 if (!use_seccomp(conf))
d58c6ad0 1197 return 0;
47f6d547 1198
769872f9
SH
1199#if HAVE_SCMP_FILTER_CTX
1200 /* XXX for debug, pass in SCMP_ACT_TRAP */
c3e3c21a
CB
1201 conf->seccomp.seccomp_ctx = seccomp_init(SCMP_ACT_KILL);
1202 ret = !conf->seccomp.seccomp_ctx;
769872f9 1203#else
50798138 1204 ret = seccomp_init(SCMP_ACT_KILL) < 0;
769872f9
SH
1205#endif
1206 if (ret) {
3ee26d19 1207 ERROR("Failed initializing seccomp");
8f2c3a70
SH
1208 return -1;
1209 }
8f2c3a70 1210
47f6d547 1211/* turn off no-new-privs. We don't want it in lxc, and it breaks
f06c6207 1212 * with apparmor */
769872f9 1213#if HAVE_SCMP_FILTER_CTX
c3e3c21a 1214 ret = seccomp_attr_set(conf->seccomp.seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0);
727c3073 1215#else
cf6624c1 1216 ret = seccomp_attr_set(SCMP_FLTATR_CTL_NNP, 0);
769872f9 1217#endif
cf6624c1 1218 if (ret < 0) {
6d1400b5 1219 errno = -ret;
1220 SYSERROR("Failed to turn off no-new-privs");
8f2c3a70
SH
1221 return -1;
1222 }
a24c5678 1223
127c5293 1224#ifdef SCMP_FLTATR_ATL_TSKIP
c3e3c21a 1225 ret = seccomp_attr_set(conf->seccomp.seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1);
a24c5678 1226 if (ret < 0) {
1227 errno = -ret;
1228 SYSWARN("Failed to turn on seccomp nop-skip, continuing");
1229 }
127c5293 1230#endif
8f2c3a70 1231
4110345b 1232 f = fopen(conf->seccomp.seccomp, "re");
8f2c3a70 1233 if (!f) {
c3e3c21a 1234 SYSERROR("Failed to open seccomp policy file %s", conf->seccomp.seccomp);
8f2c3a70
SH
1235 return -1;
1236 }
47f6d547 1237
4110345b 1238 return parse_config(f, conf);
8f2c3a70
SH
1239}
1240
1241int lxc_seccomp_load(struct lxc_conf *conf)
1242{
1243 int ret;
47f6d547 1244
c3e3c21a 1245 if (!conf->seccomp.seccomp)
8f2c3a70 1246 return 0;
47f6d547 1247
50d86993 1248 if (!use_seccomp(conf))
d58c6ad0 1249 return 0;
47f6d547 1250
769872f9 1251#if HAVE_SCMP_FILTER_CTX
c3e3c21a 1252 ret = seccomp_load(conf->seccomp.seccomp_ctx);
47f6d547
CB
1253#else
1254 ret = seccomp_load();
769872f9 1255#endif
8f2c3a70 1256 if (ret < 0) {
6d1400b5 1257 errno = -ret;
1258 SYSERROR("Error loading the seccomp policy");
8f2c3a70
SH
1259 return -1;
1260 }
5107af32 1261
1262/* After load seccomp filter into the kernel successfully, export the current seccomp
1263 * filter to log file */
1264#if HAVE_SCMP_FILTER_CTX
de96cd60 1265 if (lxc_log_trace()) {
25a8b256
CB
1266 int fd_log;
1267
1268 fd_log = lxc_log_get_fd();
1269 if (fd_log >= 0) {
1270 ret = seccomp_export_pfc(conf->seccomp.seccomp_ctx, fd_log);
1271 if (ret < 0) {
1272 errno = -ret;
1273 SYSWARN("Failed to export seccomp filter to log file");
1274 }
a24c5678 1275 }
5107af32 1276 }
1277#endif
47f6d547 1278
d7d2d2d9 1279#if HAVE_DECL_SECCOMP_NOTIFY_FD
c3e3c21a 1280 if (conf->seccomp.notifier.wants_supervision) {
da9c8317 1281 ret = seccomp_notify_fd(conf->seccomp.seccomp_ctx);
cdb2a47f
CB
1282 if (ret < 0) {
1283 errno = -ret;
1284 return -1;
1285 }
1286
a60c98aa
CB
1287 if (fd_make_nonblocking(ret))
1288 return log_error_errno(-1, errno, "Failed to make seccomp listener fd non-blocking");;
1289
c3e3c21a 1290 conf->seccomp.notifier.notify_fd = ret;
cdb2a47f
CB
1291 TRACE("Retrieved new seccomp listener fd %d", ret);
1292 }
1293#endif
1294
8f2c3a70
SH
1295 return 0;
1296}
769872f9 1297
c3e3c21a 1298void lxc_seccomp_free(struct lxc_seccomp *seccomp)
f06c6207 1299{
c3e3c21a 1300 free_disarm(seccomp->seccomp);
47f6d547 1301
769872f9 1302#if HAVE_SCMP_FILTER_CTX
c3e3c21a
CB
1303 if (seccomp->seccomp_ctx) {
1304 seccomp_release(seccomp->seccomp_ctx);
1305 seccomp->seccomp_ctx = NULL;
769872f9
SH
1306 }
1307#endif
cdb2a47f 1308
d7d2d2d9 1309#if HAVE_DECL_SECCOMP_NOTIFY_FD
c3e3c21a
CB
1310 close_prot_errno_disarm(seccomp->notifier.notify_fd);
1311 close_prot_errno_disarm(seccomp->notifier.proxy_fd);
99656206 1312 seccomp_notify_free(seccomp->notifier.req_buf, seccomp->notifier.rsp_buf);
c3e3c21a
CB
1313 seccomp->notifier.req_buf = NULL;
1314 seccomp->notifier.rsp_buf = NULL;
5dd07023 1315 free_disarm(seccomp->notifier.cookie);
cdb2a47f
CB
1316#endif
1317}
1318
d7d2d2d9 1319#if HAVE_DECL_SECCOMP_NOTIFY_FD
e35b7bf8
CB
1320static int seccomp_notify_reconnect(struct lxc_handler *handler)
1321{
f62cf1d4 1322 __do_close int notify_fd = -EBADF;
e35b7bf8 1323
c3e3c21a 1324 close_prot_errno_disarm(handler->conf->seccomp.notifier.proxy_fd);
e35b7bf8 1325
045ee721
WB
1326 notify_fd = lxc_unix_connect_type(
1327 &handler->conf->seccomp.notifier.proxy_addr, SOCK_SEQPACKET);
e35b7bf8
CB
1328 if (notify_fd < 0) {
1329 SYSERROR("Failed to reconnect to seccomp proxy");
1330 return -1;
1331 }
1332
1333 /* 30 second timeout */
1334 if (lxc_socket_set_timeout(notify_fd, 30, 30)) {
1335 SYSERROR("Failed to set socket timeout");
1336 return -1;
1337 }
c3e3c21a 1338 handler->conf->seccomp.notifier.proxy_fd = move_fd(notify_fd);
e35b7bf8
CB
1339 return 0;
1340}
1341#endif
1342
d7d2d2d9 1343#if HAVE_DECL_SECCOMP_NOTIFY_FD
651e63a7
WB
1344static void seccomp_notify_default_answer(int fd, struct seccomp_notif *req,
1345 struct seccomp_notif_resp *resp,
1346 struct lxc_handler *handler)
e35b7bf8
CB
1347{
1348 resp->id = req->id;
1349 resp->error = -ENOSYS;
dc70d7e4
CB
1350 resp->val = 0;
1351 resp->flags = 0;
e35b7bf8 1352
3c216fe2 1353 if (seccomp_notify_respond(fd, resp))
50926f4b
CB
1354 SYSERROR("Failed to send default message to seccomp notification with id(%llu)",
1355 (long long unsigned int)resp->id);
dc70d7e4 1356 else
50926f4b
CB
1357 TRACE("Sent default response for seccomp notification with id(%llu)",
1358 (long long unsigned int)resp->id);
dc70d7e4 1359 memset(resp, 0, handler->conf->seccomp.notifier.sizes.seccomp_notif_resp);
e35b7bf8
CB
1360}
1361#endif
1362
543d2f83
CB
1363int seccomp_notify_cleanup_handler(int fd, void *data)
1364{
c16d194a 1365#if HAVE_DECL_SECCOMP_NOTIFY_FD
543d2f83
CB
1366 struct lxc_handler *hdlr = data;
1367 struct lxc_conf *conf = hdlr->conf;
1368
1369 /* TODO: Make sure that we don't need to free any memory in here. */
1370 if (fd == conf->seccomp.notifier.notify_fd)
1371 fd = move_fd(conf->seccomp.notifier.notify_fd);
1372
1373 /*
1374 * If this isn't the main notify_fd it means that someone registered a
1375 * seccomp notify handler through the command socket (e.g. for attach)
1376 * and so we won't touch the container's config.
1377 */
c16d194a 1378#endif
543d2f83
CB
1379 return 0;
1380}
1381
cdb2a47f 1382int seccomp_notify_handler(int fd, uint32_t events, void *data,
3298b37d 1383 struct lxc_async_descr *descr)
cdb2a47f
CB
1384{
1385
d7d2d2d9 1386#if HAVE_DECL_SECCOMP_NOTIFY_FD
f62cf1d4
CB
1387 __do_close int fd_pid = -EBADF;
1388 __do_close int fd_mem = -EBADF;
8a99ab01 1389 int ret;
e35b7bf8 1390 ssize_t bytes;
ec49d30f 1391 int send_fd_list[3];
4a094eec
WB
1392 struct iovec iov[4];
1393 size_t iov_len, msg_base_size, msg_full_size;
18847d37
CB
1394 char mem_path[6 /* /proc/ */
1395 + INTTYPE_TO_STRLEN(int64_t)
1396 + 3 /* mem */
1397 + 1 /* \0 */];
3745ee0e 1398 bool reconnected = false;
cdb2a47f
CB
1399 struct lxc_handler *hdlr = data;
1400 struct lxc_conf *conf = hdlr->conf;
c3e3c21a
CB
1401 struct seccomp_notif *req = conf->seccomp.notifier.req_buf;
1402 struct seccomp_notif_resp *resp = conf->seccomp.notifier.rsp_buf;
1403 int listener_proxy_fd = conf->seccomp.notifier.proxy_fd;
37046066 1404 struct seccomp_notify_proxy_msg msg = {0};
4a094eec 1405 char *cookie = conf->seccomp.notifier.cookie;
a76fe490 1406 __u64 req_id;
cdb2a47f 1407
543d2f83
CB
1408 if (events & EPOLLHUP)
1409 return log_trace(LXC_MAINLOOP_DISARM, "Removing seccomp notifier fd %d", fd);
b2acb9dc 1410
dc70d7e4 1411 memset(req, 0, conf->seccomp.notifier.sizes.seccomp_notif);
e3998402 1412 ret = seccomp_notify_receive(fd, req);
e35b7bf8 1413 if (ret) {
0d724ab4
CB
1414 if (errno == ENOENT)
1415 TRACE("Intercepted system call aborted");
1416 else
1417 SYSERROR("Failed to read seccomp notification");
e35b7bf8
CB
1418 goto out;
1419 }
cdb2a47f 1420
5357b872 1421 if (listener_proxy_fd < 0) {
ed3a98c4
WB
1422 ret = -1;
1423 /* Same condition as for the initial setup_proxy() */
1424 if (conf->seccomp.notifier.wants_supervision &&
1425 conf->seccomp.notifier.proxy_addr.sun_path[1] != '\0') {
1426 ret = seccomp_notify_reconnect(hdlr);
1427 }
1428 if (ret) {
1429 ERROR("No seccomp proxy registered");
651e63a7
WB
1430 seccomp_notify_default_answer(fd, req, resp, hdlr);
1431 goto out;
ed3a98c4
WB
1432 }
1433 listener_proxy_fd = conf->seccomp.notifier.proxy_fd;
5357b872
WB
1434 }
1435
4a094eec
WB
1436 /* remember the ID in case we receive garbage from the proxy */
1437 resp->id = req_id = req->id;
50926f4b 1438 TRACE("Received seccomp notification with id(%llu)", (long long unsigned int)req_id);
4a094eec 1439
8a6bea94
CB
1440 ret = strnprintf(mem_path, sizeof(mem_path), "/proc/%d", req->pid);
1441 if (ret < 0) {
1442 seccomp_notify_default_answer(fd, req, resp, hdlr);
1443 SYSERROR("Failed to create path to process's proc directory");
1444 goto out;
1445 }
1446
637996a4
WB
1447 fd_pid = open(mem_path, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
1448 if (fd_pid < 0) {
1449 seccomp_notify_default_answer(fd, req, resp, hdlr);
1450 SYSERROR("Failed to open process pidfd for seccomp notify request");
1451 goto out;
1452 }
1453
8a6bea94
CB
1454 ret = strnprintf(mem_path, sizeof(mem_path), "/proc/%d/mem", req->pid);
1455 if (ret < 0) {
1456 seccomp_notify_default_answer(fd, req, resp, hdlr);
1457 SYSERROR("Failed to create path to process's virtual memory");
1458 goto out;
1459 }
1460
aad859c4 1461 fd_mem = open(mem_path, O_RDWR | O_CLOEXEC);
5ed06d3a 1462 if (fd_mem < 0) {
651e63a7 1463 seccomp_notify_default_answer(fd, req, resp, hdlr);
5ed06d3a
CB
1464 SYSERROR("Failed to open process memory for seccomp notify request");
1465 goto out;
1466 }
1467
1468 /*
1469 * Make sure that the fd for /proc/<pid>/mem we just opened still
1470 * refers to the correct process's memory.
1471 */
72b101ae 1472 ret = seccomp_notify_id_valid(fd, req->id);
5ed06d3a 1473 if (ret < 0) {
651e63a7 1474 seccomp_notify_default_answer(fd, req, resp, hdlr);
50926f4b 1475 SYSERROR("Invalid seccomp notify request id(%llu)", (long long unsigned int)req->id);
5ed06d3a
CB
1476 goto out;
1477 }
1478
cdb2a47f
CB
1479 msg.monitor_pid = hdlr->monitor_pid;
1480 msg.init_pid = hdlr->pid;
4a094eec
WB
1481 memcpy(&msg.sizes, &conf->seccomp.notifier.sizes, sizeof(msg.sizes));
1482
1483 msg_base_size = 0;
1484 iov[0].iov_base = &msg;
1485 msg_base_size += (iov[0].iov_len = sizeof(msg));
1486 iov[1].iov_base = req;
1487 msg_base_size += (iov[1].iov_len = msg.sizes.seccomp_notif);
1488 iov[2].iov_base = resp;
1489 msg_base_size += (iov[2].iov_len = msg.sizes.seccomp_notif_resp);
1490 msg_full_size = msg_base_size;
1491
1492 if (cookie) {
1493 size_t len = strlen(cookie);
1494
1495 msg.cookie_len = (uint64_t)len;
1496
1497 iov[3].iov_base = cookie;
1498 msg_full_size += (iov[3].iov_len = len);
1499
1500 iov_len = 4;
1501 } else {
1502 iov_len = 3;
1503 }
cdb2a47f 1504
637996a4
WB
1505 send_fd_list[0] = fd_pid;
1506 send_fd_list[1] = fd_mem;
ec49d30f 1507 send_fd_list[2] = fd;
637996a4 1508
3745ee0e 1509retry:
ec49d30f 1510 bytes = lxc_abstract_unix_send_fds_iov(listener_proxy_fd, send_fd_list, 3, iov, iov_len);
8a99ab01
WB
1511 if (bytes != (ssize_t)msg_full_size) {
1512 SYSERROR("Failed to forward message to seccomp proxy");
3745ee0e
WB
1513 if (!reconnected) {
1514 ret = seccomp_notify_reconnect(hdlr);
1515 if (ret == 0) {
1516 reconnected = true;
1517 goto retry;
1518 }
1519 }
1520
651e63a7 1521 seccomp_notify_default_answer(fd, req, resp, hdlr);
8a99ab01
WB
1522 goto out;
1523 }
e35b7bf8 1524
5ed06d3a
CB
1525 close_prot_errno_disarm(fd_mem);
1526
f910c9e5
WB
1527 if (msg.__reserved != 0) {
1528 ERROR("Proxy filled reserved data in response");
1529 seccomp_notify_default_answer(fd, req, resp, hdlr);
1530 goto out;
1531 }
1532
4a094eec 1533 if (resp->id != req_id) {
1c01dc2c 1534 ERROR("Proxy returned response with invalid id(%llu) != id(%llu)",
50926f4b 1535 (long long unsigned int)resp->id, (long long unsigned int)req_id);
4a094eec 1536 resp->id = req_id;
651e63a7 1537 seccomp_notify_default_answer(fd, req, resp, hdlr);
4a094eec
WB
1538 goto out;
1539 }
1540
cbbdd1dd 1541 bytes = lxc_recvmsg_nointr_iov(listener_proxy_fd, iov, iov_len, MSG_TRUNC);
8a99ab01
WB
1542 if (bytes != (ssize_t)msg_base_size) {
1543 SYSERROR("Failed to receive message from seccomp proxy");
651e63a7 1544 seccomp_notify_default_answer(fd, req, resp, hdlr);
8a99ab01
WB
1545 goto out;
1546 }
cdb2a47f 1547
a76fe490 1548 if (resp->id != req_id) {
1c01dc2c 1549 ERROR("Proxy returned response with invalid id(%llu) != id(%llu)",
50926f4b 1550 (long long unsigned int)resp->id, (long long unsigned int)req_id);
a76fe490
CB
1551 resp->id = req_id;
1552 }
1553
3c216fe2 1554 ret = seccomp_notify_respond(fd, resp);
cdb2a47f 1555 if (ret)
e35b7bf8 1556 SYSERROR("Failed to send seccomp notification");
a76fe490 1557 else
50926f4b
CB
1558 TRACE("Sent response for seccomp notification with id(%llu)",
1559 (long long unsigned int)resp->id);
dc70d7e4 1560 memset(resp, 0, conf->seccomp.notifier.sizes.seccomp_notif_resp);
cdb2a47f 1561
e35b7bf8 1562out:
cdb2a47f 1563#endif
f7a97743 1564 return LXC_MAINLOOP_CONTINUE;
769872f9 1565}
c3e3c21a
CB
1566
1567void seccomp_conf_init(struct lxc_conf *conf)
1568{
1569 conf->seccomp.seccomp = NULL;
1570#if HAVE_SCMP_FILTER_CTX
1571 conf->seccomp.allow_nesting = 0;
1572 memset(&conf->seccomp.seccomp_ctx, 0, sizeof(conf->seccomp.seccomp_ctx));
1573#endif /* HAVE_SCMP_FILTER_CTX */
d7d2d2d9 1574#if HAVE_DECL_SECCOMP_NOTIFY_FD
c3e3c21a
CB
1575 conf->seccomp.notifier.wants_supervision = false;
1576 conf->seccomp.notifier.notify_fd = -EBADF;
1577 conf->seccomp.notifier.proxy_fd = -EBADF;
1578 memset(&conf->seccomp.notifier.proxy_addr, 0,
1579 sizeof(conf->seccomp.notifier.proxy_addr));
1580 conf->seccomp.notifier.req_buf = NULL;
1581 conf->seccomp.notifier.rsp_buf = NULL;
5dd07023 1582 conf->seccomp.notifier.cookie = NULL;
c3e3c21a
CB
1583#endif
1584}
1585
2ac0f627 1586int lxc_seccomp_setup_proxy(struct lxc_seccomp *seccomp,
3298b37d 1587 struct lxc_async_descr *descr,
2ac0f627 1588 struct lxc_handler *handler)
c3e3c21a 1589{
d7d2d2d9 1590#if HAVE_DECL_SECCOMP_NOTIFY_FD
c3e3c21a
CB
1591 if (seccomp->notifier.wants_supervision &&
1592 seccomp->notifier.proxy_addr.sun_path[1] != '\0') {
f62cf1d4 1593 __do_close int notify_fd = -EBADF;
c3e3c21a
CB
1594 int ret;
1595
045ee721
WB
1596 notify_fd = lxc_unix_connect_type(&seccomp->notifier.proxy_addr,
1597 SOCK_SEQPACKET);
2ac0f627
CB
1598 if (notify_fd < 0) {
1599 SYSERROR("Failed to connect to seccomp proxy");
c3e3c21a 1600 return -1;
2ac0f627 1601 }
c3e3c21a
CB
1602
1603 /* 30 second timeout */
1604 ret = lxc_socket_set_timeout(notify_fd, 30, 30);
2ac0f627
CB
1605 if (ret) {
1606 SYSERROR("Failed to set timeouts for seccomp proxy");
c3e3c21a 1607 return -1;
2ac0f627
CB
1608 }
1609
4a094eec
WB
1610 ret = __seccomp(SECCOMP_GET_NOTIF_SIZES, 0,
1611 &seccomp->notifier.sizes);
1612 if (ret) {
1613 SYSERROR("Failed to query seccomp notify struct sizes");
1614 return -1;
1615 }
1616
1f51fc70 1617 ret = seccomp_notify_alloc(&seccomp->notifier.req_buf,
2ac0f627
CB
1618 &seccomp->notifier.rsp_buf);
1619 if (ret) {
1620 ERROR("Failed to allocate seccomp notify request and response buffers");
1621 errno = ret;
1622 return -1;
1623 }
c3e3c21a 1624
543d2f83
CB
1625 ret = lxc_mainloop_add_handler(descr, seccomp->notifier.notify_fd,
1626 seccomp_notify_handler,
1627 seccomp_notify_cleanup_handler,
1628 handler,
1629 "seccomp_notify_handler");
c3e3c21a
CB
1630 if (ret < 0) {
1631 ERROR("Failed to add seccomp notify handler for %d to mainloop",
2ac0f627 1632 notify_fd);
c3e3c21a
CB
1633 return -1;
1634 }
1635
1636 seccomp->notifier.proxy_fd = move_fd(notify_fd);
1637 }
1638#endif
1639 return 0;
1640}
1641
1642int lxc_seccomp_send_notifier_fd(struct lxc_seccomp *seccomp, int socket_fd)
1643{
d7d2d2d9 1644#if HAVE_DECL_SECCOMP_NOTIFY_FD
c3e3c21a
CB
1645 if (seccomp->notifier.wants_supervision) {
1646 if (lxc_abstract_unix_send_fds(socket_fd,
1647 &seccomp->notifier.notify_fd, 1,
1648 NULL, 0) < 0)
1649 return -1;
1650 close_prot_errno_disarm(seccomp->notifier.notify_fd);
1651 }
1652#endif
1653 return 0;
1654}
1655
1656int lxc_seccomp_recv_notifier_fd(struct lxc_seccomp *seccomp, int socket_fd)
1657{
d7d2d2d9 1658#if HAVE_DECL_SECCOMP_NOTIFY_FD
c3e3c21a
CB
1659 if (seccomp->notifier.wants_supervision) {
1660 int ret;
1661
d17c815d
CB
1662 ret = lxc_abstract_unix_recv_one_fd(socket_fd,
1663 &seccomp->notifier.notify_fd,
1664 NULL, 0);
c3e3c21a
CB
1665 if (ret < 0)
1666 return -1;
c3e3c21a
CB
1667 }
1668#endif
1669 return 0;
1670}
1671
1672int lxc_seccomp_add_notifier(const char *name, const char *lxcpath,
1673 struct lxc_seccomp *seccomp)
1674{
d7d2d2d9 1675#if HAVE_DECL_SECCOMP_NOTIFY_FD
2ac0f627 1676 if (seccomp->notifier.wants_supervision) {
c3e3c21a
CB
1677 int ret;
1678
1679 ret = lxc_cmd_seccomp_notify_add_listener(name, lxcpath,
2ac0f627 1680 seccomp->notifier.notify_fd,
c3e3c21a
CB
1681 -1, 0);
1682 close_prot_errno_disarm(seccomp->notifier.notify_fd);
1683 if (ret < 0)
1684 return -1;
1685 }
1686#endif
1687 return 0;
1688}