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