diff options
Diffstat (limited to 'tools/testing/selftests/kdbus/kdbus-test.c')
-rw-r--r-- | tools/testing/selftests/kdbus/kdbus-test.c | 905 |
1 files changed, 0 insertions, 905 deletions
diff --git a/tools/testing/selftests/kdbus/kdbus-test.c b/tools/testing/selftests/kdbus/kdbus-test.c deleted file mode 100644 index db5738157..000000000 --- a/tools/testing/selftests/kdbus/kdbus-test.c +++ /dev/null @@ -1,905 +0,0 @@ -#include <errno.h> -#include <stdio.h> -#include <string.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stddef.h> -#include <time.h> -#include <unistd.h> -#include <stdint.h> -#include <assert.h> -#include <getopt.h> -#include <stdbool.h> -#include <signal.h> -#include <sys/mount.h> -#include <sys/prctl.h> -#include <sys/wait.h> -#include <sys/syscall.h> -#include <sys/eventfd.h> -#include <linux/sched.h> - -#include "kdbus-util.h" -#include "kdbus-enum.h" -#include "kdbus-test.h" - -enum { - TEST_CREATE_BUS = 1 << 0, - TEST_CREATE_CONN = 1 << 1, -}; - -struct kdbus_test { - const char *name; - const char *desc; - int (*func)(struct kdbus_test_env *env); - unsigned int flags; -}; - -struct kdbus_test_args { - bool mntns; - bool pidns; - bool userns; - char *uid_map; - char *gid_map; - int loop; - int wait; - int fork; - int tap_output; - char *module; - char *root; - char *test; - char *busname; -}; - -static const struct kdbus_test tests[] = { - { - .name = "bus-make", - .desc = "bus make functions", - .func = kdbus_test_bus_make, - .flags = 0, - }, - { - .name = "hello", - .desc = "the HELLO command", - .func = kdbus_test_hello, - .flags = TEST_CREATE_BUS, - }, - { - .name = "byebye", - .desc = "the BYEBYE command", - .func = kdbus_test_byebye, - .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, - }, - { - .name = "chat", - .desc = "a chat pattern", - .func = kdbus_test_chat, - .flags = TEST_CREATE_BUS, - }, - { - .name = "daemon", - .desc = "a simple daemon", - .func = kdbus_test_daemon, - .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, - }, - { - .name = "fd-passing", - .desc = "file descriptor passing", - .func = kdbus_test_fd_passing, - .flags = TEST_CREATE_BUS, - }, - { - .name = "endpoint", - .desc = "custom endpoint", - .func = kdbus_test_custom_endpoint, - .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, - }, - { - .name = "monitor", - .desc = "monitor functionality", - .func = kdbus_test_monitor, - .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, - }, - { - .name = "name-basics", - .desc = "basic name registry functions", - .func = kdbus_test_name_basic, - .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, - }, - { - .name = "name-conflict", - .desc = "name registry conflict details", - .func = kdbus_test_name_conflict, - .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, - }, - { - .name = "name-queue", - .desc = "queuing of names", - .func = kdbus_test_name_queue, - .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, - }, - { - .name = "name-takeover", - .desc = "takeover of names", - .func = kdbus_test_name_takeover, - .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, - }, - { - .name = "message-basic", - .desc = "basic message handling", - .func = kdbus_test_message_basic, - .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, - }, - { - .name = "message-prio", - .desc = "handling of messages with priority", - .func = kdbus_test_message_prio, - .flags = TEST_CREATE_BUS, - }, - { - .name = "message-quota", - .desc = "message quotas are enforced", - .func = kdbus_test_message_quota, - .flags = TEST_CREATE_BUS, - }, - { - .name = "memory-access", - .desc = "memory access", - .func = kdbus_test_memory_access, - .flags = TEST_CREATE_BUS, - }, - { - .name = "timeout", - .desc = "timeout", - .func = kdbus_test_timeout, - .flags = TEST_CREATE_BUS, - }, - { - .name = "sync-byebye", - .desc = "synchronous replies vs. BYEBYE", - .func = kdbus_test_sync_byebye, - .flags = TEST_CREATE_BUS, - }, - { - .name = "sync-reply", - .desc = "synchronous replies", - .func = kdbus_test_sync_reply, - .flags = TEST_CREATE_BUS, - }, - { - .name = "message-free", - .desc = "freeing of memory", - .func = kdbus_test_free, - .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, - }, - { - .name = "connection-info", - .desc = "retrieving connection information", - .func = kdbus_test_conn_info, - .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, - }, - { - .name = "connection-update", - .desc = "updating connection information", - .func = kdbus_test_conn_update, - .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, - }, - { - .name = "writable-pool", - .desc = "verifying pools are never writable", - .func = kdbus_test_writable_pool, - .flags = TEST_CREATE_BUS, - }, - { - .name = "policy", - .desc = "policy", - .func = kdbus_test_policy, - .flags = TEST_CREATE_BUS, - }, - { - .name = "policy-priv", - .desc = "unprivileged bus access", - .func = kdbus_test_policy_priv, - .flags = TEST_CREATE_BUS, - }, - { - .name = "policy-ns", - .desc = "policy in user namespaces", - .func = kdbus_test_policy_ns, - .flags = TEST_CREATE_BUS, - }, - { - .name = "metadata-ns", - .desc = "metadata in different namespaces", - .func = kdbus_test_metadata_ns, - .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, - }, - { - .name = "match-id-add", - .desc = "adding of matches by id", - .func = kdbus_test_match_id_add, - .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, - }, - { - .name = "match-id-remove", - .desc = "removing of matches by id", - .func = kdbus_test_match_id_remove, - .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, - }, - { - .name = "match-replace", - .desc = "replace of matches with the same cookie", - .func = kdbus_test_match_replace, - .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, - }, - { - .name = "match-name-add", - .desc = "adding of matches by name", - .func = kdbus_test_match_name_add, - .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, - }, - { - .name = "match-name-remove", - .desc = "removing of matches by name", - .func = kdbus_test_match_name_remove, - .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, - }, - { - .name = "match-name-change", - .desc = "matching for name changes", - .func = kdbus_test_match_name_change, - .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, - }, - { - .name = "match-bloom", - .desc = "matching with bloom filters", - .func = kdbus_test_match_bloom, - .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, - }, - { - .name = "activator", - .desc = "activator connections", - .func = kdbus_test_activator, - .flags = TEST_CREATE_BUS | TEST_CREATE_CONN, - }, - { - .name = "benchmark", - .desc = "benchmark", - .func = kdbus_test_benchmark, - .flags = TEST_CREATE_BUS, - }, - { - .name = "benchmark-nomemfds", - .desc = "benchmark without using memfds", - .func = kdbus_test_benchmark_nomemfds, - .flags = TEST_CREATE_BUS, - }, - { - .name = "benchmark-uds", - .desc = "benchmark comparison to UDS", - .func = kdbus_test_benchmark_uds, - .flags = TEST_CREATE_BUS, - }, -}; - -#define N_TESTS ((int) (sizeof(tests) / sizeof(tests[0]))) - -static int test_prepare_env(const struct kdbus_test *t, - const struct kdbus_test_args *args, - struct kdbus_test_env *env) -{ - if (t->flags & TEST_CREATE_BUS) { - char *s; - char *n = NULL; - int ret; - - asprintf(&s, "%s/control", args->root); - - env->control_fd = open(s, O_RDWR); - free(s); - ASSERT_RETURN(env->control_fd >= 0); - - if (!args->busname) { - n = unique_name("test-bus"); - ASSERT_RETURN(n); - } - - ret = kdbus_create_bus(env->control_fd, - args->busname ?: n, - _KDBUS_ATTACH_ALL, &s); - free(n); - ASSERT_RETURN(ret == 0); - - asprintf(&env->buspath, "%s/%s/bus", args->root, s); - free(s); - } - - if (t->flags & TEST_CREATE_CONN) { - env->conn = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(env->conn); - } - - env->root = args->root; - env->module = args->module; - - return 0; -} - -void test_unprepare_env(const struct kdbus_test *t, struct kdbus_test_env *env) -{ - if (env->conn) { - kdbus_conn_free(env->conn); - env->conn = NULL; - } - - if (env->control_fd >= 0) { - close(env->control_fd); - env->control_fd = -1; - } - - if (env->buspath) { - free(env->buspath); - env->buspath = NULL; - } -} - -static int test_run(const struct kdbus_test *t, - const struct kdbus_test_args *kdbus_args, - int wait) -{ - int ret; - struct kdbus_test_env env = {}; - - ret = test_prepare_env(t, kdbus_args, &env); - if (ret != TEST_OK) - return ret; - - if (wait > 0) { - printf("Sleeping %d seconds before running test ...\n", wait); - sleep(wait); - } - - ret = t->func(&env); - test_unprepare_env(t, &env); - return ret; -} - -static int test_run_forked(const struct kdbus_test *t, - const struct kdbus_test_args *kdbus_args, - int wait) -{ - int ret; - pid_t pid; - - pid = fork(); - if (pid < 0) { - return TEST_ERR; - } else if (pid == 0) { - ret = test_run(t, kdbus_args, wait); - _exit(ret); - } - - pid = waitpid(pid, &ret, 0); - if (pid <= 0) - return TEST_ERR; - else if (!WIFEXITED(ret)) - return TEST_ERR; - else - return WEXITSTATUS(ret); -} - -static void print_test_result(int ret) -{ - switch (ret) { - case TEST_OK: - printf("OK"); - break; - case TEST_SKIP: - printf("SKIPPED"); - break; - case TEST_ERR: - printf("ERROR"); - break; - } -} - -static int start_all_tests(struct kdbus_test_args *kdbus_args) -{ - int ret; - unsigned int fail_cnt = 0; - unsigned int skip_cnt = 0; - unsigned int ok_cnt = 0; - unsigned int i; - - if (kdbus_args->tap_output) { - printf("1..%d\n", N_TESTS); - fflush(stdout); - } - - kdbus_util_verbose = false; - - for (i = 0; i < N_TESTS; i++) { - const struct kdbus_test *t = tests + i; - - if (!kdbus_args->tap_output) { - unsigned int n; - - printf("Testing %s (%s) ", t->desc, t->name); - for (n = 0; n < 60 - strlen(t->desc) - strlen(t->name); n++) - printf("."); - printf(" "); - } - - ret = test_run_forked(t, kdbus_args, 0); - switch (ret) { - case TEST_OK: - ok_cnt++; - break; - case TEST_SKIP: - skip_cnt++; - break; - case TEST_ERR: - fail_cnt++; - break; - } - - if (kdbus_args->tap_output) { - printf("%sok %d - %s%s (%s)\n", - (ret == TEST_ERR) ? "not " : "", i + 1, - (ret == TEST_SKIP) ? "# SKIP " : "", - t->desc, t->name); - fflush(stdout); - } else { - print_test_result(ret); - printf("\n"); - } - } - - if (kdbus_args->tap_output) - printf("Failed %d/%d tests, %.2f%% okay\n", fail_cnt, N_TESTS, - 100.0 - (fail_cnt * 100.0) / ((float) N_TESTS)); - else - printf("\nSUMMARY: %u tests passed, %u skipped, %u failed\n", - ok_cnt, skip_cnt, fail_cnt); - - return fail_cnt > 0 ? TEST_ERR : TEST_OK; -} - -static int start_one_test(struct kdbus_test_args *kdbus_args) -{ - int i, ret; - bool test_found = false; - - for (i = 0; i < N_TESTS; i++) { - const struct kdbus_test *t = tests + i; - - if (strcmp(t->name, kdbus_args->test)) - continue; - - do { - test_found = true; - if (kdbus_args->fork) - ret = test_run_forked(t, kdbus_args, - kdbus_args->wait); - else - ret = test_run(t, kdbus_args, - kdbus_args->wait); - - printf("Testing %s: ", t->desc); - print_test_result(ret); - printf("\n"); - - if (ret != TEST_OK) - break; - } while (kdbus_args->loop); - - return ret; - } - - if (!test_found) { - printf("Unknown test-id '%s'\n", kdbus_args->test); - return TEST_ERR; - } - - return TEST_OK; -} - -static void usage(const char *argv0) -{ - unsigned int i, j; - - printf("Usage: %s [options]\n" - "Options:\n" - "\t-a, --tap Output test results in TAP format\n" - "\t-m, --module <module> Kdbus module name\n" - "\t-x, --loop Run in a loop\n" - "\t-f, --fork Fork before running a test\n" - "\t-h, --help Print this help\n" - "\t-r, --root <root> Toplevel of the kdbus hierarchy\n" - "\t-t, --test <test-id> Run one specific test only, in verbose mode\n" - "\t-b, --bus <busname> Instead of generating a random bus name, take <busname>.\n" - "\t-w, --wait <secs> Wait <secs> before actually starting test\n" - "\t --mntns New mount namespace\n" - "\t --pidns New PID namespace\n" - "\t --userns New user namespace\n" - "\t --uidmap uid_map UID map for user namespace\n" - "\t --gidmap gid_map GID map for user namespace\n" - "\n", argv0); - - printf("By default, all test are run once, and a summary is printed.\n" - "Available tests for --test:\n\n"); - - for (i = 0; i < N_TESTS; i++) { - const struct kdbus_test *t = tests + i; - - printf("\t%s", t->name); - - for (j = 0; j < 24 - strlen(t->name); j++) - printf(" "); - - printf("Test %s\n", t->desc); - } - - printf("\n"); - printf("Note that some tests may, if run specifically by --test, " - "behave differently, and not terminate by themselves.\n"); - - exit(EXIT_FAILURE); -} - -void print_kdbus_test_args(struct kdbus_test_args *args) -{ - if (args->userns || args->pidns || args->mntns) - printf("# Starting tests in new %s%s%s namespaces%s\n", - args->mntns ? "MOUNT " : "", - args->pidns ? "PID " : "", - args->userns ? "USER " : "", - args->mntns ? ", kdbusfs will be remounted" : ""); - else - printf("# Starting tests in the same namespaces\n"); -} - -void print_metadata_support(void) -{ - bool no_meta_audit, no_meta_cgroups, no_meta_seclabel; - - /* - * KDBUS_ATTACH_CGROUP, KDBUS_ATTACH_AUDIT and - * KDBUS_ATTACH_SECLABEL - */ - no_meta_audit = !config_auditsyscall_is_enabled(); - no_meta_cgroups = !config_cgroups_is_enabled(); - no_meta_seclabel = !config_security_is_enabled(); - - if (no_meta_audit | no_meta_cgroups | no_meta_seclabel) - printf("# Starting tests without %s%s%s metadata support\n", - no_meta_audit ? "AUDIT " : "", - no_meta_cgroups ? "CGROUP " : "", - no_meta_seclabel ? "SECLABEL " : ""); - else - printf("# Starting tests with full metadata support\n"); -} - -int run_tests(struct kdbus_test_args *kdbus_args) -{ - int ret; - static char control[4096]; - - snprintf(control, sizeof(control), "%s/control", kdbus_args->root); - - if (access(control, W_OK) < 0) { - printf("Unable to locate control node at '%s'.\n", - control); - return TEST_ERR; - } - - if (kdbus_args->test) { - ret = start_one_test(kdbus_args); - } else { - do { - ret = start_all_tests(kdbus_args); - if (ret != TEST_OK) - break; - } while (kdbus_args->loop); - } - - return ret; -} - -static void nop_handler(int sig) {} - -static int test_prepare_mounts(struct kdbus_test_args *kdbus_args) -{ - int ret; - char kdbusfs[64] = {'\0'}; - - snprintf(kdbusfs, sizeof(kdbusfs), "%sfs", kdbus_args->module); - - /* make current mount slave */ - ret = mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL); - if (ret < 0) { - ret = -errno; - printf("error mount() root: %d (%m)\n", ret); - return ret; - } - - /* Remount procfs since we need it in our tests */ - if (kdbus_args->pidns) { - ret = mount("proc", "/proc", "proc", - MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL); - if (ret < 0) { - ret = -errno; - printf("error mount() /proc : %d (%m)\n", ret); - return ret; - } - } - - /* Remount kdbusfs */ - ret = mount(kdbusfs, kdbus_args->root, kdbusfs, - MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL); - if (ret < 0) { - ret = -errno; - printf("error mount() %s :%d (%m)\n", kdbusfs, ret); - return ret; - } - - return 0; -} - -int run_tests_in_namespaces(struct kdbus_test_args *kdbus_args) -{ - int ret; - int efd = -1; - int status; - pid_t pid, rpid; - struct sigaction oldsa; - struct sigaction sa = { - .sa_handler = nop_handler, - .sa_flags = SA_NOCLDSTOP, - }; - - efd = eventfd(0, EFD_CLOEXEC); - if (efd < 0) { - ret = -errno; - printf("eventfd() failed: %d (%m)\n", ret); - return TEST_ERR; - } - - ret = sigaction(SIGCHLD, &sa, &oldsa); - if (ret < 0) { - ret = -errno; - printf("sigaction() failed: %d (%m)\n", ret); - return TEST_ERR; - } - - /* setup namespaces */ - pid = syscall(__NR_clone, SIGCHLD| - (kdbus_args->userns ? CLONE_NEWUSER : 0) | - (kdbus_args->mntns ? CLONE_NEWNS : 0) | - (kdbus_args->pidns ? CLONE_NEWPID : 0), NULL); - if (pid < 0) { - printf("clone() failed: %d (%m)\n", -errno); - return TEST_ERR; - } - - if (pid == 0) { - eventfd_t event_status = 0; - - ret = prctl(PR_SET_PDEATHSIG, SIGKILL); - if (ret < 0) { - ret = -errno; - printf("error prctl(): %d (%m)\n", ret); - _exit(TEST_ERR); - } - - /* reset sighandlers of childs */ - ret = sigaction(SIGCHLD, &oldsa, NULL); - if (ret < 0) { - ret = -errno; - printf("sigaction() failed: %d (%m)\n", ret); - _exit(TEST_ERR); - } - - ret = eventfd_read(efd, &event_status); - if (ret < 0 || event_status != 1) { - printf("error eventfd_read()\n"); - _exit(TEST_ERR); - } - - if (kdbus_args->mntns) { - ret = test_prepare_mounts(kdbus_args); - if (ret < 0) { - printf("error preparing mounts\n"); - _exit(TEST_ERR); - } - } - - ret = run_tests(kdbus_args); - _exit(ret); - } - - /* Setup userns mapping */ - if (kdbus_args->userns) { - ret = userns_map_uid_gid(pid, kdbus_args->uid_map, - kdbus_args->gid_map); - if (ret < 0) { - printf("error mapping uid and gid in userns\n"); - eventfd_write(efd, 2); - return TEST_ERR; - } - } - - ret = eventfd_write(efd, 1); - if (ret < 0) { - ret = -errno; - printf("error eventfd_write(): %d (%m)\n", ret); - return TEST_ERR; - } - - rpid = waitpid(pid, &status, 0); - ASSERT_RETURN_VAL(rpid == pid, TEST_ERR); - - close(efd); - - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) - return TEST_ERR; - - return TEST_OK; -} - -int start_tests(struct kdbus_test_args *kdbus_args) -{ - int ret; - bool namespaces; - static char fspath[4096]; - - namespaces = (kdbus_args->mntns || kdbus_args->pidns || - kdbus_args->userns); - - /* for pidns we need mntns set */ - if (kdbus_args->pidns && !kdbus_args->mntns) { - printf("Failed: please set both pid and mnt namesapces\n"); - return TEST_ERR; - } - - if (kdbus_args->userns) { - if (!config_user_ns_is_enabled()) { - printf("User namespace not supported\n"); - return TEST_ERR; - } - - if (!kdbus_args->uid_map || !kdbus_args->gid_map) { - printf("Failed: please specify uid or gid mapping\n"); - return TEST_ERR; - } - } - - print_kdbus_test_args(kdbus_args); - print_metadata_support(); - - /* setup kdbus paths */ - if (!kdbus_args->module) - kdbus_args->module = "kdbus"; - - if (!kdbus_args->root) { - snprintf(fspath, sizeof(fspath), "/sys/fs/%s", - kdbus_args->module); - kdbus_args->root = fspath; - } - - /* Start tests */ - if (namespaces) - ret = run_tests_in_namespaces(kdbus_args); - else - ret = run_tests(kdbus_args); - - return ret; -} - -int main(int argc, char *argv[]) -{ - int t, ret = 0; - struct kdbus_test_args *kdbus_args; - enum { - ARG_MNTNS = 0x100, - ARG_PIDNS, - ARG_USERNS, - ARG_UIDMAP, - ARG_GIDMAP, - }; - - kdbus_args = malloc(sizeof(*kdbus_args)); - if (!kdbus_args) { - printf("unable to malloc() kdbus_args\n"); - return EXIT_FAILURE; - } - - memset(kdbus_args, 0, sizeof(*kdbus_args)); - - static const struct option options[] = { - { "loop", no_argument, NULL, 'x' }, - { "help", no_argument, NULL, 'h' }, - { "root", required_argument, NULL, 'r' }, - { "test", required_argument, NULL, 't' }, - { "bus", required_argument, NULL, 'b' }, - { "wait", required_argument, NULL, 'w' }, - { "fork", no_argument, NULL, 'f' }, - { "module", required_argument, NULL, 'm' }, - { "tap", no_argument, NULL, 'a' }, - { "mntns", no_argument, NULL, ARG_MNTNS }, - { "pidns", no_argument, NULL, ARG_PIDNS }, - { "userns", no_argument, NULL, ARG_USERNS }, - { "uidmap", required_argument, NULL, ARG_UIDMAP }, - { "gidmap", required_argument, NULL, ARG_GIDMAP }, - {} - }; - - srand(time(NULL)); - - while ((t = getopt_long(argc, argv, "hxfm:r:t:b:w:a", options, NULL)) >= 0) { - switch (t) { - case 'x': - kdbus_args->loop = 1; - break; - - case 'm': - kdbus_args->module = optarg; - break; - - case 'r': - kdbus_args->root = optarg; - break; - - case 't': - kdbus_args->test = optarg; - break; - - case 'b': - kdbus_args->busname = optarg; - break; - - case 'w': - kdbus_args->wait = strtol(optarg, NULL, 10); - break; - - case 'f': - kdbus_args->fork = 1; - break; - - case 'a': - kdbus_args->tap_output = 1; - break; - - case ARG_MNTNS: - kdbus_args->mntns = true; - break; - - case ARG_PIDNS: - kdbus_args->pidns = true; - break; - - case ARG_USERNS: - kdbus_args->userns = true; - break; - - case ARG_UIDMAP: - kdbus_args->uid_map = optarg; - break; - - case ARG_GIDMAP: - kdbus_args->gid_map = optarg; - break; - - default: - case 'h': - usage(argv[0]); - } - } - - ret = start_tests(kdbus_args); - if (ret == TEST_ERR) - return EXIT_FAILURE; - - free(kdbus_args); - - return 0; -} |