]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/seccomp.c
Bug #158: Deletion of unnecessary checks before calls of the function "free"
[mirror_lxc.git] / src / lxc / seccomp.c
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
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #define _GNU_SOURCE
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <seccomp.h>
28 #include <errno.h>
29 #include <seccomp.h>
30 #include <sys/utsname.h>
31 #include <sys/mount.h>
32
33 #include "config.h"
34 #include "lxcseccomp.h"
35 #include "log.h"
36
37 lxc_log_define(lxc_seccomp, lxc);
38
39 static int parse_config_v1(FILE *f, struct lxc_conf *conf)
40 {
41 char line[1024];
42 int ret;
43
44 while (fgets(line, 1024, f)) {
45 int nr;
46 ret = sscanf(line, "%d", &nr);
47 if (ret != 1)
48 return -1;
49 ret = seccomp_rule_add(
50 #if HAVE_SCMP_FILTER_CTX
51 conf->seccomp_ctx,
52 #endif
53 SCMP_ACT_ALLOW, nr, 0);
54 if (ret < 0) {
55 ERROR("failed loading allow rule for %d", nr);
56 return ret;
57 }
58 }
59 return 0;
60 }
61
62 #if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
63 static void remove_trailing_newlines(char *l)
64 {
65 char *p = l;
66
67 while (*p)
68 p++;
69 while (--p >= l && *p == '\n')
70 *p = '\0';
71 }
72
73 static uint32_t get_v2_default_action(char *line)
74 {
75 uint32_t ret_action = -1;
76
77 while (*line == ' ') line++;
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;
83 if (sscanf(line+5, "%d", &e) != 1) {
84 ERROR("Bad errno value in %s", line);
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
95 static 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 }
115 #endif
116
117 #if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
118 enum lxc_hostarch_t {
119 lxc_seccomp_arch_all = 0,
120 lxc_seccomp_arch_native,
121 lxc_seccomp_arch_i386,
122 lxc_seccomp_arch_amd64,
123 lxc_seccomp_arch_arm,
124 lxc_seccomp_arch_unknown = 999,
125 };
126
127 int get_hostarch(void)
128 {
129 struct utsname uts;
130 if (uname(&uts) < 0) {
131 SYSERROR("Failed to read host arch");
132 return -1;
133 }
134 if (strcmp(uts.machine, "i686") == 0)
135 return lxc_seccomp_arch_i386;
136 else if (strcmp(uts.machine, "x86_64") == 0)
137 return lxc_seccomp_arch_amd64;
138 else if (strncmp(uts.machine, "armv7", 5) == 0)
139 return lxc_seccomp_arch_arm;
140 return lxc_seccomp_arch_unknown;
141 }
142
143 scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_policy_action)
144 {
145 scmp_filter_ctx ctx;
146 int ret;
147 uint32_t arch;
148
149 switch(n_arch) {
150 case lxc_seccomp_arch_i386: arch = SCMP_ARCH_X86; break;
151 case lxc_seccomp_arch_amd64: arch = SCMP_ARCH_X86_64; break;
152 case lxc_seccomp_arch_arm: arch = SCMP_ARCH_ARM; break;
153 default: return NULL;
154 }
155
156 if ((ctx = seccomp_init(default_policy_action)) == NULL) {
157 ERROR("Error initializing seccomp context");
158 return NULL;
159 }
160 if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0)) {
161 ERROR("failed to turn off n-new-privs");
162 seccomp_release(ctx);
163 return NULL;
164 }
165 ret = seccomp_arch_add(ctx, arch);
166 if (ret != 0) {
167 ERROR("Seccomp error %d (%s) adding arch: %d", ret,
168 strerror(ret), (int)n_arch);
169 seccomp_release(ctx);
170 return NULL;
171 }
172 if (seccomp_arch_remove(ctx, SCMP_ARCH_NATIVE) != 0) {
173 ERROR("Seccomp error removing native arch");
174 seccomp_release(ctx);
175 return NULL;
176 }
177
178 return ctx;
179 }
180
181 bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx,
182 uint32_t action)
183 {
184 int nr, ret;
185
186 if (arch && seccomp_arch_exist(ctx, arch) != 0) {
187 ERROR("BUG: seccomp: rule and context arch do not match (arch %d)", arch);
188 return false;
189 }
190
191 if (strncmp(line, "reject_force_umount", 19) == 0) {
192 INFO("Setting seccomp rule to reject force umounts\n");
193 ret = seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(umount2),
194 1, SCMP_A1(SCMP_CMP_MASKED_EQ , MNT_FORCE , MNT_FORCE ));
195 if (ret < 0) {
196 ERROR("failed (%d) loading rule to reject force umount", ret);
197 return false;
198 }
199 return true;
200 }
201
202 nr = seccomp_syscall_resolve_name(line);
203 if (nr == __NR_SCMP_ERROR) {
204 WARN("Seccomp: failed to resolve syscall: %s", line);
205 WARN("This syscall will NOT be blacklisted");
206 return true;
207 }
208 if (nr < 0) {
209 WARN("Seccomp: got negative # for syscall: %s", line);
210 WARN("This syscall will NOT be blacklisted");
211 return true;
212 }
213 ret = seccomp_rule_add_exact(ctx, action, nr, 0);
214 if (ret < 0) {
215 ERROR("failed (%d) loading rule for %s (nr %d action %d)", ret, line, nr, action);
216 return false;
217 }
218 return true;
219 }
220
221 /*
222 * v2 consists of
223 * [x86]
224 * open
225 * read
226 * write
227 * close
228 * # a comment
229 * [x86_64]
230 * open
231 * read
232 * write
233 * close
234 */
235 static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
236 {
237 char *p;
238 int ret;
239 scmp_filter_ctx compat_ctx = NULL;
240 bool blacklist = false;
241 uint32_t default_policy_action = -1, default_rule_action = -1, action;
242 enum lxc_hostarch_t native_arch = get_hostarch(),
243 cur_rule_arch = native_arch;
244
245 if (strncmp(line, "blacklist", 9) == 0)
246 blacklist = true;
247 else if (strncmp(line, "whitelist", 9) != 0) {
248 ERROR("Bad seccomp policy style: %s", line);
249 return -1;
250 }
251
252 if ((p = strchr(line, ' '))) {
253 default_policy_action = get_v2_default_action(p+1);
254 if (default_policy_action == -2)
255 return -1;
256 }
257
258 /* for blacklist, allow any syscall which has no rule */
259 if (blacklist) {
260 if (default_policy_action == -1)
261 default_policy_action = SCMP_ACT_ALLOW;
262 if (default_rule_action == -1)
263 default_rule_action = SCMP_ACT_KILL;
264 } else {
265 if (default_policy_action == -1)
266 default_policy_action = SCMP_ACT_KILL;
267 if (default_rule_action == -1)
268 default_rule_action = SCMP_ACT_ALLOW;
269 }
270
271 if (native_arch == lxc_seccomp_arch_amd64) {
272 cur_rule_arch = lxc_seccomp_arch_all;
273 compat_ctx = get_new_ctx(lxc_seccomp_arch_i386,
274 default_policy_action);
275 if (!compat_ctx)
276 goto bad;
277 }
278
279 if (default_policy_action != SCMP_ACT_KILL) {
280 ret = seccomp_reset(conf->seccomp_ctx, default_policy_action);
281 if (ret != 0) {
282 ERROR("Error re-initializing seccomp");
283 return -1;
284 }
285 if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0)) {
286 ERROR("failed to turn off n-new-privs");
287 return -1;
288 }
289 }
290
291 while (fgets(line, 1024, f)) {
292
293 if (line[0] == '#')
294 continue;
295 if (strlen(line) == 0)
296 continue;
297 remove_trailing_newlines(line);
298 INFO("processing: .%s.", line);
299 if (line[0] == '[') {
300 // read the architecture for next set of rules
301 if (strcmp(line, "[x86]") == 0 ||
302 strcmp(line, "[X86]") == 0) {
303 if (native_arch != lxc_seccomp_arch_i386 &&
304 native_arch != lxc_seccomp_arch_amd64) {
305 cur_rule_arch = lxc_seccomp_arch_unknown;
306 continue;
307 }
308 cur_rule_arch = lxc_seccomp_arch_i386;
309 if (native_arch == lxc_seccomp_arch_amd64) {
310 if (compat_ctx)
311 continue;
312 compat_ctx = get_new_ctx(lxc_seccomp_arch_i386,
313 default_policy_action);
314 if (!compat_ctx)
315 goto bad;
316 }
317 } else if (strcmp(line, "[X86_64]") == 0 ||
318 strcmp(line, "[x86_64]") == 0) {
319 if (native_arch != lxc_seccomp_arch_amd64) {
320 cur_rule_arch = lxc_seccomp_arch_unknown;
321 continue;
322 }
323 cur_rule_arch = lxc_seccomp_arch_amd64;
324 } else if (strcmp(line, "[all]") == 0 ||
325 strcmp(line, "[ALL]") == 0) {
326 cur_rule_arch = lxc_seccomp_arch_all;
327 if (native_arch == lxc_seccomp_arch_amd64 && !compat_ctx) {
328 if (compat_ctx)
329 continue;
330 compat_ctx = get_new_ctx(lxc_seccomp_arch_i386,
331 default_policy_action);
332 if (!compat_ctx)
333 goto bad;
334 }
335 }
336 #ifdef SCMP_ARCH_ARM
337 else if (strcmp(line, "[arm]") == 0 ||
338 strcmp(line, "[ARM]") == 0) {
339 if (native_arch != lxc_seccomp_arch_arm) {
340 cur_rule_arch = lxc_seccomp_arch_unknown;
341 continue;
342 }
343 cur_rule_arch = lxc_seccomp_arch_arm;
344 }
345 #endif
346 else
347 goto bad_arch;
348
349 continue;
350 }
351
352 /* irrelevant arch - i.e. arm on i386 */
353 if (cur_rule_arch == lxc_seccomp_arch_unknown)
354 continue;
355
356 /* read optional action which follows the syscall */
357 action = get_and_clear_v2_action(line, default_rule_action);
358 if (action == -1) {
359 ERROR("Failed to interpret action");
360 goto bad_rule;
361 }
362
363 /*
364 * TODO generalize - if !is_compat_only(native_arch, cur_rule_arch)
365 *
366 * in other words, the rule is 32-bit only, on 64-bit host; don't run
367 * the rule against the native arch.
368 */
369 if (!(cur_rule_arch == lxc_seccomp_arch_i386 &&
370 native_arch == lxc_seccomp_arch_amd64)) {
371 INFO("Adding non-compat rule for %s action %d", line, action);
372 if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action))
373 goto bad_rule;
374 }
375
376 /*
377 * TODO generalize - if need_compat(native_arch, cur_rule_arch)
378 */
379 if (native_arch == lxc_seccomp_arch_amd64 &&
380 cur_rule_arch != lxc_seccomp_arch_amd64) {
381 int nr1, nr2;
382 INFO("Adding compat rule for %s action %d", line, action);
383 nr1 = seccomp_syscall_resolve_name_arch(SCMP_ARCH_X86, line);
384 nr2 = seccomp_syscall_resolve_name_arch(SCMP_ARCH_NATIVE, line);
385 if (nr1 == nr2) {
386 /* If the syscall # is the same for 32- and 64-bit, then we cannot
387 * apply it to the compat_ctx. So apply it to the noncompat ctx.
388 * We may already have done so, but that's ok
389 */
390 INFO("Adding non-compat rule bc nr1 == nr2 (%d, %d)", nr1, nr2);
391 if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action))
392 goto bad_rule;
393 continue;
394 }
395 INFO("Really adding compat rule bc nr1 == nr2 (%d, %d)", nr1, nr2);
396 if (!do_resolve_add_rule(SCMP_ARCH_X86, line,
397 compat_ctx, action))
398 goto bad_rule;
399 }
400 }
401
402 if (compat_ctx) {
403 INFO("Merging in the compat seccomp ctx into the main one");
404 if (seccomp_merge(conf->seccomp_ctx, compat_ctx) != 0) {
405 ERROR("Error merging i386 seccomp contexts");
406 goto bad;
407 }
408 }
409
410 return 0;
411
412 bad_arch:
413 ERROR("Unsupported arch: %s", line);
414 bad_rule:
415 bad:
416 if (compat_ctx)
417 seccomp_release(compat_ctx);
418 return -1;
419 }
420 #else /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
421 static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
422 {
423 return -1;
424 }
425 #endif /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
426
427 /*
428 * The first line of the config file has a policy language version
429 * the second line has some directives
430 * then comes policy subject to the directives
431 * right now version must be '1'
432 * the directives must include 'whitelist' (only type of policy currently
433 * supported) and can include 'debug' (though debug is not yet supported).
434 */
435 static int parse_config(FILE *f, struct lxc_conf *conf)
436 {
437 char line[1024];
438 int ret, version;
439
440 ret = fscanf(f, "%d\n", &version);
441 if (ret != 1 || (version != 1 && version != 2)) {
442 ERROR("invalid version");
443 return -1;
444 }
445 if (!fgets(line, 1024, f)) {
446 ERROR("invalid config file");
447 return -1;
448 }
449 if (version == 1 && !strstr(line, "whitelist")) {
450 ERROR("only whitelist policy is supported");
451 return -1;
452 }
453
454 if (strstr(line, "debug")) {
455 ERROR("debug not yet implemented");
456 return -1;
457 }
458
459 if (version == 1)
460 return parse_config_v1(f, conf);
461 return parse_config_v2(f, line, conf);
462 }
463
464 /*
465 * use_seccomp: return true if we should try and apply a seccomp policy
466 * if defined for the container.
467 * This will return false if
468 * 1. seccomp is not enabled in the kernel
469 * 2. a seccomp policy is already enabled for this task
470 */
471 static bool use_seccomp(void)
472 {
473 FILE *f = fopen("/proc/self/status", "r");
474 char line[1024];
475 bool already_enabled = false;
476 bool found = false;
477 int ret, v;
478
479 if (!f)
480 return true;
481
482 while (fgets(line, 1024, f)) {
483 if (strncmp(line, "Seccomp:", 8) == 0) {
484 found = true;
485 ret = sscanf(line+8, "%d", &v);
486 if (ret == 1 && v != 0)
487 already_enabled = true;
488 break;
489 }
490 }
491
492 fclose(f);
493 if (!found) { /* no Seccomp line, no seccomp in kernel */
494 INFO("Seccomp is not enabled in the kernel");
495 return false;
496 }
497 if (already_enabled) { /* already seccomp-confined */
498 INFO("Already seccomp-confined, not loading new policy");
499 return false;
500 }
501 return true;
502 }
503
504 int lxc_read_seccomp_config(struct lxc_conf *conf)
505 {
506 FILE *f;
507 int ret;
508
509 if (!conf->seccomp)
510 return 0;
511
512 if (!use_seccomp())
513 return 0;
514 #if HAVE_SCMP_FILTER_CTX
515 /* XXX for debug, pass in SCMP_ACT_TRAP */
516 conf->seccomp_ctx = seccomp_init(SCMP_ACT_KILL);
517 ret = !conf->seccomp_ctx;
518 #else
519 ret = seccomp_init(SCMP_ACT_KILL) < 0;
520 #endif
521 if (ret) {
522 ERROR("failed initializing seccomp");
523 return -1;
524 }
525
526 /* turn of no-new-privs. We don't want it in lxc, and it breaks
527 * with apparmor */
528 if (seccomp_attr_set(
529 #if HAVE_SCMP_FILTER_CTX
530 conf->seccomp_ctx,
531 #endif
532 SCMP_FLTATR_CTL_NNP, 0)) {
533 ERROR("failed to turn off n-new-privs");
534 return -1;
535 }
536
537 f = fopen(conf->seccomp, "r");
538 if (!f) {
539 SYSERROR("failed to open seccomp policy file %s", conf->seccomp);
540 return -1;
541 }
542 ret = parse_config(f, conf);
543 fclose(f);
544 return ret;
545 }
546
547 int lxc_seccomp_load(struct lxc_conf *conf)
548 {
549 int ret;
550 if (!conf->seccomp)
551 return 0;
552 if (!use_seccomp())
553 return 0;
554 ret = seccomp_load(
555 #if HAVE_SCMP_FILTER_CTX
556 conf->seccomp_ctx
557 #endif
558 );
559 if (ret < 0) {
560 ERROR("Error loading the seccomp policy");
561 return -1;
562 }
563 return 0;
564 }
565
566 void lxc_seccomp_free(struct lxc_conf *conf) {
567 free(conf->seccomp);
568 conf->seccomp = NULL;
569 #if HAVE_SCMP_FILTER_CTX
570 if (conf->seccomp_ctx) {
571 seccomp_release(conf->seccomp_ctx);
572 conf->seccomp_ctx = NULL;
573 }
574 #endif
575 }