Пример #1
0
int lxc_read_seccomp_config(struct lxc_conf *conf)
{
	FILE *f;
	int ret;
	int check_seccomp_attr_set;

	if (!conf->seccomp)
		return 0;

	if (!use_seccomp())
		return 0;
#if HAVE_SCMP_FILTER_CTX
	/* XXX for debug, pass in SCMP_ACT_TRAP */
	conf->seccomp_ctx = seccomp_init(SCMP_ACT_KILL);
	ret = !conf->seccomp_ctx;
#else
	ret = seccomp_init(SCMP_ACT_KILL) < 0;
#endif
	if (ret) {
		ERROR("Failed initializing seccomp.");
		return -1;
	}

/* turn off no-new-privs.  We don't want it in lxc, and it breaks
 * with apparmor */
#if HAVE_SCMP_FILTER_CTX
	check_seccomp_attr_set = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0);
#else
	check_seccomp_attr_set = seccomp_attr_set(SCMP_FLTATR_CTL_NNP, 0);
#endif
	if (check_seccomp_attr_set) {
		ERROR("Failed to turn off n-new-privs.");
		return -1;
	}
#ifdef SCMP_FLTATR_ATL_TSKIP
	if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
		WARN("Failed to turn on seccomp nop-skip, continuing");
	}
#endif

	f = fopen(conf->seccomp, "r");
	if (!f) {
		SYSERROR("Failed to open seccomp policy file %s.", conf->seccomp);
		return -1;
	}
	ret = parse_config(f, conf);
	fclose(f);
	return ret;
}
Пример #2
0
scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_policy_action)
{
	scmp_filter_ctx ctx;
	int ret;
	uint32_t arch;

	switch(n_arch) {
	case lxc_seccomp_arch_i386: arch = SCMP_ARCH_X86; break;
	case lxc_seccomp_arch_amd64: arch = SCMP_ARCH_X86_64; break;
	case lxc_seccomp_arch_arm: arch = SCMP_ARCH_ARM; break;
#ifdef SCMP_ARCH_PPC64LE
	case lxc_seccomp_arch_ppc64le: arch = SCMP_ARCH_PPC64LE; break;
#endif
#ifdef SCMP_ARCH_PPC64
	case lxc_seccomp_arch_ppc64: arch = SCMP_ARCH_PPC64; break;
#endif
#ifdef SCMP_ARCH_PPC
	case lxc_seccomp_arch_ppc: arch = SCMP_ARCH_PPC; break;
#endif
	default: return NULL;
	}

	if ((ctx = seccomp_init(default_policy_action)) == NULL) {
		ERROR("Error initializing seccomp context");
		return NULL;
	}
	if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0)) {
		ERROR("failed to turn off n-new-privs");
		seccomp_release(ctx);
		return NULL;
	}
	ret = seccomp_arch_add(ctx, arch);
	if (ret != 0) {
		ERROR("Seccomp error %d (%s) adding arch: %d", ret,
				strerror(ret), (int)n_arch);
		seccomp_release(ctx);
		return NULL;
	}
	if (seccomp_arch_remove(ctx, SCMP_ARCH_NATIVE) != 0) {
		ERROR("Seccomp error removing native arch");
		seccomp_release(ctx);
		return NULL;
	}

	return ctx;
}
Пример #3
0
int lxc_read_seccomp_config(struct lxc_conf *conf)
{
	FILE *f;
	int ret;

	if (!conf->seccomp)
		return 0;

#if HAVE_SCMP_FILTER_CTX
	/* XXX for debug, pass in SCMP_ACT_TRAP */
	conf->seccomp_ctx = seccomp_init(SCMP_ACT_ERRNO(31));
	ret = !conf->seccomp_ctx;
#else
	ret = seccomp_init(SCMP_ACT_ERRNO(31)) < 0;
#endif
	if (ret) {
		ERROR("failed initializing seccomp");
		return -1;
	}

	/* turn of no-new-privs.  We don't want it in lxc, and it breaks
	 * with apparmor */
	if (seccomp_attr_set(
#if HAVE_SCMP_FILTER_CTX
			conf->seccomp_ctx,
#endif
			SCMP_FLTATR_CTL_NNP, 0)) {
		ERROR("failed to turn off n-new-privs\n");
		return -1;
	}

	process_lock();
	f = fopen(conf->seccomp, "r");
	process_unlock();
	if (!f) {
		SYSERROR("failed to open seccomp policy file %s\n", conf->seccomp);
		return -1;
	}
	ret = parse_config(f, conf);
	process_lock();
	fclose(f);
	process_unlock();
	return ret;
}
Пример #4
0
scmp_filter_ctx sc_prepare_seccomp_context(const char *filter_profile)
{
	int rc = 0;
	scmp_filter_ctx ctx = NULL;
	FILE *f = NULL;
	size_t lineno = 0;
	uid_t real_uid, effective_uid, saved_uid;
	struct preprocess pre;
	struct seccomp_args sargs;

	debug("preparing seccomp profile associated with security tag %s",
	      filter_profile);

	// initialize hsearch map
	sc_map_init();

	ctx = seccomp_init(SCMP_ACT_KILL);
	if (ctx == NULL) {
		errno = ENOMEM;
		die("seccomp_init() failed");
	}
	// Setup native arch and any compatibility archs
	sc_add_seccomp_archs(ctx);

	// Disable NO_NEW_PRIVS because it interferes with exec transitions in
	// AppArmor. Unfortunately this means that security policies must be
	// very careful to not allow the following otherwise apps can escape
	// the sandbox:
	//   - seccomp syscall
	//   - prctl with PR_SET_SECCOMP
	//   - ptrace (trace) in AppArmor
	//   - capability sys_admin in AppArmor
	// Note that with NO_NEW_PRIVS disabled, CAP_SYS_ADMIN is required to
	// change the seccomp sandbox.

	if (getresuid(&real_uid, &effective_uid, &saved_uid) != 0)
		die("could not find user IDs");

	// If running privileged or capable of raising, disable nnp
	if (real_uid == 0 || effective_uid == 0 || saved_uid == 0)
		if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0) != 0)
			die("Cannot disable nnp");

	// Note that secure_gettenv will always return NULL when suid, so
	// SNAPPY_LAUNCHER_SECCOMP_PROFILE_DIR can't be (ab)used in that case.
	if (secure_getenv("SNAPPY_LAUNCHER_SECCOMP_PROFILE_DIR") != NULL)
		filter_profile_dir =
		    secure_getenv("SNAPPY_LAUNCHER_SECCOMP_PROFILE_DIR");

	char profile_path[512];	// arbitrary path name limit
	must_snprintf(profile_path, sizeof(profile_path), "%s/%s",
		      filter_profile_dir, filter_profile);

	f = fopen(profile_path, "r");
	if (f == NULL) {
		fprintf(stderr, "Can not open %s (%s)\n", profile_path,
			strerror(errno));
		die("aborting");
	}
	// Note, preprocess_filter() die()s on error
	preprocess_filter(f, &pre);

	if (pre.unrestricted) {
		seccomp_release(ctx);
		ctx = NULL;
		goto out;
	}
	// FIXME: right now complain mode is the equivalent to unrestricted.
	// We'll want to change this once we seccomp logging is in order.
	if (pre.complain) {
		seccomp_release(ctx);
		ctx = NULL;
		goto out;
	}

	char buf[SC_MAX_LINE_LENGTH];
	while (fgets(buf, sizeof(buf), f) != NULL) {
		lineno++;

		// skip policy-irrelevant lines
		if (validate_and_trim_line(buf, sizeof(buf), lineno) == 0)
			continue;

		char *buf_copy = strdup(buf);
		if (buf_copy == NULL)
			die("Out of memory");

		int pr_rc = parse_line(buf_copy, &sargs);
		free(buf_copy);
		if (pr_rc != PARSE_OK) {
			// as this is a syscall whitelist an invalid syscall
			// is ok and the error can be ignored
			if (pr_rc == PARSE_INVALID_SYSCALL)
				continue;
			die("could not parse line");
		}

		rc = seccomp_rule_add_exact_array(ctx, SCMP_ACT_ALLOW,
						  sargs.syscall_nr,
						  sargs.length, sargs.arg_cmp);
		if (rc != 0) {
			rc = seccomp_rule_add_array(ctx, SCMP_ACT_ALLOW,
						    sargs.syscall_nr,
						    sargs.length,
						    sargs.arg_cmp);
			if (rc != 0) {
				fprintf(stderr,
					"seccomp_rule_add_array failed with %i for '%s'\n",
					rc, buf);
				errno = 0;
				die("aborting");
			}
		}
	}

 out:
	if (f != NULL) {
		if (fclose(f) != 0)
			die("could not close seccomp file");
	}
	sc_map_destroy();
	return ctx;
}
int pcm_json_to_seccomp(char **hook)
{
	json_t *str, *rules, *hook_obj;
	u_int32_t default_action;
	int i, rc;



	if(hook) *hook = NULL; // initialize to a sane value

	/* Verify it's what we expect */
	if(! json_is_object(PCM_GLOBAL.policy)) {
		errx(EXIT_FAILURE, "root is not an object");
	}	

	/* Get the default action */
	str = json_object_get(PCM_GLOBAL.policy, "default");
	if(! json_is_string(str)) {
		errx(EXIT_FAILURE, "expected string, didn't get it :/");
	}

	default_action = pcm_string_to_policy(json_string_value(str));
	if(default_action == -1) {
		errx(EXIT_FAILURE, "converting default policy string failed, expecting ALLOW, KILL, or ERRNO");
	}

	/* Initialize seccomp with the default action */
	PCM_GLOBAL.seccomp = seccomp_init(default_action);
	if(PCM_GLOBAL.seccomp == NULL) {
		errx(EXIT_FAILURE, "Initializing seccomp context failed");
	}

	str = json_object_get(PCM_GLOBAL.policy, "no_new_privs");
	if(str) {
		// for another day, default version of jansson on this system doesn't have it.
		// int status;
		// status = json_boolean(str);
		// we'll assume they want to disable it.

		rc = seccomp_attr_set(PCM_GLOBAL.seccomp, SCMP_FLTATR_CTL_NNP, 0);	
		if(! rc) {
			errx(EXIT_FAILURE, "Unable to set no_new_privs attribute to off (%m) and rc = %d, -rc = %d\n", rc, -rc);
		}
	}

	/* And loop over the rules */

	rules = json_object_get(PCM_GLOBAL.policy, "rules");
	if(! json_is_array(rules)) {
		errx(EXIT_FAILURE, "Getting policy rules from json failed");
	}

	if(hook) {
		// XXX, should the file hook value overwrite env var etc?
		// should we just pcm_hook_set() here?
		hook_obj = json_object_get(PCM_GLOBAL.policy, "hook");
		if(hook_obj) {
			if(! json_is_string(hook_obj)) {
				errx(EXIT_FAILURE, "expected hook string, didn't get it :/");
			}

			*hook = strdup(json_string_value(hook_obj));
		}
	}

	for(i = 0; i < json_array_size(rules); i++) {
		json_t *rule;


		rule = json_array_get(rules, i);
		if(! json_is_object(rule)) {
			errx(EXIT_FAILURE, "Expected rule object, got something else instead");
		}
		
		pcm_json_rule_to_seccomp(rule);
	}

	pcm_policy_free();

	return 0;
}
Пример #6
0
int setup_seccomp(uint64_t cap_list_retain) {
        scmp_filter_ctx seccomp;
        int r;

        seccomp = seccomp_init(SCMP_ACT_ALLOW);
        if (!seccomp)
                return log_oom();

        r = seccomp_add_secondary_archs(seccomp);
        if (r < 0) {
                log_error_errno(r, "Failed to add secondary archs to seccomp filter: %m");
                goto finish;
        }

        r = seccomp_add_default_syscall_filter(seccomp, cap_list_retain);
        if (r < 0)
                goto finish;

        /*
           Audit is broken in containers, much of the userspace audit
           hookup will fail if running inside a container. We don't
           care and just turn off creation of audit sockets.

           This will make socket(AF_NETLINK, *, NETLINK_AUDIT) fail
           with EAFNOSUPPORT which audit userspace uses as indication
           that audit is disabled in the kernel.
         */

        r = seccomp_rule_add(
                        seccomp,
                        SCMP_ACT_ERRNO(EAFNOSUPPORT),
                        SCMP_SYS(socket),
                        2,
                        SCMP_A0(SCMP_CMP_EQ, AF_NETLINK),
                        SCMP_A2(SCMP_CMP_EQ, NETLINK_AUDIT));
        if (r < 0) {
                log_error_errno(r, "Failed to add audit seccomp rule: %m");
                goto finish;
        }

        r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0);
        if (r < 0) {
                log_error_errno(r, "Failed to unset NO_NEW_PRIVS: %m");
                goto finish;
        }

        r = seccomp_load(seccomp);
        if (r == -EINVAL) {
                log_debug_errno(r, "Kernel is probably not configured with CONFIG_SECCOMP. Disabling seccomp audit filter: %m");
                r = 0;
                goto finish;
        }
        if (r < 0) {
                log_error_errno(r, "Failed to install seccomp audit filter: %m");
                goto finish;
        }

finish:
        seccomp_release(seccomp);
        return r;
}
Пример #7
0
/*
 * v2 consists of
 * [x86]
 * open
 * read
 * write
 * close
 * # a comment
 * [x86_64]
 * open
 * read
 * write
 * close
 */
static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
{
	char *p;
	int ret;
	scmp_filter_ctx compat_ctx = NULL;
	bool blacklist = false;
	uint32_t default_policy_action = -1, default_rule_action = -1, action;
	enum lxc_hostarch_t native_arch = get_hostarch(),
			    cur_rule_arch = native_arch;

	if (strncmp(line, "blacklist", 9) == 0)
		blacklist = true;
	else if (strncmp(line, "whitelist", 9) != 0) {
		ERROR("Bad seccomp policy style: %s", line);
		return -1;
	}

	if ((p = strchr(line, ' '))) {
		default_policy_action = get_v2_default_action(p+1);
		if (default_policy_action == -2)
			return -1;
	}

	/* for blacklist, allow any syscall which has no rule */
	if (blacklist) {
		if (default_policy_action == -1)
			default_policy_action = SCMP_ACT_ALLOW;
		if (default_rule_action == -1)
			default_rule_action = SCMP_ACT_KILL;
	} else {
		if (default_policy_action == -1)
			default_policy_action = SCMP_ACT_KILL;
		if (default_rule_action == -1)
			default_rule_action = SCMP_ACT_ALLOW;
	}

	if (native_arch == lxc_seccomp_arch_amd64) {
		cur_rule_arch = lxc_seccomp_arch_all;
		compat_ctx = get_new_ctx(lxc_seccomp_arch_i386,
				default_policy_action);
		if (!compat_ctx)
			goto bad;
	}

	if (default_policy_action != SCMP_ACT_KILL) {
		ret = seccomp_reset(conf->seccomp_ctx, default_policy_action);
		if (ret != 0) {
			ERROR("Error re-initializing seccomp");
			return -1;
		}
		if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0)) {
			ERROR("failed to turn off n-new-privs");
			return -1;
		}
	}

	while (fgets(line, 1024, f)) {

		if (line[0] == '#')
			continue;
		if (strlen(line) == 0)
			continue;
		remove_trailing_newlines(line);
		INFO("processing: .%s.", line);
		if (line[0] == '[') {
			// read the architecture for next set of rules
			if (strcmp(line, "[x86]") == 0 ||
					strcmp(line, "[X86]") == 0) {
				if (native_arch != lxc_seccomp_arch_i386 &&
					native_arch != lxc_seccomp_arch_amd64) {
					cur_rule_arch = lxc_seccomp_arch_unknown;
					continue;
				}
				cur_rule_arch = lxc_seccomp_arch_i386;
				if (native_arch == lxc_seccomp_arch_amd64) {
					if (compat_ctx)
						continue;
					compat_ctx = get_new_ctx(lxc_seccomp_arch_i386,
							default_policy_action);
					if (!compat_ctx)
						goto bad;
				}
			} else if (strcmp(line, "[X86_64]") == 0 ||
					strcmp(line, "[x86_64]") == 0) {
				if (native_arch != lxc_seccomp_arch_amd64) {
					cur_rule_arch = lxc_seccomp_arch_unknown;
					continue;
				}
				cur_rule_arch = lxc_seccomp_arch_amd64;
			} else if (strcmp(line, "[all]") == 0 ||
					strcmp(line, "[ALL]") == 0) {
				cur_rule_arch = lxc_seccomp_arch_all;
				if (native_arch == lxc_seccomp_arch_amd64 && !compat_ctx) {
					if (compat_ctx)
						continue;
					compat_ctx = get_new_ctx(lxc_seccomp_arch_i386,
							default_policy_action);
					if (!compat_ctx)
						goto bad;
				}
			}
#ifdef SCMP_ARCH_ARM
			else if (strcmp(line, "[arm]") == 0 ||
					strcmp(line, "[ARM]") == 0) {
				if (native_arch != lxc_seccomp_arch_arm) {
					cur_rule_arch = lxc_seccomp_arch_unknown;
					continue;
				}
				cur_rule_arch = lxc_seccomp_arch_arm;
			}
#endif
#ifdef SCMP_ARCH_PPC64LE
			else if (strcmp(line, "[ppc64le]") == 0 ||
					strcmp(line, "[PPC64LE]") == 0) {
				if (native_arch != lxc_seccomp_arch_ppc64le) {
					cur_rule_arch = lxc_seccomp_arch_unknown;
					continue;
				}
				cur_rule_arch = lxc_seccomp_arch_ppc64le;
			}
#endif
#ifdef SCMP_ARCH_PPC64
			else if (strcmp(line, "[ppc64]") == 0 ||
					strcmp(line, "[PPC64]") == 0) {
				if (native_arch != lxc_seccomp_arch_ppc64) {
					cur_rule_arch = lxc_seccomp_arch_unknown;
					continue;
				}
				cur_rule_arch = lxc_seccomp_arch_ppc64;
			}
#endif
#ifdef SCMP_ARCH_PPC
			else if (strcmp(line, "[ppc]") == 0 ||
					strcmp(line, "[PPC]") == 0) {
				if (native_arch != lxc_seccomp_arch_ppc) {
					cur_rule_arch = lxc_seccomp_arch_unknown;
					continue;
				}
				cur_rule_arch = lxc_seccomp_arch_ppc;
			}
#endif
			else
				goto bad_arch;

			continue;
		}

		/* irrelevant arch - i.e. arm on i386 */
		if (cur_rule_arch == lxc_seccomp_arch_unknown)
			continue;

		/* read optional action which follows the syscall */
		action = get_and_clear_v2_action(line, default_rule_action);
		if (action == -1) {
			ERROR("Failed to interpret action");
			goto bad_rule;
		}

		/*
		 * TODO generalize - if !is_compat_only(native_arch, cur_rule_arch)
		 *
		 * in other words, the rule is 32-bit only, on 64-bit host;  don't run
		 * the rule against the native arch.
		 */
		if (!(cur_rule_arch == lxc_seccomp_arch_i386 &&
			native_arch == lxc_seccomp_arch_amd64)) {
			INFO("Adding non-compat rule for %s action %d", line, action);
			if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action))
				goto bad_rule;
		}

		/*
		 * TODO generalize - if need_compat(native_arch, cur_rule_arch)
		 */
		if (native_arch == lxc_seccomp_arch_amd64 &&
			cur_rule_arch != lxc_seccomp_arch_amd64) {
			int nr1, nr2;
			INFO("Adding compat rule for %s action %d", line, action);
			nr1 = seccomp_syscall_resolve_name_arch(SCMP_ARCH_X86, line);
			nr2 = seccomp_syscall_resolve_name_arch(SCMP_ARCH_NATIVE, line);
			if (nr1 == nr2) {
				/* If the syscall # is the same for 32- and 64-bit, then we cannot
				 * apply it to the compat_ctx.  So apply it to the noncompat ctx.
				 * We may already have done so, but that's ok
				 */
				INFO("Adding non-compat rule bc nr1 == nr2 (%d, %d)", nr1, nr2);
				if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action))
					goto bad_rule;
				continue;
			}
			INFO("Really adding compat rule bc nr1 == nr2 (%d, %d)", nr1, nr2);
			if (!do_resolve_add_rule(SCMP_ARCH_X86, line,
						compat_ctx, action))
				goto bad_rule;
		}
	}

	if (compat_ctx) {
		INFO("Merging in the compat seccomp ctx into the main one");
		if (seccomp_merge(conf->seccomp_ctx, compat_ctx) != 0) {
			ERROR("Error merging i386 seccomp contexts");
			goto bad;
		}
	}

	return 0;

bad_arch:
	ERROR("Unsupported arch: %s", line);
bad_rule:
bad:
	if (compat_ctx)
		seccomp_release(compat_ctx);
	return -1;
}
Пример #8
0
/*
 * v2 consists of
 * [x86]
 * open
 * read
 * write
 * close
 * # a comment
 * [x86_64]
 * open
 * read
 * write
 * close
 */
static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
{
	char *p;
	int ret;
	scmp_filter_ctx compat_ctx[2] = {NULL, NULL};
	bool blacklist = false;
	uint32_t default_policy_action = -1, default_rule_action = -1, action;
	enum lxc_hostarch_t native_arch = get_hostarch(),
			    cur_rule_arch = native_arch;
	uint32_t compat_arch[2] = {SCMP_ARCH_NATIVE, SCMP_ARCH_NATIVE};

	if (strncmp(line, "blacklist", 9) == 0)
		blacklist = true;
	else if (strncmp(line, "whitelist", 9) != 0) {
		ERROR("Bad seccomp policy style: %s.", line);
		return -1;
	}

	if ((p = strchr(line, ' '))) {
		default_policy_action = get_v2_default_action(p + 1);
		if (default_policy_action == -2)
			return -1;
	}

	/* for blacklist, allow any syscall which has no rule */
	if (blacklist) {
		if (default_policy_action == -1)
			default_policy_action = SCMP_ACT_ALLOW;
		if (default_rule_action == -1)
			default_rule_action = SCMP_ACT_KILL;
	} else {
		if (default_policy_action == -1)
			default_policy_action = SCMP_ACT_KILL;
		if (default_rule_action == -1)
			default_rule_action = SCMP_ACT_ALLOW;
	}

	if (native_arch == lxc_seccomp_arch_amd64) {
		cur_rule_arch = lxc_seccomp_arch_all;
		compat_arch[0] = SCMP_ARCH_X86;
		compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_i386,
				default_policy_action);
		compat_arch[1] = SCMP_ARCH_X32;
		compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_x32,
				default_policy_action);
		if (!compat_ctx[0] || !compat_ctx[1])
			goto bad;
#ifdef SCMP_ARCH_PPC
	} else if (native_arch == lxc_seccomp_arch_ppc64) {
		cur_rule_arch = lxc_seccomp_arch_all;
		compat_arch[0] = SCMP_ARCH_PPC;
		compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_ppc,
				default_policy_action);
		if (!compat_ctx[0])
			goto bad;
#endif
#ifdef SCMP_ARCH_ARM
	} else if (native_arch == lxc_seccomp_arch_arm64) {
		cur_rule_arch = lxc_seccomp_arch_all;
		compat_arch[0] = SCMP_ARCH_ARM;
		compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_arm,
				default_policy_action);
		if (!compat_ctx[0])
			goto bad;
#endif
#ifdef SCMP_ARCH_MIPS
	} else if (native_arch == lxc_seccomp_arch_mips64) {
		cur_rule_arch = lxc_seccomp_arch_all;
		compat_arch[0] = SCMP_ARCH_MIPS;
		compat_arch[1] = SCMP_ARCH_MIPS64N32;
		compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_mips,
				default_policy_action);
		compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_mips64n32,
				default_policy_action);
		if (!compat_ctx[0] || !compat_ctx[1])
			goto bad;
	} else if (native_arch == lxc_seccomp_arch_mipsel64) {
		cur_rule_arch = lxc_seccomp_arch_all;
		compat_arch[0] = SCMP_ARCH_MIPSEL;
		compat_arch[1] = SCMP_ARCH_MIPSEL64N32;
		compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_mipsel,
				default_policy_action);
		compat_ctx[1] = get_new_ctx(lxc_seccomp_arch_mipsel64n32,
				default_policy_action);
		if (!compat_ctx[0] || !compat_ctx[1])
			goto bad;
#endif
	}

	if (default_policy_action != SCMP_ACT_KILL) {
		ret = seccomp_reset(conf->seccomp_ctx, default_policy_action);
		if (ret != 0) {
			ERROR("Error re-initializing Seccomp.");
			return -1;
		}
		if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0)) {
			ERROR("Failed to turn off n-new-privs.");
			return -1;
		}
#ifdef SCMP_FLTATR_ATL_TSKIP
		if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
			WARN("Failed to turn on seccomp nop-skip, continuing");
		}
#endif
	}

	while (fgets(line, 1024, f)) {

		if (line[0] == '#')
			continue;
		if (strlen(line) == 0)
			continue;
		remove_trailing_newlines(line);
		INFO("processing: .%s.", line);
		if (line[0] == '[') {
			// read the architecture for next set of rules
			if (strcmp(line, "[x86]") == 0 ||
			    strcmp(line, "[X86]") == 0) {
				if (native_arch != lxc_seccomp_arch_i386 &&
						native_arch != lxc_seccomp_arch_amd64) {
					cur_rule_arch = lxc_seccomp_arch_unknown;
					continue;
				}
				cur_rule_arch = lxc_seccomp_arch_i386;
			} else if (strcmp(line, "[x32]") == 0 ||
				   strcmp(line, "[X32]") == 0) {
				if (native_arch != lxc_seccomp_arch_amd64) {
					cur_rule_arch = lxc_seccomp_arch_unknown;
					continue;
				}
				cur_rule_arch = lxc_seccomp_arch_x32;
			} else if (strcmp(line, "[X86_64]") == 0 ||
				   strcmp(line, "[x86_64]") == 0) {
				if (native_arch != lxc_seccomp_arch_amd64) {
					cur_rule_arch = lxc_seccomp_arch_unknown;
					continue;
				}
				cur_rule_arch = lxc_seccomp_arch_amd64;
			} else if (strcmp(line, "[all]") == 0 ||
				   strcmp(line, "[ALL]") == 0) {
				cur_rule_arch = lxc_seccomp_arch_all;
			}
#ifdef SCMP_ARCH_ARM
			else if (strcmp(line, "[arm]") == 0 ||
				 strcmp(line, "[ARM]") == 0) {
				if (native_arch != lxc_seccomp_arch_arm &&
						native_arch != lxc_seccomp_arch_arm64) {
					cur_rule_arch = lxc_seccomp_arch_unknown;
					continue;
				}
				cur_rule_arch = lxc_seccomp_arch_arm;
			}
#endif
#ifdef SCMP_ARCH_AARCH64
			else if (strcmp(line, "[arm64]") == 0 ||
				 strcmp(line, "[ARM64]") == 0) {
				if (native_arch != lxc_seccomp_arch_arm64) {
					cur_rule_arch = lxc_seccomp_arch_unknown;
					continue;
				}
				cur_rule_arch = lxc_seccomp_arch_arm64;
			}
#endif
#ifdef SCMP_ARCH_PPC64LE
			else if (strcmp(line, "[ppc64le]") == 0 ||
				 strcmp(line, "[PPC64LE]") == 0) {
				if (native_arch != lxc_seccomp_arch_ppc64le) {
					cur_rule_arch = lxc_seccomp_arch_unknown;
					continue;
				}
				cur_rule_arch = lxc_seccomp_arch_ppc64le;
			}
#endif
#ifdef SCMP_ARCH_PPC64
			else if (strcmp(line, "[ppc64]") == 0 ||
				 strcmp(line, "[PPC64]") == 0) {
				if (native_arch != lxc_seccomp_arch_ppc64) {
					cur_rule_arch = lxc_seccomp_arch_unknown;
					continue;
				}
				cur_rule_arch = lxc_seccomp_arch_ppc64;
			}
#endif
#ifdef SCMP_ARCH_PPC
			else if (strcmp(line, "[ppc]") == 0 ||
				 strcmp(line, "[PPC]") == 0) {
				if (native_arch != lxc_seccomp_arch_ppc &&
						native_arch != lxc_seccomp_arch_ppc64) {
					cur_rule_arch = lxc_seccomp_arch_unknown;
					continue;
				}
				cur_rule_arch = lxc_seccomp_arch_ppc;
			}
#endif
#ifdef SCMP_ARCH_MIPS
			else if (strcmp(line, "[mips64]") == 0 ||
				 strcmp(line, "[MIPS64]") == 0) {
				if (native_arch != lxc_seccomp_arch_mips64) {
					cur_rule_arch = lxc_seccomp_arch_unknown;
					continue;
				}
				cur_rule_arch = lxc_seccomp_arch_mips64;
			} else if (strcmp(line, "[mips64n32]") == 0 ||
				   strcmp(line, "[MIPS64N32]") == 0) {
				if (native_arch != lxc_seccomp_arch_mips64) {
					cur_rule_arch = lxc_seccomp_arch_unknown;
					continue;
				}
				cur_rule_arch = lxc_seccomp_arch_mips64n32;
			} else if (strcmp(line, "[mips]") == 0 ||
				   strcmp(line, "[MIPS]") == 0) {
				if (native_arch != lxc_seccomp_arch_mips &&
						native_arch != lxc_seccomp_arch_mips64) {
					cur_rule_arch = lxc_seccomp_arch_unknown;
					continue;
				}
				cur_rule_arch = lxc_seccomp_arch_mips;
			} else if (strcmp(line, "[mipsel64]") == 0 ||
				   strcmp(line, "[MIPSEL64]") == 0) {
				if (native_arch != lxc_seccomp_arch_mipsel64) {
					cur_rule_arch = lxc_seccomp_arch_unknown;
					continue;
				}
				cur_rule_arch = lxc_seccomp_arch_mipsel64;
			} else if (strcmp(line, "[mipsel64n32]") == 0 ||
				   strcmp(line, "[MIPSEL64N32]") == 0) {
				if (native_arch != lxc_seccomp_arch_mipsel64) {
					cur_rule_arch = lxc_seccomp_arch_unknown;
					continue;
				}
				cur_rule_arch = lxc_seccomp_arch_mipsel64n32;
			} else if (strcmp(line, "[mipsel]") == 0 ||
				   strcmp(line, "[MIPSEL]") == 0) {
				if (native_arch != lxc_seccomp_arch_mipsel &&
						native_arch != lxc_seccomp_arch_mipsel64) {
					cur_rule_arch = lxc_seccomp_arch_unknown;
					continue;
				}
				cur_rule_arch = lxc_seccomp_arch_mipsel;
			}
#endif
#ifdef SCMP_ARCH_S390X
			else if (strcmp(line, "[s390x]") == 0 ||
				 strcmp(line, "[S390X]") == 0) {
				if (native_arch != lxc_seccomp_arch_s390x) {
					cur_rule_arch = lxc_seccomp_arch_unknown;
					continue;
				}
				cur_rule_arch = lxc_seccomp_arch_s390x;
			}
#endif
			else
				goto bad_arch;

			continue;
		}

		/* irrelevant arch - i.e. arm on i386 */
		if (cur_rule_arch == lxc_seccomp_arch_unknown)
			continue;

		/* read optional action which follows the syscall */
		action = get_and_clear_v2_action(line, default_rule_action);
		if (action == -1) {
			ERROR("Failed to interpret action.");
			goto bad_rule;
		}

		if (cur_rule_arch == native_arch ||
		    cur_rule_arch == lxc_seccomp_arch_native ||
		    compat_arch[0] == SCMP_ARCH_NATIVE) {
			INFO("Adding native rule for %s action %d.", line, action);
			if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action))
				goto bad_rule;
		}
		else if (cur_rule_arch != lxc_seccomp_arch_all) {
			int arch_index =
				cur_rule_arch == lxc_seccomp_arch_mips64n32 ||
				cur_rule_arch == lxc_seccomp_arch_mipsel64n32 ? 1 : 0;

			INFO("Adding compat-only rule for %s action %d.", line, action);
			if (!do_resolve_add_rule(compat_arch[arch_index], line, compat_ctx[arch_index], action))
				goto bad_rule;
		}
		else {
			INFO("Adding native rule for %s action %d.", line, action);
			if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action))
				goto bad_rule;
			INFO("Adding compat rule for %s action %d.", line, action);
			if (!do_resolve_add_rule(compat_arch[0], line, compat_ctx[0], action))
				goto bad_rule;
			if (compat_arch[1] != SCMP_ARCH_NATIVE &&
				!do_resolve_add_rule(compat_arch[1], line, compat_ctx[1], action))
				goto bad_rule;
		}
	}

	if (compat_ctx[0]) {
		INFO("Merging in the compat Seccomp ctx into the main one.");
		if (seccomp_merge(conf->seccomp_ctx, compat_ctx[0]) != 0 ||
			(compat_ctx[1] != NULL && seccomp_merge(conf->seccomp_ctx, compat_ctx[1]) != 0)) {
			ERROR("Error merging compat Seccomp contexts.");
			goto bad;
		}
	}

	return 0;

bad_arch:
	ERROR("Unsupported arch: %s.", line);
bad_rule:
bad:
	if (compat_ctx[0])
		seccomp_release(compat_ctx[0]);
	if (compat_ctx[1])
		seccomp_release(compat_ctx[1]);
	return -1;
}
Пример #9
0
scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_policy_action)
{
	scmp_filter_ctx ctx;
	int ret;
	uint32_t arch;

	switch(n_arch) {
	case lxc_seccomp_arch_i386: arch = SCMP_ARCH_X86; break;
	case lxc_seccomp_arch_x32: arch = SCMP_ARCH_X32; break;
	case lxc_seccomp_arch_amd64: arch = SCMP_ARCH_X86_64; break;
	case lxc_seccomp_arch_arm: arch = SCMP_ARCH_ARM; break;
#ifdef SCMP_ARCH_AARCH64
	case lxc_seccomp_arch_arm64: arch = SCMP_ARCH_AARCH64; break;
#endif
#ifdef SCMP_ARCH_PPC64LE
	case lxc_seccomp_arch_ppc64le: arch = SCMP_ARCH_PPC64LE; break;
#endif
#ifdef SCMP_ARCH_PPC64
	case lxc_seccomp_arch_ppc64: arch = SCMP_ARCH_PPC64; break;
#endif
#ifdef SCMP_ARCH_PPC
	case lxc_seccomp_arch_ppc: arch = SCMP_ARCH_PPC; break;
#endif
#ifdef SCMP_ARCH_MIPS
	case lxc_seccomp_arch_mips: arch = SCMP_ARCH_MIPS; break;
	case lxc_seccomp_arch_mips64: arch = SCMP_ARCH_MIPS64; break;
	case lxc_seccomp_arch_mips64n32: arch = SCMP_ARCH_MIPS64N32; break;
	case lxc_seccomp_arch_mipsel: arch = SCMP_ARCH_MIPSEL; break;
	case lxc_seccomp_arch_mipsel64: arch = SCMP_ARCH_MIPSEL64; break;
	case lxc_seccomp_arch_mipsel64n32: arch = SCMP_ARCH_MIPSEL64N32; break;
#endif
#ifdef SCMP_ARCH_S390X
	case lxc_seccomp_arch_s390x: arch = SCMP_ARCH_S390X; break;
#endif
	default: return NULL;
	}

	if ((ctx = seccomp_init(default_policy_action)) == NULL) {
		ERROR("Error initializing seccomp context.");
		return NULL;
	}
	if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0)) {
		ERROR("Failed to turn off n-new-privs.");
		seccomp_release(ctx);
		return NULL;
	}
#ifdef SCMP_FLTATR_ATL_TSKIP
	if (seccomp_attr_set(ctx, SCMP_FLTATR_ATL_TSKIP, 1)) {
		WARN("Failed to turn on seccomp nop-skip, continuing");
	}
#endif
	ret = seccomp_arch_add(ctx, arch);
	if (ret != 0) {
		ERROR("Seccomp error %d (%s) adding arch: %d", ret,
		      strerror(-ret), (int)n_arch);
		seccomp_release(ctx);
		return NULL;
	}
	if (seccomp_arch_remove(ctx, SCMP_ARCH_NATIVE) != 0) {
		ERROR("Seccomp error removing native arch");
		seccomp_release(ctx);
		return NULL;
	}

	return ctx;
}
Пример #10
0
/*
 * v2 consists of
 * [x86]
 * open
 * read
 * write
 * close
 * # a comment
 * [x86_64]
 * open
 * read
 * write
 * close
 */
static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
{
#if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
	char *p;
	int ret;
	scmp_filter_ctx *ctx = NULL;
	bool blacklist = false;
	uint32_t default_policy_action = -1, default_rule_action = -1, action;
	uint32_t arch = SCMP_ARCH_NATIVE;

	if (strncmp(line, "blacklist", 9) == 0)
		blacklist = true;
	else if (strncmp(line, "whitelist", 9) != 0) {
		ERROR("Bad seccomp policy style: %s", line);
		return -1;
	}

	if ((p = strchr(line, ' '))) {
		default_policy_action = get_v2_default_action(p+1);
		if (default_policy_action == -2)
			return -1;
	}

	/* for blacklist, allow any syscall which has no rule */
	if (blacklist) {
		if (default_policy_action == -1)
			default_policy_action = SCMP_ACT_ALLOW;
		if (default_rule_action == -1)
			default_rule_action = SCMP_ACT_KILL;
	} else {
		if (default_policy_action == -1)
			default_policy_action = SCMP_ACT_KILL;
		if (default_rule_action == -1)
			default_rule_action = SCMP_ACT_ALLOW;
	}

	if (default_policy_action != SCMP_ACT_KILL) {
		ret = seccomp_reset(conf->seccomp_ctx, default_policy_action);
		if (ret != 0) {
			ERROR("Error re-initializing seccomp");
			return -1;
		}
		if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0)) {
			ERROR("failed to turn off n-new-privs");
			return -1;
		}
	}

	while (fgets(line, 1024, f)) {
		int nr;

		if (line[0] == '#')
			continue;
		if (strlen(line) == 0)
			continue;
		remove_trailing_newlines(line);
		INFO("processing: .%s.", line);
		if (line[0] == '[') {
			// read the architecture for next set of rules
			if (strcmp(line, "[x86]") == 0 ||
					strcmp(line, "[X86]") == 0)
				arch = SCMP_ARCH_X86;
			else if (strcmp(line, "[X86_64]") == 0 ||
					strcmp(line, "[x86_64]") == 0)
				arch = SCMP_ARCH_X86_64;
#ifdef SCMP_ARCH_ARM
			else if (strcmp(line, "[arm]") == 0 ||
					strcmp(line, "[ARM]") == 0)
				arch = SCMP_ARCH_ARM;
#endif
			else
				goto bad_arch;
			if (ctx) {
				ERROR("Only two arch sections per policy supported");
				goto bad_arch;
			}
			if ((ctx = seccomp_init(default_policy_action)) == NULL) {
				ERROR("Error initializing seccomp context");
				return -1;
			}
			if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0)) {
				ERROR("failed to turn off n-new-privs");
				seccomp_release(ctx);
				return -1;
			}
			ret = seccomp_arch_add(ctx, arch);
			if (ret == -EEXIST) {
				seccomp_release(ctx);
				ctx = NULL;
				continue;
			}
			if (ret != 0) {
				ERROR("Error %d adding arch: %s", ret, line);
				goto bad_arch;
			}
			if (seccomp_arch_remove(ctx, SCMP_ARCH_NATIVE) != 0) {
				ERROR("Error removing native arch from %s", line);
				goto bad_arch;
			}
			continue;
		}

		action = get_and_clear_v2_action(line, default_rule_action);
		if (action == -1) {
			ERROR("Failed to interpret action");
			goto bad_rule;
		}
		nr = seccomp_syscall_resolve_name_arch(arch, line);
		if (nr < 0) {
			ERROR("Failed to resolve syscall: %s", line);
			goto bad_rule;
		}
		ret = seccomp_rule_add(ctx ? ctx : conf->seccomp_ctx,
				action, nr, 0);
		if (ret < 0) {
			ERROR("failed (%d) loading rule for %s", ret, line);
			goto bad_rule;
		}
	}
	if (ctx) {
		if (seccomp_merge(conf->seccomp_ctx, ctx) != 0) {
			seccomp_release(ctx);
			ERROR("Error merging seccomp contexts");
			return -1;
		}
	}
	return 0;

bad_arch:
	ERROR("Unsupported arch: %s", line);
bad_rule:
	if (ctx)
		seccomp_release(ctx);
	return -1;
#else
	return -1;
#endif
}