]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/seccomp.c
Merge pull request #1539 from brauner/2017-05-06/fix_abstract_unix_sockets
[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
24#define _GNU_SOURCE
567b2049 25#include <errno.h>
8f2c3a70
SH
26#include <stdio.h>
27#include <stdlib.h>
28#include <seccomp.h>
6166fa6d 29#include <sys/mount.h>
567b2049 30#include <sys/utsname.h>
f2363e38 31
769872f9 32#include "config.h"
8f2c3a70 33#include "log.h"
567b2049 34#include "lxcseccomp.h"
8f2c3a70
SH
35
36lxc_log_define(lxc_seccomp, lxc);
37
50798138
SH
38static int parse_config_v1(FILE *f, struct lxc_conf *conf)
39{
40 char line[1024];
41 int ret;
42
43 while (fgets(line, 1024, f)) {
44 int nr;
45 ret = sscanf(line, "%d", &nr);
46 if (ret != 1)
47 return -1;
48 ret = seccomp_rule_add(
49#if HAVE_SCMP_FILTER_CTX
f06c6207 50 conf->seccomp_ctx,
50798138 51#endif
f06c6207 52 SCMP_ACT_ALLOW, nr, 0);
50798138 53 if (ret < 0) {
f06c6207 54 ERROR("Failed loading allow rule for %d.", nr);
50798138
SH
55 return ret;
56 }
57 }
58 return 0;
59}
60
2b0ae718 61#if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
50798138
SH
62static void remove_trailing_newlines(char *l)
63{
64 char *p = l;
65
66 while (*p)
67 p++;
68 while (--p >= l && *p == '\n')
69 *p = '\0';
70}
71
72static uint32_t get_v2_default_action(char *line)
73{
74 uint32_t ret_action = -1;
75
f06c6207
CB
76 while (*line == ' ')
77 line++;
50798138
SH
78 // after 'whitelist' or 'blacklist' comes default behavior
79 if (strncmp(line, "kill", 4) == 0)
80 ret_action = SCMP_ACT_KILL;
81 else if (strncmp(line, "errno", 5) == 0) {
82 int e;
f06c6207
CB
83 if (sscanf(line + 5, "%d", &e) != 1) {
84 ERROR("Bad errno value in %s.", line);
50798138
SH
85 return -2;
86 }
87 ret_action = SCMP_ACT_ERRNO(e);
88 } else if (strncmp(line, "allow", 5) == 0)
89 ret_action = SCMP_ACT_ALLOW;
90 else if (strncmp(line, "trap", 4) == 0)
91 ret_action = SCMP_ACT_TRAP;
92 return ret_action;
93}
94
95static uint32_t get_and_clear_v2_action(char *line, uint32_t def_action)
96{
97 char *p = strchr(line, ' ');
98 uint32_t ret;
99
100 if (!p)
101 return def_action;
102 *p = '\0';
103 p++;
104 while (*p == ' ')
105 p++;
106 if (!*p || *p == '#')
107 return def_action;
108 ret = get_v2_default_action(p);
109 switch(ret) {
110 case -2: return -1;
111 case -1: return def_action;
112 default: return ret;
113 }
114}
2b0ae718 115#endif
50798138 116
d58c6ad0
SH
117#if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
118enum lxc_hostarch_t {
119 lxc_seccomp_arch_all = 0,
120 lxc_seccomp_arch_native,
121 lxc_seccomp_arch_i386,
11de80d6 122 lxc_seccomp_arch_x32,
d58c6ad0
SH
123 lxc_seccomp_arch_amd64,
124 lxc_seccomp_arch_arm,
9d291dd2 125 lxc_seccomp_arch_arm64,
b4067426
BP
126 lxc_seccomp_arch_ppc64,
127 lxc_seccomp_arch_ppc64le,
128 lxc_seccomp_arch_ppc,
2ccd9eda
JC
129 lxc_seccomp_arch_mips,
130 lxc_seccomp_arch_mips64,
131 lxc_seccomp_arch_mips64n32,
132 lxc_seccomp_arch_mipsel,
133 lxc_seccomp_arch_mipsel64,
134 lxc_seccomp_arch_mipsel64n32,
be038e49 135 lxc_seccomp_arch_s390x,
d58c6ad0
SH
136 lxc_seccomp_arch_unknown = 999,
137};
138
2ccd9eda
JC
139#ifdef __MIPSEL__
140# define MIPS_ARCH_O32 lxc_seccomp_arch_mipsel
141# define MIPS_ARCH_N64 lxc_seccomp_arch_mipsel64
142#else
143# define MIPS_ARCH_O32 lxc_seccomp_arch_mips
144# define MIPS_ARCH_N64 lxc_seccomp_arch_mips64
145#endif
146
d58c6ad0
SH
147int get_hostarch(void)
148{
149 struct utsname uts;
150 if (uname(&uts) < 0) {
f06c6207 151 SYSERROR("Failed to read host arch.");
d58c6ad0
SH
152 return -1;
153 }
154 if (strcmp(uts.machine, "i686") == 0)
155 return lxc_seccomp_arch_i386;
11de80d6 156 // no x32 kernels
d58c6ad0
SH
157 else if (strcmp(uts.machine, "x86_64") == 0)
158 return lxc_seccomp_arch_amd64;
159 else if (strncmp(uts.machine, "armv7", 5) == 0)
160 return lxc_seccomp_arch_arm;
9d291dd2
BP
161 else if (strncmp(uts.machine, "aarch64", 7) == 0)
162 return lxc_seccomp_arch_arm64;
b4067426
BP
163 else if (strncmp(uts.machine, "ppc64le", 7) == 0)
164 return lxc_seccomp_arch_ppc64le;
165 else if (strncmp(uts.machine, "ppc64", 5) == 0)
166 return lxc_seccomp_arch_ppc64;
167 else if (strncmp(uts.machine, "ppc", 3) == 0)
168 return lxc_seccomp_arch_ppc;
2ccd9eda
JC
169 else if (strncmp(uts.machine, "mips64", 6) == 0)
170 return MIPS_ARCH_N64;
171 else if (strncmp(uts.machine, "mips", 4) == 0)
172 return MIPS_ARCH_O32;
be038e49
CB
173 else if (strncmp(uts.machine, "s390x", 5) == 0)
174 return lxc_seccomp_arch_s390x;
d58c6ad0
SH
175 return lxc_seccomp_arch_unknown;
176}
177
178scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_policy_action)
179{
180 scmp_filter_ctx ctx;
181 int ret;
182 uint32_t arch;
183
184 switch(n_arch) {
185 case lxc_seccomp_arch_i386: arch = SCMP_ARCH_X86; break;
11de80d6 186 case lxc_seccomp_arch_x32: arch = SCMP_ARCH_X32; break;
d58c6ad0
SH
187 case lxc_seccomp_arch_amd64: arch = SCMP_ARCH_X86_64; break;
188 case lxc_seccomp_arch_arm: arch = SCMP_ARCH_ARM; break;
9d291dd2
BP
189#ifdef SCMP_ARCH_AARCH64
190 case lxc_seccomp_arch_arm64: arch = SCMP_ARCH_AARCH64; break;
191#endif
b4067426
BP
192#ifdef SCMP_ARCH_PPC64LE
193 case lxc_seccomp_arch_ppc64le: arch = SCMP_ARCH_PPC64LE; break;
194#endif
195#ifdef SCMP_ARCH_PPC64
196 case lxc_seccomp_arch_ppc64: arch = SCMP_ARCH_PPC64; break;
197#endif
198#ifdef SCMP_ARCH_PPC
199 case lxc_seccomp_arch_ppc: arch = SCMP_ARCH_PPC; break;
2ccd9eda
JC
200#endif
201#ifdef SCMP_ARCH_MIPS
202 case lxc_seccomp_arch_mips: arch = SCMP_ARCH_MIPS; break;
203 case lxc_seccomp_arch_mips64: arch = SCMP_ARCH_MIPS64; break;
204 case lxc_seccomp_arch_mips64n32: arch = SCMP_ARCH_MIPS64N32; break;
205 case lxc_seccomp_arch_mipsel: arch = SCMP_ARCH_MIPSEL; break;
206 case lxc_seccomp_arch_mipsel64: arch = SCMP_ARCH_MIPSEL64; break;
207 case lxc_seccomp_arch_mipsel64n32: arch = SCMP_ARCH_MIPSEL64N32; break;
be038e49
CB
208#endif
209#ifdef SCMP_ARCH_S390X
210 case lxc_seccomp_arch_s390x: arch = SCMP_ARCH_S390X; break;
b4067426 211#endif
d58c6ad0
SH
212 default: return NULL;
213 }
214
215 if ((ctx = seccomp_init(default_policy_action)) == NULL) {
f06c6207 216 ERROR("Error initializing seccomp context.");
d58c6ad0
SH
217 return NULL;
218 }
219 if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0)) {
f06c6207 220 ERROR("Failed to turn off n-new-privs.");
d58c6ad0
SH
221 seccomp_release(ctx);
222 return NULL;
223 }
127c5293
SH
224#ifdef SCMP_FLTATR_ATL_TSKIP
225 if (seccomp_attr_set(ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
226 WARN("Failed to turn on seccomp nop-skip, continuing");
227 }
228#endif
d58c6ad0
SH
229 ret = seccomp_arch_add(ctx, arch);
230 if (ret != 0) {
231 ERROR("Seccomp error %d (%s) adding arch: %d", ret,
f06c6207 232 strerror(-ret), (int)n_arch);
d58c6ad0
SH
233 seccomp_release(ctx);
234 return NULL;
235 }
236 if (seccomp_arch_remove(ctx, SCMP_ARCH_NATIVE) != 0) {
237 ERROR("Seccomp error removing native arch");
238 seccomp_release(ctx);
239 return NULL;
240 }
241
242 return ctx;
243}
244
245bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx,
246 uint32_t action)
247{
248 int nr, ret;
249
f06c6207
CB
250 ret = seccomp_arch_exist(ctx, arch);
251 if (arch && ret != 0) {
252 ERROR("BUG: Seccomp: rule and context arch do not match (arch "
253 "%d): %s.",
254 arch, strerror(-ret));
d58c6ad0
SH
255 return false;
256 }
6166fa6d
SH
257
258 if (strncmp(line, "reject_force_umount", 19) == 0) {
f06c6207 259 INFO("Setting Seccomp rule to reject force umounts.");
6166fa6d
SH
260 ret = seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(umount2),
261 1, SCMP_A1(SCMP_CMP_MASKED_EQ , MNT_FORCE , MNT_FORCE ));
262 if (ret < 0) {
f06c6207
CB
263 ERROR("Failed (%d) loading rule to reject force "
264 "umount: %s.",
265 ret, strerror(-ret));
6166fa6d
SH
266 return false;
267 }
268 return true;
269 }
270
cd75548b 271 nr = seccomp_syscall_resolve_name(line);
d58c6ad0 272 if (nr == __NR_SCMP_ERROR) {
f06c6207
CB
273 WARN("Seccomp: failed to resolve syscall: %s.", line);
274 WARN("This syscall will NOT be blacklisted.");
d58c6ad0
SH
275 return true;
276 }
277 if (nr < 0) {
f06c6207
CB
278 WARN("Seccomp: got negative for syscall: %d: %s.", nr, line);
279 WARN("This syscall will NOT be blacklisted.");
d58c6ad0
SH
280 return true;
281 }
282 ret = seccomp_rule_add_exact(ctx, action, nr, 0);
283 if (ret < 0) {
f06c6207
CB
284 ERROR("Failed (%d) loading rule for %s (nr %d action %d): %s.",
285 ret, line, nr, action, strerror(-ret));
d58c6ad0
SH
286 return false;
287 }
288 return true;
289}
290
50798138
SH
291/*
292 * v2 consists of
293 * [x86]
294 * open
295 * read
296 * write
297 * close
298 * # a comment
299 * [x86_64]
300 * open
301 * read
302 * write
303 * close
304 */
305static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
306{
50798138
SH
307 char *p;
308 int ret;
f06c6207 309 scmp_filter_ctx compat_ctx[2] = {NULL, NULL};
50798138
SH
310 bool blacklist = false;
311 uint32_t default_policy_action = -1, default_rule_action = -1, action;
d58c6ad0
SH
312 enum lxc_hostarch_t native_arch = get_hostarch(),
313 cur_rule_arch = native_arch;
f06c6207 314 uint32_t compat_arch[2] = {SCMP_ARCH_NATIVE, SCMP_ARCH_NATIVE};
50798138
SH
315
316 if (strncmp(line, "blacklist", 9) == 0)
317 blacklist = true;
318 else if (strncmp(line, "whitelist", 9) != 0) {
f06c6207 319 ERROR("Bad seccomp policy style: %s.", line);
50798138
SH
320 return -1;
321 }
322
323 if ((p = strchr(line, ' '))) {
f06c6207 324 default_policy_action = get_v2_default_action(p + 1);
50798138
SH
325 if (default_policy_action == -2)
326 return -1;
327 }
328
329 /* for blacklist, allow any syscall which has no rule */
330 if (blacklist) {
331 if (default_policy_action == -1)
332 default_policy_action = SCMP_ACT_ALLOW;
333 if (default_rule_action == -1)
334 default_rule_action = SCMP_ACT_KILL;
335 } else {
336 if (default_policy_action == -1)
337 default_policy_action = SCMP_ACT_KILL;
338 if (default_rule_action == -1)
339 default_rule_action = SCMP_ACT_ALLOW;
340 }
341
d58c6ad0
SH
342 if (native_arch == lxc_seccomp_arch_amd64) {
343 cur_rule_arch = lxc_seccomp_arch_all;
2ccd9eda
JC
344 compat_arch[0] = SCMP_ARCH_X86;
345 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_i386,
ab5e52f6 346 default_policy_action);
11de80d6
AB
347 compat_arch[1] = SCMP_ARCH_X32;
348 compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_x32,
349 default_policy_action);
350 if (!compat_ctx[0] || !compat_ctx[1])
ab5e52f6 351 goto bad;
ca399594 352#ifdef SCMP_ARCH_PPC
7635139a
SH
353 } else if (native_arch == lxc_seccomp_arch_ppc64) {
354 cur_rule_arch = lxc_seccomp_arch_all;
2ccd9eda
JC
355 compat_arch[0] = SCMP_ARCH_PPC;
356 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_ppc,
7635139a 357 default_policy_action);
2ccd9eda 358 if (!compat_ctx[0])
7635139a 359 goto bad;
ca399594
CB
360#endif
361#ifdef SCMP_ARCH_ARM
7635139a
SH
362 } else if (native_arch == lxc_seccomp_arch_arm64) {
363 cur_rule_arch = lxc_seccomp_arch_all;
2ccd9eda
JC
364 compat_arch[0] = SCMP_ARCH_ARM;
365 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_arm,
7635139a 366 default_policy_action);
2ccd9eda
JC
367 if (!compat_ctx[0])
368 goto bad;
369#endif
370#ifdef SCMP_ARCH_MIPS
371 } else if (native_arch == lxc_seccomp_arch_mips64) {
372 cur_rule_arch = lxc_seccomp_arch_all;
373 compat_arch[0] = SCMP_ARCH_MIPS;
374 compat_arch[1] = SCMP_ARCH_MIPS64N32;
375 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_mips,
376 default_policy_action);
377 compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_mips64n32,
378 default_policy_action);
379 if (!compat_ctx[0] || !compat_ctx[1])
380 goto bad;
381 } else if (native_arch == lxc_seccomp_arch_mipsel64) {
382 cur_rule_arch = lxc_seccomp_arch_all;
383 compat_arch[0] = SCMP_ARCH_MIPSEL;
384 compat_arch[1] = SCMP_ARCH_MIPSEL64N32;
385 compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_mipsel,
386 default_policy_action);
387 compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_mipsel64n32,
388 default_policy_action);
389 if (!compat_ctx[0] || !compat_ctx[1])
7635139a 390 goto bad;
be038e49 391#endif
d58c6ad0
SH
392 }
393
50798138
SH
394 if (default_policy_action != SCMP_ACT_KILL) {
395 ret = seccomp_reset(conf->seccomp_ctx, default_policy_action);
396 if (ret != 0) {
f06c6207 397 ERROR("Error re-initializing Seccomp.");
50798138
SH
398 return -1;
399 }
400 if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0)) {
f06c6207 401 ERROR("Failed to turn off n-new-privs.");
50798138
SH
402 return -1;
403 }
127c5293
SH
404#ifdef SCMP_FLTATR_ATL_TSKIP
405 if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
406 WARN("Failed to turn on seccomp nop-skip, continuing");
407 }
408#endif
50798138
SH
409 }
410
411 while (fgets(line, 1024, f)) {
50798138
SH
412
413 if (line[0] == '#')
414 continue;
415 if (strlen(line) == 0)
416 continue;
417 remove_trailing_newlines(line);
418 INFO("processing: .%s.", line);
419 if (line[0] == '[') {
420 // read the architecture for next set of rules
421 if (strcmp(line, "[x86]") == 0 ||
f06c6207 422 strcmp(line, "[X86]") == 0) {
d58c6ad0 423 if (native_arch != lxc_seccomp_arch_i386 &&
7635139a 424 native_arch != lxc_seccomp_arch_amd64) {
d58c6ad0
SH
425 cur_rule_arch = lxc_seccomp_arch_unknown;
426 continue;
427 }
428 cur_rule_arch = lxc_seccomp_arch_i386;
11de80d6
AB
429 } else if (strcmp(line, "[x32]") == 0 ||
430 strcmp(line, "[X32]") == 0) {
431 if (native_arch != lxc_seccomp_arch_amd64) {
432 cur_rule_arch = lxc_seccomp_arch_unknown;
433 continue;
434 }
435 cur_rule_arch = lxc_seccomp_arch_x32;
d58c6ad0 436 } else if (strcmp(line, "[X86_64]") == 0 ||
f06c6207 437 strcmp(line, "[x86_64]") == 0) {
d58c6ad0
SH
438 if (native_arch != lxc_seccomp_arch_amd64) {
439 cur_rule_arch = lxc_seccomp_arch_unknown;
440 continue;
441 }
442 cur_rule_arch = lxc_seccomp_arch_amd64;
d58c6ad0 443 } else if (strcmp(line, "[all]") == 0 ||
f06c6207 444 strcmp(line, "[ALL]") == 0) {
d58c6ad0 445 cur_rule_arch = lxc_seccomp_arch_all;
d58c6ad0 446 }
2b0ae718 447#ifdef SCMP_ARCH_ARM
50798138 448 else if (strcmp(line, "[arm]") == 0 ||
f06c6207 449 strcmp(line, "[ARM]") == 0) {
7635139a
SH
450 if (native_arch != lxc_seccomp_arch_arm &&
451 native_arch != lxc_seccomp_arch_arm64) {
d58c6ad0
SH
452 cur_rule_arch = lxc_seccomp_arch_unknown;
453 continue;
454 }
455 cur_rule_arch = lxc_seccomp_arch_arm;
d58c6ad0 456 }
b4067426 457#endif
9d291dd2
BP
458#ifdef SCMP_ARCH_AARCH64
459 else if (strcmp(line, "[arm64]") == 0 ||
f06c6207 460 strcmp(line, "[ARM64]") == 0) {
9d291dd2
BP
461 if (native_arch != lxc_seccomp_arch_arm64) {
462 cur_rule_arch = lxc_seccomp_arch_unknown;
463 continue;
464 }
465 cur_rule_arch = lxc_seccomp_arch_arm64;
466 }
467#endif
b4067426
BP
468#ifdef SCMP_ARCH_PPC64LE
469 else if (strcmp(line, "[ppc64le]") == 0 ||
f06c6207 470 strcmp(line, "[PPC64LE]") == 0) {
b4067426
BP
471 if (native_arch != lxc_seccomp_arch_ppc64le) {
472 cur_rule_arch = lxc_seccomp_arch_unknown;
473 continue;
474 }
475 cur_rule_arch = lxc_seccomp_arch_ppc64le;
476 }
477#endif
478#ifdef SCMP_ARCH_PPC64
479 else if (strcmp(line, "[ppc64]") == 0 ||
f06c6207 480 strcmp(line, "[PPC64]") == 0) {
b4067426
BP
481 if (native_arch != lxc_seccomp_arch_ppc64) {
482 cur_rule_arch = lxc_seccomp_arch_unknown;
483 continue;
484 }
485 cur_rule_arch = lxc_seccomp_arch_ppc64;
486 }
487#endif
488#ifdef SCMP_ARCH_PPC
489 else if (strcmp(line, "[ppc]") == 0 ||
f06c6207 490 strcmp(line, "[PPC]") == 0) {
7635139a
SH
491 if (native_arch != lxc_seccomp_arch_ppc &&
492 native_arch != lxc_seccomp_arch_ppc64) {
b4067426
BP
493 cur_rule_arch = lxc_seccomp_arch_unknown;
494 continue;
495 }
496 cur_rule_arch = lxc_seccomp_arch_ppc;
497 }
2ccd9eda
JC
498#endif
499#ifdef SCMP_ARCH_MIPS
500 else if (strcmp(line, "[mips64]") == 0 ||
f06c6207 501 strcmp(line, "[MIPS64]") == 0) {
2ccd9eda
JC
502 if (native_arch != lxc_seccomp_arch_mips64) {
503 cur_rule_arch = lxc_seccomp_arch_unknown;
504 continue;
505 }
506 cur_rule_arch = lxc_seccomp_arch_mips64;
507 } else if (strcmp(line, "[mips64n32]") == 0 ||
f06c6207 508 strcmp(line, "[MIPS64N32]") == 0) {
2ccd9eda
JC
509 if (native_arch != lxc_seccomp_arch_mips64) {
510 cur_rule_arch = lxc_seccomp_arch_unknown;
511 continue;
512 }
513 cur_rule_arch = lxc_seccomp_arch_mips64n32;
514 } else if (strcmp(line, "[mips]") == 0 ||
f06c6207 515 strcmp(line, "[MIPS]") == 0) {
2ccd9eda
JC
516 if (native_arch != lxc_seccomp_arch_mips &&
517 native_arch != lxc_seccomp_arch_mips64) {
518 cur_rule_arch = lxc_seccomp_arch_unknown;
519 continue;
520 }
521 cur_rule_arch = lxc_seccomp_arch_mips;
522 } else if (strcmp(line, "[mipsel64]") == 0 ||
f06c6207 523 strcmp(line, "[MIPSEL64]") == 0) {
2ccd9eda
JC
524 if (native_arch != lxc_seccomp_arch_mipsel64) {
525 cur_rule_arch = lxc_seccomp_arch_unknown;
526 continue;
527 }
528 cur_rule_arch = lxc_seccomp_arch_mipsel64;
529 } else if (strcmp(line, "[mipsel64n32]") == 0 ||
f06c6207 530 strcmp(line, "[MIPSEL64N32]") == 0) {
2ccd9eda
JC
531 if (native_arch != lxc_seccomp_arch_mipsel64) {
532 cur_rule_arch = lxc_seccomp_arch_unknown;
533 continue;
534 }
535 cur_rule_arch = lxc_seccomp_arch_mipsel64n32;
536 } else if (strcmp(line, "[mipsel]") == 0 ||
f06c6207 537 strcmp(line, "[MIPSEL]") == 0) {
2ccd9eda
JC
538 if (native_arch != lxc_seccomp_arch_mipsel &&
539 native_arch != lxc_seccomp_arch_mipsel64) {
540 cur_rule_arch = lxc_seccomp_arch_unknown;
541 continue;
542 }
543 cur_rule_arch = lxc_seccomp_arch_mipsel;
544 }
be038e49
CB
545#endif
546#ifdef SCMP_ARCH_S390X
547 else if (strcmp(line, "[s390x]") == 0 ||
f06c6207 548 strcmp(line, "[S390X]") == 0) {
be038e49
CB
549 if (native_arch != lxc_seccomp_arch_s390x) {
550 cur_rule_arch = lxc_seccomp_arch_unknown;
551 continue;
552 }
553 cur_rule_arch = lxc_seccomp_arch_s390x;
554 }
2b0ae718 555#endif
50798138
SH
556 else
557 goto bad_arch;
d58c6ad0 558
50798138
SH
559 continue;
560 }
561
d58c6ad0
SH
562 /* irrelevant arch - i.e. arm on i386 */
563 if (cur_rule_arch == lxc_seccomp_arch_unknown)
564 continue;
565
566 /* read optional action which follows the syscall */
50798138
SH
567 action = get_and_clear_v2_action(line, default_rule_action);
568 if (action == -1) {
f06c6207 569 ERROR("Failed to interpret action.");
50798138
SH
570 goto bad_rule;
571 }
d58c6ad0 572
d6417887
WB
573 if (cur_rule_arch == native_arch ||
574 cur_rule_arch == lxc_seccomp_arch_native ||
2ccd9eda 575 compat_arch[0] == SCMP_ARCH_NATIVE) {
f06c6207 576 INFO("Adding native rule for %s action %d.", line, action);
cd75548b 577 if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action))
d58c6ad0 578 goto bad_rule;
50798138 579 }
d6417887 580 else if (cur_rule_arch != lxc_seccomp_arch_all) {
2ccd9eda
JC
581 int arch_index =
582 cur_rule_arch == lxc_seccomp_arch_mips64n32 ||
583 cur_rule_arch == lxc_seccomp_arch_mipsel64n32 ? 1 : 0;
584
f06c6207 585 INFO("Adding compat-only rule for %s action %d.", line, action);
2ccd9eda 586 if (!do_resolve_add_rule(compat_arch[arch_index], line, compat_ctx[arch_index], action))
d6417887
WB
587 goto bad_rule;
588 }
589 else {
f06c6207 590 INFO("Adding native rule for %s action %d.", line, action);
d6417887
WB
591 if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action))
592 goto bad_rule;
f06c6207 593 INFO("Adding compat rule for %s action %d.", line, action);
2ccd9eda
JC
594 if (!do_resolve_add_rule(compat_arch[0], line, compat_ctx[0], action))
595 goto bad_rule;
596 if (compat_arch[1] != SCMP_ARCH_NATIVE &&
597 !do_resolve_add_rule(compat_arch[1], line, compat_ctx[1], action))
d58c6ad0 598 goto bad_rule;
50798138
SH
599 }
600 }
d58c6ad0 601
2ccd9eda 602 if (compat_ctx[0]) {
f06c6207 603 INFO("Merging in the compat Seccomp ctx into the main one.");
2ccd9eda
JC
604 if (seccomp_merge(conf->seccomp_ctx, compat_ctx[0]) != 0 ||
605 (compat_ctx[1] != NULL && seccomp_merge(conf->seccomp_ctx, compat_ctx[1]) != 0)) {
f06c6207 606 ERROR("Error merging compat Seccomp contexts.");
d58c6ad0 607 goto bad;
50798138
SH
608 }
609 }
6166fa6d 610
50798138
SH
611 return 0;
612
613bad_arch:
f06c6207 614 ERROR("Unsupported arch: %s.", line);
50798138 615bad_rule:
d58c6ad0 616bad:
2ccd9eda
JC
617 if (compat_ctx[0])
618 seccomp_release(compat_ctx[0]);
619 if (compat_ctx[1])
620 seccomp_release(compat_ctx[1]);
50798138 621 return -1;
d58c6ad0
SH
622}
623#else /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
624static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
625{
50798138 626 return -1;
50798138 627}
d58c6ad0 628#endif /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
50798138 629
8f2c3a70
SH
630/*
631 * The first line of the config file has a policy language version
632 * the second line has some directives
633 * then comes policy subject to the directives
634 * right now version must be '1'
635 * the directives must include 'whitelist' (only type of policy currently
636 * supported) and can include 'debug' (though debug is not yet supported).
637 */
638static int parse_config(FILE *f, struct lxc_conf *conf)
639{
640 char line[1024];
641 int ret, version;
642
643 ret = fscanf(f, "%d\n", &version);
50798138 644 if (ret != 1 || (version != 1 && version != 2)) {
f06c6207 645 ERROR("Invalid version.");
8f2c3a70
SH
646 return -1;
647 }
648 if (!fgets(line, 1024, f)) {
f06c6207 649 ERROR("Invalid config file.");
8f2c3a70
SH
650 return -1;
651 }
50798138 652 if (version == 1 && !strstr(line, "whitelist")) {
f06c6207 653 ERROR("Only whitelist policy is supported.");
8f2c3a70
SH
654 return -1;
655 }
50798138 656
8f2c3a70 657 if (strstr(line, "debug")) {
f06c6207 658 ERROR("Debug not yet implemented.");
8f2c3a70
SH
659 return -1;
660 }
50798138
SH
661
662 if (version == 1)
663 return parse_config_v1(f, conf);
664 return parse_config_v2(f, line, conf);
8f2c3a70
SH
665}
666
cd75548b
SH
667/*
668 * use_seccomp: return true if we should try and apply a seccomp policy
669 * if defined for the container.
670 * This will return false if
671 * 1. seccomp is not enabled in the kernel
672 * 2. a seccomp policy is already enabled for this task
673 */
674static bool use_seccomp(void)
d58c6ad0
SH
675{
676 FILE *f = fopen("/proc/self/status", "r");
677 char line[1024];
cd75548b
SH
678 bool already_enabled = false;
679 bool found = false;
d58c6ad0
SH
680 int ret, v;
681
682 if (!f)
cd75548b 683 return true;
d58c6ad0
SH
684
685 while (fgets(line, 1024, f)) {
686 if (strncmp(line, "Seccomp:", 8) == 0) {
cd75548b 687 found = true;
f06c6207 688 ret = sscanf(line + 8, "%d", &v);
cd75548b
SH
689 if (ret == 1 && v != 0)
690 already_enabled = true;
691 break;
d58c6ad0
SH
692 }
693 }
694
d58c6ad0 695 fclose(f);
f06c6207
CB
696 if (!found) { /* no Seccomp line, no seccomp in kernel */
697 INFO("Seccomp is not enabled in the kernel.");
cd75548b
SH
698 return false;
699 }
f06c6207
CB
700 if (already_enabled) { /* already seccomp-confined */
701 INFO("Already seccomp-confined, not loading new policy.");
cd75548b
SH
702 return false;
703 }
704 return true;
d58c6ad0
SH
705}
706
8f2c3a70
SH
707int lxc_read_seccomp_config(struct lxc_conf *conf)
708{
709 FILE *f;
710 int ret;
727c3073 711 int check_seccomp_attr_set;
8f2c3a70 712
769872f9
SH
713 if (!conf->seccomp)
714 return 0;
715
cd75548b 716 if (!use_seccomp())
d58c6ad0 717 return 0;
769872f9
SH
718#if HAVE_SCMP_FILTER_CTX
719 /* XXX for debug, pass in SCMP_ACT_TRAP */
50798138 720 conf->seccomp_ctx = seccomp_init(SCMP_ACT_KILL);
769872f9
SH
721 ret = !conf->seccomp_ctx;
722#else
50798138 723 ret = seccomp_init(SCMP_ACT_KILL) < 0;
769872f9
SH
724#endif
725 if (ret) {
f06c6207 726 ERROR("Failed initializing seccomp.");
8f2c3a70
SH
727 return -1;
728 }
8f2c3a70 729
127c5293 730/* turn off no-new-privs. We don't want it in lxc, and it breaks
f06c6207 731 * with apparmor */
769872f9 732#if HAVE_SCMP_FILTER_CTX
f06c6207 733 check_seccomp_attr_set = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0);
727c3073 734#else
f06c6207 735 check_seccomp_attr_set = seccomp_attr_set(SCMP_FLTATR_CTL_NNP, 0);
769872f9 736#endif
727c3073 737 if (check_seccomp_attr_set) {
f06c6207 738 ERROR("Failed to turn off n-new-privs.");
8f2c3a70
SH
739 return -1;
740 }
127c5293
SH
741#ifdef SCMP_FLTATR_ATL_TSKIP
742 if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
743 WARN("Failed to turn on seccomp nop-skip, continuing");
744 }
745#endif
8f2c3a70
SH
746
747 f = fopen(conf->seccomp, "r");
748 if (!f) {
f06c6207 749 SYSERROR("Failed to open seccomp policy file %s.", conf->seccomp);
8f2c3a70
SH
750 return -1;
751 }
752 ret = parse_config(f, conf);
753 fclose(f);
754 return ret;
755}
756
757int lxc_seccomp_load(struct lxc_conf *conf)
758{
759 int ret;
760 if (!conf->seccomp)
761 return 0;
cd75548b 762 if (!use_seccomp())
d58c6ad0 763 return 0;
769872f9
SH
764 ret = seccomp_load(
765#if HAVE_SCMP_FILTER_CTX
f06c6207 766 conf->seccomp_ctx
769872f9 767#endif
f06c6207 768 );
8f2c3a70 769 if (ret < 0) {
bd4307f0 770 ERROR("Error loading the seccomp policy: %s.", strerror(-ret));
8f2c3a70
SH
771 return -1;
772 }
773 return 0;
774}
769872f9 775
f06c6207
CB
776void lxc_seccomp_free(struct lxc_conf *conf)
777{
f10fad2f
ME
778 free(conf->seccomp);
779 conf->seccomp = NULL;
769872f9
SH
780#if HAVE_SCMP_FILTER_CTX
781 if (conf->seccomp_ctx) {
782 seccomp_release(conf->seccomp_ctx);
783 conf->seccomp_ctx = NULL;
784 }
785#endif
786}