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