123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- /* SPDX-License-Identifier: GPL-2.0 */
- /*
- * Landlock test helpers
- *
- * Copyright © 2017-2020 Mickaël Salaün <[email protected]>
- * Copyright © 2019-2020 ANSSI
- * Copyright © 2021 Microsoft Corporation
- */
- #include <errno.h>
- #include <linux/landlock.h>
- #include <sys/capability.h>
- #include <sys/syscall.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <unistd.h>
- #include "../kselftest_harness.h"
- /*
- * TEST_F_FORK() is useful when a test drop privileges but the corresponding
- * FIXTURE_TEARDOWN() requires them (e.g. to remove files from a directory
- * where write actions are denied). For convenience, FIXTURE_TEARDOWN() is
- * also called when the test failed, but not when FIXTURE_SETUP() failed. For
- * this to be possible, we must not call abort() but instead exit smoothly
- * (hence the step print).
- */
- /* clang-format off */
- #define TEST_F_FORK(fixture_name, test_name) \
- static void fixture_name##_##test_name##_child( \
- struct __test_metadata *_metadata, \
- FIXTURE_DATA(fixture_name) *self, \
- const FIXTURE_VARIANT(fixture_name) *variant); \
- TEST_F(fixture_name, test_name) \
- { \
- int status; \
- const pid_t child = fork(); \
- if (child < 0) \
- abort(); \
- if (child == 0) { \
- _metadata->no_print = 1; \
- fixture_name##_##test_name##_child(_metadata, self, variant); \
- if (_metadata->skip) \
- _exit(255); \
- if (_metadata->passed) \
- _exit(0); \
- _exit(_metadata->step); \
- } \
- if (child != waitpid(child, &status, 0)) \
- abort(); \
- if (WIFSIGNALED(status) || !WIFEXITED(status)) { \
- _metadata->passed = 0; \
- _metadata->step = 1; \
- return; \
- } \
- switch (WEXITSTATUS(status)) { \
- case 0: \
- _metadata->passed = 1; \
- break; \
- case 255: \
- _metadata->passed = 1; \
- _metadata->skip = 1; \
- break; \
- default: \
- _metadata->passed = 0; \
- _metadata->step = WEXITSTATUS(status); \
- break; \
- } \
- } \
- static void fixture_name##_##test_name##_child( \
- struct __test_metadata __attribute__((unused)) *_metadata, \
- FIXTURE_DATA(fixture_name) __attribute__((unused)) *self, \
- const FIXTURE_VARIANT(fixture_name) \
- __attribute__((unused)) *variant)
- /* clang-format on */
- #ifndef landlock_create_ruleset
- static inline int
- landlock_create_ruleset(const struct landlock_ruleset_attr *const attr,
- const size_t size, const __u32 flags)
- {
- return syscall(__NR_landlock_create_ruleset, attr, size, flags);
- }
- #endif
- #ifndef landlock_add_rule
- static inline int landlock_add_rule(const int ruleset_fd,
- const enum landlock_rule_type rule_type,
- const void *const rule_attr,
- const __u32 flags)
- {
- return syscall(__NR_landlock_add_rule, ruleset_fd, rule_type, rule_attr,
- flags);
- }
- #endif
- #ifndef landlock_restrict_self
- static inline int landlock_restrict_self(const int ruleset_fd,
- const __u32 flags)
- {
- return syscall(__NR_landlock_restrict_self, ruleset_fd, flags);
- }
- #endif
- static void _init_caps(struct __test_metadata *const _metadata, bool drop_all)
- {
- cap_t cap_p;
- /* Only these three capabilities are useful for the tests. */
- const cap_value_t caps[] = {
- CAP_DAC_OVERRIDE,
- CAP_MKNOD,
- CAP_SYS_ADMIN,
- CAP_SYS_CHROOT,
- };
- cap_p = cap_get_proc();
- EXPECT_NE(NULL, cap_p)
- {
- TH_LOG("Failed to cap_get_proc: %s", strerror(errno));
- }
- EXPECT_NE(-1, cap_clear(cap_p))
- {
- TH_LOG("Failed to cap_clear: %s", strerror(errno));
- }
- if (!drop_all) {
- EXPECT_NE(-1, cap_set_flag(cap_p, CAP_PERMITTED,
- ARRAY_SIZE(caps), caps, CAP_SET))
- {
- TH_LOG("Failed to cap_set_flag: %s", strerror(errno));
- }
- }
- EXPECT_NE(-1, cap_set_proc(cap_p))
- {
- TH_LOG("Failed to cap_set_proc: %s", strerror(errno));
- }
- EXPECT_NE(-1, cap_free(cap_p))
- {
- TH_LOG("Failed to cap_free: %s", strerror(errno));
- }
- }
- /* We cannot put such helpers in a library because of kselftest_harness.h . */
- __attribute__((__unused__)) static void
- disable_caps(struct __test_metadata *const _metadata)
- {
- _init_caps(_metadata, false);
- }
- __attribute__((__unused__)) static void
- drop_caps(struct __test_metadata *const _metadata)
- {
- _init_caps(_metadata, true);
- }
- static void _effective_cap(struct __test_metadata *const _metadata,
- const cap_value_t caps, const cap_flag_value_t value)
- {
- cap_t cap_p;
- cap_p = cap_get_proc();
- EXPECT_NE(NULL, cap_p)
- {
- TH_LOG("Failed to cap_get_proc: %s", strerror(errno));
- }
- EXPECT_NE(-1, cap_set_flag(cap_p, CAP_EFFECTIVE, 1, &caps, value))
- {
- TH_LOG("Failed to cap_set_flag: %s", strerror(errno));
- }
- EXPECT_NE(-1, cap_set_proc(cap_p))
- {
- TH_LOG("Failed to cap_set_proc: %s", strerror(errno));
- }
- EXPECT_NE(-1, cap_free(cap_p))
- {
- TH_LOG("Failed to cap_free: %s", strerror(errno));
- }
- }
- __attribute__((__unused__)) static void
- set_cap(struct __test_metadata *const _metadata, const cap_value_t caps)
- {
- _effective_cap(_metadata, caps, CAP_SET);
- }
- __attribute__((__unused__)) static void
- clear_cap(struct __test_metadata *const _metadata, const cap_value_t caps)
- {
- _effective_cap(_metadata, caps, CAP_CLEAR);
- }
|