X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fcore%2Fexecute.c;h=9de6e8726f2c42ac05e6a855cc29dadac13016d0;hb=f513e420c8b1a1d4c13092cd378f048b69793497;hp=f8b7521ff9ceb20b4a8f81b96036d40cb37c2e68;hpb=1756a0118ea1ab25fd46c853e89853c7e4b3038c;p=elogind.git diff --git a/src/core/execute.c b/src/core/execute.c index f8b7521ff..9de6e8726 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -55,6 +55,10 @@ #include #endif +#ifdef HAVE_APPARMOR +#include +#endif + #include "execute.h" #include "strv.h" #include "macro.h" @@ -77,6 +81,8 @@ #include "async.h" #include "selinux-util.h" #include "errno-list.h" +#include "af-list.h" +#include "apparmor-util.h" #ifdef HAVE_SECCOMP #include "seccomp-util.h" @@ -964,34 +970,155 @@ static int apply_seccomp(ExecContext *c) { r = seccomp_arch_add(seccomp, PTR_TO_UINT32(id) - 1); if (r == -EEXIST) continue; - if (r < 0) { - seccomp_release(seccomp); - return r; - } + if (r < 0) + goto finish; } - } else { + } else { r = seccomp_add_secondary_archs(seccomp); - if (r < 0) { - seccomp_release(seccomp); - return r; - } + if (r < 0) + goto finish; } action = c->syscall_whitelist ? SCMP_ACT_ALLOW : negative_action; SET_FOREACH(id, c->syscall_filter, i) { r = seccomp_rule_add(seccomp, action, PTR_TO_INT(id) - 1, 0); - if (r < 0) { - seccomp_release(seccomp); - return r; - } + if (r < 0) + goto finish; } + r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0); + if (r < 0) + goto finish; + r = seccomp_load(seccomp); + +finish: seccomp_release(seccomp); + return r; +} + +static int apply_address_families(ExecContext *c) { + scmp_filter_ctx *seccomp; + Iterator i; + int r; + + assert(c); + + seccomp = seccomp_init(SCMP_ACT_ALLOW); + if (!seccomp) + return -ENOMEM; + r = seccomp_add_secondary_archs(seccomp); + if (r < 0) + goto finish; + + if (c->address_families_whitelist) { + int af, first = 0, last = 0; + void *afp; + + /* If this is a whitelist, we first block the address + * families that are out of range and then everything + * that is not in the set. First, we find the lowest + * and highest address family in the set. */ + + SET_FOREACH(afp, c->address_families, i) { + af = PTR_TO_INT(afp); + + if (af <= 0 || af >= af_max()) + continue; + + if (first == 0 || af < first) + first = af; + + if (last == 0 || af > last) + last = af; + } + + assert((first == 0) == (last == 0)); + + if (first == 0) { + + /* No entries in the valid range, block everything */ + r = seccomp_rule_add( + seccomp, + SCMP_ACT_ERRNO(EPROTONOSUPPORT), + SCMP_SYS(socket), + 0); + if (r < 0) + goto finish; + + } else { + + /* Block everything below the first entry */ + r = seccomp_rule_add( + seccomp, + SCMP_ACT_ERRNO(EPROTONOSUPPORT), + SCMP_SYS(socket), + 1, + SCMP_A0(SCMP_CMP_LT, first)); + if (r < 0) + goto finish; + + /* Block everything above the last entry */ + r = seccomp_rule_add( + seccomp, + SCMP_ACT_ERRNO(EPROTONOSUPPORT), + SCMP_SYS(socket), + 1, + SCMP_A0(SCMP_CMP_GT, last)); + if (r < 0) + goto finish; + + /* Block everything between the first and last + * entry */ + for (af = 1; af < af_max(); af++) { + + if (set_contains(c->address_families, INT_TO_PTR(af))) + continue; + + r = seccomp_rule_add( + seccomp, + SCMP_ACT_ERRNO(EPROTONOSUPPORT), + SCMP_SYS(socket), + 1, + SCMP_A0(SCMP_CMP_EQ, af)); + if (r < 0) + goto finish; + } + } + + } else { + void *af; + + /* If this is a blacklist, then generate one rule for + * each address family that are then combined in OR + * checks. */ + + SET_FOREACH(af, c->address_families, i) { + + r = seccomp_rule_add( + seccomp, + SCMP_ACT_ERRNO(EPROTONOSUPPORT), + SCMP_SYS(socket), + 1, + SCMP_A0(SCMP_CMP_EQ, PTR_TO_INT(af))); + if (r < 0) + goto finish; + } + } + + r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0); + if (r < 0) + goto finish; + + r = seccomp_load(seccomp); + +finish: + seccomp_release(seccomp); return r; } + #endif static void do_idle_pipe_dance(int idle_pipe[4]) { @@ -1579,7 +1706,18 @@ int exec_spawn(ExecCommand *command, } #ifdef HAVE_SECCOMP - if (context->syscall_filter || context->syscall_archs) { + if (context->address_families_whitelist || + !set_isempty(context->address_families)) { + err = apply_address_families(context); + if (err < 0) { + r = EXIT_ADDRESS_FAMILIES; + goto fail_child; + } + } + + if (context->syscall_whitelist || + !set_isempty(context->syscall_filter) || + !set_isempty(context->syscall_archs)) { err = apply_seccomp(context); if (err < 0) { r = EXIT_SECCOMP; @@ -1597,6 +1735,16 @@ int exec_spawn(ExecCommand *command, } } #endif + +#ifdef HAVE_APPARMOR + if (context->apparmor_profile && use_apparmor()) { + err = aa_change_onexec(context->apparmor_profile); + if (err < 0 && !context->apparmor_profile_ignore) { + r = EXIT_APPARMOR_PROFILE; + goto fail_child; + } + } +#endif } err = build_environment(context, n_fds, watchdog_usec, home, username, shell, &our_env); @@ -1759,13 +1907,17 @@ void exec_context_done(ExecContext *c) { free(c->selinux_context); c->selinux_context = NULL; -#ifdef HAVE_SECCOMP + free(c->apparmor_profile); + c->apparmor_profile = NULL; + set_free(c->syscall_filter); c->syscall_filter = NULL; set_free(c->syscall_archs); c->syscall_archs = NULL; -#endif + + set_free(c->address_families); + c->address_families = NULL; } void exec_command_done(ExecCommand *c) { @@ -2188,6 +2340,11 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { fprintf(f, "%sSystemCallErrorNumber: %s\n", prefix, strna(errno_to_name(c->syscall_errno))); + + if (c->apparmor_profile) + fprintf(f, + "%sAppArmorProfile: %s%s\n", + prefix, c->apparmor_profile_ignore ? "-" : "", c->apparmor_profile); } void exec_status_start(ExecStatus *s, pid_t pid) {