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