]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/test/test-capability.c
tree-wide: "<n>bit" → "<n>-bit"
[thirdparty/systemd.git] / src / test / test-capability.c
index 249323f8cf78e59652bd0687545fd0df75cce817..bfdba4f29424d691c6d7cccf64a6bbde020056a5 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <netinet/in.h>
 #include <pwd.h>
@@ -7,6 +7,8 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#define TEST_CAPABILITY_C
+
 #include "alloc-util.h"
 #include "capability-util.h"
 #include "errno-util.h"
@@ -15,6 +17,7 @@
 #include "macro.h"
 #include "missing_prctl.h"
 #include "parse-util.h"
+#include "process-util.h"
 #include "string-util.h"
 #include "tests.h"
 
@@ -101,22 +104,15 @@ static int setup_tests(bool *run_ambient) {
 
         nobody = getpwnam(NOBODY_USER_NAME);
         if (!nobody)
-                return log_error_errno(SYNTHETIC_ERRNO(ENOENT), "Could not find nobody user: %m");
+                return log_warning_errno(SYNTHETIC_ERRNO(ENOENT), "Couldn't find 'nobody' user: %m");
 
         test_uid = nobody->pw_uid;
         test_gid = nobody->pw_gid;
 
-        *run_ambient = false;
-
         r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
-
-        /* There's support for PR_CAP_AMBIENT if the prctl() call
-         * succeeded or error code was something else than EINVAL. The
-         * EINVAL check should be good enough to rule out false
-         * positives. */
-
-        if (r >= 0 || errno != EINVAL)
-                *run_ambient = true;
+        /* There's support for PR_CAP_AMBIENT if the prctl() call succeeded or error code was something else
+         * than EINVAL. The EINVAL check should be good enough to rule out false positives. */
+        *run_ambient = r >= 0 || errno != EINVAL;
 
         return 0;
 }
@@ -164,21 +160,27 @@ static void test_drop_privileges_fail(void) {
 }
 
 static void test_drop_privileges(void) {
+        fork_test(test_drop_privileges_fail);
+
+        if (have_effective_cap(CAP_NET_RAW) <= 0) /* The remaining two tests only work if we have CAP_NET_RAW
+                                                   * in the first place. If we are run in some restricted
+                                                   * container environment we might not. */
+                return;
+
         fork_test(test_drop_privileges_keep_net_raw);
         fork_test(test_drop_privileges_dontkeep_net_raw);
-        fork_test(test_drop_privileges_fail);
 }
 
 static void test_have_effective_cap(void) {
-        assert_se(have_effective_cap(CAP_KILL));
-        assert_se(have_effective_cap(CAP_CHOWN));
+        assert_se(have_effective_cap(CAP_KILL) > 0);
+        assert_se(have_effective_cap(CAP_CHOWN) > 0);
 
         assert_se(drop_privileges(test_uid, test_gid, test_flags | (1ULL << CAP_KILL)) >= 0);
         assert_se(getuid() == test_uid);
         assert_se(getgid() == test_gid);
 
-        assert_se(have_effective_cap(CAP_KILL));
-        assert_se(!have_effective_cap(CAP_CHOWN));
+        assert_se(have_effective_cap(CAP_KILL) > 0);
+        assert_se(have_effective_cap(CAP_CHOWN) == 0);
 }
 
 static void test_update_inherited_set(void) {
@@ -193,7 +195,7 @@ static void test_update_inherited_set(void) {
 
         assert_se(!capability_update_inherited_set(caps, set));
         assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv));
-        assert(fv == CAP_SET);
+        assert_se(fv == CAP_SET);
 
         cap_free(caps);
 }
@@ -227,7 +229,7 @@ static void test_apply_ambient_caps(void) {
         assert_se(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0) == 0);
 }
 
-static void test_ensure_cap_64bit(void) {
+static void test_ensure_cap_64_bit(void) {
         _cleanup_free_ char *content = NULL;
         unsigned long p = 0;
         int r;
@@ -239,19 +241,69 @@ static void test_ensure_cap_64bit(void) {
 
         assert_se(safe_atolu(content, &p) >= 0);
 
-        /* If caps don't fit into 64bit anymore, we have a problem, fail the test. */
+        /* If caps don't fit into 64-bit anymore, we have a problem, fail the test. */
         assert_se(p <= 63);
 
         /* Also check for the header definition */
         assert_cc(CAP_LAST_CAP <= 63);
 }
 
+static void test_capability_get_ambient(void) {
+        uint64_t c;
+        int r;
+
+        assert_se(capability_get_ambient(&c) >= 0);
+
+        r = safe_fork("(getambient)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_WAIT|FORK_LOG, NULL);
+        assert_se(r >= 0);
+
+        if (r == 0) {
+                int x, y;
+                /* child */
+                assert_se(capability_get_ambient(&c) >= 0);
+
+                x = capability_ambient_set_apply(
+                                (UINT64_C(1) << CAP_MKNOD)|
+                                (UINT64_C(1) << CAP_LINUX_IMMUTABLE),
+                                /* also_inherit= */ true);
+                assert_se(x >= 0 || ERRNO_IS_PRIVILEGE(x));
+
+                assert_se(capability_get_ambient(&c) >= 0);
+                assert_se(x < 0 || FLAGS_SET(c, UINT64_C(1) << CAP_MKNOD));
+                assert_se(x < 0 || FLAGS_SET(c, UINT64_C(1) << CAP_LINUX_IMMUTABLE));
+                assert_se(x < 0 || !FLAGS_SET(c, UINT64_C(1) << CAP_SETPCAP));
+
+                y = capability_bounding_set_drop(
+                                ((UINT64_C(1) << CAP_LINUX_IMMUTABLE)|
+                                 (UINT64_C(1) << CAP_SETPCAP)),
+                                /* right_now= */ true);
+                assert_se(y >= 0 || ERRNO_IS_PRIVILEGE(y));
+
+                assert_se(capability_get_ambient(&c) >= 0);
+                assert_se(x < 0 || y < 0 || !FLAGS_SET(c, UINT64_C(1) << CAP_MKNOD));
+                assert_se(x < 0 || y < 0 || FLAGS_SET(c, UINT64_C(1) << CAP_LINUX_IMMUTABLE));
+                assert_se(x < 0 || y < 0 || !FLAGS_SET(c, UINT64_C(1) << CAP_SETPCAP));
+
+                y = capability_bounding_set_drop(
+                                (UINT64_C(1) << CAP_SETPCAP),
+                                /* right_now= */ true);
+                assert_se(y >= 0 || ERRNO_IS_PRIVILEGE(y));
+
+                assert_se(capability_get_ambient(&c) >= 0);
+                assert_se(x < 0 || y < 0 || !FLAGS_SET(c, UINT64_C(1) << CAP_MKNOD));
+                assert_se(x < 0 || y < 0 || !FLAGS_SET(c, UINT64_C(1) << CAP_LINUX_IMMUTABLE));
+                assert_se(x < 0 || y < 0 || !FLAGS_SET(c, UINT64_C(1) << CAP_SETPCAP));
+
+                _exit(EXIT_SUCCESS);
+        }
+}
+
 int main(int argc, char *argv[]) {
         bool run_ambient;
 
-        test_setup_logging(LOG_INFO);
+        test_setup_logging(LOG_DEBUG);
 
-        test_ensure_cap_64bit();
+        test_ensure_cap_64_bit();
 
         test_last_cap_file();
         test_last_cap_probe();
@@ -274,5 +326,7 @@ int main(int argc, char *argv[]) {
         if (run_ambient)
                 fork_test(test_apply_ambient_caps);
 
+        test_capability_get_ambient();
+
         return 0;
 }