Merge pull request #2347 from brauner/2018-05-24/seccomp_cleanups

seccomp: cleanup
This commit is contained in:
Stéphane Graber 2018-05-24 16:57:13 -04:00 committed by GitHub
commit b3365b9346
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 318 additions and 208 deletions

View File

@ -2684,15 +2684,6 @@ out:
return bret; return bret;
} }
static void strip_newline(char *p)
{
size_t len = strlen(p);
if (len < 1)
return;
if (p[len-1] == '\n')
p[len-1] = '\0';
}
void mod_all_rdeps(struct lxc_container *c, bool inc) void mod_all_rdeps(struct lxc_container *c, bool inc)
{ {
struct lxc_container *p; struct lxc_container *p;
@ -2715,8 +2706,10 @@ void mod_all_rdeps(struct lxc_container *c, bool inc)
ERROR("badly formatted file %s", path); ERROR("badly formatted file %s", path);
goto out; goto out;
} }
strip_newline(lxcpath);
strip_newline(lxcname); remove_trailing_newlines(lxcpath);
remove_trailing_newlines(lxcname);
if ((p = lxc_container_new(lxcname, lxcpath)) == NULL) { if ((p = lxc_container_new(lxcname, lxcpath)) == NULL) {
ERROR("Unable to find dependent container %s:%s", ERROR("Unable to find dependent container %s:%s",
lxcpath, lxcname); lxcpath, lxcname);

View File

@ -27,24 +27,25 @@
#include "conf.h" #include "conf.h"
#ifdef HAVE_SECCOMP #ifdef HAVE_SECCOMP
int lxc_seccomp_load(struct lxc_conf *conf); extern int lxc_seccomp_load(struct lxc_conf *conf);
int lxc_read_seccomp_config(struct lxc_conf *conf); extern int lxc_read_seccomp_config(struct lxc_conf *conf);
void lxc_seccomp_free(struct lxc_conf *conf); extern void lxc_seccomp_free(struct lxc_conf *conf);
#else #else
static inline int lxc_seccomp_load(struct lxc_conf *conf) { static inline int lxc_seccomp_load(struct lxc_conf *conf)
{
return 0; return 0;
} }
static inline int lxc_read_seccomp_config(struct lxc_conf *conf) { static inline int lxc_read_seccomp_config(struct lxc_conf *conf)
{
return 0; return 0;
} }
static inline void lxc_seccomp_free(struct lxc_conf *conf) { static inline void lxc_seccomp_free(struct lxc_conf *conf)
if (conf->seccomp) { {
free(conf->seccomp); free(conf->seccomp);
conf->seccomp = NULL; conf->seccomp = NULL;
} }
}
#endif #endif
#endif #endif

View File

@ -23,9 +23,9 @@
#define _GNU_SOURCE #define _GNU_SOURCE
#include <errno.h> #include <errno.h>
#include <seccomp.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <seccomp.h>
#include <sys/mount.h> #include <sys/mount.h>
#include <sys/utsname.h> #include <sys/utsname.h>
@ -34,65 +34,45 @@
#include "lxcseccomp.h" #include "lxcseccomp.h"
#include "utils.h" #include "utils.h"
#ifdef __MIPSEL__
#define MIPS_ARCH_O32 lxc_seccomp_arch_mipsel
#define MIPS_ARCH_N64 lxc_seccomp_arch_mipsel64
#else
#define MIPS_ARCH_O32 lxc_seccomp_arch_mips
#define MIPS_ARCH_N64 lxc_seccomp_arch_mips64
#endif
lxc_log_define(lxc_seccomp, lxc); lxc_log_define(lxc_seccomp, lxc);
static int parse_config_v1(FILE *f, struct lxc_conf *conf) static int parse_config_v1(FILE *f, struct lxc_conf *conf)
{ {
char line[1024]; int ret = 0;
int ret; size_t line_bufsz = 0;
char *line = NULL;
while (fgets(line, 1024, f)) { while (getline(&line, &line_bufsz, f) != -1) {
int nr; int nr;
ret = sscanf(line, "%d", &nr); ret = sscanf(line, "%d", &nr);
if (ret != 1) if (ret != 1)
return -1; return -1;
ret = seccomp_rule_add(
#if HAVE_SCMP_FILTER_CTX #if HAVE_SCMP_FILTER_CTX
conf->seccomp_ctx, ret = seccomp_rule_add(conf->seccomp_ctx, SCMP_ACT_ALLOW, nr, 0);
#else
ret = seccomp_rule_add(SCMP_ACT_ALLOW, nr, 0);
#endif #endif
SCMP_ACT_ALLOW, nr, 0);
if (ret < 0) { if (ret < 0) {
ERROR("Failed loading allow rule for %d", nr); ERROR("Failed loading allow rule for %d", nr);
break;
}
}
free(line);
return ret; return ret;
} }
}
return 0;
}
#if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH #if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
static void remove_trailing_newlines(char *l)
{
char *p = l;
while (*p)
p++;
while (--p >= l && *p == '\n')
*p = '\0';
}
static uint32_t get_v2_default_action(char *line)
{
uint32_t ret_action = -1;
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);
return -2;
}
ret_action = SCMP_ACT_ERRNO(e);
} else if (strncmp(line, "allow", 5) == 0)
ret_action = SCMP_ACT_ALLOW;
else if (strncmp(line, "trap", 4) == 0)
ret_action = SCMP_ACT_TRAP;
return ret_action;
}
static const char *get_action_name(uint32_t action) static const char *get_action_name(uint32_t action)
{ {
/* The upper 16 bits indicate the type of the seccomp action. */ /* The upper 16 bits indicate the type of the seccomp action. */
@ -105,32 +85,68 @@ static const char *get_action_name(uint32_t action)
return "trap"; return "trap";
case SCMP_ACT_ERRNO(0): case SCMP_ACT_ERRNO(0):
return "errno"; return "errno";
default: }
return "invalid action"; return "invalid action";
} }
static uint32_t get_v2_default_action(char *line)
{
uint32_t ret_action = -1;
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, ret;
ret = sscanf(line + 5, "%d", &e);
if (ret != 1) {
ERROR("Failed to parse errno value from %s", line);
return -2;
}
ret_action = SCMP_ACT_ERRNO(e);
} else if (strncmp(line, "allow", 5) == 0) {
ret_action = SCMP_ACT_ALLOW;
} else if (strncmp(line, "trap", 4) == 0) {
ret_action = SCMP_ACT_TRAP;
}
return ret_action;
} }
static uint32_t get_v2_action(char *line, uint32_t def_action) static uint32_t get_v2_action(char *line, uint32_t def_action)
{ {
char *p = strchr(line, ' '); char *p;
uint32_t ret; uint32_t ret;
p = strchr(line, ' ');
if (!p) if (!p)
return def_action; return def_action;
p++; p++;
while (*p == ' ') while (*p == ' ')
p++; p++;
if (!*p || *p == '#') if (!*p || *p == '#')
return def_action; return def_action;
ret = get_v2_default_action(p); ret = get_v2_default_action(p);
switch (ret) { switch (ret) {
case -2: return -1; case -2:
case -1: return def_action; return -1;
default: return ret; case -1:
} return def_action;
} }
struct v2_rule_args { return ret;
}
struct seccomp_v2_rule_args {
uint32_t index; uint32_t index;
uint64_t value; uint64_t value;
uint64_t mask; uint64_t mask;
@ -140,7 +156,7 @@ struct v2_rule_args {
struct seccomp_v2_rule { struct seccomp_v2_rule {
uint32_t action; uint32_t action;
uint32_t args_num; uint32_t args_num;
struct v2_rule_args args_value[6]; struct seccomp_v2_rule_args args_value[6];
}; };
static enum scmp_compare parse_v2_rule_op(char *s) static enum scmp_compare parse_v2_rule_op(char *s)
@ -163,7 +179,8 @@ static enum scmp_compare parse_v2_rule_op(char *s)
return _SCMP_CMP_MAX; return _SCMP_CMP_MAX;
} }
/* This function is used to parse the args string into the structure. /*
* This function is used to parse the args string into the structure.
* args string format:[index,value,op,valueTwo] or [index,value,op] * args string format:[index,value,op,valueTwo] or [index,value,op]
* index: the index for syscall arguments (type uint) * index: the index for syscall arguments (type uint)
* value: the value for syscall arguments (type uint64) * value: the value for syscall arguments (type uint64)
@ -174,21 +191,21 @@ static enum scmp_compare parse_v2_rule_op(char *s)
* valueTwo: the value for syscall arguments only used for mask eq (type uint64, optional) * valueTwo: the value for syscall arguments only used for mask eq (type uint64, optional)
* Returns 0 on success, < 0 otherwise. * Returns 0 on success, < 0 otherwise.
*/ */
static int get_seccomp_arg_value(char *key, struct v2_rule_args *rule_args) static int get_seccomp_arg_value(char *key, struct seccomp_v2_rule_args *rule_args)
{ {
int ret = 0; int ret = 0;
uint64_t value = 0;
uint64_t mask = 0;
enum scmp_compare op = 0;
uint32_t index = 0; uint32_t index = 0;
char s[31] = {0}, v[24] = {0}, m[24] = {0}; uint64_t mask = 0, value = 0;
enum scmp_compare op = 0;
char *tmp = NULL; char *tmp = NULL;
char s[31] = {0}, v[24] = {0}, m[24] = {0};
tmp = strchr(key, '['); tmp = strchr(key, '[');
if (!tmp) { if (!tmp) {
ERROR("Failed to interpret args"); ERROR("Failed to interpret args");
return -1; return -1;
} }
ret = sscanf(tmp, "[%i,%23[^,],%30[^0-9^,],%23[^,]", &index, v, s, m); ret = sscanf(tmp, "[%i,%23[^,],%30[^0-9^,],%23[^,]", &index, v, s, m);
if ((ret != 3 && ret != 4) || index >= 6) { if ((ret != 3 && ret != 4) || index >= 6) {
ERROR("Failed to interpret args value"); ERROR("Failed to interpret args value");
@ -201,7 +218,7 @@ static int get_seccomp_arg_value(char *key, struct v2_rule_args *rule_args)
return -1; return -1;
} }
ret = lxc_safe_uint64(v, &mask); ret = lxc_safe_uint64(m, &mask);
if (ret < 0) { if (ret < 0) {
ERROR("Invalid argument mask"); ERROR("Invalid argument mask");
return -1; return -1;
@ -226,13 +243,11 @@ static int get_seccomp_arg_value(char *key, struct v2_rule_args *rule_args)
* @rules : output struct. * @rules : output struct.
* Returns 0 on success, < 0 otherwise. * Returns 0 on success, < 0 otherwise.
*/ */
static int parse_v2_rules(char *line, uint32_t def_action, struct seccomp_v2_rule *rules) static int parse_v2_rules(char *line, uint32_t def_action,
struct seccomp_v2_rule *rules)
{ {
int ret = 0 ; int i = 0, ret = -1;
int i = 0; char *key = NULL, *saveptr = NULL, *tmp = NULL;
char *tmp = NULL;
char *key = NULL;
char *saveptr = NULL;
tmp = strdup(line); tmp = strdup(line);
if (!tmp) if (!tmp)
@ -240,33 +255,29 @@ static int parse_v2_rules(char *line, uint32_t def_action, struct seccomp_v2_rul
/* read optional action which follows the syscall */ /* read optional action which follows the syscall */
rules->action = get_v2_action(tmp, def_action); rules->action = get_v2_action(tmp, def_action);
if (rules->action == -1) {
ERROR("Failed to interpret action");
ret = -1;
goto out;
}
rules->args_num = 0;
if (!strchr(tmp, '[')) {
ret = 0; ret = 0;
rules->args_num = 0;
if (!strchr(tmp, '['))
goto out; goto out;
}
for ((key = strtok_r(tmp, "]", &saveptr)), i = 0; key && i < 6; (key = strtok_r(NULL, "]", &saveptr)), i++) {
ret = get_seccomp_arg_value(key, &rules->args_value[i]);
if (ret < 0) {
ret = -1; ret = -1;
for ((key = strtok_r(tmp, "]", &saveptr)), i = 0; key && i < 6;
(key = strtok_r(NULL, "]", &saveptr)), i++) {
ret = get_seccomp_arg_value(key, &rules->args_value[i]);
if (ret < 0)
goto out; goto out;
}
rules->args_num++; rules->args_num++;
} }
ret = 0; ret = 0;
out: out:
free(tmp); free(tmp);
return ret; return ret;
} }
#endif #endif
#if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH #if HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH
@ -291,14 +302,6 @@ enum lxc_hostarch_t {
lxc_seccomp_arch_unknown = 999, lxc_seccomp_arch_unknown = 999,
}; };
#ifdef __MIPSEL__
# define MIPS_ARCH_O32 lxc_seccomp_arch_mipsel
# define MIPS_ARCH_N64 lxc_seccomp_arch_mipsel64
#else
# define MIPS_ARCH_O32 lxc_seccomp_arch_mips
# define MIPS_ARCH_N64 lxc_seccomp_arch_mips64
#endif
int get_hostarch(void) int get_hostarch(void)
{ {
struct utsname uts; struct utsname uts;
@ -306,6 +309,7 @@ int get_hostarch(void)
SYSERROR("Failed to read host arch"); SYSERROR("Failed to read host arch");
return -1; return -1;
} }
if (strcmp(uts.machine, "i686") == 0) if (strcmp(uts.machine, "i686") == 0)
return lxc_seccomp_arch_i386; return lxc_seccomp_arch_i386;
/* no x32 kernels */ /* no x32 kernels */
@ -327,59 +331,96 @@ int get_hostarch(void)
return MIPS_ARCH_O32; return MIPS_ARCH_O32;
else if (strncmp(uts.machine, "s390x", 5) == 0) else if (strncmp(uts.machine, "s390x", 5) == 0)
return lxc_seccomp_arch_s390x; return lxc_seccomp_arch_s390x;
return lxc_seccomp_arch_unknown; return lxc_seccomp_arch_unknown;
} }
scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_policy_action, bool *needs_merge) 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; int ret;
uint32_t arch; uint32_t arch;
scmp_filter_ctx ctx;
switch (n_arch) { switch (n_arch) {
case lxc_seccomp_arch_i386: arch = SCMP_ARCH_X86; break; case lxc_seccomp_arch_i386:
case lxc_seccomp_arch_x32: arch = SCMP_ARCH_X32; break; arch = SCMP_ARCH_X86;
case lxc_seccomp_arch_amd64: arch = SCMP_ARCH_X86_64; break; break;
case lxc_seccomp_arch_arm: arch = SCMP_ARCH_ARM; 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 #ifdef SCMP_ARCH_AARCH64
case lxc_seccomp_arch_arm64: arch = SCMP_ARCH_AARCH64; break; case lxc_seccomp_arch_arm64:
arch = SCMP_ARCH_AARCH64;
break;
#endif #endif
#ifdef SCMP_ARCH_PPC64LE #ifdef SCMP_ARCH_PPC64LE
case lxc_seccomp_arch_ppc64le: arch = SCMP_ARCH_PPC64LE; break; case lxc_seccomp_arch_ppc64le:
arch = SCMP_ARCH_PPC64LE;
break;
#endif #endif
#ifdef SCMP_ARCH_PPC64 #ifdef SCMP_ARCH_PPC64
case lxc_seccomp_arch_ppc64: arch = SCMP_ARCH_PPC64; break; case lxc_seccomp_arch_ppc64:
arch = SCMP_ARCH_PPC64;
break;
#endif #endif
#ifdef SCMP_ARCH_PPC #ifdef SCMP_ARCH_PPC
case lxc_seccomp_arch_ppc: arch = SCMP_ARCH_PPC; break; case lxc_seccomp_arch_ppc:
arch = SCMP_ARCH_PPC;
break;
#endif #endif
#ifdef SCMP_ARCH_MIPS #ifdef SCMP_ARCH_MIPS
case lxc_seccomp_arch_mips: arch = SCMP_ARCH_MIPS; break; case lxc_seccomp_arch_mips:
case lxc_seccomp_arch_mips64: arch = SCMP_ARCH_MIPS64; break; arch = SCMP_ARCH_MIPS;
case lxc_seccomp_arch_mips64n32: arch = SCMP_ARCH_MIPS64N32; break; break;
case lxc_seccomp_arch_mipsel: arch = SCMP_ARCH_MIPSEL; break; case lxc_seccomp_arch_mips64:
case lxc_seccomp_arch_mipsel64: arch = SCMP_ARCH_MIPSEL64; break; arch = SCMP_ARCH_MIPS64;
case lxc_seccomp_arch_mipsel64n32: arch = SCMP_ARCH_MIPSEL64N32; break; 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 #endif
#ifdef SCMP_ARCH_S390X #ifdef SCMP_ARCH_S390X
case lxc_seccomp_arch_s390x: arch = SCMP_ARCH_S390X; break; case lxc_seccomp_arch_s390x:
arch = SCMP_ARCH_S390X;
break;
#endif #endif
default: return NULL; default:
return NULL;
} }
if ((ctx = seccomp_init(default_policy_action)) == NULL) { ctx = seccomp_init(default_policy_action);
if (!ctx) {
ERROR("Error initializing seccomp context"); ERROR("Error initializing seccomp context");
return NULL; return NULL;
} }
if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0)) {
ERROR("Failed to turn off no-new-privs"); ret = seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 0);
if (ret < 0) {
ERROR("%s - Failed to turn off no-new-privs", strerror(-ret));
seccomp_release(ctx); seccomp_release(ctx);
return NULL; return NULL;
} }
#ifdef SCMP_FLTATR_ATL_TSKIP #ifdef SCMP_FLTATR_ATL_TSKIP
if (seccomp_attr_set(ctx, SCMP_FLTATR_ATL_TSKIP, 1)) { ret = seccomp_attr_set(ctx, SCMP_FLTATR_ATL_TSKIP, 1);
WARN("Failed to turn on seccomp nop-skip, continuing"); if (ret < 0)
} WARN("%s - Failed to turn on seccomp nop-skip, continuing", strerror(-ret));
#endif #endif
ret = seccomp_arch_exist(ctx, arch); ret = seccomp_arch_exist(ctx, arch);
@ -421,16 +462,12 @@ scmp_filter_ctx get_new_ctx(enum lxc_hostarch_t n_arch, uint32_t default_policy_
bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx, bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx,
struct seccomp_v2_rule *rule) struct seccomp_v2_rule *rule)
{ {
int nr, ret, i; int i, nr, ret;
struct scmp_arg_cmp arg_cmp[6]; struct scmp_arg_cmp arg_cmp[6];
memset(arg_cmp, 0 ,sizeof(arg_cmp));
ret = seccomp_arch_exist(ctx, arch); ret = seccomp_arch_exist(ctx, arch);
if (arch && ret != 0) { if (arch && ret != 0) {
ERROR("BUG: Seccomp: rule and context arch do not match (arch " ERROR("%s - Seccomp: rule and context arch do not match (arch %d)", strerror(-ret), arch);
"%d): %s",
arch, strerror(-ret));
return false; return false;
} }
@ -440,30 +477,32 @@ bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx,
*p = '\0'; *p = '\0';
if (strncmp(line, "reject_force_umount", 19) == 0) { if (strncmp(line, "reject_force_umount", 19) == 0) {
INFO("Setting Seccomp rule to reject force umounts"); ret = seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EACCES),
ret = seccomp_rule_add_exact(ctx, SCMP_ACT_ERRNO(EACCES), SCMP_SYS(umount2), SCMP_SYS(umount2), 1,
1, SCMP_A1(SCMP_CMP_MASKED_EQ , MNT_FORCE , MNT_FORCE )); SCMP_A1(SCMP_CMP_MASKED_EQ, MNT_FORCE, MNT_FORCE));
if (ret < 0) { if (ret < 0) {
ERROR("Failed (%d) loading rule to reject force " ERROR("%s - Failed loading rule to reject force umount", strerror(-ret));
"umount: %s",
ret, strerror(-ret));
return false; return false;
} }
INFO("Set seccomp rule to reject force umounts");
return true; return true;
} }
nr = seccomp_syscall_resolve_name(line); nr = seccomp_syscall_resolve_name(line);
if (nr == __NR_SCMP_ERROR) { if (nr == __NR_SCMP_ERROR) {
WARN("Seccomp: failed to resolve syscall: %s", line); WARN("Failed to resolve syscall \"%s\"", line);
WARN("This syscall will NOT be blacklisted");
return true;
}
if (nr < 0) {
WARN("Seccomp: got negative for syscall: %d: %s", nr, line);
WARN("This syscall will NOT be blacklisted"); WARN("This syscall will NOT be blacklisted");
return true; return true;
} }
if (nr < 0) {
WARN("Got negative return value %d for syscall \"%s\"", nr, line);
WARN("This syscall will NOT be blacklisted");
return true;
}
memset(&arg_cmp, 0, sizeof(arg_cmp));
for (i = 0; i < rule->args_num; i++) { for (i = 0; i < rule->args_num; i++) {
INFO("arg_cmp[%d]: SCMP_CMP(%u, %llu, %llu, %llu)", i, INFO("arg_cmp[%d]: SCMP_CMP(%u, %llu, %llu, %llu)", i,
rule->args_value[i].index, rule->args_value[i].index,
@ -472,17 +511,25 @@ bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx,
(long long unsigned int)rule->args_value[i].value); (long long unsigned int)rule->args_value[i].value);
if (SCMP_CMP_MASKED_EQ == rule->args_value[i].op) if (SCMP_CMP_MASKED_EQ == rule->args_value[i].op)
arg_cmp[i] = SCMP_CMP(rule->args_value[i].index, rule->args_value[i].op, rule->args_value[i].mask, rule->args_value[i].value); arg_cmp[i] = SCMP_CMP(rule->args_value[i].index,
rule->args_value[i].op,
rule->args_value[i].mask,
rule->args_value[i].value);
else else
arg_cmp[i] = SCMP_CMP(rule->args_value[i].index, rule->args_value[i].op, rule->args_value[i].value); arg_cmp[i] = SCMP_CMP(rule->args_value[i].index,
rule->args_value[i].op,
rule->args_value[i].value);
} }
ret = seccomp_rule_add_exact_array(ctx, rule->action, nr, rule->args_num, arg_cmp); ret = seccomp_rule_add_exact_array(ctx, rule->action, nr,
rule->args_num, arg_cmp);
if (ret < 0) { if (ret < 0) {
ERROR("Failed (%d) loading rule for %s (nr %d action %d(%s)): %s", ERROR("%s - Failed loading rule for %s (nr %d action %d (%s))",
ret, line, nr, rule->action, get_action_name(rule->action), strerror(-ret)); strerror(-ret), line, nr, rule->action,
get_action_name(rule->action));
return false; return false;
} }
return true; return true;
} }
@ -502,12 +549,13 @@ bool do_resolve_add_rule(uint32_t arch, char *line, scmp_filter_ctx ctx,
*/ */
static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf) static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
{ {
char *p;
int ret; int ret;
char *p;
enum lxc_hostarch_t cur_rule_arch, native_arch;
size_t line_bufsz = 0;
bool blacklist = false; bool blacklist = false;
char *rule_line = NULL;
uint32_t default_policy_action = -1, default_rule_action = -1; uint32_t default_policy_action = -1, default_rule_action = -1;
enum lxc_hostarch_t native_arch = get_hostarch(),
cur_rule_arch = native_arch;
struct seccomp_v2_rule rule; struct seccomp_v2_rule rule;
struct scmp_ctx_info { struct scmp_ctx_info {
uint32_t architectures[3]; uint32_t architectures[3];
@ -518,11 +566,12 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
if (strncmp(line, "blacklist", 9) == 0) if (strncmp(line, "blacklist", 9) == 0)
blacklist = true; blacklist = true;
else if (strncmp(line, "whitelist", 9) != 0) { else if (strncmp(line, "whitelist", 9) != 0) {
ERROR("Bad seccomp policy style: %s", line); ERROR("Bad seccomp policy style \"%s\"", line);
return -1; return -1;
} }
if ((p = strchr(line, ' '))) { p = strchr(line, ' ');
if (p) {
default_policy_action = get_v2_default_action(p + 1); default_policy_action = get_v2_default_action(p + 1);
if (default_policy_action == -2) if (default_policy_action == -2)
return -1; return -1;
@ -532,11 +581,13 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
if (blacklist) { if (blacklist) {
if (default_policy_action == -1) if (default_policy_action == -1)
default_policy_action = SCMP_ACT_ALLOW; default_policy_action = SCMP_ACT_ALLOW;
if (default_rule_action == -1) if (default_rule_action == -1)
default_rule_action = SCMP_ACT_KILL; default_rule_action = SCMP_ACT_KILL;
} else { } else {
if (default_policy_action == -1) if (default_policy_action == -1)
default_policy_action = SCMP_ACT_KILL; default_policy_action = SCMP_ACT_KILL;
if (default_rule_action == -1) if (default_rule_action == -1)
default_rule_action = SCMP_ACT_ALLOW; default_rule_action = SCMP_ACT_ALLOW;
} }
@ -545,6 +596,8 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
ctx.architectures[0] = SCMP_ARCH_NATIVE; ctx.architectures[0] = SCMP_ARCH_NATIVE;
ctx.architectures[1] = SCMP_ARCH_NATIVE; ctx.architectures[1] = SCMP_ARCH_NATIVE;
ctx.architectures[2] = SCMP_ARCH_NATIVE; ctx.architectures[2] = SCMP_ARCH_NATIVE;
native_arch = get_hostarch();
cur_rule_arch = native_arch;
if (native_arch == lxc_seccomp_arch_amd64) { if (native_arch == lxc_seccomp_arch_amd64) {
cur_rule_arch = lxc_seccomp_arch_all; cur_rule_arch = lxc_seccomp_arch_all;
@ -591,16 +644,16 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
cur_rule_arch = lxc_seccomp_arch_all; cur_rule_arch = lxc_seccomp_arch_all;
ctx.architectures[0] = SCMP_ARCH_ARM; ctx.architectures[0] = SCMP_ARCH_ARM;
ctx.contexts[0] = ctx.contexts[0] = get_new_ctx(lxc_seccomp_arch_arm,
get_new_ctx(lxc_seccomp_arch_arm, default_policy_action, default_policy_action,
&ctx.needs_merge[0]); &ctx.needs_merge[0]);
if (!ctx.contexts[0]) if (!ctx.contexts[0])
goto bad; goto bad;
#ifdef SCMP_ARCH_AARCH64 #ifdef SCMP_ARCH_AARCH64
ctx.architectures[2] = SCMP_ARCH_AARCH64; ctx.architectures[2] = SCMP_ARCH_AARCH64;
ctx.contexts[2] = ctx.contexts[2] = get_new_ctx(lxc_seccomp_arch_arm64,
get_new_ctx(lxc_seccomp_arch_arm64, default_policy_action, default_policy_action,
&ctx.needs_merge[2]); &ctx.needs_merge[2]);
if (!ctx.contexts[2]) if (!ctx.contexts[2])
goto bad; goto bad;
@ -662,25 +715,30 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
ERROR("Error re-initializing Seccomp"); ERROR("Error re-initializing Seccomp");
return -1; return -1;
} }
if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0)) {
ERROR("Failed to turn off no-new-privs"); ret = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_CTL_NNP, 0);
if (ret < 0) {
ERROR("%s - Failed to turn off no-new-privs", strerror(-ret));
return -1; return -1;
} }
#ifdef SCMP_FLTATR_ATL_TSKIP #ifdef SCMP_FLTATR_ATL_TSKIP
if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1)) { ret = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1);
WARN("Failed to turn on seccomp nop-skip, continuing"); if (ret < 0)
} WARN("%s - Failed to turn on seccomp nop-skip, continuing", strerror(-ret));
#endif #endif
} }
while (fgets(line, 1024, f)) { while (getline(&rule_line, &line_bufsz, f) != -1) {
if (line[0] == '#') if (line[0] == '#')
continue; continue;
if (strlen(line) == 0)
if (line[0] == '\0')
continue; continue;
remove_trailing_newlines(line); remove_trailing_newlines(line);
INFO("processing: .%s", line);
INFO("Processing \"%s\"", line);
if (line[0] == '[') { if (line[0] == '[') {
/* Read the architecture for next set of rules. */ /* Read the architecture for next set of rules. */
if (strcmp(line, "[x86]") == 0 || if (strcmp(line, "[x86]") == 0 ||
@ -690,6 +748,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
cur_rule_arch = lxc_seccomp_arch_unknown; cur_rule_arch = lxc_seccomp_arch_unknown;
continue; continue;
} }
cur_rule_arch = lxc_seccomp_arch_i386; cur_rule_arch = lxc_seccomp_arch_i386;
} else if (strcmp(line, "[x32]") == 0 || } else if (strcmp(line, "[x32]") == 0 ||
strcmp(line, "[X32]") == 0) { strcmp(line, "[X32]") == 0) {
@ -697,6 +756,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
cur_rule_arch = lxc_seccomp_arch_unknown; cur_rule_arch = lxc_seccomp_arch_unknown;
continue; continue;
} }
cur_rule_arch = lxc_seccomp_arch_x32; cur_rule_arch = lxc_seccomp_arch_x32;
} else if (strcmp(line, "[X86_64]") == 0 || } else if (strcmp(line, "[X86_64]") == 0 ||
strcmp(line, "[x86_64]") == 0) { strcmp(line, "[x86_64]") == 0) {
@ -704,6 +764,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
cur_rule_arch = lxc_seccomp_arch_unknown; cur_rule_arch = lxc_seccomp_arch_unknown;
continue; continue;
} }
cur_rule_arch = lxc_seccomp_arch_amd64; cur_rule_arch = lxc_seccomp_arch_amd64;
} else if (strcmp(line, "[all]") == 0 || } else if (strcmp(line, "[all]") == 0 ||
strcmp(line, "[ALL]") == 0) { strcmp(line, "[ALL]") == 0) {
@ -717,6 +778,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
cur_rule_arch = lxc_seccomp_arch_unknown; cur_rule_arch = lxc_seccomp_arch_unknown;
continue; continue;
} }
cur_rule_arch = lxc_seccomp_arch_arm; cur_rule_arch = lxc_seccomp_arch_arm;
} }
#endif #endif
@ -727,6 +789,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
cur_rule_arch = lxc_seccomp_arch_unknown; cur_rule_arch = lxc_seccomp_arch_unknown;
continue; continue;
} }
cur_rule_arch = lxc_seccomp_arch_arm64; cur_rule_arch = lxc_seccomp_arch_arm64;
} }
#endif #endif
@ -737,6 +800,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
cur_rule_arch = lxc_seccomp_arch_unknown; cur_rule_arch = lxc_seccomp_arch_unknown;
continue; continue;
} }
cur_rule_arch = lxc_seccomp_arch_ppc64le; cur_rule_arch = lxc_seccomp_arch_ppc64le;
} }
#endif #endif
@ -747,6 +811,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
cur_rule_arch = lxc_seccomp_arch_unknown; cur_rule_arch = lxc_seccomp_arch_unknown;
continue; continue;
} }
cur_rule_arch = lxc_seccomp_arch_ppc64; cur_rule_arch = lxc_seccomp_arch_ppc64;
} }
#endif #endif
@ -758,6 +823,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
cur_rule_arch = lxc_seccomp_arch_unknown; cur_rule_arch = lxc_seccomp_arch_unknown;
continue; continue;
} }
cur_rule_arch = lxc_seccomp_arch_ppc; cur_rule_arch = lxc_seccomp_arch_ppc;
} }
#endif #endif
@ -768,6 +834,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
cur_rule_arch = lxc_seccomp_arch_unknown; cur_rule_arch = lxc_seccomp_arch_unknown;
continue; continue;
} }
cur_rule_arch = lxc_seccomp_arch_mips64; cur_rule_arch = lxc_seccomp_arch_mips64;
} else if (strcmp(line, "[mips64n32]") == 0 || } else if (strcmp(line, "[mips64n32]") == 0 ||
strcmp(line, "[MIPS64N32]") == 0) { strcmp(line, "[MIPS64N32]") == 0) {
@ -775,6 +842,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
cur_rule_arch = lxc_seccomp_arch_unknown; cur_rule_arch = lxc_seccomp_arch_unknown;
continue; continue;
} }
cur_rule_arch = lxc_seccomp_arch_mips64n32; cur_rule_arch = lxc_seccomp_arch_mips64n32;
} else if (strcmp(line, "[mips]") == 0 || } else if (strcmp(line, "[mips]") == 0 ||
strcmp(line, "[MIPS]") == 0) { strcmp(line, "[MIPS]") == 0) {
@ -783,6 +851,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
cur_rule_arch = lxc_seccomp_arch_unknown; cur_rule_arch = lxc_seccomp_arch_unknown;
continue; continue;
} }
cur_rule_arch = lxc_seccomp_arch_mips; cur_rule_arch = lxc_seccomp_arch_mips;
} else if (strcmp(line, "[mipsel64]") == 0 || } else if (strcmp(line, "[mipsel64]") == 0 ||
strcmp(line, "[MIPSEL64]") == 0) { strcmp(line, "[MIPSEL64]") == 0) {
@ -790,6 +859,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
cur_rule_arch = lxc_seccomp_arch_unknown; cur_rule_arch = lxc_seccomp_arch_unknown;
continue; continue;
} }
cur_rule_arch = lxc_seccomp_arch_mipsel64; cur_rule_arch = lxc_seccomp_arch_mipsel64;
} else if (strcmp(line, "[mipsel64n32]") == 0 || } else if (strcmp(line, "[mipsel64n32]") == 0 ||
strcmp(line, "[MIPSEL64N32]") == 0) { strcmp(line, "[MIPSEL64N32]") == 0) {
@ -797,6 +867,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
cur_rule_arch = lxc_seccomp_arch_unknown; cur_rule_arch = lxc_seccomp_arch_unknown;
continue; continue;
} }
cur_rule_arch = lxc_seccomp_arch_mipsel64n32; cur_rule_arch = lxc_seccomp_arch_mipsel64n32;
} else if (strcmp(line, "[mipsel]") == 0 || } else if (strcmp(line, "[mipsel]") == 0 ||
strcmp(line, "[MIPSEL]") == 0) { strcmp(line, "[MIPSEL]") == 0) {
@ -805,6 +876,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
cur_rule_arch = lxc_seccomp_arch_unknown; cur_rule_arch = lxc_seccomp_arch_unknown;
continue; continue;
} }
cur_rule_arch = lxc_seccomp_arch_mipsel; cur_rule_arch = lxc_seccomp_arch_mipsel;
} }
#endif #endif
@ -815,11 +887,12 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
cur_rule_arch = lxc_seccomp_arch_unknown; cur_rule_arch = lxc_seccomp_arch_unknown;
continue; continue;
} }
cur_rule_arch = lxc_seccomp_arch_s390x; cur_rule_arch = lxc_seccomp_arch_s390x;
}
#endif #endif
else } else {
goto bad_arch; goto bad_arch;
}
continue; continue;
} }
@ -839,6 +912,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line, if (!do_resolve_add_rule(SCMP_ARCH_NATIVE, line,
conf->seccomp_ctx, &rule)) conf->seccomp_ctx, &rule))
goto bad_rule; goto bad_rule;
INFO("Added native rule for arch %d for %s action %d(%s)", INFO("Added native rule for arch %d for %s action %d(%s)",
SCMP_ARCH_NATIVE, line, rule.action, SCMP_ARCH_NATIVE, line, rule.action,
get_action_name(rule.action)); get_action_name(rule.action));
@ -847,6 +921,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
if (!do_resolve_add_rule(ctx.architectures[0], line, if (!do_resolve_add_rule(ctx.architectures[0], line,
ctx.contexts[0], &rule)) ctx.contexts[0], &rule))
goto bad_rule; goto bad_rule;
INFO("Added compat rule for arch %d for %s action %d(%s)", INFO("Added compat rule for arch %d for %s action %d(%s)",
ctx.architectures[0], line, rule.action, ctx.architectures[0], line, rule.action,
get_action_name(rule.action)); get_action_name(rule.action));
@ -856,6 +931,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
if (!do_resolve_add_rule(ctx.architectures[1], line, if (!do_resolve_add_rule(ctx.architectures[1], line,
ctx.contexts[1], &rule)) ctx.contexts[1], &rule))
goto bad_rule; goto bad_rule;
INFO("Added compat rule for arch %d for %s action %d(%s)", INFO("Added compat rule for arch %d for %s action %d(%s)",
ctx.architectures[1], line, rule.action, ctx.architectures[1], line, rule.action,
get_action_name(rule.action)); get_action_name(rule.action));
@ -865,6 +941,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
if (!do_resolve_add_rule(ctx.architectures[2], line, if (!do_resolve_add_rule(ctx.architectures[2], line,
ctx.contexts[2], &rule)) ctx.contexts[2], &rule))
goto bad_rule; goto bad_rule;
INFO("Added native rule for arch %d for %s action %d(%s)", INFO("Added native rule for arch %d for %s action %d(%s)",
ctx.architectures[2], line, rule.action, ctx.architectures[2], line, rule.action,
get_action_name(rule.action)); get_action_name(rule.action));
@ -880,6 +957,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
"context into main context"); "context into main context");
goto bad; goto bad;
} }
TRACE("Merged first compat seccomp context into main context"); TRACE("Merged first compat seccomp context into main context");
} else { } else {
seccomp_release(ctx.contexts[0]); seccomp_release(ctx.contexts[0]);
@ -895,6 +973,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
"context into main context"); "context into main context");
goto bad; goto bad;
} }
TRACE("Merged second compat seccomp context into main context"); TRACE("Merged second compat seccomp context into main context");
} else { } else {
seccomp_release(ctx.contexts[1]); seccomp_release(ctx.contexts[1]);
@ -910,6 +989,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
"context into main context"); "context into main context");
goto bad; goto bad;
} }
TRACE("Merged third compat seccomp context into main context"); TRACE("Merged third compat seccomp context into main context");
} else { } else {
seccomp_release(ctx.contexts[2]); seccomp_release(ctx.contexts[2]);
@ -917,19 +997,25 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
} }
} }
free(rule_line);
return 0; return 0;
bad_arch: bad_arch:
ERROR("Unsupported arch: %s.", line); ERROR("Unsupported architecture \"%s\"", line);
bad_rule: bad_rule:
bad: bad:
if (ctx.contexts[0]) if (ctx.contexts[0])
seccomp_release(ctx.contexts[0]); seccomp_release(ctx.contexts[0]);
if (ctx.contexts[1]) if (ctx.contexts[1])
seccomp_release(ctx.contexts[1]); seccomp_release(ctx.contexts[1]);
if (ctx.contexts[2]) if (ctx.contexts[2])
seccomp_release(ctx.contexts[2]); seccomp_release(ctx.contexts[2]);
free(rule_line);
return -1; return -1;
} }
#else /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */ #else /* HAVE_DECL_SECCOMP_SYSCALL_RESOLVE_NAME_ARCH */
@ -949,7 +1035,7 @@ static int parse_config_v2(FILE *f, char *line, struct lxc_conf *conf)
*/ */
static int parse_config(FILE *f, struct lxc_conf *conf) static int parse_config(FILE *f, struct lxc_conf *conf)
{ {
char line[1024]; char line[MAXPATHLEN];
int ret, version; int ret, version;
ret = fscanf(f, "%d\n", &version); ret = fscanf(f, "%d\n", &version);
@ -957,10 +1043,12 @@ static int parse_config(FILE *f, struct lxc_conf *conf)
ERROR("Invalid version"); ERROR("Invalid version");
return -1; return -1;
} }
if (!fgets(line, 1024, f)) {
if (!fgets(line, MAXPATHLEN, f)) {
ERROR("Invalid config file"); ERROR("Invalid config file");
return -1; return -1;
} }
if (version == 1 && !strstr(line, "whitelist")) { if (version == 1 && !strstr(line, "whitelist")) {
ERROR("Only whitelist policy is supported"); ERROR("Only whitelist policy is supported");
return -1; return -1;
@ -973,6 +1061,7 @@ static int parse_config(FILE *f, struct lxc_conf *conf)
if (version == 1) if (version == 1)
return parse_config_v1(f, conf); return parse_config_v1(f, conf);
return parse_config_v2(f, line, conf); return parse_config_v2(f, line, conf);
} }
@ -985,48 +1074,54 @@ static int parse_config(FILE *f, struct lxc_conf *conf)
*/ */
static bool use_seccomp(void) static bool use_seccomp(void)
{ {
FILE *f = fopen("/proc/self/status", "r");
char line[1024];
bool already_enabled = false;
bool found = false;
int ret, v; int ret, v;
FILE *f;
size_t line_bufsz = 0;
char *line = NULL;
bool already_enabled = false, found = false;
f = fopen("/proc/self/status", "r");
if (!f) if (!f)
return true; return true;
while (fgets(line, 1024, f)) { while (getline(&line, &line_bufsz, f) != -1) {
if (strncmp(line, "Seccomp:", 8) == 0) { if (strncmp(line, "Seccomp:", 8) == 0) {
found = true; found = true;
ret = sscanf(line + 8, "%d", &v); ret = sscanf(line + 8, "%d", &v);
if (ret == 1 && v != 0) if (ret == 1 && v != 0)
already_enabled = true; already_enabled = true;
break; break;
} }
} }
free(line);
fclose(f); fclose(f);
if (!found) { /* no Seccomp line, no seccomp in kernel */
if (!found) {
INFO("Seccomp is not enabled in the kernel"); INFO("Seccomp is not enabled in the kernel");
return false; return false;
} }
if (already_enabled) { /* already seccomp-confined */
if (already_enabled) {
INFO("Already seccomp-confined, not loading new policy"); INFO("Already seccomp-confined, not loading new policy");
return false; return false;
} }
return true; return true;
} }
int lxc_read_seccomp_config(struct lxc_conf *conf) int lxc_read_seccomp_config(struct lxc_conf *conf)
{ {
int check_seccomp_attr_set, ret;
FILE *f; FILE *f;
int ret;
int check_seccomp_attr_set;
if (!conf->seccomp) if (!conf->seccomp)
return 0; return 0;
if (!use_seccomp()) if (!use_seccomp())
return 0; return 0;
#if HAVE_SCMP_FILTER_CTX #if HAVE_SCMP_FILTER_CTX
/* XXX for debug, pass in SCMP_ACT_TRAP */ /* XXX for debug, pass in SCMP_ACT_TRAP */
conf->seccomp_ctx = seccomp_init(SCMP_ACT_KILL); conf->seccomp_ctx = seccomp_init(SCMP_ACT_KILL);
@ -1047,13 +1142,14 @@ int lxc_read_seccomp_config(struct lxc_conf *conf)
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 #endif
if (check_seccomp_attr_set) { if (check_seccomp_attr_set) {
ERROR("Failed to turn off no-new-privs"); ERROR("%s - Failed to turn off no-new-privs", strerror(-check_seccomp_attr_set));
return -1; return -1;
} }
#ifdef SCMP_FLTATR_ATL_TSKIP #ifdef SCMP_FLTATR_ATL_TSKIP
if (seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1)) { check_seccomp_attr_set = seccomp_attr_set(conf->seccomp_ctx, SCMP_FLTATR_ATL_TSKIP, 1);
WARN("Failed to turn on seccomp nop-skip, continuing"); if (check_seccomp_attr_set < 0)
} WARN("%s - Failed to turn on seccomp nop-skip, continuing",
strerror(-check_seccomp_attr_set));
#endif #endif
f = fopen(conf->seccomp, "r"); f = fopen(conf->seccomp, "r");
@ -1061,39 +1157,46 @@ int lxc_read_seccomp_config(struct lxc_conf *conf)
SYSERROR("Failed to open seccomp policy file %s", conf->seccomp); SYSERROR("Failed to open seccomp policy file %s", conf->seccomp);
return -1; return -1;
} }
ret = parse_config(f, conf); ret = parse_config(f, conf);
fclose(f); fclose(f);
return ret; return ret;
} }
int lxc_seccomp_load(struct lxc_conf *conf) int lxc_seccomp_load(struct lxc_conf *conf)
{ {
int ret; int ret;
if (!conf->seccomp) if (!conf->seccomp)
return 0; return 0;
if (!use_seccomp()) if (!use_seccomp())
return 0; return 0;
ret = seccomp_load(
#if HAVE_SCMP_FILTER_CTX #if HAVE_SCMP_FILTER_CTX
conf->seccomp_ctx ret = seccomp_load(conf->seccomp_ctx);
#else
ret = seccomp_load();
#endif #endif
);
if (ret < 0) { if (ret < 0) {
ERROR("Error loading the seccomp policy: %s", strerror(-ret)); ERROR("%s- Error loading the seccomp policy", strerror(-ret));
return -1; return -1;
} }
/* After load seccomp filter into the kernel successfully, export the current seccomp /* After load seccomp filter into the kernel successfully, export the current seccomp
* filter to log file */ * filter to log file */
#if HAVE_SCMP_FILTER_CTX #if HAVE_SCMP_FILTER_CTX
if ((lxc_log_get_level() <= LXC_LOG_LEVEL_TRACE || conf->loglevel <= LXC_LOG_LEVEL_TRACE) && if ((lxc_log_get_level() <= LXC_LOG_LEVEL_TRACE ||
conf->loglevel <= LXC_LOG_LEVEL_TRACE) &&
lxc_log_fd >= 0) { lxc_log_fd >= 0) {
ret = seccomp_export_pfc(conf->seccomp_ctx, lxc_log_fd); ret = seccomp_export_pfc(conf->seccomp_ctx, lxc_log_fd);
/* Just give an warning when export error */ /* Just give an warning when export error */
if (ret < 0) if (ret < 0)
WARN("Failed to export seccomp filter to log file: %s", strerror(-ret)); WARN("%s - Failed to export seccomp filter to log file", strerror(-ret));
} }
#endif #endif
return 0; return 0;
} }
@ -1101,6 +1204,7 @@ void lxc_seccomp_free(struct lxc_conf *conf)
{ {
free(conf->seccomp); free(conf->seccomp);
conf->seccomp = NULL; conf->seccomp = NULL;
#if HAVE_SCMP_FILTER_CTX #if HAVE_SCMP_FILTER_CTX
if (conf->seccomp_ctx) { if (conf->seccomp_ctx) {
seccomp_release(conf->seccomp_ctx); seccomp_release(conf->seccomp_ctx);

View File

@ -2533,3 +2533,14 @@ int lxc_set_death_signal(int signal)
return 0; return 0;
} }
void remove_trailing_newlines(char *l)
{
char *p = l;
while (*p)
p++;
while (--p >= l && *p == '\n')
*p = '\0';
}

View File

@ -453,6 +453,7 @@ extern void lxc_free_array(void **array, lxc_free_fn element_free_fn);
extern size_t lxc_array_len(void **array); extern size_t lxc_array_len(void **array);
extern void **lxc_append_null_to_array(void **array, size_t count); extern void **lxc_append_null_to_array(void **array, size_t count);
extern void remove_trailing_newlines(char *l);
/* initialize rand with urandom */ /* initialize rand with urandom */
extern int randseed(bool); extern int randseed(bool);