Merge pull request #2281 from brauner/2018-04-15/seccomp_fixes

seccomp: handle arch inversion - The Architecture Strikes Back
This commit is contained in:
Serge Hallyn 2018-04-18 11:35:11 -05:00 committed by GitHub
commit a5fb69a3f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 186 additions and 74 deletions

View File

@ -50,6 +50,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<cmdsynopsis>
<command>lxc-execute</command>
<arg choice="req">-n <replaceable>name</replaceable></arg>
<arg choice="opt">-d</arg>
<arg choice="opt">-f <replaceable>config_file</replaceable></arg>
<arg choice="opt">-s KEY=VAL</arg>
<arg choice="opt">-- <replaceable>command</replaceable></arg>
@ -124,6 +125,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>-d, --daemon</option>
</term>
<listitem>
<para>
Run the container as a daemon. As the container has no
more tty, if an error occurs nothing will be displayed,
the log file can be used to check the error.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--</option></term>
<listitem>

View File

@ -319,7 +319,7 @@ int get_hostarch(void)
return lxc_seccomp_arch_unknown;
}
scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_policy_action)
scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_policy_action, bool *needs_merge)
{
scmp_filter_ctx ctx;
int ret;
@ -397,7 +397,10 @@ scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_policy_
return NULL;
}
TRACE("Removed native arch from main seccomp context");
*needs_merge = true;
} else {
*needs_merge = false;
TRACE("Arch %d already present in main seccomp context", (int)n_arch);
}
@ -490,13 +493,16 @@ 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;
enum lxc_hostarch_t native_arch = get_hostarch(),
cur_rule_arch = native_arch;
uint32_t compat_arch[2] = {SCMP_ARCH_NATIVE, SCMP_ARCH_NATIVE};
struct seccomp_v2_rule rule;
struct scmp_ctx_info {
uint32_t architectures[3];
scmp_filter_ctx contexts[3];
bool needs_merge[3];
} ctx;
if (strncmp(line, "blacklist", 9) == 0)
blacklist = true;
@ -524,54 +530,115 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
default_rule_action = SCMP_ACT_ALLOW;
}
memset(&ctx, 0, sizeof(ctx));
ctx.architectures[0] = SCMP_ARCH_NATIVE;
ctx.architectures[1] = SCMP_ARCH_NATIVE;
ctx.architectures[2] = SCMP_ARCH_NATIVE;
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])
ctx.architectures[0] = SCMP_ARCH_X86;
ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_i386,
default_policy_action,
&ctx.needs_merge[0]);
if (!ctx.contexts[0])
goto bad;
ctx.architectures[1] = SCMP_ARCH_X32;
ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_x32,
default_policy_action,
&ctx.needs_merge[1]);
if (!ctx.contexts[1])
goto bad;
ctx.architectures[2] = SCMP_ARCH_X86_64;
ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_amd64,
default_policy_action,
&ctx.needs_merge[2]);
if (!ctx.contexts[2])
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])
ctx.architectures[0] = SCMP_ARCH_PPC;
ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_ppc,
default_policy_action,
&ctx.needs_merge[0]);
if (!ctx.contexts[0])
goto bad;
ctx.architectures[2] = SCMP_ARCH_PPC64;
ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_ppc64,
default_policy_action,
&ctx.needs_merge[2]);
if (!ctx.contexts[2])
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])
ctx.architectures[0] = SCMP_ARCH_ARM;
ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_arm,
default_policy_action,
&ctx.needs_merge[0]);
if (!ctx.contexts[0])
goto bad;
ctx.architectures[2] = SCMP_ARCH_AARCH64;
ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_arm64,
default_policy_action,
&ctx.needs_merge[2]);
if (!ctx.contexts[2])
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])
ctx.architectures[0] = SCMP_ARCH_MIPS;
ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_mips,
default_policy_action,
&ctx.needs_merge[0]);
if (!ctx.contexts[0])
goto bad;
ctx.architectures[1] = SCMP_ARCH_MIPS64N32;
ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_mips64n32,
default_policy_action,
&ctx.needs_merge[1]);
if (!ctx.contexts[1])
goto bad;
ctx.architectures[2] = SCMP_ARCH_MIPS64;
ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_mips64,
default_policy_action,
&ctx.needs_merge[2]);
if (!ctx.contexts[2])
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])
ctx.architectures[0] = SCMP_ARCH_MIPSEL;
ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_mipsel,
default_policy_action,
&ctx.needs_merge[0]);
if (!ctx.contexts[0])
goto bad;
ctx.architectures[1] = SCMP_ARCH_MIPSEL64N32;
ctx.contexts[1] = get_new_ctx(lxc_seccomp_arch_mipsel64n32,
default_policy_action,
&ctx.needs_merge[1]);
if (!ctx.contexts[1])
goto bad;
ctx.architectures[2] = SCMP_ARCH_MIPSEL64;
ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_mipsel64,
default_policy_action,
&ctx.needs_merge[2]);
if (!ctx.contexts[2])
goto bad;
#endif
}
@ -606,7 +673,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
if (strcmp(line, "[x86]") == 0 ||
strcmp(line, "[X86]") == 0) {
if (native_arch != lxc_seccomp_arch_i386 &&
native_arch != lxc_seccomp_arch_amd64) {
native_arch != lxc_seccomp_arch_amd64) {
cur_rule_arch = lxc_seccomp_arch_unknown;
continue;
}
@ -633,7 +700,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
else if (strcmp(line, "[arm]") == 0 ||
strcmp(line, "[ARM]") == 0) {
if (native_arch != lxc_seccomp_arch_arm &&
native_arch != lxc_seccomp_arch_arm64) {
native_arch != lxc_seccomp_arch_arm64) {
cur_rule_arch = lxc_seccomp_arch_unknown;
continue;
}
@ -674,7 +741,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
else if (strcmp(line, "[ppc]") == 0 ||
strcmp(line, "[PPC]") == 0) {
if (native_arch != lxc_seccomp_arch_ppc &&
native_arch != lxc_seccomp_arch_ppc64) {
native_arch != lxc_seccomp_arch_ppc64) {
cur_rule_arch = lxc_seccomp_arch_unknown;
continue;
}
@ -699,7 +766,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
} else if (strcmp(line, "[mips]") == 0 ||
strcmp(line, "[MIPS]") == 0) {
if (native_arch != lxc_seccomp_arch_mips &&
native_arch != lxc_seccomp_arch_mips64) {
native_arch != lxc_seccomp_arch_mips64) {
cur_rule_arch = lxc_seccomp_arch_unknown;
continue;
}
@ -721,7 +788,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
} else if (strcmp(line, "[mipsel]") == 0 ||
strcmp(line, "[MIPSEL]") == 0) {
if (native_arch != lxc_seccomp_arch_mipsel &&
native_arch != lxc_seccomp_arch_mipsel64) {
native_arch != lxc_seccomp_arch_mipsel64) {
cur_rule_arch = lxc_seccomp_arch_unknown;
continue;
}
@ -756,57 +823,84 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
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(%s)", line, rule.action,
get_action_name(rule.action));
if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, &rule))
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;
if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line,
conf->seccomp_ctx, &rule))
goto bad_rule;
INFO("Added native rule for arch %d for %s action %d(%s)",
SCMP_ARCH_NATIVE, line, rule.action,
get_action_name(rule.action));
INFO("Adding compat-only rule for %s action %d(%s)", line, rule.action,
get_action_name(rule.action));
if (!do_resolve_add_rule(compat_arch[arch_index], line, compat_ctx[arch_index], &rule))
if (ctx.architectures[0] != SCMP_ARCH_NATIVE) {
if (!do_resolve_add_rule(ctx.architectures[0], line,
ctx.contexts[0], &rule))
goto bad_rule;
INFO("Added compat rule for arch %d for %s action %d(%s)",
ctx.architectures[0], line, rule.action,
get_action_name(rule.action));
}
else {
INFO("Adding native rule for %s action %d(%s)", line, rule.action,
if (ctx.architectures[1] != SCMP_ARCH_NATIVE) {
if (!do_resolve_add_rule(ctx.architectures[1], line,
ctx.contexts[1], &rule))
goto bad_rule;
INFO("Added compat rule for arch %d for %s action %d(%s)",
ctx.architectures[1], line, rule.action,
get_action_name(rule.action));
if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, &rule))
}
if (ctx.architectures[2] != SCMP_ARCH_NATIVE) {
if (!do_resolve_add_rule(ctx.architectures[2], line,
ctx.contexts[2], &rule))
goto bad_rule;
INFO("Adding compat rule for %s action %d(%s)", line, rule.action,
INFO("Added native rule for arch %d for %s action %d(%s)",
ctx.architectures[2], line, rule.action,
get_action_name(rule.action));
if (!do_resolve_add_rule(compat_arch[0], line, compat_ctx[0], &rule))
goto bad_rule;
if (compat_arch[1] != SCMP_ARCH_NATIVE &&
!do_resolve_add_rule(compat_arch[1], line, compat_ctx[1], &rule))
goto bad_rule;
}
}
if (compat_ctx[0]) {
INFO("Merging compat seccomp contexts into main context");
if (compat_arch[0] != native_arch && compat_arch[0] != seccomp_arch_native()) {
ret = seccomp_merge(conf->seccomp_ctx, compat_ctx[0]);
INFO("Merging compat seccomp contexts into main context");
if (ctx.contexts[0]) {
if (ctx.needs_merge[0]) {
ret = seccomp_merge(conf->seccomp_ctx, ctx.contexts[0]);
if (ret < 0) {
ERROR("Failed to merge first compat seccomp context into main context");
ERROR("Failed to merge first compat seccomp "
"context into main context");
goto bad;
}
TRACE("Merged first compat seccomp context into main context");
} else {
seccomp_release(ctx.contexts[0]);
ctx.contexts[0] = NULL;
}
}
if (compat_arch[1] && compat_arch[1] != native_arch && compat_arch[1] != seccomp_arch_native()) {
ret = seccomp_merge(conf->seccomp_ctx, compat_ctx[1]);
if (ctx.contexts[1]) {
if (ctx.needs_merge[1]) {
ret = seccomp_merge(conf->seccomp_ctx, ctx.contexts[1]);
if (ret < 0) {
ERROR("Failed to merge first compat seccomp context into main context");
ERROR("Failed to merge first compat seccomp "
"context into main context");
goto bad;
}
TRACE("Merged second compat seccomp context into main context");
} else {
seccomp_release(ctx.contexts[1]);
ctx.contexts[1] = NULL;
}
}
if (ctx.contexts[2]) {
if (ctx.needs_merge[2]) {
ret = seccomp_merge(conf->seccomp_ctx, ctx.contexts[2]);
if (ret < 0) {
ERROR("Failed to merge third compat seccomp "
"context into main context");
goto bad;
}
TRACE("Merged third compat seccomp context into main context");
} else {
seccomp_release(ctx.contexts[2]);
ctx.contexts[2] = NULL;
}
}
@ -816,10 +910,13 @@ 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]);
if (ctx.contexts[0])
seccomp_release(ctx.contexts[0]);
if (ctx.contexts[1])
seccomp_release(ctx.contexts[1]);
if (ctx.contexts[2])
seccomp_release(ctx.contexts[2]);
return -1;
}
#else /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */

View File

@ -104,6 +104,7 @@ and execs COMMAND into this container.\n\
\n\
Options :\n\
-n, --name=NAME NAME of the container\n\
-d, --daemon Daemonize the container\n\
-f, --rcfile=FILE Load configuration file FILE\n\
-s, --define KEY=VAL Assign VAL to configuration variable KEY\n\
-u, --uid=UID Execute COMMAND with UID inside the container\n\

View File

@ -59,7 +59,6 @@ int main(int argc, char *argv[])
lxc_error("%s\n", "Container \"reboot\" is not defined");
goto on_error_put;
}
c->clear_config(c);
if (!c->load_config(c, NULL)) {