capability-util: introduce capability_apply() and use it in capability_ambient_set_apply()

This commit is contained in:
Yu Watanabe
2025-10-23 23:16:06 +09:00
parent e1c134ba9c
commit aa8ab67a6d
3 changed files with 32 additions and 45 deletions

View File

@@ -11,6 +11,7 @@
#include "bitfield.h"
#include "capability-list.h"
#include "capability-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "log.h"
@@ -44,6 +45,29 @@ int capability_get(CapabilityQuintet *ret) {
return 0;
}
static int capability_apply(const CapabilityQuintet *q) {
assert(q);
struct __user_cap_header_struct hdr = {
.version = _LINUX_CAPABILITY_VERSION_3,
.pid = getpid_cached(),
};
struct __user_cap_data_struct data[_LINUX_CAPABILITY_U32S_3] = {
{
.effective = (uint32_t) (q->effective & UINT32_MAX),
.inheritable = (uint32_t) (q->inheritable & UINT32_MAX),
.permitted = (uint32_t) (q->permitted & UINT32_MAX),
},
{
.effective = (uint32_t) (q->effective >> 32),
.inheritable = (uint32_t) (q->inheritable >> 32),
.permitted = (uint32_t) (q->permitted >> 32),
},
};
return RET_NERRNO(syscall(SYS_capset, &hdr, data));
}
unsigned cap_last_cap(void) {
static atomic_int saved = INT_MAX;
int r, c;
@@ -124,25 +148,7 @@ int have_inheritable_cap(unsigned cap) {
return BIT_SET(q.inheritable, cap);
}
int capability_update_inherited_set(cap_t caps, uint64_t set) {
/* Add capabilities in the set to the inherited caps, drops capabilities not in the set.
* Do not apply them yet. */
for (unsigned i = 0; i <= cap_last_cap(); i++) {
cap_flag_value_t flag = set & (UINT64_C(1) << i) ? CAP_SET : CAP_CLEAR;
cap_value_t v;
v = (cap_value_t) i;
if (cap_set_flag(caps, CAP_INHERITABLE, 1, &v, flag) < 0)
return -errno;
}
return 0;
}
int capability_ambient_set_apply(uint64_t set, bool also_inherit) {
_cleanup_cap_free_ cap_t caps = NULL;
int r;
/* Remove capabilities requested in ambient set, but not in the bounding set */
@@ -160,16 +166,17 @@ int capability_ambient_set_apply(uint64_t set, bool also_inherit) {
/* Add the capabilities to the ambient set (an possibly also the inheritable set) */
if (also_inherit) {
caps = cap_get_proc();
if (!caps)
return -errno;
CapabilityQuintet q;
r = capability_update_inherited_set(caps, set);
r = capability_get(&q);
if (r < 0)
return -errno;
return r;
if (cap_set_proc(caps) < 0)
return -errno;
q.inheritable = set;
r = capability_apply(&q);
if (r < 0)
return r;
}
for (unsigned i = 0; i <= cap_last_cap(); i++)

View File

@@ -53,7 +53,6 @@ int capability_bounding_set_drop(uint64_t keep, bool right_now);
int capability_bounding_set_drop_usermode(uint64_t keep);
int capability_ambient_set_apply(uint64_t set, bool also_inherit);
int capability_update_inherited_set(cap_t caps, uint64_t ambient_set);
int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities);

View File

@@ -183,23 +183,6 @@ static void test_have_effective_cap(void) {
assert_se(have_effective_cap(CAP_CHOWN) == 0);
}
static void test_update_inherited_set(void) {
cap_t caps;
uint64_t set = 0;
cap_flag_value_t fv;
caps = cap_get_proc();
assert_se(caps);
set = (UINT64_C(1) << CAP_CHOWN);
assert_se(!capability_update_inherited_set(caps, set));
assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv));
assert_se(fv == CAP_SET);
cap_free(caps);
}
static void test_apply_ambient_caps(void) {
cap_t caps;
uint64_t set = 0;
@@ -336,8 +319,6 @@ int main(int argc, char *argv[]) {
if (!userns_has_single_user())
test_drop_privileges();
test_update_inherited_set();
if (!userns_has_single_user())
fork_test(test_have_effective_cap);