*/
#define _GNU_SOURCE
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <seccomp.h>
-#include <errno.h>
-#include <seccomp.h>
-#include <sys/utsname.h>
#include <sys/mount.h>
+#include <sys/utsname.h>
#include "config.h"
-#include "lxcseccomp.h"
#include "log.h"
+#include "lxcseccomp.h"
lxc_log_define(lxc_seccomp, lxc);
return -1;
ret = seccomp_rule_add(
#if HAVE_SCMP_FILTER_CTX
- conf->seccomp_ctx,
+ conf->seccomp_ctx,
#endif
- SCMP_ACT_ALLOW, nr, 0);
+ SCMP_ACT_ALLOW, nr, 0);
if (ret < 0) {
- ERROR("failed loading allow rule for %d", nr);
+ ERROR("Failed loading allow rule for %d.", nr);
return ret;
}
}
{
uint32_t ret_action = -1;
- while (*line == ' ') line++;
- // after 'whitelist' or 'blacklist' comes default behavior
+ while (*line == ' ')
+ line++;
+ /* After 'whitelist' or 'blacklist' comes default behavior. */
if (strncmp(line, "kill", 4) == 0)
ret_action = SCMP_ACT_KILL;
else if (strncmp(line, "errno", 5) == 0) {
int e;
- if (sscanf(line+5, "%d", &e) != 1) {
- ERROR("Bad errno value in %s", line);
+ if (sscanf(line + 5, "%d", &e) != 1) {
+ ERROR("Bad errno value in %s.", line);
return -2;
}
ret_action = SCMP_ACT_ERRNO(e);
return ret_action;
}
+static const char *get_action_name(uint32_t action)
+{
+ /* The upper 16 bits indicate the type of the seccomp action. */
+ switch(action & 0xffff0000){
+ case SCMP_ACT_KILL:
+ return "kill";
+ case SCMP_ACT_ALLOW:
+ return "allow";
+ case SCMP_ACT_TRAP:
+ return "trap";
+ case SCMP_ACT_ERRNO(0):
+ return "errno";
+ default:
+ return "invalid action";
+ }
+}
+
static uint32_t get_and_clear_v2_action(char *line, uint32_t def_action)
{
char *p = strchr(line, ' ');
lxc_seccomp_arch_all = 0,
lxc_seccomp_arch_native,
lxc_seccomp_arch_i386,
+ lxc_seccomp_arch_x32,
lxc_seccomp_arch_amd64,
lxc_seccomp_arch_arm,
lxc_seccomp_arch_arm64,
lxc_seccomp_arch_mipsel,
lxc_seccomp_arch_mipsel64,
lxc_seccomp_arch_mipsel64n32,
+ lxc_seccomp_arch_s390x,
lxc_seccomp_arch_unknown = 999,
};
{
struct utsname uts;
if (uname(&uts) < 0) {
- SYSERROR("Failed to read host arch");
+ SYSERROR("Failed to read host arch.");
return -1;
}
if (strcmp(uts.machine, "i686") == 0)
return lxc_seccomp_arch_i386;
+ /* no x32 kernels */
else if (strcmp(uts.machine, "x86_64") == 0)
return lxc_seccomp_arch_amd64;
else if (strncmp(uts.machine, "armv7", 5) == 0)
return MIPS_ARCH_N64;
else if (strncmp(uts.machine, "mips", 4) == 0)
return MIPS_ARCH_O32;
+ else if (strncmp(uts.machine, "s390x", 5) == 0)
+ return lxc_seccomp_arch_s390x;
return lxc_seccomp_arch_unknown;
}
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_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");
+ 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");
+ ERROR("Failed to turn off no-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);
+ strerror(-ret), (int)n_arch);
seccomp_release(ctx);
return NULL;
}
{
int nr, ret;
- if (arch && seccomp_arch_exist(ctx, arch) != 0) {
- ERROR("BUG: seccomp: rule and context arch do not match (arch %d)", arch);
+ ret = seccomp_arch_exist(ctx, arch);
+ if (arch && ret != 0) {
+ ERROR("BUG: Seccomp: rule and context arch do not match (arch "
+ "%d): %s.",
+ arch, strerror(-ret));
return false;
}
if (strncmp(line, "reject_force_umount", 19) == 0) {
- INFO("Setting seccomp rule to reject force umounts\n");
+ INFO("Setting Seccomp rule to reject force umounts.");
ret = seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(umount2),
1, SCMP_A1(SCMP_CMP_MASKED_EQ , MNT_FORCE , MNT_FORCE ));
if (ret < 0) {
- ERROR("failed (%d) loading rule to reject force umount", ret);
+ ERROR("Failed (%d) loading rule to reject force "
+ "umount: %s.",
+ ret, strerror(-ret));
return false;
}
return true;
nr = seccomp_syscall_resolve_name(line);
if (nr == __NR_SCMP_ERROR) {
- WARN("Seccomp: failed to resolve syscall: %s", line);
- WARN("This syscall will NOT be blacklisted");
+ WARN("Seccomp: failed to resolve syscall: %s.", line);
+ WARN("This syscall will NOT be blacklisted.");
return true;
}
if (nr < 0) {
- WARN("Seccomp: got negative # for syscall: %s", line);
- WARN("This syscall will NOT be blacklisted");
+ WARN("Seccomp: got negative for syscall: %d: %s.", nr, line);
+ WARN("This syscall will NOT be blacklisted.");
return true;
}
ret = seccomp_rule_add_exact(ctx, action, nr, 0);
if (ret < 0) {
- ERROR("failed (%d) loading rule for %s (nr %d action %d)", ret, line, nr, action);
+ ERROR("Failed (%d) loading rule for %s (nr %d action %d(%s)): %s.",
+ ret, line, nr, action, get_action_name(action), strerror(-ret));
return false;
}
return true;
{
char *p;
int ret;
- scmp_filter_ctx compat_ctx[2] = { NULL, NULL };
+ 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 };
+ 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);
+ ERROR("Bad seccomp policy style: %s.", line);
return -1;
}
if ((p = strchr(line, ' '))) {
- default_policy_action = get_v2_default_action(p+1);
+ default_policy_action = get_v2_default_action(p + 1);
if (default_policy_action == -2)
return -1;
}
compat_arch[0] = SCMP_ARCH_X86;
compat_ctx[0] = get_new_ctx(lxc_seccomp_arch_i386,
default_policy_action);
- if (!compat_ctx[0])
+ 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) {
if (default_policy_action != SCMP_ACT_KILL) {
ret = seccomp_reset(conf->seccomp_ctx, default_policy_action);
if (ret != 0) {
- ERROR("Error re-initializing seccomp");
+ 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");
+ ERROR("Failed to turn off no-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)) {
remove_trailing_newlines(line);
INFO("processing: .%s.", line);
if (line[0] == '[') {
- // read the architecture for next set of rules
+ /* Read the architecture for next set of rules. */
if (strcmp(line, "[x86]") == 0 ||
- 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) {
+ 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) {
+ 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) {
+ strcmp(line, "[ARM]") == 0) {
if (native_arch != lxc_seccomp_arch_arm &&
native_arch != lxc_seccomp_arch_arm64) {
cur_rule_arch = lxc_seccomp_arch_unknown;
#endif
#ifdef SCMP_ARCH_AARCH64
else if (strcmp(line, "[arm64]") == 0 ||
- strcmp(line, "[ARM64]") == 0) {
+ strcmp(line, "[ARM64]") == 0) {
if (native_arch != lxc_seccomp_arch_arm64) {
cur_rule_arch = lxc_seccomp_arch_unknown;
continue;
#endif
#ifdef SCMP_ARCH_PPC64LE
else if (strcmp(line, "[ppc64le]") == 0 ||
- strcmp(line, "[PPC64LE]") == 0) {
+ strcmp(line, "[PPC64LE]") == 0) {
if (native_arch != lxc_seccomp_arch_ppc64le) {
cur_rule_arch = lxc_seccomp_arch_unknown;
continue;
#endif
#ifdef SCMP_ARCH_PPC64
else if (strcmp(line, "[ppc64]") == 0 ||
- strcmp(line, "[PPC64]") == 0) {
+ strcmp(line, "[PPC64]") == 0) {
if (native_arch != lxc_seccomp_arch_ppc64) {
cur_rule_arch = lxc_seccomp_arch_unknown;
continue;
#endif
#ifdef SCMP_ARCH_PPC
else if (strcmp(line, "[ppc]") == 0 ||
- 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;
#endif
#ifdef SCMP_ARCH_MIPS
else if (strcmp(line, "[mips64]") == 0 ||
- 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) {
+ 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) {
+ strcmp(line, "[MIPS]") == 0) {
if (native_arch != lxc_seccomp_arch_mips &&
native_arch != lxc_seccomp_arch_mips64) {
cur_rule_arch = lxc_seccomp_arch_unknown;
}
cur_rule_arch = lxc_seccomp_arch_mips;
} else if (strcmp(line, "[mipsel64]") == 0 ||
- 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) {
+ 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) {
+ strcmp(line, "[MIPSEL]") == 0) {
if (native_arch != lxc_seccomp_arch_mipsel &&
native_arch != lxc_seccomp_arch_mipsel64) {
cur_rule_arch = lxc_seccomp_arch_unknown;
}
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;
/* 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");
+ 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);
+ INFO("Adding native rule for %s action %d(%s).", line, action,
+ get_action_name(action));
if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, conf->seccomp_ctx, action))
goto bad_rule;
}
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);
+ INFO("Adding compat-only rule for %s action %d(%s).", line, action,
+ get_action_name(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);
+ INFO("Adding native rule for %s action %d(%s).", line, action,
+ get_action_name(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);
+ INFO("Adding compat rule for %s action %d(%s).", line, action,
+ get_action_name(action));
if (!do_resolve_add_rule(compat_arch[0], line, compat_ctx[0], action))
goto bad_rule;
if (compat_arch[1] != SCMP_ARCH_NATIVE &&
}
if (compat_ctx[0]) {
- INFO("Merging in the compat seccomp ctx into the main one");
+ 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");
+ ERROR("Error merging compat Seccomp contexts.");
goto bad;
}
}
return 0;
bad_arch:
- ERROR("Unsupported arch: %s", line);
+ ERROR("Unsupported arch: %s.", line);
bad_rule:
bad:
if (compat_ctx[0])
* The first line of the config file has a policy language version
* the second line has some directives
* then comes policy subject to the directives
- * right now version must be '1'
- * the directives must include 'whitelist' (only type of policy currently
- * supported) and can include 'debug' (though debug is not yet supported).
+ * right now version must be '1' or '2'
+ * the directives must include 'whitelist'(version == 1 or 2) or 'blacklist'
+ * (version == 2) and can include 'debug' (though debug is not yet supported).
*/
static int parse_config(FILE *f, struct lxc_conf *conf)
{
ret = fscanf(f, "%d\n", &version);
if (ret != 1 || (version != 1 && version != 2)) {
- ERROR("invalid version");
+ ERROR("Invalid version.");
return -1;
}
if (!fgets(line, 1024, f)) {
- ERROR("invalid config file");
+ ERROR("Invalid config file.");
return -1;
}
if (version == 1 && !strstr(line, "whitelist")) {
- ERROR("only whitelist policy is supported");
+ ERROR("Only whitelist policy is supported.");
return -1;
}
if (strstr(line, "debug")) {
- ERROR("debug not yet implemented");
+ ERROR("Debug not yet implemented.");
return -1;
}
while (fgets(line, 1024, f)) {
if (strncmp(line, "Seccomp:", 8) == 0) {
found = true;
- ret = sscanf(line+8, "%d", &v);
+ ret = sscanf(line + 8, "%d", &v);
if (ret == 1 && v != 0)
already_enabled = true;
break;
}
fclose(f);
- if (!found) { /* no Seccomp line, no seccomp in kernel */
- INFO("Seccomp is not enabled in the kernel");
+ if (!found) { /* no Seccomp line, no seccomp in kernel */
+ INFO("Seccomp is not enabled in the kernel.");
return false;
}
- if (already_enabled) { /* already seccomp-confined */
- INFO("Already seccomp-confined, not loading new policy");
+ if (already_enabled) { /* already seccomp-confined */
+ INFO("Already seccomp-confined, not loading new policy.");
return false;
}
return true;
ret = seccomp_init(SCMP_ACT_KILL) < 0;
#endif
if (ret) {
- ERROR("failed initializing seccomp");
+ ERROR("Failed initializing seccomp.");
return -1;
}
- /* turn of no-new-privs. We don't want it in lxc, and it breaks
- * with apparmor */
+/* 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);
+ 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);
+ 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");
+ ERROR("Failed to turn off no-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);
+ SYSERROR("Failed to open seccomp policy file %s.", conf->seccomp);
return -1;
}
ret = parse_config(f, conf);
return 0;
ret = seccomp_load(
#if HAVE_SCMP_FILTER_CTX
- conf->seccomp_ctx
+ conf->seccomp_ctx
#endif
- );
+ );
if (ret < 0) {
- ERROR("Error loading the seccomp policy");
+ ERROR("Error loading the seccomp policy: %s.", strerror(-ret));
return -1;
}
+
+/* After load seccomp filter into the kernel successfully, export the current seccomp
+ * filter to log file */
+#if HAVE_SCMP_FILTER_CTX
+ if ((lxc_log_get_level() <= LXC_LOG_LEVEL_TRACE || conf->loglevel <= LXC_LOG_LEVEL_TRACE) &&
+ lxc_log_fd >= 0) {
+ ret = seccomp_export_pfc(conf->seccomp_ctx, lxc_log_fd);
+ /* Just give an warning when export error */
+ if (ret < 0)
+ WARN("Failed to export seccomp filter to log file: %s.", strerror(-ret));
+ }
+#endif
return 0;
}
-void lxc_seccomp_free(struct lxc_conf *conf) {
+void lxc_seccomp_free(struct lxc_conf *conf)
+{
free(conf->seccomp);
conf->seccomp = NULL;
#if HAVE_SCMP_FILTER_CTX