-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <netinet/in.h>
#include <pwd.h>
#include <sys/wait.h>
#include <unistd.h>
+#define TEST_CAPABILITY_C
+
#include "alloc-util.h"
#include "capability-util.h"
#include "errno-util.h"
#include "macro.h"
#include "missing_prctl.h"
#include "parse-util.h"
+#include "process-util.h"
#include "string-util.h"
#include "tests.h"
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;
}
}
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) {
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);
}
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;
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_se(CAP_LAST_CAP <= 63);
+ 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();
if (run_ambient)
fork_test(test_apply_ambient_caps);
+ test_capability_get_ambient();
+
return 0;
}