From: Yu Watanabe Date: Thu, 23 Oct 2025 14:07:13 +0000 (+0900) Subject: capability-util: introduce capability_get() and use it in have_effective_cap() X-Git-Tag: v259-rc1~255^2~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e1c134ba9ce2e4ca9ffa70fc94a24898b863cc8a;p=thirdparty%2Fsystemd.git capability-util: introduce capability_get() and use it in have_effective_cap() capability_get() is a wrapper of capget() syscall and converts its result to CapabilityQuintet. This also introduce have_inheritable_cap(), which is similar to have_effective_cap(). It is currently unused, but will be used later. --- diff --git a/src/basic/capability-util.c b/src/basic/capability-util.c index bf7fd151c8a..ee665df6f9b 100644 --- a/src/basic/capability-util.c +++ b/src/basic/capability-util.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "alloc-util.h" @@ -20,6 +21,29 @@ #include "stat-util.h" #include "user-util.h" +int capability_get(CapabilityQuintet *ret) { + assert(ret); + + struct __user_cap_header_struct hdr = { + .version = _LINUX_CAPABILITY_VERSION_3, + .pid = getpid_cached(), + }; + + assert_cc(_LINUX_CAPABILITY_U32S_3 == 2); + struct __user_cap_data_struct data[_LINUX_CAPABILITY_U32S_3]; + if (syscall(SYS_capget, &hdr, data) < 0) + return -errno; + + *ret = (CapabilityQuintet) { + .effective = (uint64_t) data[0].effective | ((uint64_t) data[1].effective << 32), + .bounding = UINT64_MAX, + .inheritable = (uint64_t) data[0].inheritable | ((uint64_t) data[1].inheritable << 32), + .permitted = (uint64_t) data[0].permitted | ((uint64_t) data[1].permitted << 32), + .ambient = UINT64_MAX, + }; + return 0; +} + unsigned cap_last_cap(void) { static atomic_int saved = INT_MAX; int r, c; @@ -74,19 +98,30 @@ unsigned cap_last_cap(void) { return c; } -int have_effective_cap(int value) { - _cleanup_cap_free_ cap_t cap = NULL; - cap_flag_value_t fv = CAP_CLEAR; /* To avoid false-positive use-of-uninitialized-value error reported - * by fuzzers. */ +int have_effective_cap(unsigned cap) { + CapabilityQuintet q; + int r; - cap = cap_get_proc(); - if (!cap) - return -errno; + assert(cap <= CAP_LIMIT); - if (cap_get_flag(cap, value, CAP_EFFECTIVE, &fv) < 0) - return -errno; + r = capability_get(&q); + if (r < 0) + return r; + + return BIT_SET(q.effective, cap); +} + +int have_inheritable_cap(unsigned cap) { + CapabilityQuintet q; + int r; + + assert(cap <= CAP_LIMIT); + + r = capability_get(&q); + if (r < 0) + return r; - return fv == CAP_SET; + return BIT_SET(q.inheritable, cap); } int capability_update_inherited_set(cap_t caps, uint64_t set) { diff --git a/src/basic/capability-util.h b/src/basic/capability-util.h index d658bbe0659..78bd75db7b6 100644 --- a/src/basic/capability-util.h +++ b/src/basic/capability-util.h @@ -43,8 +43,11 @@ static inline bool capability_is_set(uint64_t v) { return v != CAP_MASK_UNSET; } +int capability_get(CapabilityQuintet *ret); + unsigned cap_last_cap(void); -int have_effective_cap(int value); +int have_effective_cap(unsigned cap); +int have_inheritable_cap(unsigned cap); int capability_gain_cap_setpcap(cap_t *ret_before_caps); int capability_bounding_set_drop(uint64_t keep, bool right_now); int capability_bounding_set_drop_usermode(uint64_t keep);