From ec8927ca5940e809f0b72f530582c76f1db4f065 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 24 May 2012 04:00:56 +0200 Subject: main: add configuration option to alter capability bounding set for PID 1 This also ensures that caps dropped from the bounding set are also dropped from the inheritable set, to be extra-secure. Usually that should change very little though as the inheritable set is empty for all our uses anyway. --- src/shared/capability.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) (limited to 'src/shared/capability.c') diff --git a/src/shared/capability.c b/src/shared/capability.c index b2cd9ed75e..08b7a209da 100644 --- a/src/shared/capability.c +++ b/src/shared/capability.c @@ -40,7 +40,8 @@ int have_effective_cap(int value) { cap_flag_value_t fv; int r; - if (!(cap = cap_get_proc())) + cap = cap_get_proc(); + if (!cap) return -errno; if (cap_get_flag(cap, value, CAP_EFFECTIVE, &fv) < 0) @@ -84,3 +85,89 @@ unsigned long cap_last_cap(void) { return p; } + +int capability_bounding_set_drop(uint64_t drop, bool right_now) { + unsigned long i; + cap_t after_cap = NULL, temp_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. */ + + after_cap = cap_get_proc(); + if (!after_cap) + return -errno; + + if (cap_get_flag(after_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0) { + cap_free(after_cap); + return -errno; + } + + if (fv != CAP_SET) { + static const cap_value_t v = CAP_SETPCAP; + + temp_cap = cap_dup(after_cap); + if (!temp_cap) { + r = -errno; + goto finish; + } + + if (cap_set_flag(temp_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0) { + r = -errno; + goto finish; + } + + if (cap_set_proc(temp_cap) < 0) { + r = -errno; + goto finish; + } + } + + for (i = 0; i <= cap_last_cap(); i++) { + + if (drop & ((uint64_t) 1ULL << (uint64_t) i)) { + cap_value_t v; + + /* Drop it from the bounding set */ + if (prctl(PR_CAPBSET_DROP, i) < 0) { + r = -errno; + goto finish; + } + v = i; + + /* Also drop it from the inheritable set, so + * that anything we exec() loses the + * capability for good. */ + if (cap_set_flag(after_cap, CAP_INHERITABLE, 1, &v, CAP_CLEAR) < 0) { + r = -errno; + goto finish; + } + + /* If we shall apply this right now drop it + * also from our own capability sets. */ + if (right_now) { + if (cap_set_flag(after_cap, CAP_PERMITTED, 1, &v, CAP_CLEAR) < 0 || + cap_set_flag(after_cap, CAP_EFFECTIVE, 1, &v, CAP_CLEAR) < 0) { + r = -errno; + goto finish; + } + } + } + } + + r = 0; + +finish: + if (temp_cap) + cap_free(temp_cap); + + if (after_cap) { + cap_set_proc(after_cap); + cap_free(after_cap); + } + + return r; +} -- cgit v1.2.3-54-g00ecf