From 82d832b435a0ae799011aeec75584af8188fb8db Mon Sep 17 00:00:00 2001 From: Kevin Kuehler Date: Sun, 24 Nov 2019 01:27:09 -0800 Subject: [PATCH 1/3] basic: Drop ambient inherited capabilities by default Modify the functions capability_update_inherited_set() and capability_ambient_set_apply() to drop capabilities not explicitly requested by the user. --- src/basic/capability-util.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/basic/capability-util.c b/src/basic/capability-util.c index d084ad5cf5..93237646cc 100644 --- a/src/basic/capability-util.c +++ b/src/basic/capability-util.c @@ -86,20 +86,17 @@ unsigned long cap_last_cap(void) { int capability_update_inherited_set(cap_t caps, uint64_t set) { unsigned long i; - /* Add capabilities in the set to the inherited caps. Do not apply - * them yet. */ + /* Add capabilities in the set to the inherited caps, drops capabilities not in the set. + * Do not apply them yet. */ for (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; - if (set & (UINT64_C(1) << i)) { - cap_value_t v; + v = (cap_value_t) i; - v = (cap_value_t) i; - - /* Make the capability inheritable. */ - if (cap_set_flag(caps, CAP_INHERITABLE, 1, &v, CAP_SET) < 0) - return -errno; - } + if (cap_set_flag(caps, CAP_INHERITABLE, 1, &v, flag) < 0) + return -errno; } return 0; @@ -132,6 +129,17 @@ int capability_ambient_set_apply(uint64_t set, bool also_inherit) { /* Add the capability to the ambient set. */ if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0) < 0) return -errno; + } else { + + /* Drop the capability so we don't inherit capabilities we didn't ask for. */ + r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, i, 0, 0); + if (r < 0) + return -errno; + + if (r) + if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, i, 0, 0) < 0) + return -errno; + } } From 155a6234ea2c0ddab69d539ac9d8e57b49909e17 Mon Sep 17 00:00:00 2001 From: Kevin Kuehler Date: Mon, 25 Nov 2019 17:52:42 -0800 Subject: [PATCH 2/3] test-capability: Modify ambient capability tests to test clearing caps Change test_set_ambient_caps() to test_apply_ambient_caps(), since the function capability_ambient_set_apply() not only sets ambient capabilities, but clears inherited capabilities that are not explicitly requested by the caller. --- src/test/test-capability.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/test/test-capability.c b/src/test/test-capability.c index 295136e1ef..74b27379ea 100644 --- a/src/test/test-capability.c +++ b/src/test/test-capability.c @@ -195,7 +195,7 @@ static void test_update_inherited_set(void) { cap_free(caps); } -static void test_set_ambient_caps(void) { +static void test_apply_ambient_caps(void) { cap_t caps; uint64_t set = 0; cap_flag_value_t fv; @@ -207,11 +207,21 @@ static void test_set_ambient_caps(void) { assert_se(!capability_ambient_set_apply(set, true)); caps = cap_get_proc(); + assert_se(caps); assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv)); - assert(fv == CAP_SET); + assert_se(fv == CAP_SET); cap_free(caps); assert_se(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0) == 1); + + assert_se(!capability_ambient_set_apply(0, true)); + caps = cap_get_proc(); + assert_se(caps); + assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv)); + assert_se(fv == CAP_CLEAR); + cap_free(caps); + + assert_se(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0) == 0); } static void test_ensure_cap_64bit(void) { @@ -259,7 +269,7 @@ int main(int argc, char *argv[]) { fork_test(test_have_effective_cap); if (run_ambient) - fork_test(test_set_ambient_caps); + fork_test(test_apply_ambient_caps); return 0; } From 943800f4e7728feb2416dd57b8c296614497b94f Mon Sep 17 00:00:00 2001 From: Kevin Kuehler Date: Tue, 26 Nov 2019 11:20:14 -0800 Subject: [PATCH 3/3] execute: Call capability_ambient_set_apply even if ambient set is 0 The function capability_ambient_set_apply() now drops capabilities not in the capability_ambient_set(), so it is necessary to call it when the ambient set is empty. Fixes #13163 --- src/core/execute.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/execute.c b/src/core/execute.c index abc164ff5b..4f96d1f410 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -3595,8 +3595,7 @@ static int exec_child( /* This is done before enforce_user, but ambient set * does not survive over setresuid() if keep_caps is not set. */ - if (!needs_ambient_hack && - context->capability_ambient_set != 0) { + if (!needs_ambient_hack) { r = capability_ambient_set_apply(context->capability_ambient_set, true); if (r < 0) { *exit_status = EXIT_CAPABILITIES;