From 73090dc815390f4fca4e3ed8a7e1d3806605daaa Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Apr 2011 06:06:41 +0200 Subject: [PATCH] execute: when we run as PID 1 the kernel doesn't give us CAP_SETPCAP by default. Get that temporarily when dropping capabilities for good --- TODO | 11 ++++++++ src/execute.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 77 insertions(+), 7 deletions(-) diff --git a/TODO b/TODO index 80faf0fa3f..b4a5e3ab94 100644 --- a/TODO +++ b/TODO @@ -32,8 +32,16 @@ F15: * don't trim empty cgroups https://bugzilla.redhat.com/show_bug.cgi?id=678555 +* drop cap bounding set in logger, hostnamed, readahead, ... + +* timeout value is incorrectly parsed in /etc/fstab + Features: +* Add ListenSpecial to .socket units for /proc/kmsg and similar friends? + +* avoid DefaultStandardOutput=syslog to have any effect on StandardInput=socket services + * use pivot_root on shutdown so that we can unmount the root directory. * fix alsa mixer restore to not print error when no config is stored @@ -43,8 +51,11 @@ Features: * write blog stories about: - enabling dbus services - status update + - the new configuration files - you are a distro: why switch? +* maybe add tiny dbus services similar to hostnamed for locale? + * allow port = 0 in .socket units * rename systemd-logger to systemd-stdio-syslog-bridge diff --git a/src/execute.c b/src/execute.c index 1e376ff89e..745dcfcdb8 100644 --- a/src/execute.c +++ b/src/execute.c @@ -904,6 +904,68 @@ fail: } #endif +static int do_capability_bounding_set_drop(uint64_t drop) { + unsigned long i; + cap_t old_cap = NULL, new_cap = NULL; + cap_flag_value_t fv; + int r; + + /* If we are run as PID 1 we will lack CAP_SETPCAP by default + * in the effective set (yes, the kernel drops that when + * executing init!), so get it back temporarily so that we can + * call PR_CAPBSET_DROP. */ + + old_cap = cap_get_proc(); + if (!old_cap) + return -errno; + + if (cap_get_flag(old_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0) { + r = -errno; + goto finish; + } + + if (fv != CAP_SET) { + static const cap_value_t v = CAP_SETPCAP; + + new_cap = cap_dup(old_cap); + if (!new_cap) { + r = -errno; + goto finish; + } + + if (cap_set_flag(new_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0) { + r = -errno; + goto finish; + } + + if (cap_set_proc(new_cap) < 0) { + r = -errno; + goto finish; + } + } + + for (i = 0; i <= CAP_LAST_CAP; i++) + if (drop & ((uint64_t) 1ULL << (uint64_t) i)) { + if (prctl(PR_CAPBSET_DROP, i) < 0) { + r = -errno; + goto finish; + } + } + + r = 0; + +finish: + if (new_cap) + cap_free(new_cap); + + if (old_cap) { + cap_set_proc(old_cap); + cap_free(old_cap); + } + + return r; +} + int exec_spawn(ExecCommand *command, char **argv, const ExecContext *context, @@ -1251,13 +1313,10 @@ int exec_spawn(ExecCommand *command, } if (context->capability_bounding_set_drop) - for (i = 0; i <= CAP_LAST_CAP; i++) - if (context->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) i)) { - if (prctl(PR_CAPBSET_DROP, i) < 0) { - r = EXIT_CAPABILITIES; - goto fail_child; - } - } + if (do_capability_bounding_set_drop(context->capability_bounding_set_drop) < 0) { + r = EXIT_CAPABILITIES; + goto fail_child; + } if (context->user) if (enforce_user(context, uid) < 0) {