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