]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
capability: add new type for maintaining all five cap sets as one
authorLennart Poettering <lennart@poettering.net>
Tue, 24 Jul 2018 15:00:58 +0000 (17:00 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 29 Nov 2018 19:21:39 +0000 (20:21 +0100)
src/basic/capability-util.c
src/basic/capability-util.h

index 6ae35e078b3a296c1963cb25028e22050a9f752f..a3f3ca9f52b9663d28ca9d51d436ba631f906b01 100644 (file)
@@ -359,3 +359,128 @@ bool ambient_capabilities_supported(void) {
 
         return cache;
 }
+
+int capability_quintet_enforce(const CapabilityQuintet *q) {
+        _cleanup_cap_free_ cap_t c = NULL;
+        int r;
+
+        if (q->ambient != (uint64_t) -1) {
+                unsigned long i;
+                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++) {
+                        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 (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;
+
+                        changed = true;
+                }
+
+                if (changed)
+                        if (cap_set_proc(c) < 0)
+                                return -errno;
+
+                r = capability_ambient_set_apply(q->ambient, false);
+                if (r < 0)
+                        return r;
+        }
+
+        if (q->inheritable != (uint64_t) -1 || q->permitted != (uint64_t) -1 || q->effective != (uint64_t) -1) {
+                bool changed = false;
+                unsigned long i;
+
+                if (!c) {
+                        c = cap_get_proc();
+                        if (!c)
+                                return -errno;
+                }
+
+                for (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) {
+                                cap_flag_value_t old_value, new_value;
+
+                                if (cap_get_flag(c, cv, CAP_INHERITABLE, &old_value) < 0)
+                                        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 (q->permitted != (uint64_t) -1) {
+                                cap_flag_value_t old_value, new_value;
+
+                                if (cap_get_flag(c, cv, CAP_PERMITTED, &old_value) < 0)
+                                        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 != (uint64_t) -1) {
+                                cap_flag_value_t old_value, new_value;
+
+                                if (cap_get_flag(c, cv, CAP_EFFECTIVE, &old_value) < 0)
+                                        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)
+                        if (cap_set_proc(c) < 0)
+                                return -errno;
+        }
+
+        if (q->bounding != (uint64_t) -1) {
+                r = capability_bounding_set_drop(q->bounding, false);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
index 59591d4b521eb56039b11a0bf62d0eae2f410e90..e0e0b1c0fab7f14ca17a85228367ec07f9c87e3d 100644 (file)
@@ -43,3 +43,27 @@ bool ambient_capabilities_supported(void);
 /* Identical to linux/capability.h's CAP_TO_MASK(), but uses an unsigned 1U instead of a signed 1 for shifting left, in
  * order to avoid complaints about shifting a signed int left by 31 bits, which would make it negative. */
 #define CAP_TO_MASK_CORRECTED(x) (1U << ((x) & 31U))
+
+typedef struct CapabilityQuintet {
+        /* Stores all five types of capabilities in one go. Note that we use (uint64_t) -1 for unset here. This hence
+         * needs to be updated as soon as Linux learns more than 63 caps. */
+        uint64_t effective;
+        uint64_t bounding;
+        uint64_t inheritable;
+        uint64_t permitted;
+        uint64_t ambient;
+} CapabilityQuintet;
+
+assert_cc(CAP_LAST_CAP < 64);
+
+#define CAPABILITY_QUINTET_NULL { (uint64_t) -1, (uint64_t) -1, (uint64_t) -1, (uint64_t) -1, (uint64_t) -1 }
+
+static inline bool capability_quintet_is_set(const CapabilityQuintet *q) {
+        return q->effective != (uint64_t) -1 ||
+                q->bounding != (uint64_t) -1 ||
+                q->inheritable != (uint64_t) -1 ||
+                q->permitted != (uint64_t) -1 ||
+                q->ambient != (uint64_t) -1;
+}
+
+int capability_quintet_enforce(const CapabilityQuintet *q);