]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/basic/capability-util.c
tree-wide: use UINT64_MAX or friends
[thirdparty/systemd.git] / src / basic / capability-util.c
index caffda62af870b5d3e627b83a83e950b25dd1d34..b31a9cb2113c0ab9d2ba5eeccadabfda1728e164 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <errno.h>
 #include <stdio.h>
@@ -18,7 +18,7 @@
 #include "util.h"
 
 int have_effective_cap(int value) {
-        _cleanup_cap_free_ cap_t cap;
+        _cleanup_cap_free_ cap_t cap = NULL;
         cap_flag_value_t fv;
 
         cap = cap_get_proc();
@@ -31,8 +31,8 @@ int have_effective_cap(int value) {
         return fv == CAP_SET;
 }
 
-unsigned long cap_last_cap(void) {
-        static thread_local unsigned long saved;
+unsigned cap_last_cap(void) {
+        static thread_local unsigned saved;
         static thread_local bool valid = false;
         _cleanup_free_ char *content = NULL;
         unsigned long p = 0;
@@ -65,7 +65,7 @@ unsigned long cap_last_cap(void) {
         if (prctl(PR_CAPBSET_READ, p) < 0) {
 
                 /* Hmm, look downwards, until we find one that works */
-                for (p--; p > 0; p --)
+                for (p--; p > 0; p--)
                         if (prctl(PR_CAPBSET_READ, p) >= 0)
                                 break;
 
@@ -84,12 +84,10 @@ 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, drops capabilities not in the set.
          * Do not apply them yet. */
 
-        for (i = 0; i <= cap_last_cap(); i++) {
+        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;
 
@@ -104,14 +102,27 @@ int capability_update_inherited_set(cap_t caps, uint64_t set) {
 
 int capability_ambient_set_apply(uint64_t set, bool also_inherit) {
         _cleanup_cap_free_ cap_t caps = NULL;
-        unsigned long i;
         int r;
 
+        /* Remove capabilities requested in ambient set, but not in the bounding set */
+        for (unsigned i = 0; i <= cap_last_cap(); i++) {
+                if (set == 0)
+                        break;
+
+                if (FLAGS_SET(set, (UINT64_C(1) << i)) && prctl(PR_CAPBSET_READ, i) != 1) {
+                        log_debug("Ambient capability %s requested but missing from bounding set,"
+                                        " suppressing automatically.", capability_to_name(i));
+                        set &= ~(UINT64_C(1) << i);
+                }
+        }
+
+        /* Add the capabilities to the ambient set (an possibly also the inheritable set) */
+
         /* Check that we can use PR_CAP_AMBIENT or quit early. */
         if (!ambient_capabilities_supported())
-                return 0;
-
-        /* Add the capabilities to the ambient set. */
+                return (set & all_capabilities()) == 0 ?
+                        0 : -EOPNOTSUPP; /* if actually no ambient caps are to be set, be silent,
+                                          * otherwise fail recognizably */
 
         if (also_inherit) {
                 caps = cap_get_proc();
@@ -126,7 +137,7 @@ int capability_ambient_set_apply(uint64_t set, bool also_inherit) {
                         return -errno;
         }
 
-        for (i = 0; i <= cap_last_cap(); i++) {
+        for (unsigned i = 0; i <= cap_last_cap(); i++) {
 
                 if (set & (UINT64_C(1) << i)) {
 
@@ -150,29 +161,21 @@ int capability_ambient_set_apply(uint64_t set, bool also_inherit) {
         return 0;
 }
 
-int capability_bounding_set_drop(uint64_t keep, bool right_now) {
-        _cleanup_cap_free_ cap_t before_cap = NULL, after_cap = NULL;
+int capability_gain_cap_setpcap(cap_t *ret_before_caps) {
+        _cleanup_cap_free_ cap_t caps = NULL;
         cap_flag_value_t fv;
-        unsigned long i;
-        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. */
-
-        before_cap = cap_get_proc();
-        if (!before_cap)
+        caps = cap_get_proc();
+        if (!caps)
                 return -errno;
 
-        if (cap_get_flag(before_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0)
+        if (cap_get_flag(caps, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0)
                 return -errno;
 
         if (fv != CAP_SET) {
                 _cleanup_cap_free_ cap_t temp_cap = NULL;
                 static const cap_value_t v = CAP_SETPCAP;
 
-                temp_cap = cap_dup(before_cap);
+                temp_cap = cap_dup(caps);
                 if (!temp_cap)
                         return -errno;
 
@@ -183,14 +186,33 @@ int capability_bounding_set_drop(uint64_t keep, bool right_now) {
                         log_debug_errno(errno, "Can't acquire effective CAP_SETPCAP bit, ignoring: %m");
 
                 /* If we didn't manage to acquire the CAP_SETPCAP bit, we continue anyway, after all this just means
-                 * we'll fail later, when we actually intend to drop some capabilities. */
+                 * we'll fail later, when we actually intend to drop some capabilities or try to set securebits. */
         }
+        if (ret_before_caps)
+                /* Return the capabilities as they have been before setting CAP_SETPCAP */
+                *ret_before_caps = TAKE_PTR(caps);
+
+        return 0;
+}
+
+int capability_bounding_set_drop(uint64_t keep, bool right_now) {
+        _cleanup_cap_free_ cap_t before_cap = NULL, after_cap = NULL;
+        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. */
+
+        r = capability_gain_cap_setpcap(&before_cap);
+        if (r < 0)
+                return r;
 
         after_cap = cap_dup(before_cap);
         if (!after_cap)
                 return -errno;
 
-        for (i = 0; i <= cap_last_cap(); i++) {
+        for (unsigned i = 0; i <= cap_last_cap(); i++) {
                 cap_value_t v;
 
                 if ((keep & (UINT64_C(1) << i)))
@@ -376,7 +398,6 @@ bool ambient_capabilities_supported(void) {
 }
 
 bool capability_quintet_mangle(CapabilityQuintet *q) {
-        unsigned long i;
         uint64_t combined, drop = 0;
         bool ambient_supported;
 
@@ -384,11 +405,11 @@ bool capability_quintet_mangle(CapabilityQuintet *q) {
 
         combined = q->effective | q->bounding | q->inheritable | q->permitted;
 
-        ambient_supported = q->ambient != (uint64_t) -1;
+        ambient_supported = q->ambient != UINT64_MAX;
         if (ambient_supported)
                 combined |= q->ambient;
 
-        for (i = 0; i <= cap_last_cap(); i++) {
+        for (unsigned i = 0; i <= cap_last_cap(); i++) {
                 unsigned long bit = UINT64_C(1) << i;
                 if (!FLAGS_SET(combined, bit))
                         continue;
@@ -416,17 +437,16 @@ int capability_quintet_enforce(const CapabilityQuintet *q) {
         _cleanup_cap_free_ cap_t c = NULL, modified = NULL;
         int r;
 
-        if (q->ambient != (uint64_t) -1) {
-                unsigned long i;
+        if (q->ambient != UINT64_MAX) {
                 bool changed = false;
 
                 c = cap_get_proc();
                 if (!c)
                         return -errno;
 
-                /* In order to raise the ambient caps set we first need to raise the matching inheritable + permitted
-                 * cap */
-                for (i = 0; i <= cap_last_cap(); i++) {
+                /* 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;
@@ -459,9 +479,8 @@ int capability_quintet_enforce(const CapabilityQuintet *q) {
                         return r;
         }
 
-        if (q->inheritable != (uint64_t) -1 || q->permitted != (uint64_t) -1 || q->effective != (uint64_t) -1) {
+        if (q->inheritable != UINT64_MAX || q->permitted != UINT64_MAX || q->effective != UINT64_MAX) {
                 bool changed = false;
-                unsigned long i;
 
                 if (!c) {
                         c = cap_get_proc();
@@ -469,11 +488,11 @@ int capability_quintet_enforce(const CapabilityQuintet *q) {
                                 return -errno;
                 }
 
-                for (i = 0; i <= cap_last_cap(); i++) {
+                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 != (uint64_t) -1) {
+                        if (q->inheritable != UINT64_MAX) {
                                 cap_flag_value_t old_value, new_value;
 
                                 if (cap_get_flag(c, cv, CAP_INHERITABLE, &old_value) < 0) {
@@ -496,7 +515,7 @@ int capability_quintet_enforce(const CapabilityQuintet *q) {
                                 }
                         }
 
-                        if (q->permitted != (uint64_t) -1) {
+                        if (q->permitted != UINT64_MAX) {
                                 cap_flag_value_t old_value, new_value;
 
                                 if (cap_get_flag(c, cv, CAP_PERMITTED, &old_value) < 0) {
@@ -516,7 +535,7 @@ int capability_quintet_enforce(const CapabilityQuintet *q) {
                                 }
                         }
 
-                        if (q->effective != (uint64_t) -1) {
+                        if (q->effective != UINT64_MAX) {
                                 cap_flag_value_t old_value, new_value;
 
                                 if (cap_get_flag(c, cv, CAP_EFFECTIVE, &old_value) < 0) {
@@ -540,7 +559,7 @@ int capability_quintet_enforce(const CapabilityQuintet *q) {
                 if (changed) {
                         /* 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 != (uint64_t) -1) {
+                        if (q->bounding != UINT64_MAX) {
                                 cap_value_t cv = CAP_SETPCAP;
 
                                 modified = cap_dup(c);
@@ -568,7 +587,7 @@ int capability_quintet_enforce(const CapabilityQuintet *q) {
                 }
         }
 
-        if (q->bounding != (uint64_t) -1) {
+        if (q->bounding != UINT64_MAX) {
                 r = capability_bounding_set_drop(q->bounding, false);
                 if (r < 0)
                         return r;