From a98f710fdf1a4d8206b42ea12f026840333ef1bc Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 23 Oct 2025 23:34:31 +0900 Subject: [PATCH] capability-util: use capability_get() and _apply() in capability_quintet_enforce() --- src/basic/capability-util.c | 180 ++++++++++-------------------------- 1 file changed, 47 insertions(+), 133 deletions(-) diff --git a/src/basic/capability-util.c b/src/basic/capability-util.c index b15a8b462c7..751e9936670 100644 --- a/src/basic/capability-util.c +++ b/src/basic/capability-util.c @@ -423,156 +423,68 @@ bool capability_quintet_mangle(CapabilityQuintet *q) { } int capability_quintet_enforce(const CapabilityQuintet *q) { - _cleanup_cap_free_ cap_t c = NULL, modified = NULL; + CapabilityQuintet c; + bool modified = false; int r; - if (q->ambient != CAP_MASK_UNSET) { - bool changed = false; - - c = cap_get_proc(); - if (!c) - return -errno; + if (q->ambient != CAP_MASK_UNSET || + q->inheritable != CAP_MASK_UNSET || + q->permitted != CAP_MASK_UNSET || + q->effective != CAP_MASK_UNSET) { + r = capability_get(&c); + if (r < 0) + return r; + } + if (q->ambient != CAP_MASK_UNSET) { /* In order to raise the ambient caps set we first need to raise the matching * inheritable + permitted cap */ - for (unsigned i = 0; i <= cap_last_cap(); i++) { - uint64_t m = UINT64_C(1) << i; - cap_value_t cv = (cap_value_t) i; - cap_flag_value_t old_value_inheritable, old_value_permitted; - - if ((q->ambient & m) == 0) - continue; - - if (cap_get_flag(c, cv, CAP_INHERITABLE, &old_value_inheritable) < 0) - return -errno; - if (cap_get_flag(c, cv, CAP_PERMITTED, &old_value_permitted) < 0) - return -errno; + if (!FLAGS_SET(c.permitted, q->ambient) || + !FLAGS_SET(c.inheritable, q->ambient)) { - if (old_value_inheritable == CAP_SET && old_value_permitted == CAP_SET) - continue; - - if (cap_set_flag(c, CAP_INHERITABLE, 1, &cv, CAP_SET) < 0) - return -errno; - if (cap_set_flag(c, CAP_PERMITTED, 1, &cv, CAP_SET) < 0) - return -errno; + c.permitted |= q->ambient; + c.inheritable |= q->ambient; - changed = true; + r = capability_apply(&c); + if (r < 0) + return r; } - if (changed) - if (cap_set_proc(c) < 0) - return -errno; - - r = capability_ambient_set_apply(q->ambient, false); + r = capability_ambient_set_apply(q->ambient, /* also_inherit= */ false); if (r < 0) return r; } if (q->inheritable != CAP_MASK_UNSET || q->permitted != CAP_MASK_UNSET || q->effective != CAP_MASK_UNSET) { - bool changed = false; - - if (!c) { - c = cap_get_proc(); - if (!c) - return -errno; - } - - for (unsigned i = 0; i <= cap_last_cap(); i++) { - uint64_t m = UINT64_C(1) << i; - cap_value_t cv = (cap_value_t) i; - - if (q->inheritable != CAP_MASK_UNSET) { - cap_flag_value_t old_value, new_value; - - if (cap_get_flag(c, cv, CAP_INHERITABLE, &old_value) < 0) { - if (errno == EINVAL) /* If the kernel knows more caps than this - * version of libcap, then this will return - * EINVAL. In that case, simply ignore it, - * pretend it doesn't exist. */ - continue; - - return -errno; - } - - new_value = (q->inheritable & m) ? CAP_SET : CAP_CLEAR; - - if (old_value != new_value) { - changed = true; - - if (cap_set_flag(c, CAP_INHERITABLE, 1, &cv, new_value) < 0) - return -errno; - } - } + if (!FLAGS_SET(c.effective, q->effective) || + !FLAGS_SET(c.permitted, q->permitted) || + !FLAGS_SET(c.inheritable, q->inheritable)) { - if (q->permitted != CAP_MASK_UNSET) { - cap_flag_value_t old_value, new_value; + c.effective |= q->effective; + c.permitted |= q->permitted; + c.inheritable |= q->inheritable; - if (cap_get_flag(c, cv, CAP_PERMITTED, &old_value) < 0) { - if (errno == EINVAL) - continue; - - return -errno; - } - - new_value = (q->permitted & m) ? CAP_SET : CAP_CLEAR; - - if (old_value != new_value) { - changed = true; - - if (cap_set_flag(c, CAP_PERMITTED, 1, &cv, new_value) < 0) - return -errno; - } - } - - if (q->effective != CAP_MASK_UNSET) { - cap_flag_value_t old_value, new_value; - - if (cap_get_flag(c, cv, CAP_EFFECTIVE, &old_value) < 0) { - if (errno == EINVAL) - continue; - - return -errno; - } - - new_value = (q->effective & m) ? CAP_SET : CAP_CLEAR; - - if (old_value != new_value) { - changed = true; - - if (cap_set_flag(c, CAP_EFFECTIVE, 1, &cv, new_value) < 0) - return -errno; - } - } - } - - if (changed) { - /* In order to change the bounding caps, we need to keep CAP_SETPCAP for a bit + /* Now, let's enforce the caps for the first time. Note that this is where we acquire + * caps in any of the sets we currently don't have. We have to do this before + * dropping the bounding caps below, since at that point we can never acquire new + * caps in inherited/permitted/effective anymore, but only lose them. + * + * In order to change the bounding caps, we need to keep CAP_SETPCAP for a bit * longer. Let's add it to our list hence for now. */ - if (q->bounding != CAP_MASK_UNSET) { - cap_value_t cv = CAP_SETPCAP; + if (q->bounding != CAP_MASK_UNSET && + (!BIT_SET(c.effective, CAP_SETPCAP) || !BIT_SET(c.permitted, CAP_SETPCAP))) { + CapabilityQuintet tmp = c; - modified = cap_dup(c); - if (!modified) - return -ENOMEM; - - if (cap_set_flag(modified, CAP_PERMITTED, 1, &cv, CAP_SET) < 0) - return -errno; - if (cap_set_flag(modified, CAP_EFFECTIVE, 1, &cv, CAP_SET) < 0) - return -errno; + SET_BIT(c.effective, CAP_SETPCAP); + SET_BIT(c.permitted, CAP_SETPCAP); - if (cap_compare(modified, c) == 0) { - /* No change? then drop this nonsense again */ - cap_free(modified); - modified = NULL; - } - } + modified = true; - /* Now, let's enforce the caps for the first time. Note that this is where we acquire - * caps in any of the sets we currently don't have. We have to do this before - * dropping the bounding caps below, since at that point we can never acquire new - * caps in inherited/permitted/effective anymore, but only lose them. */ - if (cap_set_proc(modified ?: c) < 0) - return -errno; + r = capability_apply(&tmp); + } else + r = capability_apply(&c); + if (r < 0) + return r; } } @@ -586,9 +498,11 @@ int capability_quintet_enforce(const CapabilityQuintet *q) { * we have already set only in the CAP_SETPCAP bit, which we needed for dropping the bounding * bits. This call only undoes bits and doesn't acquire any which means the bounding caps don't * matter. */ - if (modified) - if (cap_set_proc(c) < 0) - return -errno; + if (modified) { + r = capability_apply(&c); + if (r < 0) + return r; + } return 0; } -- 2.47.3