diff options
Diffstat (limited to 'tools/testing/selftests')
28 files changed, 0 insertions, 10507 deletions
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index bf4ece67a..c8edff680 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -6,7 +6,6 @@ TARGETS += firmware TARGETS += ftrace TARGETS += futex TARGETS += kcmp -TARGETS += kdbus TARGETS += lib TARGETS += membarrier TARGETS += memfd diff --git a/tools/testing/selftests/kdbus/.gitignore b/tools/testing/selftests/kdbus/.gitignore deleted file mode 100644 index d3ef42f6a..000000000 --- a/tools/testing/selftests/kdbus/.gitignore +++ /dev/null @@ -1 +0,0 @@ -kdbus-test diff --git a/tools/testing/selftests/kdbus/Makefile b/tools/testing/selftests/kdbus/Makefile deleted file mode 100644 index 8f36cb566..000000000 --- a/tools/testing/selftests/kdbus/Makefile +++ /dev/null @@ -1,49 +0,0 @@ -CFLAGS += -I../../../../usr/include/ -CFLAGS += -I../../../../samples/kdbus/ -CFLAGS += -I../../../../include/uapi/ -CFLAGS += -std=gnu99 -CFLAGS += -DKBUILD_MODNAME=\"kdbus\" -D_GNU_SOURCE -LDLIBS = -pthread -lcap -lm - -OBJS= \ - kdbus-enum.o \ - kdbus-util.o \ - kdbus-test.o \ - kdbus-test.o \ - test-activator.o \ - test-benchmark.o \ - test-bus.o \ - test-chat.o \ - test-connection.o \ - test-daemon.o \ - test-endpoint.o \ - test-fd.o \ - test-free.o \ - test-match.o \ - test-message.o \ - test-metadata-ns.o \ - test-monitor.o \ - test-names.o \ - test-policy.o \ - test-policy-ns.o \ - test-policy-priv.o \ - test-sync.o \ - test-timeout.o - -all: kdbus-test - -include ../lib.mk - -%.o: %.c kdbus-enum.h kdbus-test.h kdbus-util.h - $(CC) $(CFLAGS) -c $< -o $@ - -kdbus-test: $(OBJS) - $(CC) $(CFLAGS) $^ $(LDLIBS) -o $@ - -TEST_PROGS := kdbus-test - -run_tests: - ./kdbus-test --tap - -clean: - rm -f *.o kdbus-test diff --git a/tools/testing/selftests/kdbus/kdbus-enum.c b/tools/testing/selftests/kdbus/kdbus-enum.c deleted file mode 100644 index 4f1e57978..000000000 --- a/tools/testing/selftests/kdbus/kdbus-enum.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#include <stdio.h> -#include <string.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <stdint.h> -#include <errno.h> - -#include "kdbus-util.h" -#include "kdbus-enum.h" - -struct kdbus_enum_table { - long long id; - const char *name; -}; - -#define TABLE(what) static struct kdbus_enum_table kdbus_table_##what[] -#define ENUM(_id) { .id = _id, .name = STRINGIFY(_id) } -#define LOOKUP(what) \ - const char *enum_##what(long long id) \ - { \ - for (size_t i = 0; i < ELEMENTSOF(kdbus_table_##what); i++) \ - if (id == kdbus_table_##what[i].id) \ - return kdbus_table_##what[i].name; \ - return "UNKNOWN"; \ - } - -TABLE(CMD) = { - ENUM(KDBUS_CMD_BUS_MAKE), - ENUM(KDBUS_CMD_ENDPOINT_MAKE), - ENUM(KDBUS_CMD_HELLO), - ENUM(KDBUS_CMD_SEND), - ENUM(KDBUS_CMD_RECV), - ENUM(KDBUS_CMD_LIST), - ENUM(KDBUS_CMD_NAME_RELEASE), - ENUM(KDBUS_CMD_CONN_INFO), - ENUM(KDBUS_CMD_MATCH_ADD), - ENUM(KDBUS_CMD_MATCH_REMOVE), -}; -LOOKUP(CMD); - -TABLE(MSG) = { - ENUM(_KDBUS_ITEM_NULL), - ENUM(KDBUS_ITEM_PAYLOAD_VEC), - ENUM(KDBUS_ITEM_PAYLOAD_OFF), - ENUM(KDBUS_ITEM_PAYLOAD_MEMFD), - ENUM(KDBUS_ITEM_FDS), - ENUM(KDBUS_ITEM_BLOOM_PARAMETER), - ENUM(KDBUS_ITEM_BLOOM_FILTER), - ENUM(KDBUS_ITEM_DST_NAME), - ENUM(KDBUS_ITEM_MAKE_NAME), - ENUM(KDBUS_ITEM_ATTACH_FLAGS_SEND), - ENUM(KDBUS_ITEM_ATTACH_FLAGS_RECV), - ENUM(KDBUS_ITEM_ID), - ENUM(KDBUS_ITEM_NAME), - ENUM(KDBUS_ITEM_TIMESTAMP), - ENUM(KDBUS_ITEM_CREDS), - ENUM(KDBUS_ITEM_PIDS), - ENUM(KDBUS_ITEM_AUXGROUPS), - ENUM(KDBUS_ITEM_OWNED_NAME), - ENUM(KDBUS_ITEM_TID_COMM), - ENUM(KDBUS_ITEM_PID_COMM), - ENUM(KDBUS_ITEM_EXE), - ENUM(KDBUS_ITEM_CMDLINE), - ENUM(KDBUS_ITEM_CGROUP), - ENUM(KDBUS_ITEM_CAPS), - ENUM(KDBUS_ITEM_SECLABEL), - ENUM(KDBUS_ITEM_AUDIT), - ENUM(KDBUS_ITEM_CONN_DESCRIPTION), - ENUM(KDBUS_ITEM_NAME_ADD), - ENUM(KDBUS_ITEM_NAME_REMOVE), - ENUM(KDBUS_ITEM_NAME_CHANGE), - ENUM(KDBUS_ITEM_ID_ADD), - ENUM(KDBUS_ITEM_ID_REMOVE), - ENUM(KDBUS_ITEM_REPLY_TIMEOUT), - ENUM(KDBUS_ITEM_REPLY_DEAD), -}; -LOOKUP(MSG); - -TABLE(PAYLOAD) = { - ENUM(KDBUS_PAYLOAD_KERNEL), - ENUM(KDBUS_PAYLOAD_DBUS), -}; -LOOKUP(PAYLOAD); diff --git a/tools/testing/selftests/kdbus/kdbus-enum.h b/tools/testing/selftests/kdbus/kdbus-enum.h deleted file mode 100644 index ed28cca26..000000000 --- a/tools/testing/selftests/kdbus/kdbus-enum.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#pragma once - -const char *enum_CMD(long long id); -const char *enum_MSG(long long id); -const char *enum_MATCH(long long id); -const char *enum_PAYLOAD(long long id); 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; -} diff --git a/tools/testing/selftests/kdbus/kdbus-test.h b/tools/testing/selftests/kdbus/kdbus-test.h deleted file mode 100644 index ee937f9a8..000000000 --- a/tools/testing/selftests/kdbus/kdbus-test.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef _TEST_KDBUS_H_ -#define _TEST_KDBUS_H_ - -struct kdbus_test_env { - char *buspath; - const char *root; - const char *module; - int control_fd; - struct kdbus_conn *conn; -}; - -enum { - TEST_OK, - TEST_SKIP, - TEST_ERR, -}; - -#define ASSERT_RETURN_VAL(cond, val) \ - if (!(cond)) { \ - fprintf(stderr, "Assertion '%s' failed in %s(), %s:%d\n", \ - #cond, __func__, __FILE__, __LINE__); \ - return val; \ - } - -#define ASSERT_EXIT_VAL(cond, val) \ - if (!(cond)) { \ - fprintf(stderr, "Assertion '%s' failed in %s(), %s:%d\n", \ - #cond, __func__, __FILE__, __LINE__); \ - _exit(val); \ - } - -#define ASSERT_BREAK(cond) \ - if (!(cond)) { \ - fprintf(stderr, "Assertion '%s' failed in %s(), %s:%d\n", \ - #cond, __func__, __FILE__, __LINE__); \ - break; \ - } - -#define ASSERT_RETURN(cond) \ - ASSERT_RETURN_VAL(cond, TEST_ERR) - -#define ASSERT_EXIT(cond) \ - ASSERT_EXIT_VAL(cond, EXIT_FAILURE) - -int kdbus_test_activator(struct kdbus_test_env *env); -int kdbus_test_benchmark(struct kdbus_test_env *env); -int kdbus_test_benchmark_nomemfds(struct kdbus_test_env *env); -int kdbus_test_benchmark_uds(struct kdbus_test_env *env); -int kdbus_test_bus_make(struct kdbus_test_env *env); -int kdbus_test_byebye(struct kdbus_test_env *env); -int kdbus_test_chat(struct kdbus_test_env *env); -int kdbus_test_conn_info(struct kdbus_test_env *env); -int kdbus_test_conn_update(struct kdbus_test_env *env); -int kdbus_test_daemon(struct kdbus_test_env *env); -int kdbus_test_custom_endpoint(struct kdbus_test_env *env); -int kdbus_test_fd_passing(struct kdbus_test_env *env); -int kdbus_test_free(struct kdbus_test_env *env); -int kdbus_test_hello(struct kdbus_test_env *env); -int kdbus_test_match_bloom(struct kdbus_test_env *env); -int kdbus_test_match_id_add(struct kdbus_test_env *env); -int kdbus_test_match_id_remove(struct kdbus_test_env *env); -int kdbus_test_match_replace(struct kdbus_test_env *env); -int kdbus_test_match_name_add(struct kdbus_test_env *env); -int kdbus_test_match_name_change(struct kdbus_test_env *env); -int kdbus_test_match_name_remove(struct kdbus_test_env *env); -int kdbus_test_message_basic(struct kdbus_test_env *env); -int kdbus_test_message_prio(struct kdbus_test_env *env); -int kdbus_test_message_quota(struct kdbus_test_env *env); -int kdbus_test_memory_access(struct kdbus_test_env *env); -int kdbus_test_metadata_ns(struct kdbus_test_env *env); -int kdbus_test_monitor(struct kdbus_test_env *env); -int kdbus_test_name_basic(struct kdbus_test_env *env); -int kdbus_test_name_conflict(struct kdbus_test_env *env); -int kdbus_test_name_queue(struct kdbus_test_env *env); -int kdbus_test_name_takeover(struct kdbus_test_env *env); -int kdbus_test_policy(struct kdbus_test_env *env); -int kdbus_test_policy_ns(struct kdbus_test_env *env); -int kdbus_test_policy_priv(struct kdbus_test_env *env); -int kdbus_test_sync_byebye(struct kdbus_test_env *env); -int kdbus_test_sync_reply(struct kdbus_test_env *env); -int kdbus_test_timeout(struct kdbus_test_env *env); -int kdbus_test_writable_pool(struct kdbus_test_env *env); - -#endif /* _TEST_KDBUS_H_ */ diff --git a/tools/testing/selftests/kdbus/kdbus-util.c b/tools/testing/selftests/kdbus/kdbus-util.c deleted file mode 100644 index 82fa89b1a..000000000 --- a/tools/testing/selftests/kdbus/kdbus-util.c +++ /dev/null @@ -1,1612 +0,0 @@ -/* - * Copyright (C) 2013-2015 Daniel Mack - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2014-2015 Djalal Harouni - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#include <stdio.h> -#include <stdarg.h> -#include <string.h> -#include <time.h> -#include <inttypes.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <stdint.h> -#include <stdbool.h> -#include <errno.h> -#include <assert.h> -#include <poll.h> -#include <grp.h> -#include <sys/capability.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <linux/unistd.h> -#include <linux/memfd.h> - -#ifndef __NR_memfd_create - #ifdef __x86_64__ - #define __NR_memfd_create 319 - #elif defined __arm__ - #define __NR_memfd_create 385 - #else - #define __NR_memfd_create 356 - #endif -#endif - -#include "kdbus-api.h" -#include "kdbus-util.h" -#include "kdbus-enum.h" - -#ifndef F_ADD_SEALS -#define F_LINUX_SPECIFIC_BASE 1024 -#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9) -#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10) - -#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */ -#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */ -#define F_SEAL_GROW 0x0004 /* prevent file from growing */ -#define F_SEAL_WRITE 0x0008 /* prevent writes */ -#endif - -int kdbus_util_verbose = true; - -int kdbus_sysfs_get_parameter_mask(const char *path, uint64_t *mask) -{ - int ret; - FILE *file; - unsigned long long value; - - file = fopen(path, "r"); - if (!file) { - ret = -errno; - kdbus_printf("--- error fopen(): %d (%m)\n", ret); - return ret; - } - - ret = fscanf(file, "%llu", &value); - if (ret != 1) { - if (ferror(file)) - ret = -errno; - else - ret = -EIO; - - kdbus_printf("--- error fscanf(): %d\n", ret); - fclose(file); - return ret; - } - - *mask = (uint64_t)value; - - fclose(file); - - return 0; -} - -int kdbus_sysfs_set_parameter_mask(const char *path, uint64_t mask) -{ - int ret; - FILE *file; - - file = fopen(path, "w"); - if (!file) { - ret = -errno; - kdbus_printf("--- error open(): %d (%m)\n", ret); - return ret; - } - - ret = fprintf(file, "%llu", (unsigned long long)mask); - if (ret <= 0) { - ret = -EIO; - kdbus_printf("--- error fprintf(): %d\n", ret); - } - - fclose(file); - - return ret > 0 ? 0 : ret; -} - -int kdbus_create_bus(int control_fd, const char *name, - uint64_t owner_meta, char **path) -{ - struct { - struct kdbus_cmd cmd; - - /* bloom size item */ - struct { - uint64_t size; - uint64_t type; - struct kdbus_bloom_parameter bloom; - } bp; - - /* owner metadata items */ - struct { - uint64_t size; - uint64_t type; - uint64_t flags; - } attach; - - /* name item */ - struct { - uint64_t size; - uint64_t type; - char str[64]; - } name; - } bus_make; - int ret; - - memset(&bus_make, 0, sizeof(bus_make)); - bus_make.bp.size = sizeof(bus_make.bp); - bus_make.bp.type = KDBUS_ITEM_BLOOM_PARAMETER; - bus_make.bp.bloom.size = 64; - bus_make.bp.bloom.n_hash = 1; - - snprintf(bus_make.name.str, sizeof(bus_make.name.str), - "%u-%s", getuid(), name); - - bus_make.attach.type = KDBUS_ITEM_ATTACH_FLAGS_SEND; - bus_make.attach.size = sizeof(bus_make.attach); - bus_make.attach.flags = owner_meta; - - bus_make.name.type = KDBUS_ITEM_MAKE_NAME; - bus_make.name.size = KDBUS_ITEM_HEADER_SIZE + - strlen(bus_make.name.str) + 1; - - bus_make.cmd.flags = KDBUS_MAKE_ACCESS_WORLD; - bus_make.cmd.size = sizeof(bus_make.cmd) + - bus_make.bp.size + - bus_make.attach.size + - bus_make.name.size; - - kdbus_printf("Creating bus with name >%s< on control fd %d ...\n", - name, control_fd); - - ret = kdbus_cmd_bus_make(control_fd, &bus_make.cmd); - if (ret < 0) { - kdbus_printf("--- error when making bus: %d (%m)\n", ret); - return ret; - } - - if (ret == 0 && path) - *path = strdup(bus_make.name.str); - - return ret; -} - -struct kdbus_conn * -kdbus_hello(const char *path, uint64_t flags, - const struct kdbus_item *item, size_t item_size) -{ - struct kdbus_cmd_free cmd_free = {}; - int fd, ret; - struct { - struct kdbus_cmd_hello hello; - - struct { - uint64_t size; - uint64_t type; - char str[16]; - } conn_name; - - uint8_t extra_items[item_size]; - } h; - struct kdbus_conn *conn; - - memset(&h, 0, sizeof(h)); - - if (item_size > 0) - memcpy(h.extra_items, item, item_size); - - kdbus_printf("-- opening bus connection %s\n", path); - fd = open(path, O_RDWR|O_CLOEXEC); - if (fd < 0) { - kdbus_printf("--- error %d (%m)\n", fd); - return NULL; - } - - h.hello.flags = flags | KDBUS_HELLO_ACCEPT_FD; - h.hello.attach_flags_send = _KDBUS_ATTACH_ALL; - h.hello.attach_flags_recv = _KDBUS_ATTACH_ALL; - h.conn_name.type = KDBUS_ITEM_CONN_DESCRIPTION; - strcpy(h.conn_name.str, "this-is-my-name"); - h.conn_name.size = KDBUS_ITEM_HEADER_SIZE + strlen(h.conn_name.str) + 1; - - h.hello.size = sizeof(h); - h.hello.pool_size = POOL_SIZE; - - ret = kdbus_cmd_hello(fd, (struct kdbus_cmd_hello *) &h.hello); - if (ret < 0) { - kdbus_printf("--- error when saying hello: %d (%m)\n", ret); - return NULL; - } - kdbus_printf("-- Our peer ID for %s: %llu -- bus uuid: '%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x'\n", - path, (unsigned long long)h.hello.id, - h.hello.id128[0], h.hello.id128[1], h.hello.id128[2], - h.hello.id128[3], h.hello.id128[4], h.hello.id128[5], - h.hello.id128[6], h.hello.id128[7], h.hello.id128[8], - h.hello.id128[9], h.hello.id128[10], h.hello.id128[11], - h.hello.id128[12], h.hello.id128[13], h.hello.id128[14], - h.hello.id128[15]); - - cmd_free.size = sizeof(cmd_free); - cmd_free.offset = h.hello.offset; - kdbus_cmd_free(fd, &cmd_free); - - conn = malloc(sizeof(*conn)); - if (!conn) { - kdbus_printf("unable to malloc()!?\n"); - return NULL; - } - - conn->buf = mmap(NULL, POOL_SIZE, PROT_READ, MAP_SHARED, fd, 0); - if (conn->buf == MAP_FAILED) { - free(conn); - close(fd); - kdbus_printf("--- error mmap (%m)\n"); - return NULL; - } - - conn->fd = fd; - conn->id = h.hello.id; - return conn; -} - -struct kdbus_conn * -kdbus_hello_registrar(const char *path, const char *name, - const struct kdbus_policy_access *access, - size_t num_access, uint64_t flags) -{ - struct kdbus_item *item, *items; - size_t i, size; - - size = KDBUS_ITEM_SIZE(strlen(name) + 1) + - num_access * KDBUS_ITEM_SIZE(sizeof(*access)); - - items = alloca(size); - - item = items; - item->size = KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1; - item->type = KDBUS_ITEM_NAME; - strcpy(item->str, name); - item = KDBUS_ITEM_NEXT(item); - - for (i = 0; i < num_access; i++) { - item->size = KDBUS_ITEM_HEADER_SIZE + - sizeof(struct kdbus_policy_access); - item->type = KDBUS_ITEM_POLICY_ACCESS; - - item->policy_access.type = access[i].type; - item->policy_access.access = access[i].access; - item->policy_access.id = access[i].id; - - item = KDBUS_ITEM_NEXT(item); - } - - return kdbus_hello(path, flags, items, size); -} - -struct kdbus_conn *kdbus_hello_activator(const char *path, const char *name, - const struct kdbus_policy_access *access, - size_t num_access) -{ - return kdbus_hello_registrar(path, name, access, num_access, - KDBUS_HELLO_ACTIVATOR); -} - -bool kdbus_item_in_message(struct kdbus_msg *msg, uint64_t type) -{ - const struct kdbus_item *item; - - KDBUS_ITEM_FOREACH(item, msg, items) - if (item->type == type) - return true; - - return false; -} - -int kdbus_bus_creator_info(struct kdbus_conn *conn, - uint64_t flags, - uint64_t *offset) -{ - struct kdbus_cmd_info *cmd; - size_t size = sizeof(*cmd); - int ret; - - cmd = alloca(size); - memset(cmd, 0, size); - cmd->size = size; - cmd->attach_flags = flags; - - ret = kdbus_cmd_bus_creator_info(conn->fd, cmd); - if (ret < 0) { - kdbus_printf("--- error when requesting info: %d (%m)\n", ret); - return ret; - } - - if (offset) - *offset = cmd->offset; - else - kdbus_free(conn, cmd->offset); - - return 0; -} - -int kdbus_conn_info(struct kdbus_conn *conn, uint64_t id, - const char *name, uint64_t flags, - uint64_t *offset) -{ - struct kdbus_cmd_info *cmd; - size_t size = sizeof(*cmd); - struct kdbus_info *info; - int ret; - - if (name) - size += KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1; - - cmd = alloca(size); - memset(cmd, 0, size); - cmd->size = size; - cmd->attach_flags = flags; - - if (name) { - cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1; - cmd->items[0].type = KDBUS_ITEM_NAME; - strcpy(cmd->items[0].str, name); - } else { - cmd->id = id; - } - - ret = kdbus_cmd_conn_info(conn->fd, cmd); - if (ret < 0) { - kdbus_printf("--- error when requesting info: %d (%m)\n", ret); - return ret; - } - - info = (struct kdbus_info *) (conn->buf + cmd->offset); - if (info->size != cmd->info_size) { - kdbus_printf("%s(): size mismatch: %d != %d\n", __func__, - (int) info->size, (int) cmd->info_size); - return -EIO; - } - - if (offset) - *offset = cmd->offset; - else - kdbus_free(conn, cmd->offset); - - return 0; -} - -void kdbus_conn_free(struct kdbus_conn *conn) -{ - if (!conn) - return; - - if (conn->buf) - munmap(conn->buf, POOL_SIZE); - - if (conn->fd >= 0) - close(conn->fd); - - free(conn); -} - -int sys_memfd_create(const char *name, __u64 size) -{ - int ret, fd; - - fd = syscall(__NR_memfd_create, name, MFD_ALLOW_SEALING); - if (fd < 0) - return fd; - - ret = ftruncate(fd, size); - if (ret < 0) { - close(fd); - return ret; - } - - return fd; -} - -int sys_memfd_seal_set(int fd) -{ - return fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | - F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL); -} - -off_t sys_memfd_get_size(int fd, off_t *size) -{ - struct stat stat; - int ret; - - ret = fstat(fd, &stat); - if (ret < 0) { - kdbus_printf("stat() failed: %m\n"); - return ret; - } - - *size = stat.st_size; - return 0; -} - -static int __kdbus_msg_send(const struct kdbus_conn *conn, - const char *name, - uint64_t cookie, - uint64_t flags, - uint64_t timeout, - int64_t priority, - uint64_t dst_id, - uint64_t cmd_flags, - int cancel_fd) -{ - struct kdbus_cmd_send *cmd = NULL; - struct kdbus_msg *msg = NULL; - const char ref1[1024 * 128 + 3] = "0123456789_0"; - const char ref2[] = "0123456789_1"; - struct kdbus_item *item; - struct timespec now; - uint64_t size; - int memfd = -1; - int ret; - - size = sizeof(*msg) + 3 * KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); - - if (dst_id == KDBUS_DST_ID_BROADCAST) - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + 64; - else { - memfd = sys_memfd_create("my-name-is-nice", 1024 * 1024); - if (memfd < 0) { - kdbus_printf("failed to create memfd: %m\n"); - return memfd; - } - - if (write(memfd, "kdbus memfd 1234567", 19) != 19) { - ret = -errno; - kdbus_printf("writing to memfd failed: %m\n"); - goto out; - } - - ret = sys_memfd_seal_set(memfd); - if (ret < 0) { - ret = -errno; - kdbus_printf("memfd sealing failed: %m\n"); - goto out; - } - - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd)); - } - - if (name) - size += KDBUS_ITEM_SIZE(strlen(name) + 1); - - msg = malloc(size); - if (!msg) { - ret = -errno; - kdbus_printf("unable to malloc()!?\n"); - goto out; - } - - if (dst_id == KDBUS_DST_ID_BROADCAST) - flags |= KDBUS_MSG_SIGNAL; - - memset(msg, 0, size); - msg->flags = flags; - msg->priority = priority; - msg->size = size; - msg->src_id = conn->id; - msg->dst_id = name ? 0 : dst_id; - msg->cookie = cookie; - msg->payload_type = KDBUS_PAYLOAD_DBUS; - - if (timeout) { - ret = clock_gettime(CLOCK_MONOTONIC_COARSE, &now); - if (ret < 0) - goto out; - - msg->timeout_ns = now.tv_sec * 1000000000ULL + - now.tv_nsec + timeout; - } - - item = msg->items; - - if (name) { - item->type = KDBUS_ITEM_DST_NAME; - item->size = KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1; - strcpy(item->str, name); - item = KDBUS_ITEM_NEXT(item); - } - - item->type = KDBUS_ITEM_PAYLOAD_VEC; - item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); - item->vec.address = (uintptr_t)&ref1; - item->vec.size = sizeof(ref1); - item = KDBUS_ITEM_NEXT(item); - - /* data padding for ref1 */ - item->type = KDBUS_ITEM_PAYLOAD_VEC; - item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); - item->vec.address = (uintptr_t)NULL; - item->vec.size = KDBUS_ALIGN8(sizeof(ref1)) - sizeof(ref1); - item = KDBUS_ITEM_NEXT(item); - - item->type = KDBUS_ITEM_PAYLOAD_VEC; - item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); - item->vec.address = (uintptr_t)&ref2; - item->vec.size = sizeof(ref2); - item = KDBUS_ITEM_NEXT(item); - - if (dst_id == KDBUS_DST_ID_BROADCAST) { - item->type = KDBUS_ITEM_BLOOM_FILTER; - item->size = KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + 64; - item->bloom_filter.generation = 0; - } else { - item->type = KDBUS_ITEM_PAYLOAD_MEMFD; - item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_memfd); - item->memfd.size = 16; - item->memfd.fd = memfd; - } - item = KDBUS_ITEM_NEXT(item); - - size = sizeof(*cmd); - if (cancel_fd != -1) - size += KDBUS_ITEM_SIZE(sizeof(cancel_fd)); - - cmd = malloc(size); - if (!cmd) { - ret = -errno; - kdbus_printf("unable to malloc()!?\n"); - goto out; - } - - cmd->size = size; - cmd->flags = cmd_flags; - cmd->msg_address = (uintptr_t)msg; - - item = cmd->items; - - if (cancel_fd != -1) { - item->type = KDBUS_ITEM_CANCEL_FD; - item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(cancel_fd); - item->fds[0] = cancel_fd; - item = KDBUS_ITEM_NEXT(item); - } - - ret = kdbus_cmd_send(conn->fd, cmd); - if (ret < 0) { - kdbus_printf("error sending message: %d (%m)\n", ret); - goto out; - } - - if (cmd_flags & KDBUS_SEND_SYNC_REPLY) { - struct kdbus_msg *reply; - - kdbus_printf("SYNC REPLY @offset %llu:\n", cmd->reply.offset); - reply = (struct kdbus_msg *)(conn->buf + cmd->reply.offset); - kdbus_msg_dump(conn, reply); - - kdbus_msg_free(reply); - - ret = kdbus_free(conn, cmd->reply.offset); - if (ret < 0) - goto out; - } - -out: - free(msg); - free(cmd); - - if (memfd >= 0) - close(memfd); - - return ret < 0 ? ret : 0; -} - -int kdbus_msg_send(const struct kdbus_conn *conn, const char *name, - uint64_t cookie, uint64_t flags, uint64_t timeout, - int64_t priority, uint64_t dst_id) -{ - return __kdbus_msg_send(conn, name, cookie, flags, timeout, priority, - dst_id, 0, -1); -} - -int kdbus_msg_send_sync(const struct kdbus_conn *conn, const char *name, - uint64_t cookie, uint64_t flags, uint64_t timeout, - int64_t priority, uint64_t dst_id, int cancel_fd) -{ - return __kdbus_msg_send(conn, name, cookie, flags, timeout, priority, - dst_id, KDBUS_SEND_SYNC_REPLY, cancel_fd); -} - -int kdbus_msg_send_reply(const struct kdbus_conn *conn, - uint64_t reply_cookie, - uint64_t dst_id) -{ - struct kdbus_cmd_send cmd = {}; - struct kdbus_msg *msg; - const char ref1[1024 * 128 + 3] = "0123456789_0"; - struct kdbus_item *item; - uint64_t size; - int ret; - - size = sizeof(struct kdbus_msg); - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); - - msg = malloc(size); - if (!msg) { - kdbus_printf("unable to malloc()!?\n"); - return -ENOMEM; - } - - memset(msg, 0, size); - msg->size = size; - msg->src_id = conn->id; - msg->dst_id = dst_id; - msg->cookie_reply = reply_cookie; - msg->payload_type = KDBUS_PAYLOAD_DBUS; - - item = msg->items; - - item->type = KDBUS_ITEM_PAYLOAD_VEC; - item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); - item->vec.address = (uintptr_t)&ref1; - item->vec.size = sizeof(ref1); - item = KDBUS_ITEM_NEXT(item); - - cmd.size = sizeof(cmd); - cmd.msg_address = (uintptr_t)msg; - - ret = kdbus_cmd_send(conn->fd, &cmd); - if (ret < 0) - kdbus_printf("error sending message: %d (%m)\n", ret); - - free(msg); - - return ret; -} - -static char *msg_id(uint64_t id, char *buf) -{ - if (id == 0) - return "KERNEL"; - if (id == ~0ULL) - return "BROADCAST"; - sprintf(buf, "%llu", (unsigned long long)id); - return buf; -} - -int kdbus_msg_dump(const struct kdbus_conn *conn, const struct kdbus_msg *msg) -{ - const struct kdbus_item *item = msg->items; - char buf_src[32]; - char buf_dst[32]; - uint64_t timeout = 0; - uint64_t cookie_reply = 0; - int ret = 0; - - if (msg->flags & KDBUS_MSG_EXPECT_REPLY) - timeout = msg->timeout_ns; - else - cookie_reply = msg->cookie_reply; - - kdbus_printf("MESSAGE: %s (%llu bytes) flags=0x%08llx, %s → %s, " - "cookie=%llu, timeout=%llu cookie_reply=%llu priority=%lli\n", - enum_PAYLOAD(msg->payload_type), (unsigned long long)msg->size, - (unsigned long long)msg->flags, - msg_id(msg->src_id, buf_src), msg_id(msg->dst_id, buf_dst), - (unsigned long long)msg->cookie, (unsigned long long)timeout, - (unsigned long long)cookie_reply, (long long)msg->priority); - - KDBUS_ITEM_FOREACH(item, msg, items) { - if (item->size < KDBUS_ITEM_HEADER_SIZE) { - kdbus_printf(" +%s (%llu bytes) invalid data record\n", - enum_MSG(item->type), item->size); - ret = -EINVAL; - break; - } - - switch (item->type) { - case KDBUS_ITEM_PAYLOAD_OFF: { - char *s; - - if (item->vec.offset == ~0ULL) - s = "[\\0-bytes]"; - else - s = (char *)msg + item->vec.offset; - - kdbus_printf(" +%s (%llu bytes) off=%llu size=%llu '%s'\n", - enum_MSG(item->type), item->size, - (unsigned long long)item->vec.offset, - (unsigned long long)item->vec.size, s); - break; - } - - case KDBUS_ITEM_FDS: { - int i, n = (item->size - KDBUS_ITEM_HEADER_SIZE) / - sizeof(int); - - kdbus_printf(" +%s (%llu bytes, %d fds)\n", - enum_MSG(item->type), item->size, n); - - for (i = 0; i < n; i++) - kdbus_printf(" fd[%d] = %d\n", - i, item->fds[i]); - - break; - } - - case KDBUS_ITEM_PAYLOAD_MEMFD: { - char *buf; - off_t size; - - buf = mmap(NULL, item->memfd.size, PROT_READ, - MAP_PRIVATE, item->memfd.fd, 0); - if (buf == MAP_FAILED) { - kdbus_printf("mmap() fd=%i size=%llu failed: %m\n", - item->memfd.fd, item->memfd.size); - break; - } - - if (sys_memfd_get_size(item->memfd.fd, &size) < 0) { - kdbus_printf("KDBUS_CMD_MEMFD_SIZE_GET failed: %m\n"); - break; - } - - kdbus_printf(" +%s (%llu bytes) fd=%i size=%llu filesize=%llu '%s'\n", - enum_MSG(item->type), item->size, item->memfd.fd, - (unsigned long long)item->memfd.size, - (unsigned long long)size, buf); - munmap(buf, item->memfd.size); - break; - } - - case KDBUS_ITEM_CREDS: - kdbus_printf(" +%s (%llu bytes) uid=%lld, euid=%lld, suid=%lld, fsuid=%lld, " - "gid=%lld, egid=%lld, sgid=%lld, fsgid=%lld\n", - enum_MSG(item->type), item->size, - item->creds.uid, item->creds.euid, - item->creds.suid, item->creds.fsuid, - item->creds.gid, item->creds.egid, - item->creds.sgid, item->creds.fsgid); - break; - - case KDBUS_ITEM_PIDS: - kdbus_printf(" +%s (%llu bytes) pid=%lld, tid=%lld, ppid=%lld\n", - enum_MSG(item->type), item->size, - item->pids.pid, item->pids.tid, - item->pids.ppid); - break; - - case KDBUS_ITEM_AUXGROUPS: { - int i, n; - - kdbus_printf(" +%s (%llu bytes)\n", - enum_MSG(item->type), item->size); - n = (item->size - KDBUS_ITEM_HEADER_SIZE) / - sizeof(uint64_t); - - for (i = 0; i < n; i++) - kdbus_printf(" gid[%d] = %lld\n", - i, item->data64[i]); - break; - } - - case KDBUS_ITEM_NAME: - case KDBUS_ITEM_PID_COMM: - case KDBUS_ITEM_TID_COMM: - case KDBUS_ITEM_EXE: - case KDBUS_ITEM_CGROUP: - case KDBUS_ITEM_SECLABEL: - case KDBUS_ITEM_DST_NAME: - case KDBUS_ITEM_CONN_DESCRIPTION: - kdbus_printf(" +%s (%llu bytes) '%s' (%zu)\n", - enum_MSG(item->type), item->size, - item->str, strlen(item->str)); - break; - - case KDBUS_ITEM_OWNED_NAME: { - kdbus_printf(" +%s (%llu bytes) '%s' (%zu) flags=0x%08llx\n", - enum_MSG(item->type), item->size, - item->name.name, strlen(item->name.name), - item->name.flags); - break; - } - - case KDBUS_ITEM_CMDLINE: { - size_t size = item->size - KDBUS_ITEM_HEADER_SIZE; - const char *str = item->str; - int count = 0; - - kdbus_printf(" +%s (%llu bytes) ", - enum_MSG(item->type), item->size); - while (size) { - kdbus_printf("'%s' ", str); - size -= strlen(str) + 1; - str += strlen(str) + 1; - count++; - } - - kdbus_printf("(%d string%s)\n", - count, (count == 1) ? "" : "s"); - break; - } - - case KDBUS_ITEM_AUDIT: - kdbus_printf(" +%s (%llu bytes) loginuid=%u sessionid=%u\n", - enum_MSG(item->type), item->size, - item->audit.loginuid, item->audit.sessionid); - break; - - case KDBUS_ITEM_CAPS: { - const uint32_t *cap; - int n, i; - - kdbus_printf(" +%s (%llu bytes) len=%llu bytes, last_cap %d\n", - enum_MSG(item->type), item->size, - (unsigned long long)item->size - - KDBUS_ITEM_HEADER_SIZE, - (int) item->caps.last_cap); - - cap = item->caps.caps; - n = (item->size - offsetof(struct kdbus_item, caps.caps)) - / 4 / sizeof(uint32_t); - - kdbus_printf(" CapInh="); - for (i = 0; i < n; i++) - kdbus_printf("%08x", cap[(0 * n) + (n - i - 1)]); - - kdbus_printf(" CapPrm="); - for (i = 0; i < n; i++) - kdbus_printf("%08x", cap[(1 * n) + (n - i - 1)]); - - kdbus_printf(" CapEff="); - for (i = 0; i < n; i++) - kdbus_printf("%08x", cap[(2 * n) + (n - i - 1)]); - - kdbus_printf(" CapBnd="); - for (i = 0; i < n; i++) - kdbus_printf("%08x", cap[(3 * n) + (n - i - 1)]); - kdbus_printf("\n"); - break; - } - - case KDBUS_ITEM_TIMESTAMP: - kdbus_printf(" +%s (%llu bytes) seq=%llu realtime=%lluns monotonic=%lluns\n", - enum_MSG(item->type), item->size, - (unsigned long long)item->timestamp.seqnum, - (unsigned long long)item->timestamp.realtime_ns, - (unsigned long long)item->timestamp.monotonic_ns); - break; - - case KDBUS_ITEM_REPLY_TIMEOUT: - kdbus_printf(" +%s (%llu bytes) cookie=%llu\n", - enum_MSG(item->type), item->size, - msg->cookie_reply); - break; - - case KDBUS_ITEM_NAME_ADD: - case KDBUS_ITEM_NAME_REMOVE: - case KDBUS_ITEM_NAME_CHANGE: - kdbus_printf(" +%s (%llu bytes) '%s', old id=%lld, now id=%lld, old_flags=0x%llx new_flags=0x%llx\n", - enum_MSG(item->type), - (unsigned long long) item->size, - item->name_change.name, - item->name_change.old_id.id, - item->name_change.new_id.id, - item->name_change.old_id.flags, - item->name_change.new_id.flags); - break; - - case KDBUS_ITEM_ID_ADD: - case KDBUS_ITEM_ID_REMOVE: - kdbus_printf(" +%s (%llu bytes) id=%llu flags=%llu\n", - enum_MSG(item->type), - (unsigned long long) item->size, - (unsigned long long) item->id_change.id, - (unsigned long long) item->id_change.flags); - break; - - default: - kdbus_printf(" +%s (%llu bytes)\n", - enum_MSG(item->type), item->size); - break; - } - } - - if ((char *)item - ((char *)msg + msg->size) >= 8) { - kdbus_printf("invalid padding at end of message\n"); - ret = -EINVAL; - } - - kdbus_printf("\n"); - - return ret; -} - -void kdbus_msg_free(struct kdbus_msg *msg) -{ - const struct kdbus_item *item; - int nfds, i; - - if (!msg) - return; - - KDBUS_ITEM_FOREACH(item, msg, items) { - switch (item->type) { - /* close all memfds */ - case KDBUS_ITEM_PAYLOAD_MEMFD: - close(item->memfd.fd); - break; - case KDBUS_ITEM_FDS: - nfds = (item->size - KDBUS_ITEM_HEADER_SIZE) / - sizeof(int); - - for (i = 0; i < nfds; i++) - close(item->fds[i]); - - break; - } - } -} - -int kdbus_msg_recv(struct kdbus_conn *conn, - struct kdbus_msg **msg_out, - uint64_t *offset) -{ - struct kdbus_cmd_recv recv = { .size = sizeof(recv) }; - struct kdbus_msg *msg; - int ret; - - ret = kdbus_cmd_recv(conn->fd, &recv); - if (ret < 0) - return ret; - - msg = (struct kdbus_msg *)(conn->buf + recv.msg.offset); - ret = kdbus_msg_dump(conn, msg); - if (ret < 0) { - kdbus_msg_free(msg); - return ret; - } - - if (msg_out) { - *msg_out = msg; - - if (offset) - *offset = recv.msg.offset; - } else { - kdbus_msg_free(msg); - - ret = kdbus_free(conn, recv.msg.offset); - if (ret < 0) - return ret; - } - - return 0; -} - -/* - * Returns: 0 on success, negative errno on failure. - * - * We must return -ETIMEDOUT, -ECONNREST, -EAGAIN and other errors. - * We must return the result of kdbus_msg_recv() - */ -int kdbus_msg_recv_poll(struct kdbus_conn *conn, - int timeout_ms, - struct kdbus_msg **msg_out, - uint64_t *offset) -{ - int ret; - - do { - struct timeval before, after, diff; - struct pollfd fd; - - fd.fd = conn->fd; - fd.events = POLLIN | POLLPRI | POLLHUP; - fd.revents = 0; - - gettimeofday(&before, NULL); - ret = poll(&fd, 1, timeout_ms); - gettimeofday(&after, NULL); - - if (ret == 0) { - ret = -ETIMEDOUT; - break; - } - - if (ret > 0) { - if (fd.revents & POLLIN) - ret = kdbus_msg_recv(conn, msg_out, offset); - - if (fd.revents & (POLLHUP | POLLERR)) - ret = -ECONNRESET; - } - - if (ret == 0 || ret != -EAGAIN) - break; - - timersub(&after, &before, &diff); - timeout_ms -= diff.tv_sec * 1000UL + - diff.tv_usec / 1000UL; - } while (timeout_ms > 0); - - return ret; -} - -int kdbus_free(const struct kdbus_conn *conn, uint64_t offset) -{ - struct kdbus_cmd_free cmd_free = {}; - int ret; - - cmd_free.size = sizeof(cmd_free); - cmd_free.offset = offset; - cmd_free.flags = 0; - - ret = kdbus_cmd_free(conn->fd, &cmd_free); - if (ret < 0) { - kdbus_printf("KDBUS_CMD_FREE failed: %d (%m)\n", ret); - return ret; - } - - return 0; -} - -int kdbus_name_acquire(struct kdbus_conn *conn, - const char *name, uint64_t *flags) -{ - struct kdbus_cmd *cmd_name; - size_t name_len = strlen(name) + 1; - uint64_t size = sizeof(*cmd_name) + KDBUS_ITEM_SIZE(name_len); - struct kdbus_item *item; - int ret; - - cmd_name = alloca(size); - - memset(cmd_name, 0, size); - - item = cmd_name->items; - item->size = KDBUS_ITEM_HEADER_SIZE + name_len; - item->type = KDBUS_ITEM_NAME; - strcpy(item->str, name); - - cmd_name->size = size; - if (flags) - cmd_name->flags = *flags; - - ret = kdbus_cmd_name_acquire(conn->fd, cmd_name); - if (ret < 0) { - kdbus_printf("error aquiring name: %s\n", strerror(-ret)); - return ret; - } - - kdbus_printf("%s(): flags after call: 0x%llx\n", __func__, - cmd_name->return_flags); - - if (flags) - *flags = cmd_name->return_flags; - - return 0; -} - -int kdbus_name_release(struct kdbus_conn *conn, const char *name) -{ - struct kdbus_cmd *cmd_name; - size_t name_len = strlen(name) + 1; - uint64_t size = sizeof(*cmd_name) + KDBUS_ITEM_SIZE(name_len); - struct kdbus_item *item; - int ret; - - cmd_name = alloca(size); - - memset(cmd_name, 0, size); - - item = cmd_name->items; - item->size = KDBUS_ITEM_HEADER_SIZE + name_len; - item->type = KDBUS_ITEM_NAME; - strcpy(item->str, name); - - cmd_name->size = size; - - kdbus_printf("conn %lld giving up name '%s'\n", - (unsigned long long) conn->id, name); - - ret = kdbus_cmd_name_release(conn->fd, cmd_name); - if (ret < 0) { - kdbus_printf("error releasing name: %s\n", strerror(-ret)); - return ret; - } - - return 0; -} - -int kdbus_list(struct kdbus_conn *conn, uint64_t flags) -{ - struct kdbus_cmd_list cmd_list = {}; - struct kdbus_info *list, *name; - int ret; - - cmd_list.size = sizeof(cmd_list); - cmd_list.flags = flags; - - ret = kdbus_cmd_list(conn->fd, &cmd_list); - if (ret < 0) { - kdbus_printf("error listing names: %d (%m)\n", ret); - return ret; - } - - kdbus_printf("REGISTRY:\n"); - list = (struct kdbus_info *)(conn->buf + cmd_list.offset); - - KDBUS_FOREACH(name, list, cmd_list.list_size) { - uint64_t flags = 0; - struct kdbus_item *item; - const char *n = "MISSING-NAME"; - - if (name->size == sizeof(struct kdbus_cmd)) - continue; - - KDBUS_ITEM_FOREACH(item, name, items) - if (item->type == KDBUS_ITEM_OWNED_NAME) { - n = item->name.name; - flags = item->name.flags; - - kdbus_printf("%8llu flags=0x%08llx conn=0x%08llx '%s'\n", - name->id, - (unsigned long long) flags, - name->flags, n); - } - } - kdbus_printf("\n"); - - ret = kdbus_free(conn, cmd_list.offset); - - return ret; -} - -int kdbus_conn_update_attach_flags(struct kdbus_conn *conn, - uint64_t attach_flags_send, - uint64_t attach_flags_recv) -{ - int ret; - size_t size; - struct kdbus_cmd *update; - struct kdbus_item *item; - - size = sizeof(struct kdbus_cmd); - size += KDBUS_ITEM_SIZE(sizeof(uint64_t)) * 2; - - update = malloc(size); - if (!update) { - kdbus_printf("error malloc: %m\n"); - return -ENOMEM; - } - - memset(update, 0, size); - update->size = size; - - item = update->items; - - item->type = KDBUS_ITEM_ATTACH_FLAGS_SEND; - item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(uint64_t); - item->data64[0] = attach_flags_send; - item = KDBUS_ITEM_NEXT(item); - - item->type = KDBUS_ITEM_ATTACH_FLAGS_RECV; - item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(uint64_t); - item->data64[0] = attach_flags_recv; - item = KDBUS_ITEM_NEXT(item); - - ret = kdbus_cmd_update(conn->fd, update); - if (ret < 0) - kdbus_printf("error conn update: %d (%m)\n", ret); - - free(update); - - return ret; -} - -int kdbus_conn_update_policy(struct kdbus_conn *conn, const char *name, - const struct kdbus_policy_access *access, - size_t num_access) -{ - struct kdbus_cmd *update; - struct kdbus_item *item; - size_t i, size; - int ret; - - size = sizeof(struct kdbus_cmd); - size += KDBUS_ITEM_SIZE(strlen(name) + 1); - size += num_access * KDBUS_ITEM_SIZE(sizeof(struct kdbus_policy_access)); - - update = malloc(size); - if (!update) { - kdbus_printf("error malloc: %m\n"); - return -ENOMEM; - } - - memset(update, 0, size); - update->size = size; - - item = update->items; - - item->type = KDBUS_ITEM_NAME; - item->size = KDBUS_ITEM_HEADER_SIZE + strlen(name) + 1; - strcpy(item->str, name); - item = KDBUS_ITEM_NEXT(item); - - for (i = 0; i < num_access; i++) { - item->size = KDBUS_ITEM_HEADER_SIZE + - sizeof(struct kdbus_policy_access); - item->type = KDBUS_ITEM_POLICY_ACCESS; - - item->policy_access.type = access[i].type; - item->policy_access.access = access[i].access; - item->policy_access.id = access[i].id; - - item = KDBUS_ITEM_NEXT(item); - } - - ret = kdbus_cmd_update(conn->fd, update); - if (ret < 0) - kdbus_printf("error conn update: %d (%m)\n", ret); - - free(update); - - return ret; -} - -int kdbus_add_match_id(struct kdbus_conn *conn, uint64_t cookie, - uint64_t type, uint64_t id) -{ - struct { - struct kdbus_cmd_match cmd; - struct { - uint64_t size; - uint64_t type; - struct kdbus_notify_id_change chg; - } item; - } buf; - int ret; - - memset(&buf, 0, sizeof(buf)); - - buf.cmd.size = sizeof(buf); - buf.cmd.cookie = cookie; - buf.item.size = sizeof(buf.item); - buf.item.type = type; - buf.item.chg.id = id; - - ret = kdbus_cmd_match_add(conn->fd, &buf.cmd); - if (ret < 0) - kdbus_printf("--- error adding conn match: %d (%m)\n", ret); - - return ret; -} - -int kdbus_add_match_empty(struct kdbus_conn *conn) -{ - struct { - struct kdbus_cmd_match cmd; - struct kdbus_item item; - } buf; - int ret; - - memset(&buf, 0, sizeof(buf)); - - buf.item.size = sizeof(uint64_t) * 3; - buf.item.type = KDBUS_ITEM_ID; - buf.item.id = KDBUS_MATCH_ID_ANY; - - buf.cmd.size = sizeof(buf.cmd) + buf.item.size; - - ret = kdbus_cmd_match_add(conn->fd, &buf.cmd); - if (ret < 0) - kdbus_printf("--- error adding conn match: %d (%m)\n", ret); - - return ret; -} - -static int all_ids_are_mapped(const char *path) -{ - int ret; - FILE *file; - uint32_t inside_id, length; - - file = fopen(path, "r"); - if (!file) { - ret = -errno; - kdbus_printf("error fopen() %s: %d (%m)\n", - path, ret); - return ret; - } - - ret = fscanf(file, "%u\t%*u\t%u", &inside_id, &length); - if (ret != 2) { - if (ferror(file)) - ret = -errno; - else - ret = -EIO; - - kdbus_printf("--- error fscanf(): %d\n", ret); - fclose(file); - return ret; - } - - fclose(file); - - /* - * If length is 4294967295 which means the invalid uid - * (uid_t) -1 then we are able to map all uid/gids - */ - if (inside_id == 0 && length == (uid_t) -1) - return 1; - - return 0; -} - -int all_uids_gids_are_mapped(void) -{ - int ret; - - ret = all_ids_are_mapped("/proc/self/uid_map"); - if (ret <= 0) { - kdbus_printf("--- error not all uids are mapped\n"); - return 0; - } - - ret = all_ids_are_mapped("/proc/self/gid_map"); - if (ret <= 0) { - kdbus_printf("--- error not all gids are mapped\n"); - return 0; - } - - return 1; -} - -int drop_privileges(uid_t uid, gid_t gid) -{ - int ret; - - ret = setgroups(0, NULL); - if (ret < 0) { - ret = -errno; - kdbus_printf("error setgroups: %d (%m)\n", ret); - return ret; - } - - ret = setresgid(gid, gid, gid); - if (ret < 0) { - ret = -errno; - kdbus_printf("error setresgid: %d (%m)\n", ret); - return ret; - } - - ret = setresuid(uid, uid, uid); - if (ret < 0) { - ret = -errno; - kdbus_printf("error setresuid: %d (%m)\n", ret); - return ret; - } - - return ret; -} - -uint64_t now(clockid_t clock) -{ - struct timespec spec; - - clock_gettime(clock, &spec); - return spec.tv_sec * 1000ULL * 1000ULL * 1000ULL + spec.tv_nsec; -} - -char *unique_name(const char *prefix) -{ - unsigned int i; - uint64_t u_now; - char n[17]; - char *str; - int r; - - /* - * This returns a random string which is guaranteed to be - * globally unique across all calls to unique_name(). We - * compose the string as: - * <prefix>-<random>-<time> - * With: - * <prefix>: string provided by the caller - * <random>: a random alpha string of 16 characters - * <time>: the current time in micro-seconds since last boot - * - * The <random> part makes the string always look vastly different, - * the <time> part makes sure no two calls return the same string. - */ - - u_now = now(CLOCK_MONOTONIC); - - for (i = 0; i < sizeof(n) - 1; ++i) - n[i] = 'a' + (rand() % ('z' - 'a')); - n[sizeof(n) - 1] = 0; - - r = asprintf(&str, "%s-%s-%" PRIu64, prefix, n, u_now); - if (r < 0) - return NULL; - - return str; -} - -static int do_userns_map_id(pid_t pid, - const char *map_file, - const char *map_id) -{ - int ret; - int fd; - char *map; - unsigned int i; - - map = strndupa(map_id, strlen(map_id)); - if (!map) { - ret = -errno; - kdbus_printf("error strndupa %s: %d (%m)\n", - map_file, ret); - return ret; - } - - for (i = 0; i < strlen(map); i++) - if (map[i] == ',') - map[i] = '\n'; - - fd = open(map_file, O_RDWR); - if (fd < 0) { - ret = -errno; - kdbus_printf("error open %s: %d (%m)\n", - map_file, ret); - return ret; - } - - ret = write(fd, map, strlen(map)); - if (ret < 0) { - ret = -errno; - kdbus_printf("error write to %s: %d (%m)\n", - map_file, ret); - goto out; - } - - ret = 0; - -out: - close(fd); - return ret; -} - -int userns_map_uid_gid(pid_t pid, - const char *map_uid, - const char *map_gid) -{ - int fd, ret; - char file_id[128] = {'\0'}; - - snprintf(file_id, sizeof(file_id), "/proc/%ld/uid_map", - (long) pid); - - ret = do_userns_map_id(pid, file_id, map_uid); - if (ret < 0) - return ret; - - snprintf(file_id, sizeof(file_id), "/proc/%ld/setgroups", - (long) pid); - - fd = open(file_id, O_WRONLY); - if (fd >= 0) { - write(fd, "deny\n", 5); - close(fd); - } - - snprintf(file_id, sizeof(file_id), "/proc/%ld/gid_map", - (long) pid); - - return do_userns_map_id(pid, file_id, map_gid); -} - -static int do_cap_get_flag(cap_t caps, cap_value_t cap) -{ - int ret; - cap_flag_value_t flag_set; - - ret = cap_get_flag(caps, cap, CAP_EFFECTIVE, &flag_set); - if (ret < 0) { - ret = -errno; - kdbus_printf("error cap_get_flag(): %d (%m)\n", ret); - return ret; - } - - return (flag_set == CAP_SET); -} - -/* - * Returns: - * 1 in case all the requested effective capabilities are set. - * 0 in case we do not have the requested capabilities. This value - * will be used to abort tests with TEST_SKIP - * Negative errno on failure. - * - * Terminate args with a negative value. - */ -int test_is_capable(int cap, ...) -{ - int ret; - va_list ap; - cap_t caps; - - caps = cap_get_proc(); - if (!caps) { - ret = -errno; - kdbus_printf("error cap_get_proc(): %d (%m)\n", ret); - return ret; - } - - ret = do_cap_get_flag(caps, (cap_value_t)cap); - if (ret <= 0) - goto out; - - va_start(ap, cap); - while ((cap = va_arg(ap, int)) > 0) { - ret = do_cap_get_flag(caps, (cap_value_t)cap); - if (ret <= 0) - break; - } - va_end(ap); - -out: - cap_free(caps); - return ret; -} - -int config_user_ns_is_enabled(void) -{ - return (access("/proc/self/uid_map", F_OK) == 0); -} - -int config_auditsyscall_is_enabled(void) -{ - return (access("/proc/self/loginuid", F_OK) == 0); -} - -int config_cgroups_is_enabled(void) -{ - return (access("/proc/self/cgroup", F_OK) == 0); -} - -int config_security_is_enabled(void) -{ - int fd; - int ret; - char buf[128]; - - /* CONFIG_SECURITY is disabled */ - if (access("/proc/self/attr/current", F_OK) != 0) - return 0; - - /* - * Now only if read() fails with -EINVAL then we assume - * that SECLABEL and LSM are disabled - */ - fd = open("/proc/self/attr/current", O_RDONLY|O_CLOEXEC); - if (fd < 0) - return 1; - - ret = read(fd, buf, sizeof(buf)); - if (ret == -1 && errno == EINVAL) - ret = 0; - else - ret = 1; - - close(fd); - - return ret; -} diff --git a/tools/testing/selftests/kdbus/kdbus-util.h b/tools/testing/selftests/kdbus/kdbus-util.h deleted file mode 100644 index e1e18b92f..000000000 --- a/tools/testing/selftests/kdbus/kdbus-util.h +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Daniel Mack - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#pragma once - -#define BIT(X) (1 << (X)) - -#include <time.h> -#include <stdbool.h> -#include <linux/kdbus.h> - -#define _STRINGIFY(x) #x -#define STRINGIFY(x) _STRINGIFY(x) -#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0])) - -#define KDBUS_PTR(addr) ((void *)(uintptr_t)(addr)) - -#define KDBUS_ALIGN8(l) (((l) + 7) & ~7) -#define KDBUS_ITEM_HEADER_SIZE offsetof(struct kdbus_item, data) -#define KDBUS_ITEM_SIZE(s) KDBUS_ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE) - -#define KDBUS_ITEM_NEXT(item) \ - (typeof(item))((uint8_t *)(item) + KDBUS_ALIGN8((item)->size)) -#define KDBUS_ITEM_FOREACH(item, head, first) \ - for ((item) = (head)->first; \ - ((uint8_t *)(item) < (uint8_t *)(head) + (head)->size) && \ - ((uint8_t *)(item) >= (uint8_t *)(head)); \ - (item) = KDBUS_ITEM_NEXT(item)) -#define KDBUS_FOREACH(iter, first, _size) \ - for ((iter) = (first); \ - ((uint8_t *)(iter) < (uint8_t *)(first) + (_size)) && \ - ((uint8_t *)(iter) >= (uint8_t *)(first)); \ - (iter) = (void *)((uint8_t *)(iter) + KDBUS_ALIGN8((iter)->size))) - -#define _KDBUS_ATTACH_BITS_SET_NR (__builtin_popcountll(_KDBUS_ATTACH_ALL)) - -/* Sum of KDBUS_ITEM_* that reflects _KDBUS_ATTACH_ALL */ -#define KDBUS_ATTACH_ITEMS_TYPE_SUM \ - ((((_KDBUS_ATTACH_BITS_SET_NR - 1) * \ - ((_KDBUS_ATTACH_BITS_SET_NR - 1) + 1)) / 2) + \ - (_KDBUS_ITEM_ATTACH_BASE * _KDBUS_ATTACH_BITS_SET_NR)) - -#define POOL_SIZE (16 * 1024LU * 1024LU) - -#define UNPRIV_UID 65534 -#define UNPRIV_GID 65534 - -/* Dump as user of process, useful for user namespace testing */ -#define SUID_DUMP_USER 1 - -extern int kdbus_util_verbose; - -#define kdbus_printf(X...) \ - if (kdbus_util_verbose) \ - printf(X) - -#define RUN_UNPRIVILEGED(child_uid, child_gid, _child_, _parent_) ({ \ - pid_t pid, rpid; \ - int ret; \ - \ - pid = fork(); \ - if (pid == 0) { \ - ret = drop_privileges(child_uid, child_gid); \ - ASSERT_EXIT_VAL(ret == 0, ret); \ - \ - _child_; \ - _exit(0); \ - } else if (pid > 0) { \ - _parent_; \ - rpid = waitpid(pid, &ret, 0); \ - ASSERT_RETURN(rpid == pid); \ - ASSERT_RETURN(WIFEXITED(ret)); \ - ASSERT_RETURN(WEXITSTATUS(ret) == 0); \ - ret = TEST_OK; \ - } else { \ - ret = pid; \ - } \ - \ - ret; \ - }) - -#define RUN_UNPRIVILEGED_CONN(_var_, _bus_, _code_) \ - RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_GID, ({ \ - struct kdbus_conn *_var_; \ - _var_ = kdbus_hello(_bus_, 0, NULL, 0); \ - ASSERT_EXIT(_var_); \ - _code_; \ - kdbus_conn_free(_var_); \ - }), ({ 0; })) - -#define RUN_CLONE_CHILD(clone_ret, flags, _setup_, _child_body_, \ - _parent_setup_, _parent_body_) ({ \ - pid_t pid, rpid; \ - int ret; \ - int efd = -1; \ - \ - _setup_; \ - efd = eventfd(0, EFD_CLOEXEC); \ - ASSERT_RETURN(efd >= 0); \ - *(clone_ret) = 0; \ - pid = syscall(__NR_clone, flags, NULL); \ - if (pid == 0) { \ - eventfd_t event_status = 0; \ - ret = prctl(PR_SET_PDEATHSIG, SIGKILL); \ - ASSERT_EXIT(ret == 0); \ - ret = eventfd_read(efd, &event_status); \ - if (ret < 0 || event_status != 1) { \ - kdbus_printf("error eventfd_read()\n"); \ - _exit(EXIT_FAILURE); \ - } \ - _child_body_; \ - _exit(0); \ - } else if (pid > 0) { \ - _parent_setup_; \ - ret = eventfd_write(efd, 1); \ - ASSERT_RETURN(ret >= 0); \ - _parent_body_; \ - rpid = waitpid(pid, &ret, 0); \ - ASSERT_RETURN(rpid == pid); \ - ASSERT_RETURN(WIFEXITED(ret)); \ - ASSERT_RETURN(WEXITSTATUS(ret) == 0); \ - ret = TEST_OK; \ - } else { \ - ret = -errno; \ - *(clone_ret) = -errno; \ - } \ - close(efd); \ - ret; \ -}) - -/* Enums for parent if it should drop privs or not */ -enum kdbus_drop_parent { - DO_NOT_DROP, - DROP_SAME_UNPRIV, - DROP_OTHER_UNPRIV, -}; - -struct kdbus_conn { - int fd; - uint64_t id; - unsigned char *buf; -}; - -int kdbus_sysfs_get_parameter_mask(const char *path, uint64_t *mask); -int kdbus_sysfs_set_parameter_mask(const char *path, uint64_t mask); - -int sys_memfd_create(const char *name, __u64 size); -int sys_memfd_seal_set(int fd); -off_t sys_memfd_get_size(int fd, off_t *size); - -int kdbus_list(struct kdbus_conn *conn, uint64_t flags); -int kdbus_name_release(struct kdbus_conn *conn, const char *name); -int kdbus_name_acquire(struct kdbus_conn *conn, const char *name, - uint64_t *flags); -void kdbus_msg_free(struct kdbus_msg *msg); -int kdbus_msg_recv(struct kdbus_conn *conn, - struct kdbus_msg **msg, uint64_t *offset); -int kdbus_msg_recv_poll(struct kdbus_conn *conn, int timeout_ms, - struct kdbus_msg **msg_out, uint64_t *offset); -int kdbus_free(const struct kdbus_conn *conn, uint64_t offset); -int kdbus_msg_dump(const struct kdbus_conn *conn, - const struct kdbus_msg *msg); -int kdbus_create_bus(int control_fd, const char *name, - uint64_t owner_meta, char **path); -int kdbus_msg_send(const struct kdbus_conn *conn, const char *name, - uint64_t cookie, uint64_t flags, uint64_t timeout, - int64_t priority, uint64_t dst_id); -int kdbus_msg_send_sync(const struct kdbus_conn *conn, const char *name, - uint64_t cookie, uint64_t flags, uint64_t timeout, - int64_t priority, uint64_t dst_id, int cancel_fd); -int kdbus_msg_send_reply(const struct kdbus_conn *conn, - uint64_t reply_cookie, - uint64_t dst_id); -struct kdbus_conn *kdbus_hello(const char *path, uint64_t hello_flags, - const struct kdbus_item *item, - size_t item_size); -struct kdbus_conn *kdbus_hello_registrar(const char *path, const char *name, - const struct kdbus_policy_access *access, - size_t num_access, uint64_t flags); -struct kdbus_conn *kdbus_hello_activator(const char *path, const char *name, - const struct kdbus_policy_access *access, - size_t num_access); -bool kdbus_item_in_message(struct kdbus_msg *msg, uint64_t type); -int kdbus_bus_creator_info(struct kdbus_conn *conn, - uint64_t flags, - uint64_t *offset); -int kdbus_conn_info(struct kdbus_conn *conn, uint64_t id, - const char *name, uint64_t flags, uint64_t *offset); -void kdbus_conn_free(struct kdbus_conn *conn); -int kdbus_conn_update_attach_flags(struct kdbus_conn *conn, - uint64_t attach_flags_send, - uint64_t attach_flags_recv); -int kdbus_conn_update_policy(struct kdbus_conn *conn, const char *name, - const struct kdbus_policy_access *access, - size_t num_access); - -int kdbus_add_match_id(struct kdbus_conn *conn, uint64_t cookie, - uint64_t type, uint64_t id); -int kdbus_add_match_empty(struct kdbus_conn *conn); - -int all_uids_gids_are_mapped(void); -int drop_privileges(uid_t uid, gid_t gid); -uint64_t now(clockid_t clock); -char *unique_name(const char *prefix); - -int userns_map_uid_gid(pid_t pid, const char *map_uid, const char *map_gid); -int test_is_capable(int cap, ...); -int config_user_ns_is_enabled(void); -int config_auditsyscall_is_enabled(void); -int config_cgroups_is_enabled(void); -int config_security_is_enabled(void); diff --git a/tools/testing/selftests/kdbus/test-activator.c b/tools/testing/selftests/kdbus/test-activator.c deleted file mode 100644 index c576a30ad..000000000 --- a/tools/testing/selftests/kdbus/test-activator.c +++ /dev/null @@ -1,321 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stdbool.h> -#include <stddef.h> -#include <unistd.h> -#include <stdint.h> -#include <errno.h> -#include <assert.h> -#include <poll.h> -#include <sys/capability.h> -#include <sys/types.h> -#include <sys/wait.h> - -#include "kdbus-test.h" -#include "kdbus-util.h" -#include "kdbus-enum.h" - -static int kdbus_starter_poll(struct kdbus_conn *conn) -{ - int ret; - struct pollfd fd; - - fd.fd = conn->fd; - fd.events = POLLIN | POLLPRI | POLLHUP; - fd.revents = 0; - - ret = poll(&fd, 1, 100); - if (ret == 0) - return -ETIMEDOUT; - else if (ret > 0) { - if (fd.revents & POLLIN) - return 0; - - if (fd.revents & (POLLHUP | POLLERR)) - ret = -ECONNRESET; - } - - return ret; -} - -/* Ensure that kdbus activator logic is safe */ -static int kdbus_priv_activator(struct kdbus_test_env *env) -{ - int ret; - struct kdbus_msg *msg = NULL; - uint64_t cookie = 0xdeadbeef; - uint64_t flags; - struct kdbus_conn *activator; - struct kdbus_conn *service; - struct kdbus_conn *client; - struct kdbus_conn *holder; - struct kdbus_policy_access *access; - - access = (struct kdbus_policy_access[]){ - { - .type = KDBUS_POLICY_ACCESS_USER, - .id = getuid(), - .access = KDBUS_POLICY_OWN, - }, - { - .type = KDBUS_POLICY_ACCESS_USER, - .id = getuid(), - .access = KDBUS_POLICY_TALK, - }, - }; - - activator = kdbus_hello_activator(env->buspath, "foo.priv.activator", - access, 2); - ASSERT_RETURN(activator); - - service = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(service); - - client = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(client); - - /* - * Make sure that other users can't TALK to the activator - */ - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - /* Try to talk using the ID */ - ret = kdbus_msg_send(unpriv, NULL, 0xdeadbeef, 0, 0, - 0, activator->id); - ASSERT_EXIT(ret == -ENXIO); - - /* Try to talk to the name */ - ret = kdbus_msg_send(unpriv, "foo.priv.activator", - 0xdeadbeef, 0, 0, 0, - KDBUS_DST_ID_NAME); - ASSERT_EXIT(ret == -EPERM); - })); - ASSERT_RETURN(ret >= 0); - - /* - * Make sure that we did not receive anything, so the - * service will not be started automatically - */ - - ret = kdbus_starter_poll(activator); - ASSERT_RETURN(ret == -ETIMEDOUT); - - /* - * Now try to emulate the starter/service logic and - * acquire the name. - */ - - cookie++; - ret = kdbus_msg_send(service, "foo.priv.activator", cookie, - 0, 0, 0, KDBUS_DST_ID_NAME); - ASSERT_RETURN(ret == 0); - - ret = kdbus_starter_poll(activator); - ASSERT_RETURN(ret == 0); - - /* Policies are still checked, access denied */ - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - flags = KDBUS_NAME_REPLACE_EXISTING; - ret = kdbus_name_acquire(unpriv, "foo.priv.activator", - &flags); - ASSERT_RETURN(ret == -EPERM); - })); - ASSERT_RETURN(ret >= 0); - - flags = KDBUS_NAME_REPLACE_EXISTING; - ret = kdbus_name_acquire(service, "foo.priv.activator", - &flags); - ASSERT_RETURN(ret == 0); - - /* We read our previous starter message */ - - ret = kdbus_msg_recv_poll(service, 100, NULL, NULL); - ASSERT_RETURN(ret == 0); - - /* Try to talk, we still fail */ - - cookie++; - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - /* Try to talk to the name */ - ret = kdbus_msg_send(unpriv, "foo.priv.activator", - cookie, 0, 0, 0, - KDBUS_DST_ID_NAME); - ASSERT_EXIT(ret == -EPERM); - })); - ASSERT_RETURN(ret >= 0); - - /* Still nothing to read */ - - ret = kdbus_msg_recv_poll(service, 100, NULL, NULL); - ASSERT_RETURN(ret == -ETIMEDOUT); - - /* We receive every thing now */ - - cookie++; - ret = kdbus_msg_send(client, "foo.priv.activator", cookie, - 0, 0, 0, KDBUS_DST_ID_NAME); - ASSERT_RETURN(ret == 0); - ret = kdbus_msg_recv_poll(service, 100, &msg, NULL); - ASSERT_RETURN(ret == 0 && msg->cookie == cookie); - - kdbus_msg_free(msg); - - /* Policies default to deny TALK now */ - kdbus_conn_free(activator); - - cookie++; - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - /* Try to talk to the name */ - ret = kdbus_msg_send(unpriv, "foo.priv.activator", - cookie, 0, 0, 0, - KDBUS_DST_ID_NAME); - ASSERT_EXIT(ret == -EPERM); - })); - ASSERT_RETURN(ret >= 0); - - ret = kdbus_msg_recv_poll(service, 100, NULL, NULL); - ASSERT_RETURN(ret == -ETIMEDOUT); - - /* Same user is able to TALK */ - cookie++; - ret = kdbus_msg_send(client, "foo.priv.activator", cookie, - 0, 0, 0, KDBUS_DST_ID_NAME); - ASSERT_RETURN(ret == 0); - ret = kdbus_msg_recv_poll(service, 100, &msg, NULL); - ASSERT_RETURN(ret == 0 && msg->cookie == cookie); - - kdbus_msg_free(msg); - - access = (struct kdbus_policy_access []){ - { - .type = KDBUS_POLICY_ACCESS_WORLD, - .id = getuid(), - .access = KDBUS_POLICY_TALK, - }, - }; - - holder = kdbus_hello_registrar(env->buspath, "foo.priv.activator", - access, 1, KDBUS_HELLO_POLICY_HOLDER); - ASSERT_RETURN(holder); - - /* Now we are able to TALK to the name */ - - cookie++; - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - /* Try to talk to the name */ - ret = kdbus_msg_send(unpriv, "foo.priv.activator", - cookie, 0, 0, 0, - KDBUS_DST_ID_NAME); - ASSERT_EXIT(ret == 0); - })); - ASSERT_RETURN(ret >= 0); - - ret = kdbus_msg_recv_poll(service, 100, NULL, NULL); - ASSERT_RETURN(ret == 0); - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - flags = KDBUS_NAME_REPLACE_EXISTING; - ret = kdbus_name_acquire(unpriv, "foo.priv.activator", - &flags); - ASSERT_RETURN(ret == -EPERM); - })); - ASSERT_RETURN(ret >= 0); - - kdbus_conn_free(service); - kdbus_conn_free(client); - kdbus_conn_free(holder); - - return 0; -} - -int kdbus_test_activator(struct kdbus_test_env *env) -{ - int ret; - struct kdbus_conn *activator; - struct pollfd fds[2]; - bool activator_done = false; - struct kdbus_policy_access access[2]; - - access[0].type = KDBUS_POLICY_ACCESS_USER; - access[0].id = getuid(); - access[0].access = KDBUS_POLICY_OWN; - - access[1].type = KDBUS_POLICY_ACCESS_WORLD; - access[1].access = KDBUS_POLICY_TALK; - - activator = kdbus_hello_activator(env->buspath, "foo.test.activator", - access, 2); - ASSERT_RETURN(activator); - - ret = kdbus_add_match_empty(env->conn); - ASSERT_RETURN(ret == 0); - - ret = kdbus_list(env->conn, KDBUS_LIST_NAMES | - KDBUS_LIST_UNIQUE | - KDBUS_LIST_ACTIVATORS | - KDBUS_LIST_QUEUED); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_send(env->conn, "foo.test.activator", 0xdeafbeef, - 0, 0, 0, KDBUS_DST_ID_NAME); - ASSERT_RETURN(ret == 0); - - fds[0].fd = activator->fd; - fds[1].fd = env->conn->fd; - - kdbus_printf("-- entering poll loop ...\n"); - - for (;;) { - int i, nfds = sizeof(fds) / sizeof(fds[0]); - - for (i = 0; i < nfds; i++) { - fds[i].events = POLLIN | POLLPRI; - fds[i].revents = 0; - } - - ret = poll(fds, nfds, 3000); - ASSERT_RETURN(ret >= 0); - - ret = kdbus_list(env->conn, KDBUS_LIST_NAMES); - ASSERT_RETURN(ret == 0); - - if ((fds[0].revents & POLLIN) && !activator_done) { - uint64_t flags = KDBUS_NAME_REPLACE_EXISTING; - - kdbus_printf("Starter was called back!\n"); - - ret = kdbus_name_acquire(env->conn, - "foo.test.activator", &flags); - ASSERT_RETURN(ret == 0); - - activator_done = true; - } - - if (fds[1].revents & POLLIN) { - kdbus_msg_recv(env->conn, NULL, NULL); - break; - } - } - - /* Check if all uids/gids are mapped */ - if (!all_uids_gids_are_mapped()) - return TEST_SKIP; - - /* Check now capabilities, so we run the previous tests */ - ret = test_is_capable(CAP_SETUID, CAP_SETGID, -1); - ASSERT_RETURN(ret >= 0); - - if (!ret) - return TEST_SKIP; - - ret = kdbus_priv_activator(env); - ASSERT_RETURN(ret == 0); - - kdbus_conn_free(activator); - - return TEST_OK; -} diff --git a/tools/testing/selftests/kdbus/test-benchmark.c b/tools/testing/selftests/kdbus/test-benchmark.c deleted file mode 100644 index 8a9744b00..000000000 --- a/tools/testing/selftests/kdbus/test-benchmark.c +++ /dev/null @@ -1,451 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <fcntl.h> -#include <locale.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <stdint.h> -#include <stdbool.h> -#include <errno.h> -#include <assert.h> -#include <poll.h> -#include <sys/time.h> -#include <sys/mman.h> -#include <sys/socket.h> -#include <math.h> - -#include "kdbus-api.h" -#include "kdbus-test.h" -#include "kdbus-util.h" -#include "kdbus-enum.h" - -#define SERVICE_NAME "foo.bar.echo" - -/* - * To have a banchmark comparison with unix socket, set: - * user_memfd = false; - * compare_uds = true; - * attach_none = true; do not attached metadata - */ - -static bool use_memfd = true; /* transmit memfd? */ -static bool compare_uds = false; /* unix-socket comparison? */ -static bool attach_none = false; /* clear attach-flags? */ -static char stress_payload[8192]; - -struct stats { - uint64_t count; - uint64_t latency_acc; - uint64_t latency_low; - uint64_t latency_high; - uint64_t latency_avg; - uint64_t latency_ssquares; -}; - -static struct stats stats; - -static void reset_stats(void) -{ - stats.count = 0; - stats.latency_acc = 0; - stats.latency_low = UINT64_MAX; - stats.latency_high = 0; - stats.latency_avg = 0; - stats.latency_ssquares = 0; -} - -static void dump_stats(bool is_uds) -{ - if (stats.count > 0) { - kdbus_printf("stats %s: %'llu packets processed, latency (nsecs) min/max/avg/dev %'7llu // %'7llu // %'7llu // %'7.f\n", - is_uds ? " (UNIX)" : "(KDBUS)", - (unsigned long long) stats.count, - (unsigned long long) stats.latency_low, - (unsigned long long) stats.latency_high, - (unsigned long long) stats.latency_avg, - sqrt(stats.latency_ssquares / stats.count)); - } else { - kdbus_printf("*** no packets received. bus stuck?\n"); - } -} - -static void add_stats(uint64_t prev) -{ - uint64_t diff, latency_avg_prev; - - diff = now(CLOCK_THREAD_CPUTIME_ID) - prev; - - stats.count++; - stats.latency_acc += diff; - - /* see Welford62 */ - latency_avg_prev = stats.latency_avg; - stats.latency_avg = stats.latency_acc / stats.count; - stats.latency_ssquares += (diff - latency_avg_prev) * (diff - stats.latency_avg); - - if (stats.latency_low > diff) - stats.latency_low = diff; - - if (stats.latency_high < diff) - stats.latency_high = diff; -} - -static int setup_simple_kdbus_msg(struct kdbus_conn *conn, - uint64_t dst_id, - struct kdbus_msg **msg_out) -{ - struct kdbus_msg *msg; - struct kdbus_item *item; - uint64_t size; - - size = sizeof(struct kdbus_msg); - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); - - msg = malloc(size); - ASSERT_RETURN_VAL(msg, -ENOMEM); - - memset(msg, 0, size); - msg->size = size; - msg->src_id = conn->id; - msg->dst_id = dst_id; - msg->payload_type = KDBUS_PAYLOAD_DBUS; - - item = msg->items; - - item->type = KDBUS_ITEM_PAYLOAD_VEC; - item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); - item->vec.address = (uintptr_t) stress_payload; - item->vec.size = sizeof(stress_payload); - item = KDBUS_ITEM_NEXT(item); - - *msg_out = msg; - - return 0; -} - -static int setup_memfd_kdbus_msg(struct kdbus_conn *conn, - uint64_t dst_id, - off_t *memfd_item_offset, - struct kdbus_msg **msg_out) -{ - struct kdbus_msg *msg; - struct kdbus_item *item; - uint64_t size; - - size = sizeof(struct kdbus_msg); - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd)); - - msg = malloc(size); - ASSERT_RETURN_VAL(msg, -ENOMEM); - - memset(msg, 0, size); - msg->size = size; - msg->src_id = conn->id; - msg->dst_id = dst_id; - msg->payload_type = KDBUS_PAYLOAD_DBUS; - - item = msg->items; - - item->type = KDBUS_ITEM_PAYLOAD_VEC; - item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); - item->vec.address = (uintptr_t) stress_payload; - item->vec.size = sizeof(stress_payload); - item = KDBUS_ITEM_NEXT(item); - - item->type = KDBUS_ITEM_PAYLOAD_MEMFD; - item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_memfd); - item->memfd.size = sizeof(uint64_t); - - *memfd_item_offset = (unsigned char *)item - (unsigned char *)msg; - *msg_out = msg; - - return 0; -} - -static int -send_echo_request(struct kdbus_conn *conn, uint64_t dst_id, - void *kdbus_msg, off_t memfd_item_offset) -{ - struct kdbus_cmd_send cmd = {}; - int memfd = -1; - int ret; - - if (use_memfd) { - uint64_t now_ns = now(CLOCK_THREAD_CPUTIME_ID); - struct kdbus_item *item = memfd_item_offset + kdbus_msg; - memfd = sys_memfd_create("memfd-name", 0); - ASSERT_RETURN_VAL(memfd >= 0, memfd); - - ret = write(memfd, &now_ns, sizeof(now_ns)); - ASSERT_RETURN_VAL(ret == sizeof(now_ns), -EAGAIN); - - ret = sys_memfd_seal_set(memfd); - ASSERT_RETURN_VAL(ret == 0, -errno); - - item->memfd.fd = memfd; - } - - cmd.size = sizeof(cmd); - cmd.msg_address = (uintptr_t)kdbus_msg; - - ret = kdbus_cmd_send(conn->fd, &cmd); - ASSERT_RETURN_VAL(ret == 0, ret); - - close(memfd); - - return 0; -} - -static int -handle_echo_reply(struct kdbus_conn *conn, uint64_t send_ns) -{ - int ret; - struct kdbus_cmd_recv recv = { .size = sizeof(recv) }; - struct kdbus_msg *msg; - const struct kdbus_item *item; - bool has_memfd = false; - - ret = kdbus_cmd_recv(conn->fd, &recv); - if (ret == -EAGAIN) - return ret; - - ASSERT_RETURN_VAL(ret == 0, ret); - - if (!use_memfd) - goto out; - - msg = (struct kdbus_msg *)(conn->buf + recv.msg.offset); - - KDBUS_ITEM_FOREACH(item, msg, items) { - switch (item->type) { - case KDBUS_ITEM_PAYLOAD_MEMFD: { - char *buf; - - buf = mmap(NULL, item->memfd.size, PROT_READ, - MAP_PRIVATE, item->memfd.fd, 0); - ASSERT_RETURN_VAL(buf != MAP_FAILED, -EINVAL); - ASSERT_RETURN_VAL(item->memfd.size == sizeof(uint64_t), - -EINVAL); - - add_stats(*(uint64_t*)buf); - munmap(buf, item->memfd.size); - close(item->memfd.fd); - has_memfd = true; - break; - } - - case KDBUS_ITEM_PAYLOAD_OFF: - /* ignore */ - break; - } - } - -out: - if (!has_memfd) - add_stats(send_ns); - - ret = kdbus_free(conn, recv.msg.offset); - ASSERT_RETURN_VAL(ret == 0, -errno); - - return 0; -} - -static int benchmark(struct kdbus_test_env *env) -{ - static char buf[sizeof(stress_payload)]; - struct kdbus_msg *kdbus_msg = NULL; - off_t memfd_cached_offset = 0; - int ret; - struct kdbus_conn *conn_a, *conn_b; - struct pollfd fds[2]; - uint64_t start, send_ns, now_ns, diff; - unsigned int i; - int uds[2]; - - setlocale(LC_ALL, ""); - - for (i = 0; i < sizeof(stress_payload); i++) - stress_payload[i] = i; - - /* setup kdbus pair */ - - conn_a = kdbus_hello(env->buspath, 0, NULL, 0); - conn_b = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn_a && conn_b); - - ret = kdbus_add_match_empty(conn_a); - ASSERT_RETURN(ret == 0); - - ret = kdbus_add_match_empty(conn_b); - ASSERT_RETURN(ret == 0); - - ret = kdbus_name_acquire(conn_a, SERVICE_NAME, NULL); - ASSERT_RETURN(ret == 0); - - if (attach_none) { - ret = kdbus_conn_update_attach_flags(conn_a, - _KDBUS_ATTACH_ALL, - 0); - ASSERT_RETURN(ret == 0); - } - - /* setup UDS pair */ - - ret = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK, 0, uds); - ASSERT_RETURN(ret == 0); - - /* setup a kdbus msg now */ - if (use_memfd) { - ret = setup_memfd_kdbus_msg(conn_b, conn_a->id, - &memfd_cached_offset, - &kdbus_msg); - ASSERT_RETURN(ret == 0); - } else { - ret = setup_simple_kdbus_msg(conn_b, conn_a->id, &kdbus_msg); - ASSERT_RETURN(ret == 0); - } - - /* start benchmark */ - - kdbus_printf("-- entering poll loop ...\n"); - - do { - /* run kdbus benchmark */ - fds[0].fd = conn_a->fd; - fds[1].fd = conn_b->fd; - - /* cancel any pending message */ - handle_echo_reply(conn_a, 0); - - start = now(CLOCK_THREAD_CPUTIME_ID); - reset_stats(); - - send_ns = now(CLOCK_THREAD_CPUTIME_ID); - ret = send_echo_request(conn_b, conn_a->id, - kdbus_msg, memfd_cached_offset); - ASSERT_RETURN(ret == 0); - - while (1) { - unsigned int nfds = sizeof(fds) / sizeof(fds[0]); - unsigned int i; - - for (i = 0; i < nfds; i++) { - fds[i].events = POLLIN | POLLPRI | POLLHUP; - fds[i].revents = 0; - } - - ret = poll(fds, nfds, 10); - if (ret < 0) - break; - - if (fds[0].revents & POLLIN) { - ret = handle_echo_reply(conn_a, send_ns); - ASSERT_RETURN(ret == 0); - - send_ns = now(CLOCK_THREAD_CPUTIME_ID); - ret = send_echo_request(conn_b, conn_a->id, - kdbus_msg, - memfd_cached_offset); - ASSERT_RETURN(ret == 0); - } - - now_ns = now(CLOCK_THREAD_CPUTIME_ID); - diff = now_ns - start; - if (diff > 1000000000ULL) { - start = now_ns; - - dump_stats(false); - break; - } - } - - if (!compare_uds) - continue; - - /* run unix-socket benchmark as comparison */ - - fds[0].fd = uds[0]; - fds[1].fd = uds[1]; - - /* cancel any pendign message */ - read(uds[1], buf, sizeof(buf)); - - start = now(CLOCK_THREAD_CPUTIME_ID); - reset_stats(); - - send_ns = now(CLOCK_THREAD_CPUTIME_ID); - ret = write(uds[0], stress_payload, sizeof(stress_payload)); - ASSERT_RETURN(ret == sizeof(stress_payload)); - - while (1) { - unsigned int nfds = sizeof(fds) / sizeof(fds[0]); - unsigned int i; - - for (i = 0; i < nfds; i++) { - fds[i].events = POLLIN | POLLPRI | POLLHUP; - fds[i].revents = 0; - } - - ret = poll(fds, nfds, 10); - if (ret < 0) - break; - - if (fds[1].revents & POLLIN) { - ret = read(uds[1], buf, sizeof(buf)); - ASSERT_RETURN(ret == sizeof(buf)); - - add_stats(send_ns); - - send_ns = now(CLOCK_THREAD_CPUTIME_ID); - ret = write(uds[0], buf, sizeof(buf)); - ASSERT_RETURN(ret == sizeof(buf)); - } - - now_ns = now(CLOCK_THREAD_CPUTIME_ID); - diff = now_ns - start; - if (diff > 1000000000ULL) { - start = now_ns; - - dump_stats(true); - break; - } - } - - } while (kdbus_util_verbose); - - kdbus_printf("-- closing bus connections\n"); - - free(kdbus_msg); - - kdbus_conn_free(conn_a); - kdbus_conn_free(conn_b); - - return (stats.count > 1) ? TEST_OK : TEST_ERR; -} - -int kdbus_test_benchmark(struct kdbus_test_env *env) -{ - use_memfd = true; - attach_none = false; - compare_uds = false; - return benchmark(env); -} - -int kdbus_test_benchmark_nomemfds(struct kdbus_test_env *env) -{ - use_memfd = false; - attach_none = false; - compare_uds = false; - return benchmark(env); -} - -int kdbus_test_benchmark_uds(struct kdbus_test_env *env) -{ - use_memfd = false; - attach_none = true; - compare_uds = true; - return benchmark(env); -} diff --git a/tools/testing/selftests/kdbus/test-bus.c b/tools/testing/selftests/kdbus/test-bus.c deleted file mode 100644 index 762fb3039..000000000 --- a/tools/testing/selftests/kdbus/test-bus.c +++ /dev/null @@ -1,175 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <stdint.h> -#include <errno.h> -#include <assert.h> -#include <limits.h> -#include <sys/mman.h> -#include <stdbool.h> - -#include "kdbus-api.h" -#include "kdbus-util.h" -#include "kdbus-enum.h" -#include "kdbus-test.h" - -static struct kdbus_item *kdbus_get_item(struct kdbus_info *info, - uint64_t type) -{ - struct kdbus_item *item; - - KDBUS_ITEM_FOREACH(item, info, items) - if (item->type == type) - return item; - - return NULL; -} - -static int test_bus_creator_info(const char *bus_path) -{ - int ret; - uint64_t offset; - struct kdbus_conn *conn; - struct kdbus_info *info; - struct kdbus_item *item; - char *tmp, *busname; - - /* extract the bus-name from @bus_path */ - tmp = strdup(bus_path); - ASSERT_RETURN(tmp); - busname = strrchr(tmp, '/'); - ASSERT_RETURN(busname); - *busname = 0; - busname = strrchr(tmp, '/'); - ASSERT_RETURN(busname); - ++busname; - - conn = kdbus_hello(bus_path, 0, NULL, 0); - ASSERT_RETURN(conn); - - ret = kdbus_bus_creator_info(conn, _KDBUS_ATTACH_ALL, &offset); - ASSERT_RETURN(ret == 0); - - info = (struct kdbus_info *)(conn->buf + offset); - - item = kdbus_get_item(info, KDBUS_ITEM_MAKE_NAME); - ASSERT_RETURN(item); - ASSERT_RETURN(!strcmp(item->str, busname)); - - ret = kdbus_free(conn, offset); - ASSERT_RETURN_VAL(ret == 0, ret); - - free(tmp); - kdbus_conn_free(conn); - return 0; -} - -int kdbus_test_bus_make(struct kdbus_test_env *env) -{ - struct { - struct kdbus_cmd cmd; - - /* bloom size item */ - struct { - uint64_t size; - uint64_t type; - struct kdbus_bloom_parameter bloom; - } bs; - - /* name item */ - uint64_t n_size; - uint64_t n_type; - char name[64]; - } bus_make; - char s[PATH_MAX], *name; - int ret, control_fd2; - uid_t uid; - - name = unique_name(""); - ASSERT_RETURN(name); - - snprintf(s, sizeof(s), "%s/control", env->root); - env->control_fd = open(s, O_RDWR|O_CLOEXEC); - ASSERT_RETURN(env->control_fd >= 0); - - control_fd2 = open(s, O_RDWR|O_CLOEXEC); - ASSERT_RETURN(control_fd2 >= 0); - - memset(&bus_make, 0, sizeof(bus_make)); - - bus_make.bs.size = sizeof(bus_make.bs); - bus_make.bs.type = KDBUS_ITEM_BLOOM_PARAMETER; - bus_make.bs.bloom.size = 64; - bus_make.bs.bloom.n_hash = 1; - - bus_make.n_type = KDBUS_ITEM_MAKE_NAME; - - uid = getuid(); - - /* missing uid prefix */ - snprintf(bus_make.name, sizeof(bus_make.name), "foo"); - bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1; - bus_make.cmd.size = sizeof(struct kdbus_cmd) + - sizeof(bus_make.bs) + bus_make.n_size; - ret = kdbus_cmd_bus_make(env->control_fd, &bus_make.cmd); - ASSERT_RETURN(ret == -EINVAL); - - /* non alphanumeric character */ - snprintf(bus_make.name, sizeof(bus_make.name), "%u-blah@123", uid); - bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1; - bus_make.cmd.size = sizeof(struct kdbus_cmd) + - sizeof(bus_make.bs) + bus_make.n_size; - ret = kdbus_cmd_bus_make(env->control_fd, &bus_make.cmd); - ASSERT_RETURN(ret == -EINVAL); - - /* '-' at the end */ - snprintf(bus_make.name, sizeof(bus_make.name), "%u-blah-", uid); - bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1; - bus_make.cmd.size = sizeof(struct kdbus_cmd) + - sizeof(bus_make.bs) + bus_make.n_size; - ret = kdbus_cmd_bus_make(env->control_fd, &bus_make.cmd); - ASSERT_RETURN(ret == -EINVAL); - - /* create a new bus */ - snprintf(bus_make.name, sizeof(bus_make.name), "%u-%s-1", uid, name); - bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1; - bus_make.cmd.size = sizeof(struct kdbus_cmd) + - sizeof(bus_make.bs) + bus_make.n_size; - ret = kdbus_cmd_bus_make(env->control_fd, &bus_make.cmd); - ASSERT_RETURN(ret == 0); - - ret = kdbus_cmd_bus_make(control_fd2, &bus_make.cmd); - ASSERT_RETURN(ret == -EEXIST); - - snprintf(s, sizeof(s), "%s/%u-%s-1/bus", env->root, uid, name); - ASSERT_RETURN(access(s, F_OK) == 0); - - ret = test_bus_creator_info(s); - ASSERT_RETURN(ret == 0); - - /* can't use the same fd for bus make twice, even though a different - * bus name is used - */ - snprintf(bus_make.name, sizeof(bus_make.name), "%u-%s-2", uid, name); - bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1; - bus_make.cmd.size = sizeof(struct kdbus_cmd) + - sizeof(bus_make.bs) + bus_make.n_size; - ret = kdbus_cmd_bus_make(env->control_fd, &bus_make.cmd); - ASSERT_RETURN(ret == -EBADFD); - - /* create a new bus, with different fd and different bus name */ - snprintf(bus_make.name, sizeof(bus_make.name), "%u-%s-2", uid, name); - bus_make.n_size = KDBUS_ITEM_HEADER_SIZE + strlen(bus_make.name) + 1; - bus_make.cmd.size = sizeof(struct kdbus_cmd) + - sizeof(bus_make.bs) + bus_make.n_size; - ret = kdbus_cmd_bus_make(control_fd2, &bus_make.cmd); - ASSERT_RETURN(ret == 0); - - close(control_fd2); - free(name); - - return TEST_OK; -} diff --git a/tools/testing/selftests/kdbus/test-chat.c b/tools/testing/selftests/kdbus/test-chat.c deleted file mode 100644 index 41e5b53fe..000000000 --- a/tools/testing/selftests/kdbus/test-chat.c +++ /dev/null @@ -1,124 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <stdint.h> -#include <errno.h> -#include <assert.h> -#include <poll.h> -#include <stdbool.h> - -#include "kdbus-test.h" -#include "kdbus-util.h" -#include "kdbus-enum.h" - -int kdbus_test_chat(struct kdbus_test_env *env) -{ - int ret, cookie; - struct kdbus_conn *conn_a, *conn_b; - struct pollfd fds[2]; - uint64_t flags; - int count; - - conn_a = kdbus_hello(env->buspath, 0, NULL, 0); - conn_b = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn_a && conn_b); - - flags = KDBUS_NAME_ALLOW_REPLACEMENT; - ret = kdbus_name_acquire(conn_a, "foo.bar.test", &flags); - ASSERT_RETURN(ret == 0); - - ret = kdbus_name_acquire(conn_a, "foo.bar.baz", NULL); - ASSERT_RETURN(ret == 0); - - flags = KDBUS_NAME_QUEUE; - ret = kdbus_name_acquire(conn_b, "foo.bar.baz", &flags); - ASSERT_RETURN(ret == 0); - - ret = kdbus_name_acquire(conn_a, "foo.bar.double", NULL); - ASSERT_RETURN(ret == 0); - - flags = 0; - ret = kdbus_name_acquire(conn_a, "foo.bar.double", &flags); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(!(flags & KDBUS_NAME_ACQUIRED)); - - ret = kdbus_name_release(conn_a, "foo.bar.double"); - ASSERT_RETURN(ret == 0); - - ret = kdbus_name_release(conn_a, "foo.bar.double"); - ASSERT_RETURN(ret == -ESRCH); - - ret = kdbus_list(conn_b, KDBUS_LIST_UNIQUE | - KDBUS_LIST_NAMES | - KDBUS_LIST_QUEUED | - KDBUS_LIST_ACTIVATORS); - ASSERT_RETURN(ret == 0); - - ret = kdbus_add_match_empty(conn_a); - ASSERT_RETURN(ret == 0); - - ret = kdbus_add_match_empty(conn_b); - ASSERT_RETURN(ret == 0); - - cookie = 0; - ret = kdbus_msg_send(conn_b, NULL, 0xc0000000 | cookie, 0, 0, 0, - KDBUS_DST_ID_BROADCAST); - ASSERT_RETURN(ret == 0); - - fds[0].fd = conn_a->fd; - fds[1].fd = conn_b->fd; - - kdbus_printf("-- entering poll loop ...\n"); - - for (count = 0;; count++) { - int i, nfds = sizeof(fds) / sizeof(fds[0]); - - for (i = 0; i < nfds; i++) { - fds[i].events = POLLIN | POLLPRI | POLLHUP; - fds[i].revents = 0; - } - - ret = poll(fds, nfds, 3000); - ASSERT_RETURN(ret >= 0); - - if (fds[0].revents & POLLIN) { - if (count > 2) - kdbus_name_release(conn_a, "foo.bar.baz"); - - ret = kdbus_msg_recv(conn_a, NULL, NULL); - ASSERT_RETURN(ret == 0); - ret = kdbus_msg_send(conn_a, NULL, - 0xc0000000 | cookie++, - 0, 0, 0, conn_b->id); - ASSERT_RETURN(ret == 0); - } - - if (fds[1].revents & POLLIN) { - ret = kdbus_msg_recv(conn_b, NULL, NULL); - ASSERT_RETURN(ret == 0); - ret = kdbus_msg_send(conn_b, NULL, - 0xc0000000 | cookie++, - 0, 0, 0, conn_a->id); - ASSERT_RETURN(ret == 0); - } - - ret = kdbus_list(conn_b, KDBUS_LIST_UNIQUE | - KDBUS_LIST_NAMES | - KDBUS_LIST_QUEUED | - KDBUS_LIST_ACTIVATORS); - ASSERT_RETURN(ret == 0); - - if (count > 10) - break; - } - - kdbus_printf("-- closing bus connections\n"); - kdbus_conn_free(conn_a); - kdbus_conn_free(conn_b); - - return TEST_OK; -} diff --git a/tools/testing/selftests/kdbus/test-connection.c b/tools/testing/selftests/kdbus/test-connection.c deleted file mode 100644 index 4688ce8ec..000000000 --- a/tools/testing/selftests/kdbus/test-connection.c +++ /dev/null @@ -1,597 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <stdint.h> -#include <errno.h> -#include <assert.h> -#include <limits.h> -#include <sys/types.h> -#include <sys/capability.h> -#include <sys/mman.h> -#include <sys/syscall.h> -#include <sys/wait.h> -#include <stdbool.h> - -#include "kdbus-api.h" -#include "kdbus-util.h" -#include "kdbus-enum.h" -#include "kdbus-test.h" - -int kdbus_test_hello(struct kdbus_test_env *env) -{ - struct kdbus_cmd_free cmd_free = {}; - struct kdbus_cmd_hello hello; - int fd, ret; - - memset(&hello, 0, sizeof(hello)); - - fd = open(env->buspath, O_RDWR|O_CLOEXEC); - ASSERT_RETURN(fd >= 0); - - hello.flags = KDBUS_HELLO_ACCEPT_FD; - hello.attach_flags_send = _KDBUS_ATTACH_ALL; - hello.attach_flags_recv = _KDBUS_ATTACH_ALL; - hello.size = sizeof(struct kdbus_cmd_hello); - hello.pool_size = POOL_SIZE; - - /* an unaligned hello must result in -EFAULT */ - ret = kdbus_cmd_hello(fd, (struct kdbus_cmd_hello *) ((char *) &hello + 1)); - ASSERT_RETURN(ret == -EFAULT); - - /* a size of 0 must return EMSGSIZE */ - hello.size = 1; - hello.flags = KDBUS_HELLO_ACCEPT_FD; - hello.attach_flags_send = _KDBUS_ATTACH_ALL; - ret = kdbus_cmd_hello(fd, &hello); - ASSERT_RETURN(ret == -EINVAL); - - hello.size = sizeof(struct kdbus_cmd_hello); - - /* check faulty flags */ - hello.flags = 1ULL << 32; - hello.attach_flags_send = _KDBUS_ATTACH_ALL; - ret = kdbus_cmd_hello(fd, &hello); - ASSERT_RETURN(ret == -EINVAL); - - /* check for faulty pool sizes */ - hello.pool_size = 0; - hello.flags = KDBUS_HELLO_ACCEPT_FD; - hello.attach_flags_send = _KDBUS_ATTACH_ALL; - ret = kdbus_cmd_hello(fd, &hello); - ASSERT_RETURN(ret == -EINVAL); - - hello.pool_size = 4097; - hello.attach_flags_send = _KDBUS_ATTACH_ALL; - ret = kdbus_cmd_hello(fd, &hello); - ASSERT_RETURN(ret == -EINVAL); - - hello.pool_size = POOL_SIZE; - - hello.attach_flags_send = _KDBUS_ATTACH_ALL; - hello.offset = (__u64)-1; - - /* success test */ - ret = kdbus_cmd_hello(fd, &hello); - ASSERT_RETURN(ret == 0); - - /* The kernel should have returned some items */ - ASSERT_RETURN(hello.offset != (__u64)-1); - cmd_free.size = sizeof(cmd_free); - cmd_free.offset = hello.offset; - ret = kdbus_cmd_free(fd, &cmd_free); - ASSERT_RETURN(ret >= 0); - - close(fd); - - fd = open(env->buspath, O_RDWR|O_CLOEXEC); - ASSERT_RETURN(fd >= 0); - - /* no ACTIVATOR flag without a name */ - hello.flags = KDBUS_HELLO_ACTIVATOR; - ret = kdbus_cmd_hello(fd, &hello); - ASSERT_RETURN(ret == -EINVAL); - - close(fd); - - return TEST_OK; -} - -int kdbus_test_byebye(struct kdbus_test_env *env) -{ - struct kdbus_conn *conn; - struct kdbus_cmd_recv cmd_recv = { .size = sizeof(cmd_recv) }; - struct kdbus_cmd cmd_byebye = { .size = sizeof(cmd_byebye) }; - int ret; - - /* create a 2nd connection */ - conn = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn != NULL); - - ret = kdbus_add_match_empty(conn); - ASSERT_RETURN(ret == 0); - - ret = kdbus_add_match_empty(env->conn); - ASSERT_RETURN(ret == 0); - - /* send over 1st connection */ - ret = kdbus_msg_send(env->conn, NULL, 0, 0, 0, 0, - KDBUS_DST_ID_BROADCAST); - ASSERT_RETURN(ret == 0); - - /* say byebye on the 2nd, which must fail */ - ret = kdbus_cmd_byebye(conn->fd, &cmd_byebye); - ASSERT_RETURN(ret == -EBUSY); - - /* receive the message */ - ret = kdbus_cmd_recv(conn->fd, &cmd_recv); - ASSERT_RETURN(ret == 0); - - ret = kdbus_free(conn, cmd_recv.msg.offset); - ASSERT_RETURN(ret == 0); - - /* and try again */ - ret = kdbus_cmd_byebye(conn->fd, &cmd_byebye); - ASSERT_RETURN(ret == 0); - - /* a 2nd try should result in -ECONNRESET */ - ret = kdbus_cmd_byebye(conn->fd, &cmd_byebye); - ASSERT_RETURN(ret == -ECONNRESET); - - kdbus_conn_free(conn); - - return TEST_OK; -} - -/* Get only the first item */ -static struct kdbus_item *kdbus_get_item(struct kdbus_info *info, - uint64_t type) -{ - struct kdbus_item *item; - - KDBUS_ITEM_FOREACH(item, info, items) - if (item->type == type) - return item; - - return NULL; -} - -static unsigned int kdbus_count_item(struct kdbus_info *info, - uint64_t type) -{ - unsigned int i = 0; - const struct kdbus_item *item; - - KDBUS_ITEM_FOREACH(item, info, items) - if (item->type == type) - i++; - - return i; -} - -static int kdbus_fuzz_conn_info(struct kdbus_test_env *env, int capable) -{ - int ret; - unsigned int cnt = 0; - uint64_t offset = 0; - struct kdbus_info *info; - struct kdbus_conn *conn; - struct kdbus_conn *privileged; - const struct kdbus_item *item; - uint64_t valid_flags = KDBUS_ATTACH_NAMES | - KDBUS_ATTACH_CREDS | - KDBUS_ATTACH_PIDS | - KDBUS_ATTACH_CONN_DESCRIPTION; - - uint64_t invalid_flags = KDBUS_ATTACH_NAMES | - KDBUS_ATTACH_CREDS | - KDBUS_ATTACH_PIDS | - KDBUS_ATTACH_CAPS | - KDBUS_ATTACH_CGROUP | - KDBUS_ATTACH_CONN_DESCRIPTION; - - struct kdbus_creds cached_creds; - uid_t ruid, euid, suid; - gid_t rgid, egid, sgid; - - getresuid(&ruid, &euid, &suid); - getresgid(&rgid, &egid, &sgid); - - cached_creds.uid = ruid; - cached_creds.euid = euid; - cached_creds.suid = suid; - cached_creds.fsuid = ruid; - - cached_creds.gid = rgid; - cached_creds.egid = egid; - cached_creds.sgid = sgid; - cached_creds.fsgid = rgid; - - struct kdbus_pids cached_pids = { - .pid = getpid(), - .tid = syscall(SYS_gettid), - .ppid = getppid(), - }; - - ret = kdbus_conn_info(env->conn, env->conn->id, NULL, - valid_flags, &offset); - ASSERT_RETURN(ret == 0); - - info = (struct kdbus_info *)(env->conn->buf + offset); - ASSERT_RETURN(info->id == env->conn->id); - - /* We do not have any well-known name */ - item = kdbus_get_item(info, KDBUS_ITEM_NAME); - ASSERT_RETURN(item == NULL); - - item = kdbus_get_item(info, KDBUS_ITEM_CONN_DESCRIPTION); - if (valid_flags & KDBUS_ATTACH_CONN_DESCRIPTION) { - ASSERT_RETURN(item); - } else { - ASSERT_RETURN(item == NULL); - } - - kdbus_free(env->conn, offset); - - conn = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn); - - privileged = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(privileged); - - ret = kdbus_conn_info(conn, conn->id, NULL, valid_flags, &offset); - ASSERT_RETURN(ret == 0); - - info = (struct kdbus_info *)(conn->buf + offset); - ASSERT_RETURN(info->id == conn->id); - - /* We do not have any well-known name */ - item = kdbus_get_item(info, KDBUS_ITEM_NAME); - ASSERT_RETURN(item == NULL); - - cnt = kdbus_count_item(info, KDBUS_ITEM_CREDS); - if (valid_flags & KDBUS_ATTACH_CREDS) { - ASSERT_RETURN(cnt == 1); - - item = kdbus_get_item(info, KDBUS_ITEM_CREDS); - ASSERT_RETURN(item); - - /* Compare received items with cached creds */ - ASSERT_RETURN(memcmp(&item->creds, &cached_creds, - sizeof(struct kdbus_creds)) == 0); - } else { - ASSERT_RETURN(cnt == 0); - } - - item = kdbus_get_item(info, KDBUS_ITEM_PIDS); - if (valid_flags & KDBUS_ATTACH_PIDS) { - ASSERT_RETURN(item); - - /* Compare item->pids with cached PIDs */ - ASSERT_RETURN(item->pids.pid == cached_pids.pid && - item->pids.tid == cached_pids.tid && - item->pids.ppid == cached_pids.ppid); - } else { - ASSERT_RETURN(item == NULL); - } - - /* We did not request KDBUS_ITEM_CAPS */ - item = kdbus_get_item(info, KDBUS_ITEM_CAPS); - ASSERT_RETURN(item == NULL); - - kdbus_free(conn, offset); - - ret = kdbus_name_acquire(conn, "com.example.a", NULL); - ASSERT_RETURN(ret >= 0); - - ret = kdbus_conn_info(conn, conn->id, NULL, valid_flags, &offset); - ASSERT_RETURN(ret == 0); - - info = (struct kdbus_info *)(conn->buf + offset); - ASSERT_RETURN(info->id == conn->id); - - item = kdbus_get_item(info, KDBUS_ITEM_OWNED_NAME); - if (valid_flags & KDBUS_ATTACH_NAMES) { - ASSERT_RETURN(item && !strcmp(item->name.name, "com.example.a")); - } else { - ASSERT_RETURN(item == NULL); - } - - kdbus_free(conn, offset); - - ret = kdbus_conn_info(conn, 0, "com.example.a", valid_flags, &offset); - ASSERT_RETURN(ret == 0); - - info = (struct kdbus_info *)(conn->buf + offset); - ASSERT_RETURN(info->id == conn->id); - - kdbus_free(conn, offset); - - /* does not have the necessary caps to drop to unprivileged */ - if (!capable) - goto continue_test; - - ret = RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_GID, ({ - ret = kdbus_conn_info(conn, conn->id, NULL, - valid_flags, &offset); - ASSERT_EXIT(ret == 0); - - info = (struct kdbus_info *)(conn->buf + offset); - ASSERT_EXIT(info->id == conn->id); - - if (valid_flags & KDBUS_ATTACH_NAMES) { - item = kdbus_get_item(info, KDBUS_ITEM_OWNED_NAME); - ASSERT_EXIT(item && - strcmp(item->name.name, - "com.example.a") == 0); - } - - if (valid_flags & KDBUS_ATTACH_CREDS) { - item = kdbus_get_item(info, KDBUS_ITEM_CREDS); - ASSERT_EXIT(item); - - /* Compare received items with cached creds */ - ASSERT_EXIT(memcmp(&item->creds, &cached_creds, - sizeof(struct kdbus_creds)) == 0); - } - - if (valid_flags & KDBUS_ATTACH_PIDS) { - item = kdbus_get_item(info, KDBUS_ITEM_PIDS); - ASSERT_EXIT(item); - - /* - * Compare item->pids with cached pids of - * privileged one. - * - * cmd_info will always return cached pids. - */ - ASSERT_EXIT(item->pids.pid == cached_pids.pid && - item->pids.tid == cached_pids.tid); - } - - kdbus_free(conn, offset); - - /* - * Use invalid_flags and make sure that userspace - * do not play with us. - */ - ret = kdbus_conn_info(conn, conn->id, NULL, - invalid_flags, &offset); - ASSERT_EXIT(ret == 0); - - /* - * Make sure that we return only one creds item and - * it points to the cached creds. - */ - cnt = kdbus_count_item(info, KDBUS_ITEM_CREDS); - if (invalid_flags & KDBUS_ATTACH_CREDS) { - ASSERT_EXIT(cnt == 1); - - item = kdbus_get_item(info, KDBUS_ITEM_CREDS); - ASSERT_EXIT(item); - - /* Compare received items with cached creds */ - ASSERT_EXIT(memcmp(&item->creds, &cached_creds, - sizeof(struct kdbus_creds)) == 0); - } else { - ASSERT_EXIT(cnt == 0); - } - - if (invalid_flags & KDBUS_ATTACH_PIDS) { - cnt = kdbus_count_item(info, KDBUS_ITEM_PIDS); - ASSERT_EXIT(cnt == 1); - - item = kdbus_get_item(info, KDBUS_ITEM_PIDS); - ASSERT_EXIT(item); - - /* Compare item->pids with cached pids */ - ASSERT_EXIT(item->pids.pid == cached_pids.pid && - item->pids.tid == cached_pids.tid); - } - - cnt = kdbus_count_item(info, KDBUS_ITEM_CGROUP); - if (invalid_flags & KDBUS_ATTACH_CGROUP) { - ASSERT_EXIT(cnt == 1); - } else { - ASSERT_EXIT(cnt == 0); - } - - cnt = kdbus_count_item(info, KDBUS_ITEM_CAPS); - if (invalid_flags & KDBUS_ATTACH_CAPS) { - ASSERT_EXIT(cnt == 1); - } else { - ASSERT_EXIT(cnt == 0); - } - - kdbus_free(conn, offset); - }), - ({ 0; })); - ASSERT_RETURN(ret == 0); - -continue_test: - - /* A second name */ - ret = kdbus_name_acquire(conn, "com.example.b", NULL); - ASSERT_RETURN(ret >= 0); - - ret = kdbus_conn_info(conn, conn->id, NULL, valid_flags, &offset); - ASSERT_RETURN(ret == 0); - - info = (struct kdbus_info *)(conn->buf + offset); - ASSERT_RETURN(info->id == conn->id); - - cnt = kdbus_count_item(info, KDBUS_ITEM_OWNED_NAME); - if (valid_flags & KDBUS_ATTACH_NAMES) { - ASSERT_RETURN(cnt == 2); - } else { - ASSERT_RETURN(cnt == 0); - } - - kdbus_free(conn, offset); - - ASSERT_RETURN(ret == 0); - - return 0; -} - -int kdbus_test_conn_info(struct kdbus_test_env *env) -{ - int ret; - int have_caps; - struct { - struct kdbus_cmd_info cmd_info; - - struct { - uint64_t size; - uint64_t type; - char str[64]; - } name; - } buf; - - buf.cmd_info.size = sizeof(struct kdbus_cmd_info); - buf.cmd_info.flags = 0; - buf.cmd_info.attach_flags = 0; - buf.cmd_info.id = env->conn->id; - - ret = kdbus_conn_info(env->conn, env->conn->id, NULL, 0, NULL); - ASSERT_RETURN(ret == 0); - - /* try to pass a name that is longer than the buffer's size */ - buf.name.size = KDBUS_ITEM_HEADER_SIZE + 1; - buf.name.type = KDBUS_ITEM_NAME; - strcpy(buf.name.str, "foo.bar.bla"); - - buf.cmd_info.id = 0; - buf.cmd_info.size = sizeof(buf.cmd_info) + buf.name.size; - ret = kdbus_cmd_conn_info(env->conn->fd, (struct kdbus_cmd_info *) &buf); - ASSERT_RETURN(ret == -EINVAL); - - /* Pass a non existent name */ - ret = kdbus_conn_info(env->conn, 0, "non.existent.name", 0, NULL); - ASSERT_RETURN(ret == -ESRCH); - - if (!all_uids_gids_are_mapped()) - return TEST_SKIP; - - /* Test for caps here, so we run the previous test */ - have_caps = test_is_capable(CAP_SETUID, CAP_SETGID, -1); - ASSERT_RETURN(have_caps >= 0); - - ret = kdbus_fuzz_conn_info(env, have_caps); - ASSERT_RETURN(ret == 0); - - /* Now if we have skipped some tests then let the user know */ - if (!have_caps) - return TEST_SKIP; - - return TEST_OK; -} - -int kdbus_test_conn_update(struct kdbus_test_env *env) -{ - struct kdbus_conn *conn; - struct kdbus_msg *msg; - int found = 0; - int ret; - - /* - * kdbus_hello() sets all attach flags. Receive a message by this - * connection, and make sure a timestamp item (just to pick one) is - * present. - */ - conn = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn); - - ret = kdbus_msg_send(env->conn, NULL, 0x12345678, 0, 0, 0, conn->id); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_recv(conn, &msg, NULL); - ASSERT_RETURN(ret == 0); - - found = kdbus_item_in_message(msg, KDBUS_ITEM_TIMESTAMP); - ASSERT_RETURN(found == 1); - - kdbus_msg_free(msg); - - /* - * Now, modify the attach flags and repeat the action. The item must - * now be missing. - */ - found = 0; - - ret = kdbus_conn_update_attach_flags(conn, - _KDBUS_ATTACH_ALL, - _KDBUS_ATTACH_ALL & - ~KDBUS_ATTACH_TIMESTAMP); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_send(env->conn, NULL, 0x12345678, 0, 0, 0, conn->id); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_recv(conn, &msg, NULL); - ASSERT_RETURN(ret == 0); - - found = kdbus_item_in_message(msg, KDBUS_ITEM_TIMESTAMP); - ASSERT_RETURN(found == 0); - - /* Provide a bogus attach_flags value */ - ret = kdbus_conn_update_attach_flags(conn, - _KDBUS_ATTACH_ALL + 1, - _KDBUS_ATTACH_ALL); - ASSERT_RETURN(ret == -EINVAL); - - kdbus_msg_free(msg); - - kdbus_conn_free(conn); - - return TEST_OK; -} - -int kdbus_test_writable_pool(struct kdbus_test_env *env) -{ - struct kdbus_cmd_free cmd_free = {}; - struct kdbus_cmd_hello hello; - int fd, ret; - void *map; - - fd = open(env->buspath, O_RDWR | O_CLOEXEC); - ASSERT_RETURN(fd >= 0); - - memset(&hello, 0, sizeof(hello)); - hello.flags = KDBUS_HELLO_ACCEPT_FD; - hello.attach_flags_send = _KDBUS_ATTACH_ALL; - hello.attach_flags_recv = _KDBUS_ATTACH_ALL; - hello.size = sizeof(struct kdbus_cmd_hello); - hello.pool_size = POOL_SIZE; - hello.offset = (__u64)-1; - - /* success test */ - ret = kdbus_cmd_hello(fd, &hello); - ASSERT_RETURN(ret == 0); - - /* The kernel should have returned some items */ - ASSERT_RETURN(hello.offset != (__u64)-1); - cmd_free.size = sizeof(cmd_free); - cmd_free.offset = hello.offset; - ret = kdbus_cmd_free(fd, &cmd_free); - ASSERT_RETURN(ret >= 0); - - /* pools cannot be mapped writable */ - map = mmap(NULL, POOL_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - ASSERT_RETURN(map == MAP_FAILED); - - /* pools can always be mapped readable */ - map = mmap(NULL, POOL_SIZE, PROT_READ, MAP_SHARED, fd, 0); - ASSERT_RETURN(map != MAP_FAILED); - - /* make sure we cannot change protection masks to writable */ - ret = mprotect(map, POOL_SIZE, PROT_READ | PROT_WRITE); - ASSERT_RETURN(ret < 0); - - munmap(map, POOL_SIZE); - close(fd); - - return TEST_OK; -} diff --git a/tools/testing/selftests/kdbus/test-daemon.c b/tools/testing/selftests/kdbus/test-daemon.c deleted file mode 100644 index 8bc238619..000000000 --- a/tools/testing/selftests/kdbus/test-daemon.c +++ /dev/null @@ -1,65 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <stdint.h> -#include <errno.h> -#include <assert.h> -#include <poll.h> -#include <stdbool.h> - -#include "kdbus-test.h" -#include "kdbus-util.h" -#include "kdbus-enum.h" - -int kdbus_test_daemon(struct kdbus_test_env *env) -{ - struct pollfd fds[2]; - int count; - int ret; - - /* This test doesn't make any sense in non-interactive mode */ - if (!kdbus_util_verbose) - return TEST_OK; - - printf("Created connection %llu on bus '%s'\n", - (unsigned long long) env->conn->id, env->buspath); - - ret = kdbus_name_acquire(env->conn, "com.example.kdbus-test", NULL); - ASSERT_RETURN(ret == 0); - printf(" Aquired name: com.example.kdbus-test\n"); - - fds[0].fd = env->conn->fd; - fds[1].fd = STDIN_FILENO; - - printf("Monitoring connections:\n"); - - for (count = 0;; count++) { - int i, nfds = sizeof(fds) / sizeof(fds[0]); - - for (i = 0; i < nfds; i++) { - fds[i].events = POLLIN | POLLPRI | POLLHUP; - fds[i].revents = 0; - } - - ret = poll(fds, nfds, -1); - if (ret <= 0) - break; - - if (fds[0].revents & POLLIN) { - ret = kdbus_msg_recv(env->conn, NULL, NULL); - ASSERT_RETURN(ret == 0); - } - - /* stdin */ - if (fds[1].revents & POLLIN) - break; - } - - printf("Closing bus connection\n"); - - return TEST_OK; -} diff --git a/tools/testing/selftests/kdbus/test-endpoint.c b/tools/testing/selftests/kdbus/test-endpoint.c deleted file mode 100644 index 34a7be49c..000000000 --- a/tools/testing/selftests/kdbus/test-endpoint.c +++ /dev/null @@ -1,352 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <stdint.h> -#include <errno.h> -#include <assert.h> -#include <libgen.h> -#include <sys/capability.h> -#include <sys/wait.h> -#include <stdbool.h> - -#include "kdbus-api.h" -#include "kdbus-util.h" -#include "kdbus-enum.h" -#include "kdbus-test.h" - -#define KDBUS_SYSNAME_MAX_LEN 63 - -static int install_name_add_match(struct kdbus_conn *conn, const char *name) -{ - struct { - struct kdbus_cmd_match cmd; - struct { - uint64_t size; - uint64_t type; - struct kdbus_notify_name_change chg; - } item; - char name[64]; - } buf; - int ret; - - /* install the match rule */ - memset(&buf, 0, sizeof(buf)); - buf.item.type = KDBUS_ITEM_NAME_ADD; - buf.item.chg.old_id.id = KDBUS_MATCH_ID_ANY; - buf.item.chg.new_id.id = KDBUS_MATCH_ID_ANY; - strncpy(buf.name, name, sizeof(buf.name) - 1); - buf.item.size = sizeof(buf.item) + strlen(buf.name) + 1; - buf.cmd.size = sizeof(buf.cmd) + buf.item.size; - - ret = kdbus_cmd_match_add(conn->fd, &buf.cmd); - if (ret < 0) - return ret; - - return 0; -} - -static int create_endpoint(const char *buspath, uid_t uid, const char *name, - uint64_t flags) -{ - struct { - struct kdbus_cmd cmd; - - /* name item */ - struct { - uint64_t size; - uint64_t type; - /* max should be KDBUS_SYSNAME_MAX_LEN */ - char str[128]; - } name; - } ep_make; - int fd, ret; - - fd = open(buspath, O_RDWR); - if (fd < 0) - return fd; - - memset(&ep_make, 0, sizeof(ep_make)); - - snprintf(ep_make.name.str, - /* Use the KDBUS_SYSNAME_MAX_LEN or sizeof(str) */ - KDBUS_SYSNAME_MAX_LEN > strlen(name) ? - KDBUS_SYSNAME_MAX_LEN : sizeof(ep_make.name.str), - "%u-%s", uid, name); - - ep_make.name.type = KDBUS_ITEM_MAKE_NAME; - ep_make.name.size = KDBUS_ITEM_HEADER_SIZE + - strlen(ep_make.name.str) + 1; - - ep_make.cmd.flags = flags; - ep_make.cmd.size = sizeof(ep_make.cmd) + ep_make.name.size; - - ret = kdbus_cmd_endpoint_make(fd, &ep_make.cmd); - if (ret < 0) { - kdbus_printf("error creating endpoint: %d (%m)\n", ret); - return ret; - } - - return fd; -} - -static int unpriv_test_custom_ep(const char *buspath) -{ - int ret, ep_fd1, ep_fd2; - char *ep1, *ep2, *tmp1, *tmp2; - - tmp1 = strdup(buspath); - tmp2 = strdup(buspath); - ASSERT_RETURN(tmp1 && tmp2); - - ret = asprintf(&ep1, "%s/%u-%s", dirname(tmp1), getuid(), "apps1"); - ASSERT_RETURN(ret >= 0); - - ret = asprintf(&ep2, "%s/%u-%s", dirname(tmp2), getuid(), "apps2"); - ASSERT_RETURN(ret >= 0); - - free(tmp1); - free(tmp2); - - /* endpoint only accessible to current uid */ - ep_fd1 = create_endpoint(buspath, getuid(), "apps1", 0); - ASSERT_RETURN(ep_fd1 >= 0); - - /* endpoint world accessible */ - ep_fd2 = create_endpoint(buspath, getuid(), "apps2", - KDBUS_MAKE_ACCESS_WORLD); - ASSERT_RETURN(ep_fd2 >= 0); - - ret = RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_UID, ({ - int ep_fd; - struct kdbus_conn *ep_conn; - - /* - * Make sure that we are not able to create custom - * endpoints - */ - ep_fd = create_endpoint(buspath, getuid(), - "unpriv_costum_ep", 0); - ASSERT_EXIT(ep_fd == -EPERM); - - /* - * Endpoint "apps1" only accessible to same users, - * that own the endpoint. Access denied by VFS - */ - ep_conn = kdbus_hello(ep1, 0, NULL, 0); - ASSERT_EXIT(!ep_conn && errno == EACCES); - - /* Endpoint "apps2" world accessible */ - ep_conn = kdbus_hello(ep2, 0, NULL, 0); - ASSERT_EXIT(ep_conn); - - kdbus_conn_free(ep_conn); - - _exit(EXIT_SUCCESS); - }), - ({ 0; })); - ASSERT_RETURN(ret == 0); - - close(ep_fd1); - close(ep_fd2); - free(ep1); - free(ep2); - - return 0; -} - -static int update_endpoint(int fd, const char *name) -{ - int len = strlen(name) + 1; - struct { - struct kdbus_cmd cmd; - - /* name item */ - struct { - uint64_t size; - uint64_t type; - char str[KDBUS_ALIGN8(len)]; - } name; - - struct { - uint64_t size; - uint64_t type; - struct kdbus_policy_access access; - } access; - } ep_update; - int ret; - - memset(&ep_update, 0, sizeof(ep_update)); - - ep_update.name.size = KDBUS_ITEM_HEADER_SIZE + len; - ep_update.name.type = KDBUS_ITEM_NAME; - strncpy(ep_update.name.str, name, sizeof(ep_update.name.str) - 1); - - ep_update.access.size = sizeof(ep_update.access); - ep_update.access.type = KDBUS_ITEM_POLICY_ACCESS; - ep_update.access.access.type = KDBUS_POLICY_ACCESS_WORLD; - ep_update.access.access.access = KDBUS_POLICY_SEE; - - ep_update.cmd.size = sizeof(ep_update); - - ret = kdbus_cmd_endpoint_update(fd, &ep_update.cmd); - if (ret < 0) { - kdbus_printf("error updating endpoint: %d (%m)\n", ret); - return ret; - } - - return 0; -} - -int kdbus_test_custom_endpoint(struct kdbus_test_env *env) -{ - char *ep, *tmp; - int ret, ep_fd; - struct kdbus_msg *msg; - struct kdbus_conn *ep_conn; - struct kdbus_conn *reader; - const char *name = "foo.bar.baz"; - const char *epname = "foo"; - char fake_ep[KDBUS_SYSNAME_MAX_LEN + 1] = {'\0'}; - - memset(fake_ep, 'X', sizeof(fake_ep) - 1); - - /* Try to create a custom endpoint with a long name */ - ret = create_endpoint(env->buspath, getuid(), fake_ep, 0); - ASSERT_RETURN(ret == -ENAMETOOLONG); - - /* Try to create a custom endpoint with a different uid */ - ret = create_endpoint(env->buspath, getuid() + 1, "foobar", 0); - ASSERT_RETURN(ret == -EINVAL); - - /* create a custom endpoint, and open a connection on it */ - ep_fd = create_endpoint(env->buspath, getuid(), "foo", 0); - ASSERT_RETURN(ep_fd >= 0); - - tmp = strdup(env->buspath); - ASSERT_RETURN(tmp); - - ret = asprintf(&ep, "%s/%u-%s", dirname(tmp), getuid(), epname); - free(tmp); - ASSERT_RETURN(ret >= 0); - - /* Register a connection that listen to broadcasts */ - reader = kdbus_hello(ep, 0, NULL, 0); - ASSERT_RETURN(reader); - - /* Register to kernel signals */ - ret = kdbus_add_match_id(reader, 0x1, KDBUS_ITEM_ID_ADD, - KDBUS_MATCH_ID_ANY); - ASSERT_RETURN(ret == 0); - - ret = kdbus_add_match_id(reader, 0x2, KDBUS_ITEM_ID_REMOVE, - KDBUS_MATCH_ID_ANY); - ASSERT_RETURN(ret == 0); - - ret = install_name_add_match(reader, name); - ASSERT_RETURN(ret == 0); - - /* Monitor connections are not supported on custom endpoints */ - ep_conn = kdbus_hello(ep, KDBUS_HELLO_MONITOR, NULL, 0); - ASSERT_RETURN(!ep_conn && errno == EOPNOTSUPP); - - ep_conn = kdbus_hello(ep, 0, NULL, 0); - ASSERT_RETURN(ep_conn); - - /* Check that the reader got the IdAdd notification */ - ret = kdbus_msg_recv(reader, &msg, NULL); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_ID_ADD); - ASSERT_RETURN(msg->items[0].id_change.id == ep_conn->id); - kdbus_msg_free(msg); - - /* - * Add a name add match on the endpoint connection, acquire name from - * the unfiltered connection, and make sure the filtered connection - * did not get the notification on the name owner change. Also, the - * endpoint connection may not be able to call conn_info, neither on - * the name nor on the ID. - */ - ret = install_name_add_match(ep_conn, name); - ASSERT_RETURN(ret == 0); - - ret = kdbus_name_acquire(env->conn, name, NULL); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_recv(ep_conn, NULL, NULL); - ASSERT_RETURN(ret == -EAGAIN); - - ret = kdbus_conn_info(ep_conn, 0, name, 0, NULL); - ASSERT_RETURN(ret == -ESRCH); - - ret = kdbus_conn_info(ep_conn, 0, "random.crappy.name", 0, NULL); - ASSERT_RETURN(ret == -ESRCH); - - ret = kdbus_conn_info(ep_conn, env->conn->id, NULL, 0, NULL); - ASSERT_RETURN(ret == -ENXIO); - - ret = kdbus_conn_info(ep_conn, 0x0fffffffffffffffULL, NULL, 0, NULL); - ASSERT_RETURN(ret == -ENXIO); - - /* Check that the reader did not receive the name notification */ - ret = kdbus_msg_recv(reader, NULL, NULL); - ASSERT_RETURN(ret == -EAGAIN); - - /* - * Release the name again, update the custom endpoint policy, - * and try again. This time, the connection on the custom endpoint - * should have gotten it. - */ - ret = kdbus_name_release(env->conn, name); - ASSERT_RETURN(ret == 0); - - /* Check that the reader did not receive the name notification */ - ret = kdbus_msg_recv(reader, NULL, NULL); - ASSERT_RETURN(ret == -EAGAIN); - - ret = update_endpoint(ep_fd, name); - ASSERT_RETURN(ret == 0); - - ret = kdbus_name_acquire(env->conn, name, NULL); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_recv(ep_conn, &msg, NULL); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_NAME_ADD); - ASSERT_RETURN(msg->items[0].name_change.old_id.id == 0); - ASSERT_RETURN(msg->items[0].name_change.new_id.id == env->conn->id); - ASSERT_RETURN(strcmp(msg->items[0].name_change.name, name) == 0); - kdbus_msg_free(msg); - - ret = kdbus_msg_recv(reader, &msg, NULL); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(strcmp(msg->items[0].name_change.name, name) == 0); - - kdbus_msg_free(msg); - - ret = kdbus_conn_info(ep_conn, 0, name, 0, NULL); - ASSERT_RETURN(ret == 0); - - ret = kdbus_conn_info(ep_conn, env->conn->id, NULL, 0, NULL); - ASSERT_RETURN(ret == 0); - - /* If we have privileges test custom endpoints */ - ret = test_is_capable(CAP_SETUID, CAP_SETGID, -1); - ASSERT_RETURN(ret >= 0); - - /* - * All uids/gids are mapped and we have the necessary caps - */ - if (ret && all_uids_gids_are_mapped()) { - ret = unpriv_test_custom_ep(env->buspath); - ASSERT_RETURN(ret == 0); - } - - kdbus_conn_free(reader); - kdbus_conn_free(ep_conn); - close(ep_fd); - - return TEST_OK; -} diff --git a/tools/testing/selftests/kdbus/test-fd.c b/tools/testing/selftests/kdbus/test-fd.c deleted file mode 100644 index 2ae0f5ae8..000000000 --- a/tools/testing/selftests/kdbus/test-fd.c +++ /dev/null @@ -1,789 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stdbool.h> -#include <stddef.h> -#include <unistd.h> -#include <stdint.h> -#include <errno.h> -#include <assert.h> -#include <sys/types.h> -#include <sys/mman.h> -#include <sys/socket.h> -#include <sys/wait.h> - -#include "kdbus-api.h" -#include "kdbus-test.h" -#include "kdbus-util.h" -#include "kdbus-enum.h" - -#define KDBUS_MSG_MAX_ITEMS 128 -#define KDBUS_USER_MAX_CONN 256 - -/* maximum number of inflight fds in a target queue per user */ -#define KDBUS_CONN_MAX_FDS_PER_USER 16 - -/* maximum number of memfd items per message */ -#define KDBUS_MSG_MAX_MEMFD_ITEMS 16 - -static int make_msg_payload_dbus(uint64_t src_id, uint64_t dst_id, - uint64_t msg_size, - struct kdbus_msg **msg_dbus) -{ - struct kdbus_msg *msg; - - msg = malloc(msg_size); - ASSERT_RETURN_VAL(msg, -ENOMEM); - - memset(msg, 0, msg_size); - msg->size = msg_size; - msg->src_id = src_id; - msg->dst_id = dst_id; - msg->payload_type = KDBUS_PAYLOAD_DBUS; - - *msg_dbus = msg; - - return 0; -} - -static void make_item_memfds(struct kdbus_item *item, - int *memfds, size_t memfd_size) -{ - size_t i; - - for (i = 0; i < memfd_size; i++) { - item->type = KDBUS_ITEM_PAYLOAD_MEMFD; - item->size = KDBUS_ITEM_HEADER_SIZE + - sizeof(struct kdbus_memfd); - item->memfd.fd = memfds[i]; - item->memfd.size = sizeof(uint64_t); /* const size */ - item = KDBUS_ITEM_NEXT(item); - } -} - -static void make_item_fds(struct kdbus_item *item, - int *fd_array, size_t fd_size) -{ - size_t i; - item->type = KDBUS_ITEM_FDS; - item->size = KDBUS_ITEM_HEADER_SIZE + (sizeof(int) * fd_size); - - for (i = 0; i < fd_size; i++) - item->fds[i] = fd_array[i]; -} - -static int memfd_write(const char *name, void *buf, size_t bufsize) -{ - ssize_t ret; - int memfd; - - memfd = sys_memfd_create(name, 0); - ASSERT_RETURN_VAL(memfd >= 0, memfd); - - ret = write(memfd, buf, bufsize); - ASSERT_RETURN_VAL(ret == (ssize_t)bufsize, -EAGAIN); - - ret = sys_memfd_seal_set(memfd); - ASSERT_RETURN_VAL(ret == 0, -errno); - - return memfd; -} - -static int send_memfds(struct kdbus_conn *conn, uint64_t dst_id, - int *memfds_array, size_t memfd_count) -{ - struct kdbus_cmd_send cmd = {}; - struct kdbus_item *item; - struct kdbus_msg *msg; - uint64_t size; - int ret; - - size = sizeof(struct kdbus_msg); - size += memfd_count * KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd)); - - if (dst_id == KDBUS_DST_ID_BROADCAST) - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + 64; - - ret = make_msg_payload_dbus(conn->id, dst_id, size, &msg); - ASSERT_RETURN_VAL(ret == 0, ret); - - item = msg->items; - - if (dst_id == KDBUS_DST_ID_BROADCAST) { - item->type = KDBUS_ITEM_BLOOM_FILTER; - item->size = KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + 64; - item = KDBUS_ITEM_NEXT(item); - - msg->flags |= KDBUS_MSG_SIGNAL; - } - - make_item_memfds(item, memfds_array, memfd_count); - - cmd.size = sizeof(cmd); - cmd.msg_address = (uintptr_t)msg; - - ret = kdbus_cmd_send(conn->fd, &cmd); - if (ret < 0) { - kdbus_printf("error sending message: %d (%m)\n", ret); - return ret; - } - - free(msg); - return 0; -} - -static int send_fds(struct kdbus_conn *conn, uint64_t dst_id, - int *fd_array, size_t fd_count) -{ - struct kdbus_cmd_send cmd = {}; - struct kdbus_item *item; - struct kdbus_msg *msg; - uint64_t size; - int ret; - - size = sizeof(struct kdbus_msg); - size += KDBUS_ITEM_SIZE(sizeof(int) * fd_count); - - if (dst_id == KDBUS_DST_ID_BROADCAST) - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + 64; - - ret = make_msg_payload_dbus(conn->id, dst_id, size, &msg); - ASSERT_RETURN_VAL(ret == 0, ret); - - item = msg->items; - - if (dst_id == KDBUS_DST_ID_BROADCAST) { - item->type = KDBUS_ITEM_BLOOM_FILTER; - item->size = KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + 64; - item = KDBUS_ITEM_NEXT(item); - - msg->flags |= KDBUS_MSG_SIGNAL; - } - - make_item_fds(item, fd_array, fd_count); - - cmd.size = sizeof(cmd); - cmd.msg_address = (uintptr_t)msg; - - ret = kdbus_cmd_send(conn->fd, &cmd); - if (ret < 0) { - kdbus_printf("error sending message: %d (%m)\n", ret); - return ret; - } - - free(msg); - return ret; -} - -static int send_fds_memfds(struct kdbus_conn *conn, uint64_t dst_id, - int *fds_array, size_t fd_count, - int *memfds_array, size_t memfd_count) -{ - struct kdbus_cmd_send cmd = {}; - struct kdbus_item *item; - struct kdbus_msg *msg; - uint64_t size; - int ret; - - size = sizeof(struct kdbus_msg); - size += memfd_count * KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd)); - size += KDBUS_ITEM_SIZE(sizeof(int) * fd_count); - - ret = make_msg_payload_dbus(conn->id, dst_id, size, &msg); - ASSERT_RETURN_VAL(ret == 0, ret); - - item = msg->items; - - make_item_fds(item, fds_array, fd_count); - item = KDBUS_ITEM_NEXT(item); - make_item_memfds(item, memfds_array, memfd_count); - - cmd.size = sizeof(cmd); - cmd.msg_address = (uintptr_t)msg; - - ret = kdbus_cmd_send(conn->fd, &cmd); - if (ret < 0) { - kdbus_printf("error sending message: %d (%m)\n", ret); - return ret; - } - - free(msg); - return ret; -} - -/* Return the number of received fds */ -static unsigned int kdbus_item_get_nfds(struct kdbus_msg *msg) -{ - unsigned int fds = 0; - const struct kdbus_item *item; - - KDBUS_ITEM_FOREACH(item, msg, items) { - switch (item->type) { - case KDBUS_ITEM_FDS: { - fds += (item->size - KDBUS_ITEM_HEADER_SIZE) / - sizeof(int); - break; - } - - case KDBUS_ITEM_PAYLOAD_MEMFD: - fds++; - break; - - default: - break; - } - } - - return fds; -} - -static struct kdbus_msg * -get_kdbus_msg_with_fd(struct kdbus_conn *conn_src, - uint64_t dst_id, uint64_t cookie, int fd) -{ - int ret; - uint64_t size; - struct kdbus_item *item; - struct kdbus_msg *msg; - - size = sizeof(struct kdbus_msg); - if (fd >= 0) - size += KDBUS_ITEM_SIZE(sizeof(int)); - - ret = make_msg_payload_dbus(conn_src->id, dst_id, size, &msg); - ASSERT_RETURN_VAL(ret == 0, NULL); - - msg->cookie = cookie; - - if (fd >= 0) { - item = msg->items; - - make_item_fds(item, (int *)&fd, 1); - } - - return msg; -} - -static int kdbus_test_no_fds(struct kdbus_test_env *env, - int *fds, int *memfd) -{ - pid_t pid; - int ret, status; - uint64_t cookie; - int connfd1, connfd2; - struct kdbus_msg *msg, *msg_sync_reply; - struct kdbus_cmd_hello hello; - struct kdbus_conn *conn_src, *conn_dst, *conn_dummy; - struct kdbus_cmd_send cmd = {}; - struct kdbus_cmd_free cmd_free = {}; - - conn_src = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn_src); - - connfd1 = open(env->buspath, O_RDWR|O_CLOEXEC); - ASSERT_RETURN(connfd1 >= 0); - - connfd2 = open(env->buspath, O_RDWR|O_CLOEXEC); - ASSERT_RETURN(connfd2 >= 0); - - /* - * Create connections without KDBUS_HELLO_ACCEPT_FD - * to test if send fd operations are blocked - */ - conn_dst = malloc(sizeof(*conn_dst)); - ASSERT_RETURN(conn_dst); - - conn_dummy = malloc(sizeof(*conn_dummy)); - ASSERT_RETURN(conn_dummy); - - memset(&hello, 0, sizeof(hello)); - hello.size = sizeof(struct kdbus_cmd_hello); - hello.pool_size = POOL_SIZE; - hello.attach_flags_send = _KDBUS_ATTACH_ALL; - - ret = kdbus_cmd_hello(connfd1, &hello); - ASSERT_RETURN(ret == 0); - - cmd_free.size = sizeof(cmd_free); - cmd_free.offset = hello.offset; - ret = kdbus_cmd_free(connfd1, &cmd_free); - ASSERT_RETURN(ret >= 0); - - conn_dst->fd = connfd1; - conn_dst->id = hello.id; - - memset(&hello, 0, sizeof(hello)); - hello.size = sizeof(struct kdbus_cmd_hello); - hello.pool_size = POOL_SIZE; - hello.attach_flags_send = _KDBUS_ATTACH_ALL; - - ret = kdbus_cmd_hello(connfd2, &hello); - ASSERT_RETURN(ret == 0); - - cmd_free.size = sizeof(cmd_free); - cmd_free.offset = hello.offset; - ret = kdbus_cmd_free(connfd2, &cmd_free); - ASSERT_RETURN(ret >= 0); - - conn_dummy->fd = connfd2; - conn_dummy->id = hello.id; - - conn_dst->buf = mmap(NULL, POOL_SIZE, PROT_READ, - MAP_SHARED, connfd1, 0); - ASSERT_RETURN(conn_dst->buf != MAP_FAILED); - - conn_dummy->buf = mmap(NULL, POOL_SIZE, PROT_READ, - MAP_SHARED, connfd2, 0); - ASSERT_RETURN(conn_dummy->buf != MAP_FAILED); - - /* - * Send fds to connection that do not accept fd passing - */ - ret = send_fds(conn_src, conn_dst->id, fds, 1); - ASSERT_RETURN(ret == -ECOMM); - - /* - * memfd are kdbus payload - */ - ret = send_memfds(conn_src, conn_dst->id, memfd, 1); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_recv_poll(conn_dst, 100, NULL, NULL); - ASSERT_RETURN(ret == 0); - - cookie = time(NULL); - - pid = fork(); - ASSERT_RETURN_VAL(pid >= 0, pid); - - if (pid == 0) { - struct timespec now; - - /* - * A sync send/reply to a connection that do not - * accept fds should fail if it contains an fd - */ - msg_sync_reply = get_kdbus_msg_with_fd(conn_dst, - conn_dummy->id, - cookie, fds[0]); - ASSERT_EXIT(msg_sync_reply); - - ret = clock_gettime(CLOCK_MONOTONIC_COARSE, &now); - ASSERT_EXIT(ret == 0); - - msg_sync_reply->timeout_ns = now.tv_sec * 1000000000ULL + - now.tv_nsec + 100000000ULL; - msg_sync_reply->flags = KDBUS_MSG_EXPECT_REPLY; - - memset(&cmd, 0, sizeof(cmd)); - cmd.size = sizeof(cmd); - cmd.msg_address = (uintptr_t)msg_sync_reply; - cmd.flags = KDBUS_SEND_SYNC_REPLY; - - ret = kdbus_cmd_send(conn_dst->fd, &cmd); - ASSERT_EXIT(ret == -ECOMM); - - /* - * Now send a normal message, but the sync reply - * will fail since it contains an fd that the - * original sender do not want. - * - * The original sender will fail with -ETIMEDOUT - */ - cookie++; - ret = kdbus_msg_send_sync(conn_dst, NULL, cookie, - KDBUS_MSG_EXPECT_REPLY, - 5000000000ULL, 0, conn_src->id, -1); - ASSERT_EXIT(ret == -EREMOTEIO); - - cookie++; - ret = kdbus_msg_recv_poll(conn_dst, 100, &msg, NULL); - ASSERT_EXIT(ret == 0); - ASSERT_EXIT(msg->cookie == cookie); - - free(msg_sync_reply); - kdbus_msg_free(msg); - - _exit(EXIT_SUCCESS); - } - - ret = kdbus_msg_recv_poll(conn_dummy, 100, NULL, NULL); - ASSERT_RETURN(ret == -ETIMEDOUT); - - cookie++; - ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL); - ASSERT_RETURN(ret == 0 && msg->cookie == cookie); - - kdbus_msg_free(msg); - - /* - * Try to reply with a kdbus connection handle, this should - * fail with -EOPNOTSUPP - */ - msg_sync_reply = get_kdbus_msg_with_fd(conn_src, - conn_dst->id, - cookie, conn_dst->fd); - ASSERT_RETURN(msg_sync_reply); - - msg_sync_reply->cookie_reply = cookie; - - memset(&cmd, 0, sizeof(cmd)); - cmd.size = sizeof(cmd); - cmd.msg_address = (uintptr_t)msg_sync_reply; - - ret = kdbus_cmd_send(conn_src->fd, &cmd); - ASSERT_RETURN(ret == -EOPNOTSUPP); - - free(msg_sync_reply); - - /* - * Try to reply with a normal fd, this should fail even - * if the response is a sync reply - * - * From the sender view we fail with -ECOMM - */ - msg_sync_reply = get_kdbus_msg_with_fd(conn_src, - conn_dst->id, - cookie, fds[0]); - ASSERT_RETURN(msg_sync_reply); - - msg_sync_reply->cookie_reply = cookie; - - memset(&cmd, 0, sizeof(cmd)); - cmd.size = sizeof(cmd); - cmd.msg_address = (uintptr_t)msg_sync_reply; - - ret = kdbus_cmd_send(conn_src->fd, &cmd); - ASSERT_RETURN(ret == -ECOMM); - - free(msg_sync_reply); - - /* - * Resend another normal message and check if the queue - * is clear - */ - cookie++; - ret = kdbus_msg_send(conn_src, NULL, cookie, 0, 0, 0, - conn_dst->id); - ASSERT_RETURN(ret == 0); - - ret = waitpid(pid, &status, 0); - ASSERT_RETURN_VAL(ret >= 0, ret); - - kdbus_conn_free(conn_dummy); - kdbus_conn_free(conn_dst); - kdbus_conn_free(conn_src); - - return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR; -} - -static int kdbus_send_multiple_fds(struct kdbus_conn *conn_src, - struct kdbus_conn *conn_dst) -{ - int ret, i; - unsigned int nfds; - int fds[KDBUS_CONN_MAX_FDS_PER_USER + 1]; - int memfds[KDBUS_MSG_MAX_ITEMS + 1]; - struct kdbus_msg *msg; - uint64_t dummy_value; - - dummy_value = time(NULL); - - for (i = 0; i < KDBUS_CONN_MAX_FDS_PER_USER + 1; i++) { - fds[i] = open("/dev/null", O_RDWR|O_CLOEXEC); - ASSERT_RETURN_VAL(fds[i] >= 0, -errno); - } - - /* Send KDBUS_CONN_MAX_FDS_PER_USER with one more fd */ - ret = send_fds(conn_src, conn_dst->id, fds, - KDBUS_CONN_MAX_FDS_PER_USER + 1); - ASSERT_RETURN(ret == -EMFILE); - - /* Retry with the correct KDBUS_CONN_MAX_FDS_PER_USER */ - ret = send_fds(conn_src, conn_dst->id, fds, - KDBUS_CONN_MAX_FDS_PER_USER); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_recv(conn_dst, &msg, NULL); - ASSERT_RETURN(ret == 0); - - /* Check we got the right number of fds */ - nfds = kdbus_item_get_nfds(msg); - ASSERT_RETURN(nfds == KDBUS_CONN_MAX_FDS_PER_USER); - - kdbus_msg_free(msg); - - for (i = 0; i < KDBUS_MSG_MAX_ITEMS + 1; i++, dummy_value++) { - memfds[i] = memfd_write("memfd-name", - &dummy_value, - sizeof(dummy_value)); - ASSERT_RETURN_VAL(memfds[i] >= 0, memfds[i]); - } - - /* Send KDBUS_MSG_MAX_ITEMS with one more memfd */ - ret = send_memfds(conn_src, conn_dst->id, - memfds, KDBUS_MSG_MAX_ITEMS + 1); - ASSERT_RETURN(ret == -E2BIG); - - ret = send_memfds(conn_src, conn_dst->id, - memfds, KDBUS_MSG_MAX_MEMFD_ITEMS + 1); - ASSERT_RETURN(ret == -E2BIG); - - /* Retry with the correct KDBUS_MSG_MAX_ITEMS */ - ret = send_memfds(conn_src, conn_dst->id, - memfds, KDBUS_MSG_MAX_MEMFD_ITEMS); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_recv(conn_dst, &msg, NULL); - ASSERT_RETURN(ret == 0); - - /* Check we got the right number of fds */ - nfds = kdbus_item_get_nfds(msg); - ASSERT_RETURN(nfds == KDBUS_MSG_MAX_MEMFD_ITEMS); - - kdbus_msg_free(msg); - - - /* - * Combine multiple KDBUS_CONN_MAX_FDS_PER_USER+1 fds and - * 10 memfds - */ - ret = send_fds_memfds(conn_src, conn_dst->id, - fds, KDBUS_CONN_MAX_FDS_PER_USER + 1, - memfds, 10); - ASSERT_RETURN(ret == -EMFILE); - - ret = kdbus_msg_recv(conn_dst, NULL, NULL); - ASSERT_RETURN(ret == -EAGAIN); - - /* - * Combine multiple KDBUS_CONN_MAX_FDS_PER_USER fds and - * (128 - 1) + 1 memfds, all fds take one item, while each - * memfd takes one item - */ - ret = send_fds_memfds(conn_src, conn_dst->id, - fds, KDBUS_CONN_MAX_FDS_PER_USER, - memfds, (KDBUS_MSG_MAX_ITEMS - 1) + 1); - ASSERT_RETURN(ret == -E2BIG); - - ret = send_fds_memfds(conn_src, conn_dst->id, - fds, KDBUS_CONN_MAX_FDS_PER_USER, - memfds, KDBUS_MSG_MAX_MEMFD_ITEMS + 1); - ASSERT_RETURN(ret == -E2BIG); - - ret = kdbus_msg_recv(conn_dst, NULL, NULL); - ASSERT_RETURN(ret == -EAGAIN); - - /* - * Send KDBUS_CONN_MAX_FDS_PER_USER fds + - * KDBUS_MSG_MAX_MEMFD_ITEMS memfds - */ - ret = send_fds_memfds(conn_src, conn_dst->id, - fds, KDBUS_CONN_MAX_FDS_PER_USER, - memfds, KDBUS_MSG_MAX_MEMFD_ITEMS); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_recv(conn_dst, &msg, NULL); - ASSERT_RETURN(ret == 0); - - /* Check we got the right number of fds */ - nfds = kdbus_item_get_nfds(msg); - ASSERT_RETURN(nfds == KDBUS_CONN_MAX_FDS_PER_USER + - KDBUS_MSG_MAX_MEMFD_ITEMS); - - kdbus_msg_free(msg); - - - /* - * Re-send fds + memfds, close them, but do not receive them - * and try to queue more - */ - ret = send_fds_memfds(conn_src, conn_dst->id, - fds, KDBUS_CONN_MAX_FDS_PER_USER, - memfds, KDBUS_MSG_MAX_MEMFD_ITEMS); - ASSERT_RETURN(ret == 0); - - /* close old references and get a new ones */ - for (i = 0; i < KDBUS_CONN_MAX_FDS_PER_USER + 1; i++) { - close(fds[i]); - fds[i] = open("/dev/null", O_RDWR|O_CLOEXEC); - ASSERT_RETURN_VAL(fds[i] >= 0, -errno); - } - - /* should fail since we have already fds in the queue */ - ret = send_fds(conn_src, conn_dst->id, fds, - KDBUS_CONN_MAX_FDS_PER_USER); - ASSERT_RETURN(ret == -EMFILE); - - /* This should succeed */ - ret = send_memfds(conn_src, conn_dst->id, - memfds, KDBUS_MSG_MAX_MEMFD_ITEMS); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_recv(conn_dst, &msg, NULL); - ASSERT_RETURN(ret == 0); - - nfds = kdbus_item_get_nfds(msg); - ASSERT_RETURN(nfds == KDBUS_CONN_MAX_FDS_PER_USER + - KDBUS_MSG_MAX_MEMFD_ITEMS); - - kdbus_msg_free(msg); - - ret = kdbus_msg_recv(conn_dst, &msg, NULL); - ASSERT_RETURN(ret == 0); - - nfds = kdbus_item_get_nfds(msg); - ASSERT_RETURN(nfds == KDBUS_MSG_MAX_MEMFD_ITEMS); - - kdbus_msg_free(msg); - - ret = kdbus_msg_recv(conn_dst, NULL, NULL); - ASSERT_RETURN(ret == -EAGAIN); - - for (i = 0; i < KDBUS_CONN_MAX_FDS_PER_USER + 1; i++) - close(fds[i]); - - for (i = 0; i < KDBUS_MSG_MAX_ITEMS + 1; i++) - close(memfds[i]); - - return 0; -} - -int kdbus_test_fd_passing(struct kdbus_test_env *env) -{ - struct kdbus_conn *conn_src, *conn_dst; - const char *str = "stackenblocken"; - const struct kdbus_item *item; - struct kdbus_msg *msg; - unsigned int i; - uint64_t now; - int fds_conn[2]; - int sock_pair[2]; - int fds[2]; - int memfd; - int ret; - - now = (uint64_t) time(NULL); - - /* create two connections */ - conn_src = kdbus_hello(env->buspath, 0, NULL, 0); - conn_dst = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn_src && conn_dst); - - fds_conn[0] = conn_src->fd; - fds_conn[1] = conn_dst->fd; - - ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sock_pair); - ASSERT_RETURN(ret == 0); - - /* Setup memfd */ - memfd = memfd_write("memfd-name", &now, sizeof(now)); - ASSERT_RETURN(memfd >= 0); - - /* Setup pipes */ - ret = pipe(fds); - ASSERT_RETURN(ret == 0); - - i = write(fds[1], str, strlen(str)); - ASSERT_RETURN(i == strlen(str)); - - /* - * Try to ass the handle of a connection as message payload. - * This must fail. - */ - ret = send_fds(conn_src, conn_dst->id, fds_conn, 2); - ASSERT_RETURN(ret == -ENOTSUP); - - ret = send_fds(conn_dst, conn_src->id, fds_conn, 2); - ASSERT_RETURN(ret == -ENOTSUP); - - ret = send_fds(conn_src, conn_dst->id, sock_pair, 2); - ASSERT_RETURN(ret == -ENOTSUP); - - /* - * Send fds and memfds to connection that do not accept fds - */ - ret = kdbus_test_no_fds(env, fds, (int *)&memfd); - ASSERT_RETURN(ret == 0); - - /* Try to broadcast file descriptors. This must fail. */ - ret = send_fds(conn_src, KDBUS_DST_ID_BROADCAST, fds, 1); - ASSERT_RETURN(ret == -ENOTUNIQ); - - /* Try to broadcast memfd. This must succeed. */ - ret = send_memfds(conn_src, KDBUS_DST_ID_BROADCAST, (int *)&memfd, 1); - ASSERT_RETURN(ret == 0); - - /* Open code this loop */ -loop_send_fds: - - /* - * Send the read end of the pipe and close it. - */ - ret = send_fds(conn_src, conn_dst->id, fds, 1); - ASSERT_RETURN(ret == 0); - close(fds[0]); - - ret = kdbus_msg_recv(conn_dst, &msg, NULL); - ASSERT_RETURN(ret == 0); - - KDBUS_ITEM_FOREACH(item, msg, items) { - if (item->type == KDBUS_ITEM_FDS) { - char tmp[14]; - int nfds = (item->size - KDBUS_ITEM_HEADER_SIZE) / - sizeof(int); - ASSERT_RETURN(nfds == 1); - - i = read(item->fds[0], tmp, sizeof(tmp)); - if (i != 0) { - ASSERT_RETURN(i == sizeof(tmp)); - ASSERT_RETURN(memcmp(tmp, str, sizeof(tmp)) == 0); - - /* Write EOF */ - close(fds[1]); - - /* - * Resend the read end of the pipe, - * the receiver still holds a reference - * to it... - */ - goto loop_send_fds; - } - - /* Got EOF */ - - /* - * Close the last reference to the read end - * of the pipe, other references are - * automatically closed just after send. - */ - close(item->fds[0]); - } - } - - /* - * Try to resend the read end of the pipe. Must fail with - * -EBADF since both the sender and receiver closed their - * references to it. We assume the above since sender and - * receiver are on the same process. - */ - ret = send_fds(conn_src, conn_dst->id, fds, 1); - ASSERT_RETURN(ret == -EBADF); - - /* Then we clear out received any data... */ - kdbus_msg_free(msg); - - ret = kdbus_send_multiple_fds(conn_src, conn_dst); - ASSERT_RETURN(ret == 0); - - close(sock_pair[0]); - close(sock_pair[1]); - close(memfd); - - kdbus_conn_free(conn_src); - kdbus_conn_free(conn_dst); - - return TEST_OK; -} diff --git a/tools/testing/selftests/kdbus/test-free.c b/tools/testing/selftests/kdbus/test-free.c deleted file mode 100644 index f666da3e8..000000000 --- a/tools/testing/selftests/kdbus/test-free.c +++ /dev/null @@ -1,64 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <stdint.h> -#include <errno.h> -#include <assert.h> -#include <stdbool.h> - -#include "kdbus-api.h" -#include "kdbus-util.h" -#include "kdbus-enum.h" -#include "kdbus-test.h" - -static int sample_ioctl_call(struct kdbus_test_env *env) -{ - int ret; - struct kdbus_cmd_list cmd_list = { - .flags = KDBUS_LIST_QUEUED, - .size = sizeof(cmd_list), - }; - - ret = kdbus_cmd_list(env->conn->fd, &cmd_list); - ASSERT_RETURN(ret == 0); - - /* DON'T FREE THIS SLICE OF MEMORY! */ - - return TEST_OK; -} - -int kdbus_test_free(struct kdbus_test_env *env) -{ - int ret; - struct kdbus_cmd_free cmd_free = {}; - - /* free an unallocated buffer */ - cmd_free.size = sizeof(cmd_free); - cmd_free.flags = 0; - cmd_free.offset = 0; - ret = kdbus_cmd_free(env->conn->fd, &cmd_free); - ASSERT_RETURN(ret == -ENXIO); - - /* free a buffer out of the pool's bounds */ - cmd_free.size = sizeof(cmd_free); - cmd_free.offset = POOL_SIZE + 1; - ret = kdbus_cmd_free(env->conn->fd, &cmd_free); - ASSERT_RETURN(ret == -ENXIO); - - /* - * The user application is responsible for freeing the allocated - * memory with the KDBUS_CMD_FREE ioctl, so let's test what happens - * if we forget about it. - */ - - ret = sample_ioctl_call(env); - ASSERT_RETURN(ret == 0); - - ret = sample_ioctl_call(env); - ASSERT_RETURN(ret == 0); - - return TEST_OK; -} diff --git a/tools/testing/selftests/kdbus/test-match.c b/tools/testing/selftests/kdbus/test-match.c deleted file mode 100644 index 2360dc1d7..000000000 --- a/tools/testing/selftests/kdbus/test-match.c +++ /dev/null @@ -1,441 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <stdint.h> -#include <errno.h> -#include <assert.h> -#include <stdbool.h> - -#include "kdbus-api.h" -#include "kdbus-util.h" -#include "kdbus-enum.h" -#include "kdbus-test.h" - -int kdbus_test_match_id_add(struct kdbus_test_env *env) -{ - struct { - struct kdbus_cmd_match cmd; - struct { - uint64_t size; - uint64_t type; - struct kdbus_notify_id_change chg; - } item; - } buf; - struct kdbus_conn *conn; - struct kdbus_msg *msg; - int ret; - - memset(&buf, 0, sizeof(buf)); - - buf.cmd.size = sizeof(buf); - buf.cmd.cookie = 0xdeafbeefdeaddead; - buf.item.size = sizeof(buf.item); - buf.item.type = KDBUS_ITEM_ID_ADD; - buf.item.chg.id = KDBUS_MATCH_ID_ANY; - - /* match on id add */ - ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd); - ASSERT_RETURN(ret == 0); - - /* create 2nd connection */ - conn = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn != NULL); - - /* 1st connection should have received a notification */ - ret = kdbus_msg_recv(env->conn, &msg, NULL); - ASSERT_RETURN(ret == 0); - - ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_ID_ADD); - ASSERT_RETURN(msg->items[0].id_change.id == conn->id); - - kdbus_conn_free(conn); - - return TEST_OK; -} - -int kdbus_test_match_id_remove(struct kdbus_test_env *env) -{ - struct { - struct kdbus_cmd_match cmd; - struct { - uint64_t size; - uint64_t type; - struct kdbus_notify_id_change chg; - } item; - } buf; - struct kdbus_conn *conn; - struct kdbus_msg *msg; - size_t id; - int ret; - - /* create 2nd connection */ - conn = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn != NULL); - id = conn->id; - - memset(&buf, 0, sizeof(buf)); - buf.cmd.size = sizeof(buf); - buf.cmd.cookie = 0xdeafbeefdeaddead; - buf.item.size = sizeof(buf.item); - buf.item.type = KDBUS_ITEM_ID_REMOVE; - buf.item.chg.id = id; - - /* register match on 2nd connection */ - ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd); - ASSERT_RETURN(ret == 0); - - /* remove 2nd connection again */ - kdbus_conn_free(conn); - - /* 1st connection should have received a notification */ - ret = kdbus_msg_recv(env->conn, &msg, NULL); - ASSERT_RETURN(ret == 0); - - ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_ID_REMOVE); - ASSERT_RETURN(msg->items[0].id_change.id == id); - - return TEST_OK; -} - -int kdbus_test_match_replace(struct kdbus_test_env *env) -{ - struct { - struct kdbus_cmd_match cmd; - struct { - uint64_t size; - uint64_t type; - struct kdbus_notify_id_change chg; - } item; - } buf; - struct kdbus_conn *conn; - struct kdbus_msg *msg; - size_t id; - int ret; - - /* add a match to id_add */ - ASSERT_RETURN(kdbus_test_match_id_add(env) == TEST_OK); - - /* do a replace of the match from id_add to id_remove */ - memset(&buf, 0, sizeof(buf)); - - buf.cmd.size = sizeof(buf); - buf.cmd.cookie = 0xdeafbeefdeaddead; - buf.cmd.flags = KDBUS_MATCH_REPLACE; - buf.item.size = sizeof(buf.item); - buf.item.type = KDBUS_ITEM_ID_REMOVE; - buf.item.chg.id = KDBUS_MATCH_ID_ANY; - - ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd); - - /* create 2nd connection */ - conn = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn != NULL); - id = conn->id; - - /* 1st connection should _not_ have received a notification */ - ret = kdbus_msg_recv(env->conn, &msg, NULL); - ASSERT_RETURN(ret != 0); - - /* remove 2nd connection */ - kdbus_conn_free(conn); - - /* 1st connection should _now_ have received a notification */ - ret = kdbus_msg_recv(env->conn, &msg, NULL); - ASSERT_RETURN(ret == 0); - - ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_ID_REMOVE); - ASSERT_RETURN(msg->items[0].id_change.id == id); - - return TEST_OK; -} - -int kdbus_test_match_name_add(struct kdbus_test_env *env) -{ - struct { - struct kdbus_cmd_match cmd; - struct { - uint64_t size; - uint64_t type; - struct kdbus_notify_name_change chg; - } item; - char name[64]; - } buf; - struct kdbus_msg *msg; - char *name; - int ret; - - name = "foo.bla.blaz"; - - /* install the match rule */ - memset(&buf, 0, sizeof(buf)); - buf.item.type = KDBUS_ITEM_NAME_ADD; - buf.item.chg.old_id.id = KDBUS_MATCH_ID_ANY; - buf.item.chg.new_id.id = KDBUS_MATCH_ID_ANY; - strncpy(buf.name, name, sizeof(buf.name) - 1); - buf.item.size = sizeof(buf.item) + strlen(buf.name) + 1; - buf.cmd.size = sizeof(buf.cmd) + buf.item.size; - - ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd); - ASSERT_RETURN(ret == 0); - - /* acquire the name */ - ret = kdbus_name_acquire(env->conn, name, NULL); - ASSERT_RETURN(ret == 0); - - /* we should have received a notification */ - ret = kdbus_msg_recv(env->conn, &msg, NULL); - ASSERT_RETURN(ret == 0); - - ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_NAME_ADD); - ASSERT_RETURN(msg->items[0].name_change.old_id.id == 0); - ASSERT_RETURN(msg->items[0].name_change.new_id.id == env->conn->id); - ASSERT_RETURN(strcmp(msg->items[0].name_change.name, name) == 0); - - return TEST_OK; -} - -int kdbus_test_match_name_remove(struct kdbus_test_env *env) -{ - struct { - struct kdbus_cmd_match cmd; - struct { - uint64_t size; - uint64_t type; - struct kdbus_notify_name_change chg; - } item; - char name[64]; - } buf; - struct kdbus_msg *msg; - char *name; - int ret; - - name = "foo.bla.blaz"; - - /* acquire the name */ - ret = kdbus_name_acquire(env->conn, name, NULL); - ASSERT_RETURN(ret == 0); - - /* install the match rule */ - memset(&buf, 0, sizeof(buf)); - buf.item.type = KDBUS_ITEM_NAME_REMOVE; - buf.item.chg.old_id.id = KDBUS_MATCH_ID_ANY; - buf.item.chg.new_id.id = KDBUS_MATCH_ID_ANY; - strncpy(buf.name, name, sizeof(buf.name) - 1); - buf.item.size = sizeof(buf.item) + strlen(buf.name) + 1; - buf.cmd.size = sizeof(buf.cmd) + buf.item.size; - - ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd); - ASSERT_RETURN(ret == 0); - - /* release the name again */ - kdbus_name_release(env->conn, name); - ASSERT_RETURN(ret == 0); - - /* we should have received a notification */ - ret = kdbus_msg_recv(env->conn, &msg, NULL); - ASSERT_RETURN(ret == 0); - - ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_NAME_REMOVE); - ASSERT_RETURN(msg->items[0].name_change.old_id.id == env->conn->id); - ASSERT_RETURN(msg->items[0].name_change.new_id.id == 0); - ASSERT_RETURN(strcmp(msg->items[0].name_change.name, name) == 0); - - return TEST_OK; -} - -int kdbus_test_match_name_change(struct kdbus_test_env *env) -{ - struct { - struct kdbus_cmd_match cmd; - struct { - uint64_t size; - uint64_t type; - struct kdbus_notify_name_change chg; - } item; - char name[64]; - } buf; - struct kdbus_conn *conn; - struct kdbus_msg *msg; - uint64_t flags; - char *name = "foo.bla.baz"; - int ret; - - /* acquire the name */ - ret = kdbus_name_acquire(env->conn, name, NULL); - ASSERT_RETURN(ret == 0); - - /* install the match rule */ - memset(&buf, 0, sizeof(buf)); - buf.item.type = KDBUS_ITEM_NAME_CHANGE; - buf.item.chg.old_id.id = KDBUS_MATCH_ID_ANY; - buf.item.chg.new_id.id = KDBUS_MATCH_ID_ANY; - strncpy(buf.name, name, sizeof(buf.name) - 1); - buf.item.size = sizeof(buf.item) + strlen(buf.name) + 1; - buf.cmd.size = sizeof(buf.cmd) + buf.item.size; - - ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd); - ASSERT_RETURN(ret == 0); - - /* create a 2nd connection */ - conn = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn != NULL); - - /* allow the new connection to own the same name */ - /* queue the 2nd connection as waiting owner */ - flags = KDBUS_NAME_QUEUE; - ret = kdbus_name_acquire(conn, name, &flags); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(flags & KDBUS_NAME_IN_QUEUE); - - /* release name from 1st connection */ - ret = kdbus_name_release(env->conn, name); - ASSERT_RETURN(ret == 0); - - /* we should have received a notification */ - ret = kdbus_msg_recv(env->conn, &msg, NULL); - ASSERT_RETURN(ret == 0); - - ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_NAME_CHANGE); - ASSERT_RETURN(msg->items[0].name_change.old_id.id == env->conn->id); - ASSERT_RETURN(msg->items[0].name_change.new_id.id == conn->id); - ASSERT_RETURN(strcmp(msg->items[0].name_change.name, name) == 0); - - kdbus_conn_free(conn); - - return TEST_OK; -} - -static int send_bloom_filter(const struct kdbus_conn *conn, - uint64_t cookie, - const uint8_t *filter, - size_t filter_size, - uint64_t filter_generation) -{ - struct kdbus_cmd_send cmd = {}; - struct kdbus_msg *msg; - struct kdbus_item *item; - uint64_t size; - int ret; - - size = sizeof(struct kdbus_msg); - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + filter_size; - - msg = alloca(size); - - memset(msg, 0, size); - msg->size = size; - msg->src_id = conn->id; - msg->dst_id = KDBUS_DST_ID_BROADCAST; - msg->flags = KDBUS_MSG_SIGNAL; - msg->payload_type = KDBUS_PAYLOAD_DBUS; - msg->cookie = cookie; - - item = msg->items; - item->type = KDBUS_ITEM_BLOOM_FILTER; - item->size = KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + - filter_size; - - item->bloom_filter.generation = filter_generation; - memcpy(item->bloom_filter.data, filter, filter_size); - - cmd.size = sizeof(cmd); - cmd.msg_address = (uintptr_t)msg; - - ret = kdbus_cmd_send(conn->fd, &cmd); - if (ret < 0) { - kdbus_printf("error sending message: %d (%m)\n", ret); - return ret; - } - - return 0; -} - -int kdbus_test_match_bloom(struct kdbus_test_env *env) -{ - struct { - struct kdbus_cmd_match cmd; - struct { - uint64_t size; - uint64_t type; - uint8_t data_gen0[64]; - uint8_t data_gen1[64]; - } item; - } buf; - struct kdbus_conn *conn; - struct kdbus_msg *msg; - uint64_t cookie = 0xf000f00f; - uint8_t filter[64]; - int ret; - - /* install the match rule */ - memset(&buf, 0, sizeof(buf)); - buf.cmd.size = sizeof(buf); - - buf.item.size = sizeof(buf.item); - buf.item.type = KDBUS_ITEM_BLOOM_MASK; - buf.item.data_gen0[0] = 0x55; - buf.item.data_gen0[63] = 0x80; - - buf.item.data_gen1[1] = 0xaa; - buf.item.data_gen1[9] = 0x02; - - ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd); - ASSERT_RETURN(ret == 0); - - /* create a 2nd connection */ - conn = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn != NULL); - - /* a message with a 0'ed out filter must not reach the other peer */ - memset(filter, 0, sizeof(filter)); - ret = send_bloom_filter(conn, ++cookie, filter, sizeof(filter), 0); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_recv(env->conn, &msg, NULL); - ASSERT_RETURN(ret == -EAGAIN); - - /* now set the filter to the connection's mask and expect success */ - filter[0] = 0x55; - filter[63] = 0x80; - ret = send_bloom_filter(conn, ++cookie, filter, sizeof(filter), 0); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_recv(env->conn, &msg, NULL); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(msg->cookie == cookie); - - /* broaden the filter and try again. this should also succeed. */ - filter[0] = 0xff; - filter[8] = 0xff; - filter[63] = 0xff; - ret = send_bloom_filter(conn, ++cookie, filter, sizeof(filter), 0); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_recv(env->conn, &msg, NULL); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(msg->cookie == cookie); - - /* the same filter must not match against bloom generation 1 */ - ret = send_bloom_filter(conn, ++cookie, filter, sizeof(filter), 1); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_recv(env->conn, &msg, NULL); - ASSERT_RETURN(ret == -EAGAIN); - - /* set a different filter and try again */ - filter[1] = 0xaa; - filter[9] = 0x02; - ret = send_bloom_filter(conn, ++cookie, filter, sizeof(filter), 1); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_recv(env->conn, &msg, NULL); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(msg->cookie == cookie); - - kdbus_conn_free(conn); - - return TEST_OK; -} diff --git a/tools/testing/selftests/kdbus/test-message.c b/tools/testing/selftests/kdbus/test-message.c deleted file mode 100644 index 33d349bb2..000000000 --- a/tools/testing/selftests/kdbus/test-message.c +++ /dev/null @@ -1,736 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <stdint.h> -#include <errno.h> -#include <assert.h> -#include <time.h> -#include <stdbool.h> -#include <sys/eventfd.h> -#include <sys/types.h> -#include <sys/wait.h> - -#include "kdbus-api.h" -#include "kdbus-util.h" -#include "kdbus-enum.h" -#include "kdbus-test.h" - -/* maximum number of queued messages from the same individual user */ -#define KDBUS_CONN_MAX_MSGS 256 - -/* maximum number of queued requests waiting for a reply */ -#define KDBUS_CONN_MAX_REQUESTS_PENDING 128 - -/* maximum message payload size */ -#define KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE (2 * 1024UL * 1024UL) - -int kdbus_test_message_basic(struct kdbus_test_env *env) -{ - struct kdbus_conn *conn; - struct kdbus_conn *sender; - struct kdbus_msg *msg; - uint64_t cookie = 0x1234abcd5678eeff; - uint64_t offset; - int ret; - - sender = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(sender != NULL); - - /* create a 2nd connection */ - conn = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn != NULL); - - ret = kdbus_add_match_empty(conn); - ASSERT_RETURN(ret == 0); - - ret = kdbus_add_match_empty(sender); - ASSERT_RETURN(ret == 0); - - /* send over 1st connection */ - ret = kdbus_msg_send(sender, NULL, cookie, 0, 0, 0, - KDBUS_DST_ID_BROADCAST); - ASSERT_RETURN(ret == 0); - - /* Make sure that we do get our own broadcasts */ - ret = kdbus_msg_recv(sender, &msg, &offset); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(msg->cookie == cookie); - - kdbus_msg_free(msg); - - /* ... and receive on the 2nd */ - ret = kdbus_msg_recv_poll(conn, 100, &msg, &offset); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(msg->cookie == cookie); - - kdbus_msg_free(msg); - - /* Msgs that expect a reply must have timeout and cookie */ - ret = kdbus_msg_send(sender, NULL, 0, KDBUS_MSG_EXPECT_REPLY, - 0, 0, conn->id); - ASSERT_RETURN(ret == -EINVAL); - - /* Faked replies with a valid reply cookie are rejected */ - ret = kdbus_msg_send_reply(conn, time(NULL) ^ cookie, sender->id); - ASSERT_RETURN(ret == -EBADSLT); - - ret = kdbus_free(conn, offset); - ASSERT_RETURN(ret == 0); - - kdbus_conn_free(sender); - kdbus_conn_free(conn); - - return TEST_OK; -} - -static int msg_recv_prio(struct kdbus_conn *conn, - int64_t requested_prio, - int64_t expected_prio) -{ - struct kdbus_cmd_recv recv = { - .size = sizeof(recv), - .flags = KDBUS_RECV_USE_PRIORITY, - .priority = requested_prio, - }; - struct kdbus_msg *msg; - int ret; - - ret = kdbus_cmd_recv(conn->fd, &recv); - if (ret < 0) { - kdbus_printf("error receiving message: %d (%m)\n", -errno); - return ret; - } - - msg = (struct kdbus_msg *)(conn->buf + recv.msg.offset); - kdbus_msg_dump(conn, msg); - - if (msg->priority != expected_prio) { - kdbus_printf("expected message prio %lld, got %lld\n", - (unsigned long long) expected_prio, - (unsigned long long) msg->priority); - return -EINVAL; - } - - kdbus_msg_free(msg); - ret = kdbus_free(conn, recv.msg.offset); - if (ret < 0) - return ret; - - return 0; -} - -int kdbus_test_message_prio(struct kdbus_test_env *env) -{ - struct kdbus_conn *a, *b; - uint64_t cookie = 0; - - a = kdbus_hello(env->buspath, 0, NULL, 0); - b = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(a && b); - - ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, 25, a->id) == 0); - ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -600, a->id) == 0); - ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, 10, a->id) == 0); - ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -35, a->id) == 0); - ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -100, a->id) == 0); - ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, 20, a->id) == 0); - ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -15, a->id) == 0); - ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -800, a->id) == 0); - ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -150, a->id) == 0); - ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, 10, a->id) == 0); - ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -800, a->id) == 0); - ASSERT_RETURN(kdbus_msg_send(b, NULL, ++cookie, 0, 0, -10, a->id) == 0); - - ASSERT_RETURN(msg_recv_prio(a, -200, -800) == 0); - ASSERT_RETURN(msg_recv_prio(a, -100, -800) == 0); - ASSERT_RETURN(msg_recv_prio(a, -400, -600) == 0); - ASSERT_RETURN(msg_recv_prio(a, -400, -600) == -EAGAIN); - ASSERT_RETURN(msg_recv_prio(a, 10, -150) == 0); - ASSERT_RETURN(msg_recv_prio(a, 10, -100) == 0); - - kdbus_printf("--- get priority (all)\n"); - ASSERT_RETURN(kdbus_msg_recv(a, NULL, NULL) == 0); - - kdbus_conn_free(a); - kdbus_conn_free(b); - - return TEST_OK; -} - -static int kdbus_test_notify_kernel_quota(struct kdbus_test_env *env) -{ - int ret; - unsigned int i; - struct kdbus_conn *conn; - struct kdbus_conn *reader; - struct kdbus_msg *msg = NULL; - struct kdbus_cmd_recv recv = { .size = sizeof(recv) }; - - reader = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(reader); - - conn = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn); - - /* Register for ID signals */ - ret = kdbus_add_match_id(reader, 0x1, KDBUS_ITEM_ID_ADD, - KDBUS_MATCH_ID_ANY); - ASSERT_RETURN(ret == 0); - - ret = kdbus_add_match_id(reader, 0x2, KDBUS_ITEM_ID_REMOVE, - KDBUS_MATCH_ID_ANY); - ASSERT_RETURN(ret == 0); - - /* Each iteration two notifications: add and remove ID */ - for (i = 0; i < KDBUS_CONN_MAX_MSGS / 2; i++) { - struct kdbus_conn *notifier; - - notifier = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(notifier); - - kdbus_conn_free(notifier); - } - - /* - * Now the reader queue is full with kernel notfications, - * but as a user we still have room to push our messages. - */ - ret = kdbus_msg_send(conn, NULL, 0xdeadbeef, 0, 0, 0, reader->id); - ASSERT_RETURN(ret == 0); - - /* More ID kernel notifications that will be lost */ - kdbus_conn_free(conn); - - conn = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn); - - kdbus_conn_free(conn); - - /* - * We lost only 3 packets since only signal msgs are - * accounted. The connection ID add/remove notification - */ - ret = kdbus_cmd_recv(reader->fd, &recv); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(recv.return_flags & KDBUS_RECV_RETURN_DROPPED_MSGS); - ASSERT_RETURN(recv.dropped_msgs == 3); - - msg = (struct kdbus_msg *)(reader->buf + recv.msg.offset); - kdbus_msg_free(msg); - - /* Read our queue */ - for (i = 0; i < KDBUS_CONN_MAX_MSGS - 1; i++) { - memset(&recv, 0, sizeof(recv)); - recv.size = sizeof(recv); - - ret = kdbus_cmd_recv(reader->fd, &recv); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(!(recv.return_flags & - KDBUS_RECV_RETURN_DROPPED_MSGS)); - - msg = (struct kdbus_msg *)(reader->buf + recv.msg.offset); - kdbus_msg_free(msg); - } - - ret = kdbus_msg_recv(reader, NULL, NULL); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_recv(reader, NULL, NULL); - ASSERT_RETURN(ret == -EAGAIN); - - kdbus_conn_free(reader); - - return 0; -} - -/* Return the number of message successfully sent */ -static int kdbus_fill_conn_queue(struct kdbus_conn *conn_src, - uint64_t dst_id, - unsigned int max_msgs) -{ - unsigned int i; - uint64_t cookie = 0; - size_t size; - struct kdbus_cmd_send cmd = {}; - struct kdbus_msg *msg; - int ret; - - size = sizeof(struct kdbus_msg); - msg = malloc(size); - ASSERT_RETURN_VAL(msg, -ENOMEM); - - memset(msg, 0, size); - msg->size = size; - msg->src_id = conn_src->id; - msg->dst_id = dst_id; - msg->payload_type = KDBUS_PAYLOAD_DBUS; - - cmd.size = sizeof(cmd); - cmd.msg_address = (uintptr_t)msg; - - for (i = 0; i < max_msgs; i++) { - msg->cookie = cookie++; - ret = kdbus_cmd_send(conn_src->fd, &cmd); - if (ret < 0) - break; - } - - free(msg); - - return i; -} - -static int kdbus_test_activator_quota(struct kdbus_test_env *env) -{ - int ret; - unsigned int i; - unsigned int activator_msgs_count = 0; - uint64_t cookie = time(NULL); - struct kdbus_conn *conn; - struct kdbus_conn *sender; - struct kdbus_conn *activator; - struct kdbus_msg *msg; - uint64_t flags; - struct kdbus_cmd_recv recv = { .size = sizeof(recv) }; - struct kdbus_policy_access access = { - .type = KDBUS_POLICY_ACCESS_USER, - .id = geteuid(), - .access = KDBUS_POLICY_OWN, - }; - - activator = kdbus_hello_activator(env->buspath, "foo.test.activator", - &access, 1); - ASSERT_RETURN(activator); - - conn = kdbus_hello(env->buspath, 0, NULL, 0); - sender = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn || sender); - - ret = kdbus_list(sender, KDBUS_LIST_NAMES | - KDBUS_LIST_UNIQUE | - KDBUS_LIST_ACTIVATORS | - KDBUS_LIST_QUEUED); - ASSERT_RETURN(ret == 0); - - for (i = 0; i < KDBUS_CONN_MAX_MSGS; i++) { - ret = kdbus_msg_send(sender, "foo.test.activator", - cookie++, 0, 0, 0, - KDBUS_DST_ID_NAME); - if (ret < 0) - break; - activator_msgs_count++; - } - - /* we must have at least sent one message */ - ASSERT_RETURN_VAL(i > 0, -errno); - ASSERT_RETURN(ret == -ENOBUFS); - - /* Good, activator queue is full now */ - - /* ENXIO on direct send (activators can never be addressed by ID) */ - ret = kdbus_msg_send(conn, NULL, cookie++, 0, 0, 0, activator->id); - ASSERT_RETURN(ret == -ENXIO); - - /* can't queue more */ - ret = kdbus_msg_send(conn, "foo.test.activator", cookie++, - 0, 0, 0, KDBUS_DST_ID_NAME); - ASSERT_RETURN(ret == -ENOBUFS); - - /* no match installed, so the broadcast will not inc dropped_msgs */ - ret = kdbus_msg_send(sender, NULL, cookie++, 0, 0, 0, - KDBUS_DST_ID_BROADCAST); - ASSERT_RETURN(ret == 0); - - /* Check activator queue */ - ret = kdbus_cmd_recv(activator->fd, &recv); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(recv.dropped_msgs == 0); - - activator_msgs_count--; - - msg = (struct kdbus_msg *)(activator->buf + recv.msg.offset); - kdbus_msg_free(msg); - - - /* Stage 1) of test check the pool memory quota */ - - /* Consume the connection pool memory */ - for (i = 0; i < KDBUS_CONN_MAX_MSGS; i++) { - ret = kdbus_msg_send(sender, NULL, - cookie++, 0, 0, 0, conn->id); - if (ret < 0) - break; - } - - /* consume one message, so later at least one can be moved */ - memset(&recv, 0, sizeof(recv)); - recv.size = sizeof(recv); - ret = kdbus_cmd_recv(conn->fd, &recv); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(recv.dropped_msgs == 0); - msg = (struct kdbus_msg *)(conn->buf + recv.msg.offset); - kdbus_msg_free(msg); - - /* Try to acquire the name now */ - flags = KDBUS_NAME_REPLACE_EXISTING; - ret = kdbus_name_acquire(conn, "foo.test.activator", &flags); - ASSERT_RETURN(ret == 0); - - /* try to read messages and see if we have lost some */ - memset(&recv, 0, sizeof(recv)); - recv.size = sizeof(recv); - ret = kdbus_cmd_recv(conn->fd, &recv); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(recv.dropped_msgs != 0); - - /* number of dropped msgs < received ones (at least one was moved) */ - ASSERT_RETURN(recv.dropped_msgs < activator_msgs_count); - - /* Deduct the number of dropped msgs from the activator msgs */ - activator_msgs_count -= recv.dropped_msgs; - - msg = (struct kdbus_msg *)(activator->buf + recv.msg.offset); - kdbus_msg_free(msg); - - /* - * Release the name and hand it back to activator, now - * we should have 'activator_msgs_count' msgs again in - * the activator queue - */ - ret = kdbus_name_release(conn, "foo.test.activator"); - ASSERT_RETURN(ret == 0); - - /* make sure that we got our previous activator msgs */ - ret = kdbus_msg_recv(activator, &msg, NULL); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(msg->src_id == sender->id); - - activator_msgs_count--; - - kdbus_msg_free(msg); - - - /* Stage 2) of test check max message quota */ - - /* Empty conn queue */ - for (i = 0; i < KDBUS_CONN_MAX_MSGS; i++) { - ret = kdbus_msg_recv(conn, NULL, NULL); - if (ret == -EAGAIN) - break; - } - - /* fill queue with max msgs quota */ - ret = kdbus_fill_conn_queue(sender, conn->id, KDBUS_CONN_MAX_MSGS); - ASSERT_RETURN(ret == KDBUS_CONN_MAX_MSGS); - - /* This one is lost but it is not accounted */ - ret = kdbus_msg_send(sender, NULL, - cookie++, 0, 0, 0, conn->id); - ASSERT_RETURN(ret == -ENOBUFS); - - /* Acquire the name again */ - flags = KDBUS_NAME_REPLACE_EXISTING; - ret = kdbus_name_acquire(conn, "foo.test.activator", &flags); - ASSERT_RETURN(ret == 0); - - memset(&recv, 0, sizeof(recv)); - recv.size = sizeof(recv); - - /* - * Try to read messages and make sure that we have lost all - * the activator messages due to quota checks. Our queue is - * already full. - */ - ret = kdbus_cmd_recv(conn->fd, &recv); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(recv.dropped_msgs == activator_msgs_count); - - msg = (struct kdbus_msg *)(activator->buf + recv.msg.offset); - kdbus_msg_free(msg); - - kdbus_conn_free(sender); - kdbus_conn_free(conn); - kdbus_conn_free(activator); - - return 0; -} - -static int kdbus_test_expected_reply_quota(struct kdbus_test_env *env) -{ - int ret; - unsigned int i, n; - unsigned int count; - uint64_t cookie = 0x1234abcd5678eeff; - struct kdbus_conn *conn; - struct kdbus_conn *connections[9]; - - conn = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn); - - for (i = 0; i < 9; i++) { - connections[i] = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(connections[i]); - } - - count = 0; - /* Send 16 messages to 8 different connections */ - for (i = 0; i < 8; i++) { - for (n = 0; n < 16; n++) { - ret = kdbus_msg_send(conn, NULL, cookie++, - KDBUS_MSG_EXPECT_REPLY, - 100000000ULL, 0, - connections[i]->id); - if (ret < 0) - break; - - count++; - } - } - - /* - * We should have queued at least - * KDBUS_CONN_MAX_REQUESTS_PENDING method call - */ - ASSERT_RETURN(count == KDBUS_CONN_MAX_REQUESTS_PENDING); - - /* - * Now try to send a message to the last connection, - * if we have reached KDBUS_CONN_MAX_REQUESTS_PENDING - * no further requests are allowed - */ - ret = kdbus_msg_send(conn, NULL, cookie++, KDBUS_MSG_EXPECT_REPLY, - 1000000000ULL, 0, connections[8]->id); - ASSERT_RETURN(ret == -EMLINK); - - for (i = 0; i < 9; i++) - kdbus_conn_free(connections[i]); - - kdbus_conn_free(conn); - - return 0; -} - -int kdbus_test_pool_quota(struct kdbus_test_env *env) -{ - struct kdbus_conn *a, *b, *c; - struct kdbus_cmd_send cmd = {}; - struct kdbus_item *item; - struct kdbus_msg *recv_msg; - struct kdbus_msg *msg; - uint64_t cookie = time(NULL); - uint64_t size; - unsigned int i; - char *payload; - int ret; - - /* just a guard */ - if (POOL_SIZE <= KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE || - POOL_SIZE % KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE != 0) - return 0; - - payload = calloc(KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE, sizeof(char)); - ASSERT_RETURN_VAL(payload, -ENOMEM); - - a = kdbus_hello(env->buspath, 0, NULL, 0); - b = kdbus_hello(env->buspath, 0, NULL, 0); - c = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(a && b && c); - - size = sizeof(struct kdbus_msg); - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); - - msg = malloc(size); - ASSERT_RETURN_VAL(msg, -ENOMEM); - - memset(msg, 0, size); - msg->size = size; - msg->src_id = a->id; - msg->dst_id = c->id; - msg->payload_type = KDBUS_PAYLOAD_DBUS; - - item = msg->items; - item->type = KDBUS_ITEM_PAYLOAD_VEC; - item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); - item->vec.address = (uintptr_t)payload; - item->vec.size = KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE; - item = KDBUS_ITEM_NEXT(item); - - cmd.size = sizeof(cmd); - cmd.msg_address = (uintptr_t)msg; - - /* - * Send 2097248 bytes, a user is only allowed to get 33% of half of - * the free space of the pool, the already used space is - * accounted as free space - */ - size += KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE; - for (i = size; i < (POOL_SIZE / 2 / 3); i += size) { - msg->cookie = cookie++; - - ret = kdbus_cmd_send(a->fd, &cmd); - ASSERT_RETURN_VAL(ret == 0, ret); - } - - /* Try to get more than 33% */ - msg->cookie = cookie++; - ret = kdbus_cmd_send(a->fd, &cmd); - ASSERT_RETURN(ret == -ENOBUFS); - - /* We still can pass small messages */ - ret = kdbus_msg_send(b, NULL, cookie++, 0, 0, 0, c->id); - ASSERT_RETURN(ret == 0); - - for (i = size; i < (POOL_SIZE / 2 / 3); i += size) { - ret = kdbus_msg_recv(c, &recv_msg, NULL); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(recv_msg->src_id == a->id); - - kdbus_msg_free(recv_msg); - } - - ret = kdbus_msg_recv(c, &recv_msg, NULL); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(recv_msg->src_id == b->id); - - kdbus_msg_free(recv_msg); - - ret = kdbus_msg_recv(c, NULL, NULL); - ASSERT_RETURN(ret == -EAGAIN); - - free(msg); - free(payload); - - kdbus_conn_free(c); - kdbus_conn_free(b); - kdbus_conn_free(a); - - return 0; -} - -int kdbus_test_message_quota(struct kdbus_test_env *env) -{ - struct kdbus_conn *a, *b; - uint64_t cookie = 0; - int ret; - int i; - - ret = kdbus_test_activator_quota(env); - ASSERT_RETURN(ret == 0); - - ret = kdbus_test_notify_kernel_quota(env); - ASSERT_RETURN(ret == 0); - - ret = kdbus_test_pool_quota(env); - ASSERT_RETURN(ret == 0); - - ret = kdbus_test_expected_reply_quota(env); - ASSERT_RETURN(ret == 0); - - a = kdbus_hello(env->buspath, 0, NULL, 0); - b = kdbus_hello(env->buspath, 0, NULL, 0); - - ret = kdbus_fill_conn_queue(b, a->id, KDBUS_CONN_MAX_MSGS); - ASSERT_RETURN(ret == KDBUS_CONN_MAX_MSGS); - - ret = kdbus_msg_send(b, NULL, ++cookie, 0, 0, 0, a->id); - ASSERT_RETURN(ret == -ENOBUFS); - - for (i = 0; i < KDBUS_CONN_MAX_MSGS; ++i) { - ret = kdbus_msg_recv(a, NULL, NULL); - ASSERT_RETURN(ret == 0); - } - - ret = kdbus_msg_recv(a, NULL, NULL); - ASSERT_RETURN(ret == -EAGAIN); - - ret = kdbus_fill_conn_queue(b, a->id, KDBUS_CONN_MAX_MSGS + 1); - ASSERT_RETURN(ret == KDBUS_CONN_MAX_MSGS); - - ret = kdbus_msg_send(b, NULL, ++cookie, 0, 0, 0, a->id); - ASSERT_RETURN(ret == -ENOBUFS); - - kdbus_conn_free(a); - kdbus_conn_free(b); - - return TEST_OK; -} - -int kdbus_test_memory_access(struct kdbus_test_env *env) -{ - struct kdbus_conn *a, *b; - struct kdbus_cmd_send cmd = {}; - struct kdbus_item *item; - struct kdbus_msg *msg; - uint64_t test_addr = 0; - char line[256]; - uint64_t size; - FILE *f; - int ret; - - /* - * Search in /proc/kallsyms for the address of a kernel symbol that - * should always be there, regardless of the config. Use that address - * in a PAYLOAD_VEC item and make sure it's inaccessible. - */ - - f = fopen("/proc/kallsyms", "r"); - if (!f) - return TEST_SKIP; - - while (fgets(line, sizeof(line), f)) { - char *s = line; - - if (!strsep(&s, " ")) - continue; - - if (!strsep(&s, " ")) - continue; - - if (!strncmp(s, "mutex_lock", 10)) { - test_addr = strtoull(line, NULL, 16); - break; - } - } - - fclose(f); - - if (!test_addr) - return TEST_SKIP; - - a = kdbus_hello(env->buspath, 0, NULL, 0); - b = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(a && b); - - size = sizeof(struct kdbus_msg); - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); - - msg = alloca(size); - ASSERT_RETURN_VAL(msg, -ENOMEM); - - memset(msg, 0, size); - msg->size = size; - msg->src_id = a->id; - msg->dst_id = b->id; - msg->payload_type = KDBUS_PAYLOAD_DBUS; - - item = msg->items; - item->type = KDBUS_ITEM_PAYLOAD_VEC; - item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); - item->vec.address = test_addr; - item->vec.size = sizeof(void*); - item = KDBUS_ITEM_NEXT(item); - - cmd.size = sizeof(cmd); - cmd.msg_address = (uintptr_t)msg; - - ret = kdbus_cmd_send(a->fd, &cmd); - ASSERT_RETURN(ret == -EFAULT); - - kdbus_conn_free(b); - kdbus_conn_free(a); - - return 0; -} diff --git a/tools/testing/selftests/kdbus/test-metadata-ns.c b/tools/testing/selftests/kdbus/test-metadata-ns.c deleted file mode 100644 index 1f6edc090..000000000 --- a/tools/testing/selftests/kdbus/test-metadata-ns.c +++ /dev/null @@ -1,500 +0,0 @@ -/* - * Test metadata in new namespaces. Even if our tests can run - * in a namespaced setup, this test is necessary so we can inspect - * metadata on the same kdbusfs but between multiple namespaces - */ - -#include <stdio.h> -#include <string.h> -#include <sched.h> -#include <time.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <stdint.h> -#include <errno.h> -#include <assert.h> -#include <signal.h> -#include <sys/wait.h> -#include <sys/prctl.h> -#include <sys/eventfd.h> -#include <sys/syscall.h> -#include <sys/capability.h> -#include <linux/sched.h> - -#include "kdbus-test.h" -#include "kdbus-util.h" -#include "kdbus-enum.h" - -static const struct kdbus_creds privileged_creds = {}; - -static const struct kdbus_creds unmapped_creds = { - .uid = UNPRIV_UID, - .euid = UNPRIV_UID, - .suid = UNPRIV_UID, - .fsuid = UNPRIV_UID, - .gid = UNPRIV_GID, - .egid = UNPRIV_GID, - .sgid = UNPRIV_GID, - .fsgid = UNPRIV_GID, -}; - -static const struct kdbus_pids unmapped_pids = {}; - -/* Get only the first item */ -static struct kdbus_item *kdbus_get_item(struct kdbus_msg *msg, - uint64_t type) -{ - struct kdbus_item *item; - - KDBUS_ITEM_FOREACH(item, msg, items) - if (item->type == type) - return item; - - return NULL; -} - -static int kdbus_match_kdbus_creds(struct kdbus_msg *msg, - const struct kdbus_creds *expected_creds) -{ - struct kdbus_item *item; - - item = kdbus_get_item(msg, KDBUS_ITEM_CREDS); - ASSERT_RETURN(item); - - ASSERT_RETURN(memcmp(&item->creds, expected_creds, - sizeof(struct kdbus_creds)) == 0); - - return 0; -} - -static int kdbus_match_kdbus_pids(struct kdbus_msg *msg, - const struct kdbus_pids *expected_pids) -{ - struct kdbus_item *item; - - item = kdbus_get_item(msg, KDBUS_ITEM_PIDS); - ASSERT_RETURN(item); - - ASSERT_RETURN(memcmp(&item->pids, expected_pids, - sizeof(struct kdbus_pids)) == 0); - - return 0; -} - -static int __kdbus_clone_userns_test(const char *bus, - struct kdbus_conn *conn, - uint64_t grandpa_pid, - int signal_fd) -{ - int clone_ret; - int ret; - struct kdbus_msg *msg = NULL; - const struct kdbus_item *item; - uint64_t cookie = time(NULL) ^ 0xdeadbeef; - struct kdbus_conn *unpriv_conn = NULL; - struct kdbus_pids parent_pids = { - .pid = getppid(), - .tid = getppid(), - .ppid = grandpa_pid, - }; - - ret = drop_privileges(UNPRIV_UID, UNPRIV_GID); - ASSERT_EXIT(ret == 0); - - unpriv_conn = kdbus_hello(bus, 0, NULL, 0); - ASSERT_EXIT(unpriv_conn); - - ret = kdbus_add_match_empty(unpriv_conn); - ASSERT_EXIT(ret == 0); - - /* - * ping privileged connection from this new unprivileged - * one - */ - - ret = kdbus_msg_send(unpriv_conn, NULL, cookie, 0, 0, - 0, conn->id); - ASSERT_EXIT(ret == 0); - - /* - * Since we just dropped privileges, the dumpable flag - * was just cleared which makes the /proc/$clone_child/uid_map - * to be owned by root, hence any userns uid mapping will fail - * with -EPERM since the mapping will be done by uid 65534. - * - * To avoid this set the dumpable flag again which makes - * procfs update the /proc/$clone_child/ inodes owner to 65534. - * - * Using this we will be able write to /proc/$clone_child/uid_map - * as uid 65534 and map the uid 65534 to 0 inside the user namespace. - */ - ret = prctl(PR_SET_DUMPABLE, SUID_DUMP_USER); - ASSERT_EXIT(ret == 0); - - /* Make child privileged in its new userns and run tests */ - - ret = RUN_CLONE_CHILD(&clone_ret, - SIGCHLD | CLONE_NEWUSER | CLONE_NEWPID, - ({ 0; /* Clone setup, nothing */ }), - ({ - eventfd_t event_status = 0; - struct kdbus_conn *userns_conn; - - /* ping connection from the new user namespace */ - userns_conn = kdbus_hello(bus, 0, NULL, 0); - ASSERT_EXIT(userns_conn); - - ret = kdbus_add_match_empty(userns_conn); - ASSERT_EXIT(ret == 0); - - cookie++; - ret = kdbus_msg_send(userns_conn, NULL, cookie, - 0, 0, 0, conn->id); - ASSERT_EXIT(ret == 0); - - /* Parent did send */ - ret = eventfd_read(signal_fd, &event_status); - ASSERT_RETURN(ret >= 0 && event_status == 1); - - /* - * Receive from privileged connection - */ - kdbus_printf("Privileged → unprivileged/privileged " - "in its userns " - "(different userns and pidns):\n"); - ret = kdbus_msg_recv_poll(userns_conn, 300, &msg, NULL); - ASSERT_EXIT(ret == 0); - ASSERT_EXIT(msg->dst_id == userns_conn->id); - - item = kdbus_get_item(msg, KDBUS_ITEM_CAPS); - ASSERT_EXIT(item); - - /* uid/gid not mapped, so we have unpriv cached creds */ - ret = kdbus_match_kdbus_creds(msg, &unmapped_creds); - ASSERT_EXIT(ret == 0); - - /* - * Diffent pid namepsaces. This is the child pidns - * so it should not see its parent kdbus_pids - */ - ret = kdbus_match_kdbus_pids(msg, &unmapped_pids); - ASSERT_EXIT(ret == 0); - - kdbus_msg_free(msg); - - - /* - * Receive broadcast from privileged connection - */ - kdbus_printf("Privileged → unprivileged/privileged " - "in its userns " - "(different userns and pidns):\n"); - ret = kdbus_msg_recv_poll(userns_conn, 300, &msg, NULL); - ASSERT_EXIT(ret == 0); - ASSERT_EXIT(msg->dst_id == KDBUS_DST_ID_BROADCAST); - - item = kdbus_get_item(msg, KDBUS_ITEM_CAPS); - ASSERT_EXIT(item); - - /* uid/gid not mapped, so we have unpriv cached creds */ - ret = kdbus_match_kdbus_creds(msg, &unmapped_creds); - ASSERT_EXIT(ret == 0); - - /* - * Diffent pid namepsaces. This is the child pidns - * so it should not see its parent kdbus_pids - */ - ret = kdbus_match_kdbus_pids(msg, &unmapped_pids); - ASSERT_EXIT(ret == 0); - - kdbus_msg_free(msg); - - kdbus_conn_free(userns_conn); - }), - ({ - /* Parent setup map child uid/gid */ - ret = userns_map_uid_gid(pid, "0 65534 1", "0 65534 1"); - ASSERT_EXIT(ret == 0); - }), - ({ 0; })); - /* Unprivileged was not able to create user namespace */ - if (clone_ret == -EPERM) { - kdbus_printf("-- CLONE_NEWUSER TEST Failed for " - "uid: %u\n -- Make sure that your kernel " - "do not allow CLONE_NEWUSER for " - "unprivileged users\n", UNPRIV_UID); - ret = 0; - goto out; - } - - ASSERT_EXIT(ret == 0); - - - /* - * Receive from privileged connection - */ - kdbus_printf("\nPrivileged → unprivileged (same namespaces):\n"); - ret = kdbus_msg_recv_poll(unpriv_conn, 300, &msg, NULL); - - ASSERT_EXIT(ret == 0); - ASSERT_EXIT(msg->dst_id == unpriv_conn->id); - - /* will get the privileged creds */ - ret = kdbus_match_kdbus_creds(msg, &privileged_creds); - ASSERT_EXIT(ret == 0); - - /* Same pidns so will get the kdbus_pids */ - ret = kdbus_match_kdbus_pids(msg, &parent_pids); - ASSERT_RETURN(ret == 0); - - kdbus_msg_free(msg); - - - /* - * Receive broadcast from privileged connection - */ - kdbus_printf("\nPrivileged → unprivileged (same namespaces):\n"); - ret = kdbus_msg_recv_poll(unpriv_conn, 300, &msg, NULL); - - ASSERT_EXIT(ret == 0); - ASSERT_EXIT(msg->dst_id == KDBUS_DST_ID_BROADCAST); - - /* will get the privileged creds */ - ret = kdbus_match_kdbus_creds(msg, &privileged_creds); - ASSERT_EXIT(ret == 0); - - ret = kdbus_match_kdbus_pids(msg, &parent_pids); - ASSERT_RETURN(ret == 0); - - kdbus_msg_free(msg); - -out: - kdbus_conn_free(unpriv_conn); - - return ret; -} - -static int kdbus_clone_userns_test(const char *bus, - struct kdbus_conn *conn) -{ - int ret, status, efd; - pid_t pid, ppid; - uint64_t unpriv_conn_id, userns_conn_id; - struct kdbus_msg *msg; - const struct kdbus_item *item; - struct kdbus_pids expected_pids; - struct kdbus_conn *monitor; - - kdbus_printf("STARTING TEST 'metadata-ns'.\n"); - - monitor = kdbus_hello(bus, KDBUS_HELLO_MONITOR, NULL, 0); - ASSERT_EXIT(monitor); - - /* - * parent will signal to child that is in its - * userns to read its queue - */ - efd = eventfd(0, EFD_CLOEXEC); - ASSERT_RETURN_VAL(efd >= 0, efd); - - ppid = getppid(); - - pid = fork(); - ASSERT_RETURN_VAL(pid >= 0, -errno); - - if (pid == 0) { - ret = prctl(PR_SET_PDEATHSIG, SIGKILL); - ASSERT_EXIT_VAL(ret == 0, -errno); - - ret = __kdbus_clone_userns_test(bus, conn, ppid, efd); - _exit(ret); - } - - - /* Phase 1) privileged receives from unprivileged */ - - /* - * Receive from the unprivileged child - */ - kdbus_printf("\nUnprivileged → privileged (same namespaces):\n"); - ret = kdbus_msg_recv_poll(conn, 300, &msg, NULL); - ASSERT_RETURN(ret == 0); - - unpriv_conn_id = msg->src_id; - - /* Unprivileged user */ - ret = kdbus_match_kdbus_creds(msg, &unmapped_creds); - ASSERT_RETURN(ret == 0); - - /* Set the expected creds_pids */ - expected_pids = (struct kdbus_pids) { - .pid = pid, - .tid = pid, - .ppid = getpid(), - }; - ret = kdbus_match_kdbus_pids(msg, &expected_pids); - ASSERT_RETURN(ret == 0); - - kdbus_msg_free(msg); - - - /* - * Receive from the unprivileged that is in his own - * userns and pidns - */ - - kdbus_printf("\nUnprivileged/privileged in its userns → privileged " - "(different userns and pidns)\n"); - ret = kdbus_msg_recv_poll(conn, 300, &msg, NULL); - if (ret == -ETIMEDOUT) - /* perhaps unprivileged userns is not allowed */ - goto wait; - - ASSERT_RETURN(ret == 0); - - userns_conn_id = msg->src_id; - - item = kdbus_get_item(msg, KDBUS_ITEM_CAPS); - ASSERT_RETURN(item); - - /* - * Compare received items, creds must be translated into - * the receiver user namespace, so the user is unprivileged - */ - ret = kdbus_match_kdbus_creds(msg, &unmapped_creds); - ASSERT_RETURN(ret == 0); - - /* - * We should have the kdbus_pids since we are the parent - * pidns - */ - item = kdbus_get_item(msg, KDBUS_ITEM_PIDS); - ASSERT_RETURN(item); - - ASSERT_RETURN(memcmp(&item->pids, &unmapped_pids, - sizeof(struct kdbus_pids)) != 0); - - /* - * Parent pid of the unprivileged/privileged in its userns - * is the unprivileged child pid that was forked here. - */ - ASSERT_RETURN((uint64_t)pid == item->pids.ppid); - - kdbus_msg_free(msg); - - - /* Phase 2) Privileged connection sends now 3 packets */ - - /* - * Sending to unprivileged connections a unicast - */ - ret = kdbus_msg_send(conn, NULL, 0xdeadbeef, 0, 0, - 0, unpriv_conn_id); - ASSERT_RETURN(ret == 0); - - /* signal to child that is in its userns */ - ret = eventfd_write(efd, 1); - ASSERT_EXIT(ret == 0); - - /* - * Sending to unprivileged/privilged in its userns - * connections a unicast - */ - ret = kdbus_msg_send(conn, NULL, 0xdeadbeef, 0, 0, - 0, userns_conn_id); - ASSERT_RETURN(ret == 0); - - /* - * Sending to unprivileged connections a broadcast - */ - ret = kdbus_msg_send(conn, NULL, 0xdeadbeef, 0, 0, - 0, KDBUS_DST_ID_BROADCAST); - ASSERT_RETURN(ret == 0); - - -wait: - ret = waitpid(pid, &status, 0); - ASSERT_RETURN(ret >= 0); - - ASSERT_RETURN(WIFEXITED(status)) - ASSERT_RETURN(!WEXITSTATUS(status)); - - /* Dump monitor queue */ - kdbus_printf("\n\nMonitor queue:\n"); - for (;;) { - ret = kdbus_msg_recv_poll(monitor, 100, &msg, NULL); - if (ret < 0) - break; - - if (msg->payload_type == KDBUS_PAYLOAD_DBUS) { - /* - * Parent pidns should see all the - * pids - */ - item = kdbus_get_item(msg, KDBUS_ITEM_PIDS); - ASSERT_RETURN(item); - - ASSERT_RETURN(item->pids.pid != 0 && - item->pids.tid != 0 && - item->pids.ppid != 0); - } - - kdbus_msg_free(msg); - } - - kdbus_conn_free(monitor); - close(efd); - - return 0; -} - -int kdbus_test_metadata_ns(struct kdbus_test_env *env) -{ - int ret; - struct kdbus_conn *holder, *conn; - struct kdbus_policy_access policy_access = { - /* Allow world so we can inspect metadata in namespace */ - .type = KDBUS_POLICY_ACCESS_WORLD, - .id = geteuid(), - .access = KDBUS_POLICY_TALK, - }; - - /* - * We require user-namespaces and all uids/gids - * should be mapped (we can just require the necessary ones) - */ - if (!config_user_ns_is_enabled() || - !all_uids_gids_are_mapped()) - return TEST_SKIP; - - ret = test_is_capable(CAP_SETUID, CAP_SETGID, CAP_SYS_ADMIN, -1); - ASSERT_RETURN(ret >= 0); - - /* no enough privileges, SKIP test */ - if (!ret) - return TEST_SKIP; - - holder = kdbus_hello_registrar(env->buspath, "com.example.metadata", - &policy_access, 1, - KDBUS_HELLO_POLICY_HOLDER); - ASSERT_RETURN(holder); - - conn = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn); - - ret = kdbus_add_match_empty(conn); - ASSERT_RETURN(ret == 0); - - ret = kdbus_name_acquire(conn, "com.example.metadata", NULL); - ASSERT_EXIT(ret >= 0); - - ret = kdbus_clone_userns_test(env->buspath, conn); - ASSERT_RETURN(ret == 0); - - kdbus_conn_free(holder); - kdbus_conn_free(conn); - - return TEST_OK; -} diff --git a/tools/testing/selftests/kdbus/test-monitor.c b/tools/testing/selftests/kdbus/test-monitor.c deleted file mode 100644 index e00d738a3..000000000 --- a/tools/testing/selftests/kdbus/test-monitor.c +++ /dev/null @@ -1,176 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <stdint.h> -#include <stdbool.h> -#include <errno.h> -#include <assert.h> -#include <signal.h> -#include <sys/time.h> -#include <sys/mman.h> -#include <sys/capability.h> -#include <sys/wait.h> - -#include "kdbus-util.h" -#include "kdbus-enum.h" - -#include "kdbus-util.h" -#include "kdbus-enum.h" -#include "kdbus-test.h" - -int kdbus_test_monitor(struct kdbus_test_env *env) -{ - struct kdbus_conn *monitor, *conn; - unsigned int cookie = 0xdeadbeef; - struct kdbus_msg *msg; - uint64_t offset = 0; - int ret; - - conn = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn); - - /* add matches to make sure the monitor do not trigger an item add or - * remove on connect and disconnect, respectively. - */ - ret = kdbus_add_match_id(conn, 0x1, KDBUS_ITEM_ID_ADD, - KDBUS_MATCH_ID_ANY); - ASSERT_RETURN(ret == 0); - - ret = kdbus_add_match_id(conn, 0x2, KDBUS_ITEM_ID_REMOVE, - KDBUS_MATCH_ID_ANY); - ASSERT_RETURN(ret == 0); - - /* register a monitor */ - monitor = kdbus_hello(env->buspath, KDBUS_HELLO_MONITOR, NULL, 0); - ASSERT_RETURN(monitor); - - /* make sure we did not receive a monitor connect notification */ - ret = kdbus_msg_recv(conn, &msg, &offset); - ASSERT_RETURN(ret == -EAGAIN); - - /* check that a monitor cannot acquire a name */ - ret = kdbus_name_acquire(monitor, "foo.bar.baz", NULL); - ASSERT_RETURN(ret == -EOPNOTSUPP); - - ret = kdbus_msg_send(env->conn, NULL, cookie, 0, 0, 0, conn->id); - ASSERT_RETURN(ret == 0); - - /* the recipient should have gotten the message */ - ret = kdbus_msg_recv(conn, &msg, &offset); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(msg->cookie == cookie); - kdbus_msg_free(msg); - kdbus_free(conn, offset); - - /* and so should the monitor */ - ret = kdbus_msg_recv(monitor, &msg, &offset); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(msg->cookie == cookie); - - kdbus_msg_free(msg); - kdbus_free(monitor, offset); - - /* Installing matches for monitors must fais must fail */ - ret = kdbus_add_match_empty(monitor); - ASSERT_RETURN(ret == -EOPNOTSUPP); - - cookie++; - ret = kdbus_msg_send(env->conn, NULL, cookie, 0, 0, 0, - KDBUS_DST_ID_BROADCAST); - ASSERT_RETURN(ret == 0); - - /* The monitor should get the message. */ - ret = kdbus_msg_recv_poll(monitor, 100, &msg, &offset); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(msg->cookie == cookie); - - kdbus_msg_free(msg); - kdbus_free(monitor, offset); - - /* - * Since we are the only monitor, update the attach flags - * and tell we are not interessted in attach flags recv - */ - - ret = kdbus_conn_update_attach_flags(monitor, - _KDBUS_ATTACH_ALL, - 0); - ASSERT_RETURN(ret == 0); - - cookie++; - ret = kdbus_msg_send(env->conn, NULL, cookie, 0, 0, 0, - KDBUS_DST_ID_BROADCAST); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_recv_poll(monitor, 100, &msg, &offset); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(msg->cookie == cookie); - - ret = kdbus_item_in_message(msg, KDBUS_ITEM_TIMESTAMP); - ASSERT_RETURN(ret == 0); - - kdbus_msg_free(msg); - kdbus_free(monitor, offset); - - /* - * Now we are interested in KDBUS_ITEM_TIMESTAMP and - * KDBUS_ITEM_CREDS - */ - ret = kdbus_conn_update_attach_flags(monitor, - _KDBUS_ATTACH_ALL, - KDBUS_ATTACH_TIMESTAMP | - KDBUS_ATTACH_CREDS); - ASSERT_RETURN(ret == 0); - - cookie++; - ret = kdbus_msg_send(env->conn, NULL, cookie, 0, 0, 0, - KDBUS_DST_ID_BROADCAST); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_recv_poll(monitor, 100, &msg, &offset); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(msg->cookie == cookie); - - ret = kdbus_item_in_message(msg, KDBUS_ITEM_TIMESTAMP); - ASSERT_RETURN(ret == 1); - - ret = kdbus_item_in_message(msg, KDBUS_ITEM_CREDS); - ASSERT_RETURN(ret == 1); - - /* the KDBUS_ITEM_PID_COMM was not requested */ - ret = kdbus_item_in_message(msg, KDBUS_ITEM_PID_COMM); - ASSERT_RETURN(ret == 0); - - kdbus_msg_free(msg); - kdbus_free(monitor, offset); - - kdbus_conn_free(monitor); - /* make sure we did not receive a monitor disconnect notification */ - ret = kdbus_msg_recv(conn, &msg, &offset); - ASSERT_RETURN(ret == -EAGAIN); - - kdbus_conn_free(conn); - - /* Make sure that monitor as unprivileged is not allowed */ - ret = test_is_capable(CAP_SETUID, CAP_SETGID, -1); - ASSERT_RETURN(ret >= 0); - - if (ret && all_uids_gids_are_mapped()) { - ret = RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_UID, ({ - monitor = kdbus_hello(env->buspath, - KDBUS_HELLO_MONITOR, - NULL, 0); - ASSERT_EXIT(!monitor && errno == EPERM); - - _exit(EXIT_SUCCESS); - }), - ({ 0; })); - ASSERT_RETURN(ret == 0); - } - - return TEST_OK; -} diff --git a/tools/testing/selftests/kdbus/test-names.c b/tools/testing/selftests/kdbus/test-names.c deleted file mode 100644 index e400dc86a..000000000 --- a/tools/testing/selftests/kdbus/test-names.c +++ /dev/null @@ -1,272 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <stdint.h> -#include <errno.h> -#include <assert.h> -#include <limits.h> -#include <getopt.h> -#include <stdbool.h> - -#include "kdbus-api.h" -#include "kdbus-util.h" -#include "kdbus-enum.h" -#include "kdbus-test.h" - -struct test_name { - const char *name; - __u64 owner_id; - __u64 flags; -}; - -static bool conn_test_names(const struct kdbus_conn *conn, - const struct test_name *tests, - unsigned int n_tests) -{ - struct kdbus_cmd_list cmd_list = {}; - struct kdbus_info *name, *list; - unsigned int i; - int ret; - - cmd_list.size = sizeof(cmd_list); - cmd_list.flags = KDBUS_LIST_NAMES | - KDBUS_LIST_ACTIVATORS | - KDBUS_LIST_QUEUED; - - ret = kdbus_cmd_list(conn->fd, &cmd_list); - ASSERT_RETURN(ret == 0); - - list = (struct kdbus_info *)(conn->buf + cmd_list.offset); - - for (i = 0; i < n_tests; i++) { - const struct test_name *t = tests + i; - bool found = false; - - KDBUS_FOREACH(name, list, cmd_list.list_size) { - struct kdbus_item *item; - - KDBUS_ITEM_FOREACH(item, name, items) { - if (item->type != KDBUS_ITEM_OWNED_NAME || - strcmp(item->name.name, t->name) != 0) - continue; - - if (t->owner_id == name->id && - t->flags == item->name.flags) { - found = true; - break; - } - } - } - - if (!found) - return false; - } - - return true; -} - -static bool conn_is_name_primary_owner(const struct kdbus_conn *conn, - const char *needle) -{ - struct test_name t = { - .name = needle, - .owner_id = conn->id, - .flags = KDBUS_NAME_PRIMARY, - }; - - return conn_test_names(conn, &t, 1); -} - -int kdbus_test_name_basic(struct kdbus_test_env *env) -{ - struct kdbus_conn *conn; - char *name, *dot_name, *invalid_name, *wildcard_name; - int ret; - - name = "foo.bla.blaz"; - dot_name = ".bla.blaz"; - invalid_name = "foo"; - wildcard_name = "foo.bla.bl.*"; - - /* create a 2nd connection */ - conn = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn != NULL); - - /* acquire name "foo.bar.xxx" name */ - ret = kdbus_name_acquire(conn, "foo.bar.xxx", NULL); - ASSERT_RETURN(ret == 0); - - /* Name is not valid, must fail */ - ret = kdbus_name_acquire(env->conn, dot_name, NULL); - ASSERT_RETURN(ret == -EINVAL); - - ret = kdbus_name_acquire(env->conn, invalid_name, NULL); - ASSERT_RETURN(ret == -EINVAL); - - ret = kdbus_name_acquire(env->conn, wildcard_name, NULL); - ASSERT_RETURN(ret == -EINVAL); - - /* check that we can acquire a name */ - ret = kdbus_name_acquire(env->conn, name, NULL); - ASSERT_RETURN(ret == 0); - - ret = conn_is_name_primary_owner(env->conn, name); - ASSERT_RETURN(ret == true); - - /* ... and release it again */ - ret = kdbus_name_release(env->conn, name); - ASSERT_RETURN(ret == 0); - - ret = conn_is_name_primary_owner(env->conn, name); - ASSERT_RETURN(ret == false); - - /* check that we can't release it again */ - ret = kdbus_name_release(env->conn, name); - ASSERT_RETURN(ret == -ESRCH); - - /* check that we can't release a name that we don't own */ - ret = kdbus_name_release(env->conn, "foo.bar.xxx"); - ASSERT_RETURN(ret == -EADDRINUSE); - - /* Name is not valid, must fail */ - ret = kdbus_name_release(env->conn, dot_name); - ASSERT_RETURN(ret == -ESRCH); - - ret = kdbus_name_release(env->conn, invalid_name); - ASSERT_RETURN(ret == -ESRCH); - - ret = kdbus_name_release(env->conn, wildcard_name); - ASSERT_RETURN(ret == -ESRCH); - - kdbus_conn_free(conn); - - return TEST_OK; -} - -int kdbus_test_name_conflict(struct kdbus_test_env *env) -{ - struct kdbus_conn *conn; - char *name; - int ret; - - name = "foo.bla.blaz"; - - /* create a 2nd connection */ - conn = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn != NULL); - - /* allow the new connection to own the same name */ - /* acquire name from the 1st connection */ - ret = kdbus_name_acquire(env->conn, name, NULL); - ASSERT_RETURN(ret == 0); - - ret = conn_is_name_primary_owner(env->conn, name); - ASSERT_RETURN(ret == true); - - /* check that we also can't acquire it again from the 2nd connection */ - ret = kdbus_name_acquire(conn, name, NULL); - ASSERT_RETURN(ret == -EEXIST); - - kdbus_conn_free(conn); - - return TEST_OK; -} - -int kdbus_test_name_queue(struct kdbus_test_env *env) -{ - struct kdbus_conn *conn; - struct test_name t[2]; - const char *name; - uint64_t flags; - int ret; - - name = "foo.bla.blaz"; - - flags = 0; - - /* create a 2nd connection */ - conn = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn != NULL); - - /* allow the new connection to own the same name */ - /* acquire name from the 1st connection */ - ret = kdbus_name_acquire(env->conn, name, &flags); - ASSERT_RETURN(ret == 0); - - ret = conn_is_name_primary_owner(env->conn, name); - ASSERT_RETURN(ret == true); - - /* queue the 2nd connection as waiting owner */ - flags = KDBUS_NAME_QUEUE; - ret = kdbus_name_acquire(conn, name, &flags); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(flags & KDBUS_NAME_IN_QUEUE); - - t[0].name = name; - t[0].owner_id = env->conn->id; - t[0].flags = KDBUS_NAME_PRIMARY; - t[1].name = name; - t[1].owner_id = conn->id; - t[1].flags = KDBUS_NAME_QUEUE | KDBUS_NAME_IN_QUEUE; - ret = conn_test_names(conn, t, 2); - ASSERT_RETURN(ret == true); - - /* release name from 1st connection */ - ret = kdbus_name_release(env->conn, name); - ASSERT_RETURN(ret == 0); - - /* now the name should be owned by the 2nd connection */ - t[0].name = name; - t[0].owner_id = conn->id; - t[0].flags = KDBUS_NAME_PRIMARY | KDBUS_NAME_QUEUE; - ret = conn_test_names(conn, t, 1); - ASSERT_RETURN(ret == true); - - kdbus_conn_free(conn); - - return TEST_OK; -} - -int kdbus_test_name_takeover(struct kdbus_test_env *env) -{ - struct kdbus_conn *conn; - struct test_name t; - const char *name; - uint64_t flags; - int ret; - - name = "foo.bla.blaz"; - - flags = KDBUS_NAME_ALLOW_REPLACEMENT; - - /* create a 2nd connection */ - conn = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn != NULL); - - /* acquire name for 1st connection */ - ret = kdbus_name_acquire(env->conn, name, &flags); - ASSERT_RETURN(ret == 0); - - t.name = name; - t.owner_id = env->conn->id; - t.flags = KDBUS_NAME_ALLOW_REPLACEMENT | KDBUS_NAME_PRIMARY; - ret = conn_test_names(conn, &t, 1); - ASSERT_RETURN(ret == true); - - /* now steal name with 2nd connection */ - flags = KDBUS_NAME_REPLACE_EXISTING; - ret = kdbus_name_acquire(conn, name, &flags); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(flags & KDBUS_NAME_ACQUIRED); - - ret = conn_is_name_primary_owner(conn, name); - ASSERT_RETURN(ret == true); - - kdbus_conn_free(conn); - - return TEST_OK; -} diff --git a/tools/testing/selftests/kdbus/test-policy-ns.c b/tools/testing/selftests/kdbus/test-policy-ns.c deleted file mode 100644 index 3437012f9..000000000 --- a/tools/testing/selftests/kdbus/test-policy-ns.c +++ /dev/null @@ -1,632 +0,0 @@ -/* - * Test metadata and policies in new namespaces. Even if our tests - * can run in a namespaced setup, this test is necessary so we can - * inspect policies on the same kdbusfs but between multiple - * namespaces. - * - * Copyright (C) 2014-2015 Djalal Harouni - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#include <stdio.h> -#include <string.h> -#include <fcntl.h> -#include <pthread.h> -#include <sched.h> -#include <stdlib.h> -#include <stddef.h> -#include <stdint.h> -#include <stdbool.h> -#include <unistd.h> -#include <errno.h> -#include <signal.h> -#include <sys/wait.h> -#include <sys/prctl.h> -#include <sys/eventfd.h> -#include <sys/syscall.h> -#include <sys/capability.h> -#include <linux/sched.h> - -#include "kdbus-test.h" -#include "kdbus-util.h" -#include "kdbus-enum.h" - -#define MAX_CONN 64 -#define POLICY_NAME "foo.test.policy-test" - -#define KDBUS_CONN_MAX_MSGS_PER_USER 16 - -/** - * Note: this test can be used to inspect policy_db->talk_access_hash - * - * The purpose of these tests: - * 1) Check KDBUS_POLICY_TALK - * 2) Check the cache state: kdbus_policy_db->talk_access_hash - * Should be extended - */ - -/** - * Check a list of connections against conn_db[0] - * conn_db[0] will own the name "foo.test.policy-test" and the - * policy holder connection for this name will update the policy - * entries, so different use cases can be tested. - */ -static struct kdbus_conn **conn_db; - -static void *kdbus_recv_echo(void *ptr) -{ - int ret; - struct kdbus_conn *conn = ptr; - - ret = kdbus_msg_recv_poll(conn, 200, NULL, NULL); - - return (void *)(long)ret; -} - -/* Trigger kdbus_policy_set() */ -static int kdbus_set_policy_talk(struct kdbus_conn *conn, - const char *name, - uid_t id, unsigned int type) -{ - int ret; - struct kdbus_policy_access access = { - .type = type, - .id = id, - .access = KDBUS_POLICY_TALK, - }; - - ret = kdbus_conn_update_policy(conn, name, &access, 1); - ASSERT_RETURN(ret == 0); - - return TEST_OK; -} - -/* return TEST_OK or TEST_ERR on failure */ -static int kdbus_register_same_activator(char *bus, const char *name, - struct kdbus_conn **c) -{ - int ret; - struct kdbus_conn *activator; - - activator = kdbus_hello_activator(bus, name, NULL, 0); - if (activator) { - *c = activator; - fprintf(stderr, "--- error was able to register name twice '%s'.\n", - name); - return TEST_ERR; - } - - ret = -errno; - /* -EEXIST means test succeeded */ - if (ret == -EEXIST) - return TEST_OK; - - return TEST_ERR; -} - -/* return TEST_OK or TEST_ERR on failure */ -static int kdbus_register_policy_holder(char *bus, const char *name, - struct kdbus_conn **conn) -{ - struct kdbus_conn *c; - struct kdbus_policy_access access[2]; - - access[0].type = KDBUS_POLICY_ACCESS_USER; - access[0].access = KDBUS_POLICY_OWN; - access[0].id = geteuid(); - - access[1].type = KDBUS_POLICY_ACCESS_WORLD; - access[1].access = KDBUS_POLICY_TALK; - access[1].id = geteuid(); - - c = kdbus_hello_registrar(bus, name, access, 2, - KDBUS_HELLO_POLICY_HOLDER); - ASSERT_RETURN(c); - - *conn = c; - - return TEST_OK; -} - -/** - * Create new threads for receiving from multiple senders, - * The 'conn_db' will be populated by newly created connections. - * Caller should free all allocated connections. - * - * return 0 on success, negative errno on failure. - */ -static int kdbus_recv_in_threads(const char *bus, const char *name, - struct kdbus_conn **conn_db) -{ - int ret; - bool pool_full = false; - unsigned int sent_packets = 0; - unsigned int lost_packets = 0; - unsigned int i, tid; - unsigned long dst_id; - unsigned long cookie = 1; - unsigned int thread_nr = MAX_CONN - 1; - pthread_t thread_id[MAX_CONN - 1] = {'\0'}; - - dst_id = name ? KDBUS_DST_ID_NAME : conn_db[0]->id; - - for (tid = 0, i = 1; tid < thread_nr; tid++, i++) { - ret = pthread_create(&thread_id[tid], NULL, - kdbus_recv_echo, (void *)conn_db[0]); - if (ret < 0) { - ret = -errno; - kdbus_printf("error pthread_create: %d (%m)\n", - ret); - break; - } - - /* just free before re-using */ - kdbus_conn_free(conn_db[i]); - conn_db[i] = NULL; - - /* We need to create connections here */ - conn_db[i] = kdbus_hello(bus, 0, NULL, 0); - if (!conn_db[i]) { - ret = -errno; - break; - } - - ret = kdbus_add_match_empty(conn_db[i]); - if (ret < 0) - break; - - ret = kdbus_msg_send(conn_db[i], name, cookie++, - 0, 0, 0, dst_id); - if (ret < 0) { - /* - * Receivers are not reading their messages, - * not scheduled ?! - * - * So set the pool full here, perhaps the - * connection pool or queue was full, later - * recheck receivers errors - */ - if (ret == -ENOBUFS || ret == -EXFULL) - pool_full = true; - break; - } - - sent_packets++; - } - - for (tid = 0; tid < thread_nr; tid++) { - int thread_ret = 0; - - if (thread_id[tid]) { - pthread_join(thread_id[tid], (void *)&thread_ret); - if (thread_ret < 0) { - /* Update only if send did not fail */ - if (ret == 0) - ret = thread_ret; - - lost_packets++; - } - } - } - - /* - * When sending if we did fail with -ENOBUFS or -EXFULL - * then we should have set lost_packet and we should at - * least have sent_packets set to KDBUS_CONN_MAX_MSGS_PER_USER - */ - if (pool_full) { - ASSERT_RETURN(lost_packets > 0); - - /* - * We should at least send KDBUS_CONN_MAX_MSGS_PER_USER - * - * For every send operation we create a thread to - * recv the packet, so we keep the queue clean - */ - ASSERT_RETURN(sent_packets >= KDBUS_CONN_MAX_MSGS_PER_USER); - - /* - * Set ret to zero since we only failed due to - * the receiving threads that have not been - * scheduled - */ - ret = 0; - } - - return ret; -} - -/* Return: TEST_OK or TEST_ERR on failure */ -static int kdbus_normal_test(const char *bus, const char *name, - struct kdbus_conn **conn_db) -{ - int ret; - - ret = kdbus_recv_in_threads(bus, name, conn_db); - ASSERT_RETURN(ret >= 0); - - return TEST_OK; -} - -static int kdbus_fork_test_by_id(const char *bus, - struct kdbus_conn **conn_db, - int parent_status, int child_status) -{ - int ret; - pid_t pid; - uint64_t cookie = 0x9876ecba; - struct kdbus_msg *msg = NULL; - uint64_t offset = 0; - int status = 0; - - /* - * If the child_status is not EXIT_SUCCESS, then we expect - * that sending from the child will fail, thus receiving - * from parent must error with -ETIMEDOUT, and vice versa. - */ - bool parent_timedout = !!child_status; - bool child_timedout = !!parent_status; - - pid = fork(); - ASSERT_RETURN_VAL(pid >= 0, pid); - - if (pid == 0) { - struct kdbus_conn *conn_src; - - ret = prctl(PR_SET_PDEATHSIG, SIGKILL); - ASSERT_EXIT(ret == 0); - - ret = drop_privileges(65534, 65534); - ASSERT_EXIT(ret == 0); - - conn_src = kdbus_hello(bus, 0, NULL, 0); - ASSERT_EXIT(conn_src); - - ret = kdbus_add_match_empty(conn_src); - ASSERT_EXIT(ret == 0); - - /* - * child_status is always checked against send - * operations, in case it fails always return - * EXIT_FAILURE. - */ - ret = kdbus_msg_send(conn_src, NULL, cookie, - 0, 0, 0, conn_db[0]->id); - ASSERT_EXIT(ret == child_status); - - ret = kdbus_msg_recv_poll(conn_src, 100, NULL, NULL); - - kdbus_conn_free(conn_src); - - /* - * Child kdbus_msg_recv_poll() should timeout since - * the parent_status was set to a non EXIT_SUCCESS - * value. - */ - if (child_timedout) - _exit(ret == -ETIMEDOUT ? EXIT_SUCCESS : EXIT_FAILURE); - - _exit(ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE); - } - - ret = kdbus_msg_recv_poll(conn_db[0], 100, &msg, &offset); - /* - * If parent_timedout is set then this should fail with - * -ETIMEDOUT since the child_status was set to a non - * EXIT_SUCCESS value. Otherwise, assume - * that kdbus_msg_recv_poll() has succeeded. - */ - if (parent_timedout) { - ASSERT_RETURN_VAL(ret == -ETIMEDOUT, TEST_ERR); - - /* timedout no need to continue, we don't have the - * child connection ID, so just terminate. */ - goto out; - } else { - ASSERT_RETURN_VAL(ret == 0, ret); - } - - ret = kdbus_msg_send(conn_db[0], NULL, ++cookie, - 0, 0, 0, msg->src_id); - /* - * parent_status is checked against send operations, - * on failures always return TEST_ERR. - */ - ASSERT_RETURN_VAL(ret == parent_status, TEST_ERR); - - kdbus_msg_free(msg); - kdbus_free(conn_db[0], offset); - -out: - ret = waitpid(pid, &status, 0); - ASSERT_RETURN_VAL(ret >= 0, ret); - - return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR; -} - -/* - * Return: TEST_OK, TEST_ERR or TEST_SKIP - * we return TEST_OK only if the children return with the expected - * 'expected_status' that is specified as an argument. - */ -static int kdbus_fork_test(const char *bus, const char *name, - struct kdbus_conn **conn_db, int expected_status) -{ - pid_t pid; - int ret = 0; - int status = 0; - - pid = fork(); - ASSERT_RETURN_VAL(pid >= 0, pid); - - if (pid == 0) { - ret = prctl(PR_SET_PDEATHSIG, SIGKILL); - ASSERT_EXIT(ret == 0); - - ret = drop_privileges(65534, 65534); - ASSERT_EXIT(ret == 0); - - ret = kdbus_recv_in_threads(bus, name, conn_db); - _exit(ret == expected_status ? EXIT_SUCCESS : EXIT_FAILURE); - } - - ret = waitpid(pid, &status, 0); - ASSERT_RETURN(ret >= 0); - - return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR; -} - -/* Return EXIT_SUCCESS, EXIT_FAILURE or negative errno */ -static int __kdbus_clone_userns_test(const char *bus, - const char *name, - struct kdbus_conn **conn_db, - int expected_status) -{ - int efd; - pid_t pid; - int ret = 0; - unsigned int uid = 65534; - int status; - - ret = drop_privileges(uid, uid); - ASSERT_RETURN_VAL(ret == 0, ret); - - /* - * Since we just dropped privileges, the dumpable flag was just - * cleared which makes the /proc/$clone_child/uid_map to be - * owned by root, hence any userns uid mapping will fail with - * -EPERM since the mapping will be done by uid 65534. - * - * To avoid this set the dumpable flag again which makes procfs - * update the /proc/$clone_child/ inodes owner to 65534. - * - * Using this we will be able write to /proc/$clone_child/uid_map - * as uid 65534 and map the uid 65534 to 0 inside the user - * namespace. - */ - ret = prctl(PR_SET_DUMPABLE, SUID_DUMP_USER); - ASSERT_RETURN_VAL(ret == 0, ret); - - /* sync parent/child */ - efd = eventfd(0, EFD_CLOEXEC); - ASSERT_RETURN_VAL(efd >= 0, efd); - - pid = syscall(__NR_clone, SIGCHLD|CLONE_NEWUSER, NULL); - if (pid < 0) { - ret = -errno; - kdbus_printf("error clone: %d (%m)\n", ret); - /* - * Normal user not allowed to create userns, - * so nothing to worry about ? - */ - if (ret == -EPERM) { - kdbus_printf("-- CLONE_NEWUSER TEST Failed for uid: %u\n" - "-- Make sure that your kernel do not allow " - "CLONE_NEWUSER for unprivileged users\n" - "-- Upstream Commit: " - "https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=5eaf563e\n", - uid); - ret = 0; - } - - return ret; - } - - if (pid == 0) { - struct kdbus_conn *conn_src; - eventfd_t event_status = 0; - - ret = prctl(PR_SET_PDEATHSIG, SIGKILL); - ASSERT_EXIT(ret == 0); - - ret = eventfd_read(efd, &event_status); - ASSERT_EXIT(ret >= 0 && event_status == 1); - - /* ping connection from the new user namespace */ - conn_src = kdbus_hello(bus, 0, NULL, 0); - ASSERT_EXIT(conn_src); - - ret = kdbus_add_match_empty(conn_src); - ASSERT_EXIT(ret == 0); - - ret = kdbus_msg_send(conn_src, name, 0xabcd1234, - 0, 0, 0, KDBUS_DST_ID_NAME); - kdbus_conn_free(conn_src); - - _exit(ret == expected_status ? EXIT_SUCCESS : EXIT_FAILURE); - } - - ret = userns_map_uid_gid(pid, "0 65534 1", "0 65534 1"); - ASSERT_RETURN_VAL(ret == 0, ret); - - /* Tell child we are ready */ - ret = eventfd_write(efd, 1); - ASSERT_RETURN_VAL(ret == 0, ret); - - ret = waitpid(pid, &status, 0); - ASSERT_RETURN_VAL(ret >= 0, ret); - - close(efd); - - return status == EXIT_SUCCESS ? TEST_OK : TEST_ERR; -} - -static int kdbus_clone_userns_test(const char *bus, - const char *name, - struct kdbus_conn **conn_db, - int expected_status) -{ - pid_t pid; - int ret = 0; - int status; - - pid = fork(); - ASSERT_RETURN_VAL(pid >= 0, -errno); - - if (pid == 0) { - ret = prctl(PR_SET_PDEATHSIG, SIGKILL); - if (ret < 0) - _exit(EXIT_FAILURE); - - ret = __kdbus_clone_userns_test(bus, name, conn_db, - expected_status); - _exit(ret); - } - - /* - * Receive in the original (root privileged) user namespace, - * must fail with -ETIMEDOUT. - */ - ret = kdbus_msg_recv_poll(conn_db[0], 100, NULL, NULL); - ASSERT_RETURN_VAL(ret == -ETIMEDOUT, ret); - - ret = waitpid(pid, &status, 0); - ASSERT_RETURN_VAL(ret >= 0, ret); - - return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR; -} - -int kdbus_test_policy_ns(struct kdbus_test_env *env) -{ - int i; - int ret; - struct kdbus_conn *activator = NULL; - struct kdbus_conn *policy_holder = NULL; - char *bus = env->buspath; - - ret = test_is_capable(CAP_SETUID, CAP_SETGID, -1); - ASSERT_RETURN(ret >= 0); - - /* no enough privileges, SKIP test */ - if (!ret) - return TEST_SKIP; - - /* we require user-namespaces */ - if (access("/proc/self/uid_map", F_OK) != 0) - return TEST_SKIP; - - /* uids/gids must be mapped */ - if (!all_uids_gids_are_mapped()) - return TEST_SKIP; - - conn_db = calloc(MAX_CONN, sizeof(struct kdbus_conn *)); - ASSERT_RETURN(conn_db); - - memset(conn_db, 0, MAX_CONN * sizeof(struct kdbus_conn *)); - - conn_db[0] = kdbus_hello(bus, 0, NULL, 0); - ASSERT_RETURN(conn_db[0]); - - ret = kdbus_add_match_empty(conn_db[0]); - ASSERT_RETURN(ret == 0); - - ret = kdbus_fork_test_by_id(bus, conn_db, -EPERM, -EPERM); - ASSERT_EXIT(ret == 0); - - ret = kdbus_register_policy_holder(bus, POLICY_NAME, - &policy_holder); - ASSERT_RETURN(ret == 0); - - /* Try to register the same name with an activator */ - ret = kdbus_register_same_activator(bus, POLICY_NAME, - &activator); - ASSERT_RETURN(ret == 0); - - /* Acquire POLICY_NAME */ - ret = kdbus_name_acquire(conn_db[0], POLICY_NAME, NULL); - ASSERT_RETURN(ret == 0); - - ret = kdbus_normal_test(bus, POLICY_NAME, conn_db); - ASSERT_RETURN(ret == 0); - - ret = kdbus_list(conn_db[0], KDBUS_LIST_NAMES | - KDBUS_LIST_UNIQUE | - KDBUS_LIST_ACTIVATORS | - KDBUS_LIST_QUEUED); - ASSERT_RETURN(ret == 0); - - ret = kdbus_fork_test(bus, POLICY_NAME, conn_db, EXIT_SUCCESS); - ASSERT_RETURN(ret == 0); - - /* - * children connections are able to talk to conn_db[0] since - * current POLICY_NAME TALK type is KDBUS_POLICY_ACCESS_WORLD, - * so expect EXIT_SUCCESS when sending from child. However, - * since the child's connection does not own any well-known - * name, The parent connection conn_db[0] should fail with - * -EPERM but since it is a privileged bus user the TALK is - * allowed. - */ - ret = kdbus_fork_test_by_id(bus, conn_db, - EXIT_SUCCESS, EXIT_SUCCESS); - ASSERT_EXIT(ret == 0); - - /* - * Connections that can talk are perhaps being destroyed now. - * Restrict the policy and purge cache entries where the - * conn_db[0] is the destination. - * - * Now only connections with uid == 0 are allowed to talk. - */ - ret = kdbus_set_policy_talk(policy_holder, POLICY_NAME, - geteuid(), KDBUS_POLICY_ACCESS_USER); - ASSERT_RETURN(ret == 0); - - /* - * Testing connections (FORK+DROP) again: - * After setting the policy re-check connections - * we expect the children to fail with -EPERM - */ - ret = kdbus_fork_test(bus, POLICY_NAME, conn_db, -EPERM); - ASSERT_RETURN(ret == 0); - - /* - * Now expect that both parent and child to fail. - * - * Child should fail with -EPERM since we just restricted - * the POLICY_NAME TALK to uid 0 and its uid is 65534. - * - * Since the parent's connection will timeout when receiving - * from the child, we never continue. FWIW just put -EPERM. - */ - ret = kdbus_fork_test_by_id(bus, conn_db, -EPERM, -EPERM); - ASSERT_EXIT(ret == 0); - - /* Check if the name can be reached in a new userns */ - ret = kdbus_clone_userns_test(bus, POLICY_NAME, conn_db, -EPERM); - ASSERT_RETURN(ret == 0); - - for (i = 0; i < MAX_CONN; i++) - kdbus_conn_free(conn_db[i]); - - kdbus_conn_free(activator); - kdbus_conn_free(policy_holder); - - free(conn_db); - - return ret; -} diff --git a/tools/testing/selftests/kdbus/test-policy-priv.c b/tools/testing/selftests/kdbus/test-policy-priv.c deleted file mode 100644 index 0208638a7..000000000 --- a/tools/testing/selftests/kdbus/test-policy-priv.c +++ /dev/null @@ -1,1285 +0,0 @@ -#include <errno.h> -#include <stdio.h> -#include <string.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stdint.h> -#include <stdbool.h> -#include <unistd.h> -#include <time.h> -#include <sys/capability.h> -#include <sys/eventfd.h> -#include <sys/wait.h> - -#include "kdbus-test.h" -#include "kdbus-util.h" -#include "kdbus-enum.h" - -static int test_policy_priv_by_id(const char *bus, - struct kdbus_conn *conn_dst, - bool drop_second_user, - int parent_status, - int child_status) -{ - int ret = 0; - uint64_t expected_cookie = time(NULL) ^ 0xdeadbeef; - - ASSERT_RETURN(conn_dst); - - ret = RUN_UNPRIVILEGED_CONN(unpriv, bus, ({ - ret = kdbus_msg_send(unpriv, NULL, - expected_cookie, 0, 0, 0, - conn_dst->id); - ASSERT_EXIT(ret == child_status); - })); - ASSERT_RETURN(ret >= 0); - - ret = kdbus_msg_recv_poll(conn_dst, 300, NULL, NULL); - ASSERT_RETURN(ret == parent_status); - - return 0; -} - -static int test_policy_priv_by_broadcast(const char *bus, - struct kdbus_conn *conn_dst, - int drop_second_user, - int parent_status, - int child_status) -{ - int efd; - int ret = 0; - eventfd_t event_status = 0; - struct kdbus_msg *msg = NULL; - uid_t second_uid = UNPRIV_UID; - gid_t second_gid = UNPRIV_GID; - struct kdbus_conn *child_2 = conn_dst; - uint64_t expected_cookie = time(NULL) ^ 0xdeadbeef; - - /* Drop to another unprivileged user other than UNPRIV_UID */ - if (drop_second_user == DROP_OTHER_UNPRIV) { - second_uid = UNPRIV_UID - 1; - second_gid = UNPRIV_GID - 1; - } - - /* child will signal parent to send broadcast */ - efd = eventfd(0, EFD_CLOEXEC); - ASSERT_RETURN_VAL(efd >= 0, efd); - - ret = RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_GID, ({ - struct kdbus_conn *child; - - child = kdbus_hello(bus, 0, NULL, 0); - ASSERT_EXIT(child); - - ret = kdbus_add_match_empty(child); - ASSERT_EXIT(ret == 0); - - /* signal parent */ - ret = eventfd_write(efd, 1); - ASSERT_EXIT(ret == 0); - - /* Use a little bit high time */ - ret = kdbus_msg_recv_poll(child, 500, &msg, NULL); - ASSERT_EXIT(ret == child_status); - - /* - * If we expect the child to get the broadcast - * message, then check the received cookie. - */ - if (ret == 0) { - ASSERT_EXIT(expected_cookie == msg->cookie); - } - - /* Use expected_cookie since 'msg' might be NULL */ - ret = kdbus_msg_send(child, NULL, expected_cookie + 1, - 0, 0, 0, KDBUS_DST_ID_BROADCAST); - ASSERT_EXIT(ret == 0); - - kdbus_msg_free(msg); - kdbus_conn_free(child); - }), - ({ - if (drop_second_user == DO_NOT_DROP) { - ASSERT_RETURN(child_2); - - ret = eventfd_read(efd, &event_status); - ASSERT_RETURN(ret >= 0 && event_status == 1); - - ret = kdbus_msg_send(child_2, NULL, - expected_cookie, 0, 0, 0, - KDBUS_DST_ID_BROADCAST); - ASSERT_RETURN(ret == 0); - - /* drop own broadcast */ - ret = kdbus_msg_recv(child_2, &msg, NULL); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(msg->src_id == child_2->id); - kdbus_msg_free(msg); - - /* Use a little bit high time */ - ret = kdbus_msg_recv_poll(child_2, 1000, - &msg, NULL); - ASSERT_RETURN(ret == parent_status); - - /* - * Check returned cookie in case we expect - * success. - */ - if (ret == 0) { - ASSERT_RETURN(msg->cookie == - expected_cookie + 1); - } - - kdbus_msg_free(msg); - } else { - /* - * Two unprivileged users will try to - * communicate using broadcast. - */ - ret = RUN_UNPRIVILEGED(second_uid, second_gid, ({ - child_2 = kdbus_hello(bus, 0, NULL, 0); - ASSERT_EXIT(child_2); - - ret = kdbus_add_match_empty(child_2); - ASSERT_EXIT(ret == 0); - - ret = eventfd_read(efd, &event_status); - ASSERT_EXIT(ret >= 0 && event_status == 1); - - ret = kdbus_msg_send(child_2, NULL, - expected_cookie, 0, 0, 0, - KDBUS_DST_ID_BROADCAST); - ASSERT_EXIT(ret == 0); - - /* drop own broadcast */ - ret = kdbus_msg_recv(child_2, &msg, NULL); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(msg->src_id == child_2->id); - kdbus_msg_free(msg); - - /* Use a little bit high time */ - ret = kdbus_msg_recv_poll(child_2, 1000, - &msg, NULL); - ASSERT_EXIT(ret == parent_status); - - /* - * Check returned cookie in case we expect - * success. - */ - if (ret == 0) { - ASSERT_EXIT(msg->cookie == - expected_cookie + 1); - } - - kdbus_msg_free(msg); - kdbus_conn_free(child_2); - }), - ({ 0; })); - ASSERT_RETURN(ret == 0); - } - })); - ASSERT_RETURN(ret == 0); - - close(efd); - - return ret; -} - -static void nosig(int sig) -{ -} - -static int test_priv_before_policy_upload(struct kdbus_test_env *env) -{ - int ret = 0; - struct kdbus_conn *conn; - - conn = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn); - - /* - * Make sure unprivileged bus user cannot acquire names - * before registring any policy holder. - */ - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - ret = kdbus_name_acquire(unpriv, "com.example.a", NULL); - ASSERT_EXIT(ret < 0); - })); - ASSERT_RETURN(ret == 0); - - /* - * Make sure unprivileged bus users cannot talk by default - * to privileged ones, unless a policy holder that allows - * this was uploaded. - */ - - ret = test_policy_priv_by_id(env->buspath, conn, false, - -ETIMEDOUT, -EPERM); - ASSERT_RETURN(ret == 0); - - /* Activate matching for a privileged connection */ - ret = kdbus_add_match_empty(conn); - ASSERT_RETURN(ret == 0); - - /* - * First make sure that BROADCAST with msg flag - * KDBUS_MSG_EXPECT_REPLY will fail with -ENOTUNIQ - */ - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - ret = kdbus_msg_send(unpriv, NULL, 0xdeadbeef, - KDBUS_MSG_EXPECT_REPLY, - 5000000000ULL, 0, - KDBUS_DST_ID_BROADCAST); - ASSERT_EXIT(ret == -ENOTUNIQ); - })); - ASSERT_RETURN(ret == 0); - - /* - * Test broadcast with a privileged connection. - * - * The first unprivileged receiver should not get the - * broadcast message sent by the privileged connection, - * since there is no a TALK policy that allows the - * unprivileged to TALK to the privileged connection. It - * will fail with -ETIMEDOUT - * - * Then second case: - * The privileged connection should get the broadcast - * message from the unprivileged one. Since the receiver is - * a privileged bus user and it has default TALK access to - * all connections it will receive those. - */ - - ret = test_policy_priv_by_broadcast(env->buspath, conn, - DO_NOT_DROP, - 0, -ETIMEDOUT); - ASSERT_RETURN(ret == 0); - - - /* - * Test broadcast with two unprivileged connections running - * under the same user. - * - * Both connections should succeed. - */ - - ret = test_policy_priv_by_broadcast(env->buspath, NULL, - DROP_SAME_UNPRIV, 0, 0); - ASSERT_RETURN(ret == 0); - - /* - * Test broadcast with two unprivileged connections running - * under different users. - * - * Both connections will fail with -ETIMEDOUT. - */ - - ret = test_policy_priv_by_broadcast(env->buspath, NULL, - DROP_OTHER_UNPRIV, - -ETIMEDOUT, -ETIMEDOUT); - ASSERT_RETURN(ret == 0); - - kdbus_conn_free(conn); - - return ret; -} - -static int test_broadcast_after_policy_upload(struct kdbus_test_env *env) -{ - int ret; - int efd; - eventfd_t event_status = 0; - struct kdbus_msg *msg = NULL; - struct kdbus_conn *owner_a, *owner_b; - struct kdbus_conn *holder_a, *holder_b; - struct kdbus_policy_access access = {}; - uint64_t expected_cookie = time(NULL) ^ 0xdeadbeef; - - owner_a = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(owner_a); - - ret = kdbus_name_acquire(owner_a, "com.example.broadcastA", NULL); - ASSERT_EXIT(ret >= 0); - - /* - * Make sure unprivileged bus users cannot talk by default - * to privileged ones, unless a policy holder that allows - * this was uploaded. - */ - - ++expected_cookie; - ret = test_policy_priv_by_id(env->buspath, owner_a, false, - -ETIMEDOUT, -EPERM); - ASSERT_RETURN(ret == 0); - - /* - * Make sure that privileged won't receive broadcasts unless - * it installs a match. It will fail with -ETIMEDOUT - * - * At same time check that the unprivileged connection will - * not receive the broadcast message from the privileged one - * since the privileged one owns a name with a restricted - * policy TALK (actually the TALK policy is still not - * registered so we fail by default), thus the unprivileged - * receiver is not able to TALK to that name. - */ - - /* Activate matching for a privileged connection */ - ret = kdbus_add_match_empty(owner_a); - ASSERT_RETURN(ret == 0); - - /* - * Redo the previous test. The privileged conn owner_a is - * able to TALK to any connection so it will receive the - * broadcast message now. - */ - - ret = test_policy_priv_by_broadcast(env->buspath, owner_a, - DO_NOT_DROP, - 0, -ETIMEDOUT); - ASSERT_RETURN(ret == 0); - - /* - * Test that broadcast between two unprivileged users running - * under the same user still succeed. - */ - - ret = test_policy_priv_by_broadcast(env->buspath, NULL, - DROP_SAME_UNPRIV, 0, 0); - ASSERT_RETURN(ret == 0); - - /* - * Test broadcast with two unprivileged connections running - * under different users. - * - * Both connections will fail with -ETIMEDOUT. - */ - - ret = test_policy_priv_by_broadcast(env->buspath, NULL, - DROP_OTHER_UNPRIV, - -ETIMEDOUT, -ETIMEDOUT); - ASSERT_RETURN(ret == 0); - - access = (struct kdbus_policy_access){ - .type = KDBUS_POLICY_ACCESS_USER, - .id = geteuid(), - .access = KDBUS_POLICY_OWN, - }; - - holder_a = kdbus_hello_registrar(env->buspath, - "com.example.broadcastA", - &access, 1, - KDBUS_HELLO_POLICY_HOLDER); - ASSERT_RETURN(holder_a); - - holder_b = kdbus_hello_registrar(env->buspath, - "com.example.broadcastB", - &access, 1, - KDBUS_HELLO_POLICY_HOLDER); - ASSERT_RETURN(holder_b); - - /* Free connections and their received messages and restart */ - kdbus_conn_free(owner_a); - - owner_a = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(owner_a); - - /* Activate matching for a privileged connection */ - ret = kdbus_add_match_empty(owner_a); - ASSERT_RETURN(ret == 0); - - ret = kdbus_name_acquire(owner_a, "com.example.broadcastA", NULL); - ASSERT_EXIT(ret >= 0); - - owner_b = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(owner_b); - - ret = kdbus_name_acquire(owner_b, "com.example.broadcastB", NULL); - ASSERT_EXIT(ret >= 0); - - /* Activate matching for a privileged connection */ - ret = kdbus_add_match_empty(owner_b); - ASSERT_RETURN(ret == 0); - - /* - * Test that even if "com.example.broadcastA" and - * "com.example.broadcastB" do have a TALK access by default - * they are able to signal each other using broadcast due to - * the fact they are privileged connections, they receive - * all broadcasts if the match allows it. - */ - - ++expected_cookie; - ret = kdbus_msg_send(owner_a, NULL, expected_cookie, 0, - 0, 0, KDBUS_DST_ID_BROADCAST); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_recv_poll(owner_a, 100, &msg, NULL); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(msg->cookie == expected_cookie); - - /* Check src ID */ - ASSERT_RETURN(msg->src_id == owner_a->id); - - kdbus_msg_free(msg); - - ret = kdbus_msg_recv_poll(owner_b, 100, &msg, NULL); - ASSERT_RETURN(ret == 0); - ASSERT_RETURN(msg->cookie == expected_cookie); - - /* Check src ID */ - ASSERT_RETURN(msg->src_id == owner_a->id); - - kdbus_msg_free(msg); - - /* Release name "com.example.broadcastB" */ - - ret = kdbus_name_release(owner_b, "com.example.broadcastB"); - ASSERT_EXIT(ret >= 0); - - /* KDBUS_POLICY_OWN for unprivileged connections */ - access = (struct kdbus_policy_access){ - .type = KDBUS_POLICY_ACCESS_WORLD, - .id = geteuid(), - .access = KDBUS_POLICY_OWN, - }; - - /* Update the policy so unprivileged will own the name */ - - ret = kdbus_conn_update_policy(holder_b, - "com.example.broadcastB", - &access, 1); - ASSERT_RETURN(ret == 0); - - /* - * Send broadcasts from an unprivileged connection that - * owns a name "com.example.broadcastB". - * - * We'll have four destinations here: - * - * 1) destination owner_a: privileged connection that owns - * "com.example.broadcastA". It will receive the broadcast - * since it is a privileged has default TALK access to all - * connections, and it is subscribed to the match. - * Will succeed. - * - * owner_b: privileged connection (running under a different - * uid) that do not own names, but with an empty broadcast - * match, so it will receive broadcasts since it has default - * TALK access to all connection. - * - * unpriv_a: unpriv connection that do not own any name. - * It will receive the broadcast since it is running under - * the same user of the one broadcasting and did install - * matches. It should get the message. - * - * unpriv_b: unpriv connection is not interested in broadcast - * messages, so it did not install broadcast matches. Should - * fail with -ETIMEDOUT - */ - - ++expected_cookie; - efd = eventfd(0, EFD_CLOEXEC); - ASSERT_RETURN_VAL(efd >= 0, efd); - - ret = RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_UID, ({ - struct kdbus_conn *unpriv_owner; - struct kdbus_conn *unpriv_a, *unpriv_b; - - unpriv_owner = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_EXIT(unpriv_owner); - - unpriv_a = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_EXIT(unpriv_a); - - unpriv_b = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_EXIT(unpriv_b); - - ret = kdbus_name_acquire(unpriv_owner, - "com.example.broadcastB", - NULL); - ASSERT_EXIT(ret >= 0); - - ret = kdbus_add_match_empty(unpriv_a); - ASSERT_EXIT(ret == 0); - - /* Signal that we are doing broadcasts */ - ret = eventfd_write(efd, 1); - ASSERT_EXIT(ret == 0); - - /* - * Do broadcast from a connection that owns the - * names "com.example.broadcastB". - */ - ret = kdbus_msg_send(unpriv_owner, NULL, - expected_cookie, - 0, 0, 0, - KDBUS_DST_ID_BROADCAST); - ASSERT_EXIT(ret == 0); - - /* - * Unprivileged connection running under the same - * user. It should succeed. - */ - ret = kdbus_msg_recv_poll(unpriv_a, 300, &msg, NULL); - ASSERT_EXIT(ret == 0 && msg->cookie == expected_cookie); - - /* - * Did not install matches, not interested in - * broadcasts - */ - ret = kdbus_msg_recv_poll(unpriv_b, 300, NULL, NULL); - ASSERT_EXIT(ret == -ETIMEDOUT); - }), - ({ - ret = eventfd_read(efd, &event_status); - ASSERT_RETURN(ret >= 0 && event_status == 1); - - /* - * owner_a must fail with -ETIMEDOUT, since it owns - * name "com.example.broadcastA" and its TALK - * access is restriced. - */ - ret = kdbus_msg_recv_poll(owner_a, 300, &msg, NULL); - ASSERT_RETURN(ret == 0); - - /* confirm the received cookie */ - ASSERT_RETURN(msg->cookie == expected_cookie); - - kdbus_msg_free(msg); - - /* - * owner_b got the broadcast from an unprivileged - * connection. - */ - ret = kdbus_msg_recv_poll(owner_b, 300, &msg, NULL); - ASSERT_RETURN(ret == 0); - - /* confirm the received cookie */ - ASSERT_RETURN(msg->cookie == expected_cookie); - - kdbus_msg_free(msg); - - })); - ASSERT_RETURN(ret == 0); - - close(efd); - - /* - * Test broadcast with two unprivileged connections running - * under different users. - * - * Both connections will fail with -ETIMEDOUT. - */ - - ret = test_policy_priv_by_broadcast(env->buspath, NULL, - DROP_OTHER_UNPRIV, - -ETIMEDOUT, -ETIMEDOUT); - ASSERT_RETURN(ret == 0); - - /* Drop received broadcasts by privileged */ - ret = kdbus_msg_recv_poll(owner_a, 100, NULL, NULL); - ret = kdbus_msg_recv_poll(owner_a, 100, NULL, NULL); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_recv(owner_a, NULL, NULL); - ASSERT_RETURN(ret == -EAGAIN); - - ret = kdbus_msg_recv_poll(owner_b, 100, NULL, NULL); - ret = kdbus_msg_recv_poll(owner_b, 100, NULL, NULL); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_recv(owner_b, NULL, NULL); - ASSERT_RETURN(ret == -EAGAIN); - - /* - * Perform last tests, allow others to talk to name - * "com.example.broadcastA". So now receiving broadcasts - * from it should succeed since the TALK policy allow it. - */ - - /* KDBUS_POLICY_OWN for unprivileged connections */ - access = (struct kdbus_policy_access){ - .type = KDBUS_POLICY_ACCESS_WORLD, - .id = geteuid(), - .access = KDBUS_POLICY_TALK, - }; - - ret = kdbus_conn_update_policy(holder_a, - "com.example.broadcastA", - &access, 1); - ASSERT_RETURN(ret == 0); - - /* - * Unprivileged is able to TALK to "com.example.broadcastA" - * now so it will receive its broadcasts - */ - ret = test_policy_priv_by_broadcast(env->buspath, owner_a, - DO_NOT_DROP, 0, 0); - ASSERT_RETURN(ret == 0); - - ++expected_cookie; - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - ret = kdbus_name_acquire(unpriv, "com.example.broadcastB", - NULL); - ASSERT_EXIT(ret >= 0); - ret = kdbus_msg_send(unpriv, NULL, expected_cookie, - 0, 0, 0, KDBUS_DST_ID_BROADCAST); - ASSERT_EXIT(ret == 0); - })); - ASSERT_RETURN(ret == 0); - - /* owner_a is privileged it will get the broadcast now. */ - ret = kdbus_msg_recv_poll(owner_a, 300, &msg, NULL); - ASSERT_RETURN(ret == 0); - - /* confirm the received cookie */ - ASSERT_RETURN(msg->cookie == expected_cookie); - - kdbus_msg_free(msg); - - /* - * owner_a released name "com.example.broadcastA". It should - * receive broadcasts since it is still privileged and has - * the right match. - * - * Unprivileged connection will own a name and will try to - * signal to the privileged connection. - */ - - ret = kdbus_name_release(owner_a, "com.example.broadcastA"); - ASSERT_EXIT(ret >= 0); - - ++expected_cookie; - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - ret = kdbus_name_acquire(unpriv, "com.example.broadcastB", - NULL); - ASSERT_EXIT(ret >= 0); - ret = kdbus_msg_send(unpriv, NULL, expected_cookie, - 0, 0, 0, KDBUS_DST_ID_BROADCAST); - ASSERT_EXIT(ret == 0); - })); - ASSERT_RETURN(ret == 0); - - /* owner_a will get the broadcast now. */ - ret = kdbus_msg_recv_poll(owner_a, 300, &msg, NULL); - ASSERT_RETURN(ret == 0); - - /* confirm the received cookie */ - ASSERT_RETURN(msg->cookie == expected_cookie); - - kdbus_msg_free(msg); - - kdbus_conn_free(owner_a); - kdbus_conn_free(owner_b); - kdbus_conn_free(holder_a); - kdbus_conn_free(holder_b); - - return 0; -} - -static int test_policy_priv(struct kdbus_test_env *env) -{ - struct kdbus_conn *conn_a, *conn_b, *conn, *owner; - struct kdbus_policy_access access, *acc; - sigset_t sset; - size_t num; - int ret; - - /* - * Make sure we have CAP_SETUID/SETGID so we can drop privileges - */ - - ret = test_is_capable(CAP_SETUID, CAP_SETGID, -1); - ASSERT_RETURN(ret >= 0); - - if (!ret) - return TEST_SKIP; - - /* make sure that uids and gids are mapped */ - if (!all_uids_gids_are_mapped()) - return TEST_SKIP; - - /* - * Setup: - * conn_a: policy holder for com.example.a - * conn_b: name holder of com.example.b - */ - - signal(SIGUSR1, nosig); - sigemptyset(&sset); - sigaddset(&sset, SIGUSR1); - sigprocmask(SIG_BLOCK, &sset, NULL); - - conn = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn); - - /* - * Before registering any policy holder, make sure that the - * bus is secure by default. This test is necessary, it catches - * several cases where old D-Bus was vulnerable. - */ - - ret = test_priv_before_policy_upload(env); - ASSERT_RETURN(ret == 0); - - /* - * Make sure unprivileged are not able to register policy - * holders - */ - - ret = RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_GID, ({ - struct kdbus_conn *holder; - - holder = kdbus_hello_registrar(env->buspath, - "com.example.a", NULL, 0, - KDBUS_HELLO_POLICY_HOLDER); - ASSERT_EXIT(holder == NULL && errno == EPERM); - }), - ({ 0; })); - ASSERT_RETURN(ret == 0); - - - /* Register policy holder */ - - conn_a = kdbus_hello_registrar(env->buspath, "com.example.a", - NULL, 0, KDBUS_HELLO_POLICY_HOLDER); - ASSERT_RETURN(conn_a); - - conn_b = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn_b); - - ret = kdbus_name_acquire(conn_b, "com.example.b", NULL); - ASSERT_EXIT(ret >= 0); - - /* - * Make sure bus-owners can always acquire names. - */ - ret = kdbus_name_acquire(conn, "com.example.a", NULL); - ASSERT_EXIT(ret >= 0); - - kdbus_conn_free(conn); - - /* - * Make sure unprivileged users cannot acquire names with default - * policy assigned. - */ - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - ret = kdbus_name_acquire(unpriv, "com.example.a", NULL); - ASSERT_EXIT(ret < 0); - })); - ASSERT_RETURN(ret >= 0); - - /* - * Make sure unprivileged users can acquire names if we make them - * world-accessible. - */ - - access = (struct kdbus_policy_access){ - .type = KDBUS_POLICY_ACCESS_WORLD, - .id = 0, - .access = KDBUS_POLICY_OWN, - }; - - /* - * Make sure unprivileged/normal connections are not able - * to update policies - */ - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - ret = kdbus_conn_update_policy(unpriv, "com.example.a", - &access, 1); - ASSERT_EXIT(ret == -EOPNOTSUPP); - })); - ASSERT_RETURN(ret == 0); - - ret = kdbus_conn_update_policy(conn_a, "com.example.a", &access, 1); - ASSERT_RETURN(ret == 0); - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - ret = kdbus_name_acquire(unpriv, "com.example.a", NULL); - ASSERT_EXIT(ret >= 0); - })); - ASSERT_RETURN(ret >= 0); - - /* - * Make sure unprivileged users can acquire names if we make them - * gid-accessible. But only if the gid matches. - */ - - access = (struct kdbus_policy_access){ - .type = KDBUS_POLICY_ACCESS_GROUP, - .id = UNPRIV_GID, - .access = KDBUS_POLICY_OWN, - }; - - ret = kdbus_conn_update_policy(conn_a, "com.example.a", &access, 1); - ASSERT_RETURN(ret == 0); - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - ret = kdbus_name_acquire(unpriv, "com.example.a", NULL); - ASSERT_EXIT(ret >= 0); - })); - ASSERT_RETURN(ret >= 0); - - access = (struct kdbus_policy_access){ - .type = KDBUS_POLICY_ACCESS_GROUP, - .id = 1, - .access = KDBUS_POLICY_OWN, - }; - - ret = kdbus_conn_update_policy(conn_a, "com.example.a", &access, 1); - ASSERT_RETURN(ret == 0); - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - ret = kdbus_name_acquire(unpriv, "com.example.a", NULL); - ASSERT_EXIT(ret < 0); - })); - ASSERT_RETURN(ret >= 0); - - /* - * Make sure unprivileged users can acquire names if we make them - * uid-accessible. But only if the uid matches. - */ - - access = (struct kdbus_policy_access){ - .type = KDBUS_POLICY_ACCESS_USER, - .id = UNPRIV_UID, - .access = KDBUS_POLICY_OWN, - }; - - ret = kdbus_conn_update_policy(conn_a, "com.example.a", &access, 1); - ASSERT_RETURN(ret == 0); - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - ret = kdbus_name_acquire(unpriv, "com.example.a", NULL); - ASSERT_EXIT(ret >= 0); - })); - ASSERT_RETURN(ret >= 0); - - access = (struct kdbus_policy_access){ - .type = KDBUS_POLICY_ACCESS_USER, - .id = 1, - .access = KDBUS_POLICY_OWN, - }; - - ret = kdbus_conn_update_policy(conn_a, "com.example.a", &access, 1); - ASSERT_RETURN(ret == 0); - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - ret = kdbus_name_acquire(unpriv, "com.example.a", NULL); - ASSERT_EXIT(ret < 0); - })); - ASSERT_RETURN(ret >= 0); - - /* - * Make sure unprivileged users cannot acquire names if no owner-policy - * matches, even if SEE/TALK policies match. - */ - - num = 4; - acc = (struct kdbus_policy_access[]){ - { - .type = KDBUS_POLICY_ACCESS_GROUP, - .id = UNPRIV_GID, - .access = KDBUS_POLICY_SEE, - }, - { - .type = KDBUS_POLICY_ACCESS_USER, - .id = UNPRIV_UID, - .access = KDBUS_POLICY_TALK, - }, - { - .type = KDBUS_POLICY_ACCESS_WORLD, - .id = 0, - .access = KDBUS_POLICY_TALK, - }, - { - .type = KDBUS_POLICY_ACCESS_WORLD, - .id = 0, - .access = KDBUS_POLICY_SEE, - }, - }; - - ret = kdbus_conn_update_policy(conn_a, "com.example.a", acc, num); - ASSERT_RETURN(ret == 0); - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - ret = kdbus_name_acquire(unpriv, "com.example.a", NULL); - ASSERT_EXIT(ret < 0); - })); - ASSERT_RETURN(ret >= 0); - - /* - * Make sure unprivileged users can acquire names if the only matching - * policy is somewhere in the middle. - */ - - num = 5; - acc = (struct kdbus_policy_access[]){ - { - .type = KDBUS_POLICY_ACCESS_USER, - .id = 1, - .access = KDBUS_POLICY_OWN, - }, - { - .type = KDBUS_POLICY_ACCESS_USER, - .id = 2, - .access = KDBUS_POLICY_OWN, - }, - { - .type = KDBUS_POLICY_ACCESS_USER, - .id = UNPRIV_UID, - .access = KDBUS_POLICY_OWN, - }, - { - .type = KDBUS_POLICY_ACCESS_USER, - .id = 3, - .access = KDBUS_POLICY_OWN, - }, - { - .type = KDBUS_POLICY_ACCESS_USER, - .id = 4, - .access = KDBUS_POLICY_OWN, - }, - }; - - ret = kdbus_conn_update_policy(conn_a, "com.example.a", acc, num); - ASSERT_RETURN(ret == 0); - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - ret = kdbus_name_acquire(unpriv, "com.example.a", NULL); - ASSERT_EXIT(ret >= 0); - })); - ASSERT_RETURN(ret >= 0); - - /* - * Clear policies - */ - - ret = kdbus_conn_update_policy(conn_a, "com.example.a", NULL, 0); - ASSERT_RETURN(ret == 0); - - /* - * Make sure privileged bus users can _always_ talk to others. - */ - - conn = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn); - - ret = kdbus_msg_send(conn, "com.example.b", 0xdeadbeef, 0, 0, 0, 0); - ASSERT_EXIT(ret >= 0); - - ret = kdbus_msg_recv_poll(conn_b, 300, NULL, NULL); - ASSERT_EXIT(ret >= 0); - - kdbus_conn_free(conn); - - /* - * Make sure unprivileged bus users cannot talk by default. - */ - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0, - 0, 0); - ASSERT_EXIT(ret == -EPERM); - })); - ASSERT_RETURN(ret >= 0); - - /* - * Make sure unprivileged bus users can talk to equals, even without - * policy. - */ - - access = (struct kdbus_policy_access){ - .type = KDBUS_POLICY_ACCESS_USER, - .id = UNPRIV_UID, - .access = KDBUS_POLICY_OWN, - }; - - ret = kdbus_conn_update_policy(conn_a, "com.example.c", &access, 1); - ASSERT_RETURN(ret == 0); - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - struct kdbus_conn *owner; - - owner = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(owner); - - ret = kdbus_name_acquire(owner, "com.example.c", NULL); - ASSERT_EXIT(ret >= 0); - - ret = kdbus_msg_send(unpriv, "com.example.c", 0xdeadbeef, 0, 0, - 0, 0); - ASSERT_EXIT(ret >= 0); - ret = kdbus_msg_recv_poll(owner, 100, NULL, NULL); - ASSERT_EXIT(ret >= 0); - - kdbus_conn_free(owner); - })); - ASSERT_RETURN(ret >= 0); - - /* - * Make sure unprivileged bus users can talk to privileged users if a - * suitable UID policy is set. - */ - - access = (struct kdbus_policy_access){ - .type = KDBUS_POLICY_ACCESS_USER, - .id = UNPRIV_UID, - .access = KDBUS_POLICY_TALK, - }; - - ret = kdbus_conn_update_policy(conn_a, "com.example.b", &access, 1); - ASSERT_RETURN(ret == 0); - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0, - 0, 0); - ASSERT_EXIT(ret >= 0); - })); - ASSERT_RETURN(ret >= 0); - - ret = kdbus_msg_recv_poll(conn_b, 100, NULL, NULL); - ASSERT_EXIT(ret >= 0); - - /* - * Make sure unprivileged bus users can talk to privileged users if a - * suitable GID policy is set. - */ - - access = (struct kdbus_policy_access){ - .type = KDBUS_POLICY_ACCESS_GROUP, - .id = UNPRIV_GID, - .access = KDBUS_POLICY_TALK, - }; - - ret = kdbus_conn_update_policy(conn_a, "com.example.b", &access, 1); - ASSERT_RETURN(ret == 0); - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0, - 0, 0); - ASSERT_EXIT(ret >= 0); - })); - ASSERT_RETURN(ret >= 0); - - ret = kdbus_msg_recv_poll(conn_b, 100, NULL, NULL); - ASSERT_EXIT(ret >= 0); - - /* - * Make sure unprivileged bus users can talk to privileged users if a - * suitable WORLD policy is set. - */ - - access = (struct kdbus_policy_access){ - .type = KDBUS_POLICY_ACCESS_WORLD, - .id = 0, - .access = KDBUS_POLICY_TALK, - }; - - ret = kdbus_conn_update_policy(conn_a, "com.example.b", &access, 1); - ASSERT_RETURN(ret == 0); - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0, - 0, 0); - ASSERT_EXIT(ret >= 0); - })); - ASSERT_RETURN(ret >= 0); - - ret = kdbus_msg_recv_poll(conn_b, 100, NULL, NULL); - ASSERT_EXIT(ret >= 0); - - /* - * Make sure unprivileged bus users cannot talk to privileged users if - * no suitable policy is set. - */ - - num = 5; - acc = (struct kdbus_policy_access[]){ - { - .type = KDBUS_POLICY_ACCESS_USER, - .id = 0, - .access = KDBUS_POLICY_OWN, - }, - { - .type = KDBUS_POLICY_ACCESS_USER, - .id = 1, - .access = KDBUS_POLICY_TALK, - }, - { - .type = KDBUS_POLICY_ACCESS_USER, - .id = UNPRIV_UID, - .access = KDBUS_POLICY_SEE, - }, - { - .type = KDBUS_POLICY_ACCESS_USER, - .id = 3, - .access = KDBUS_POLICY_TALK, - }, - { - .type = KDBUS_POLICY_ACCESS_USER, - .id = 4, - .access = KDBUS_POLICY_TALK, - }, - }; - - ret = kdbus_conn_update_policy(conn_a, "com.example.b", acc, num); - ASSERT_RETURN(ret == 0); - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0, - 0, 0); - ASSERT_EXIT(ret == -EPERM); - })); - ASSERT_RETURN(ret >= 0); - - /* - * Make sure unprivileged bus users can talk to privileged users if a - * suitable OWN privilege overwrites TALK. - */ - - access = (struct kdbus_policy_access){ - .type = KDBUS_POLICY_ACCESS_WORLD, - .id = 0, - .access = KDBUS_POLICY_OWN, - }; - - ret = kdbus_conn_update_policy(conn_a, "com.example.b", &access, 1); - ASSERT_RETURN(ret == 0); - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0, - 0, 0); - ASSERT_EXIT(ret >= 0); - })); - ASSERT_RETURN(ret >= 0); - - ret = kdbus_msg_recv_poll(conn_b, 100, NULL, NULL); - ASSERT_EXIT(ret >= 0); - - /* - * Make sure the TALK cache is reset correctly when policies are - * updated. - */ - - access = (struct kdbus_policy_access){ - .type = KDBUS_POLICY_ACCESS_WORLD, - .id = 0, - .access = KDBUS_POLICY_TALK, - }; - - ret = kdbus_conn_update_policy(conn_a, "com.example.b", &access, 1); - ASSERT_RETURN(ret == 0); - - ret = RUN_UNPRIVILEGED_CONN(unpriv, env->buspath, ({ - ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0, - 0, 0); - ASSERT_EXIT(ret >= 0); - - ret = kdbus_msg_recv_poll(conn_b, 100, NULL, NULL); - ASSERT_EXIT(ret >= 0); - - ret = kdbus_conn_update_policy(conn_a, "com.example.b", - NULL, 0); - ASSERT_RETURN(ret == 0); - - ret = kdbus_msg_send(unpriv, "com.example.b", 0xdeadbeef, 0, 0, - 0, 0); - ASSERT_EXIT(ret == -EPERM); - })); - ASSERT_RETURN(ret >= 0); - - /* - * Make sure the TALK cache is reset correctly when policy holders - * disconnect. - */ - - access = (struct kdbus_policy_access){ - .type = KDBUS_POLICY_ACCESS_WORLD, - .id = 0, - .access = KDBUS_POLICY_OWN, - }; - - conn = kdbus_hello_registrar(env->buspath, "com.example.c", - NULL, 0, KDBUS_HELLO_POLICY_HOLDER); - ASSERT_RETURN(conn); - - ret = kdbus_conn_update_policy(conn, "com.example.c", &access, 1); - ASSERT_RETURN(ret == 0); - - owner = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(owner); - - ret = kdbus_name_acquire(owner, "com.example.c", NULL); - ASSERT_RETURN(ret >= 0); - - ret = RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_GID, ({ - struct kdbus_conn *unpriv; - - /* wait for parent to be finished */ - sigemptyset(&sset); - ret = sigsuspend(&sset); - ASSERT_RETURN(ret == -1 && errno == EINTR); - - unpriv = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(unpriv); - - ret = kdbus_msg_send(unpriv, "com.example.c", 0xdeadbeef, 0, 0, - 0, 0); - ASSERT_EXIT(ret >= 0); - - ret = kdbus_msg_recv_poll(owner, 100, NULL, NULL); - ASSERT_EXIT(ret >= 0); - - /* free policy holder */ - kdbus_conn_free(conn); - - ret = kdbus_msg_send(unpriv, "com.example.c", 0xdeadbeef, 0, 0, - 0, 0); - ASSERT_EXIT(ret == -EPERM); - - kdbus_conn_free(unpriv); - }), ({ - /* make sure policy holder is only valid in child */ - kdbus_conn_free(conn); - kill(pid, SIGUSR1); - })); - ASSERT_RETURN(ret >= 0); - - - /* - * The following tests are necessary. - */ - - ret = test_broadcast_after_policy_upload(env); - ASSERT_RETURN(ret == 0); - - kdbus_conn_free(owner); - - /* - * cleanup resources - */ - - kdbus_conn_free(conn_b); - kdbus_conn_free(conn_a); - - return TEST_OK; -} - -int kdbus_test_policy_priv(struct kdbus_test_env *env) -{ - pid_t pid; - int ret; - - /* make sure to exit() if a child returns from fork() */ - pid = getpid(); - ret = test_policy_priv(env); - if (pid != getpid()) - exit(1); - - return ret; -} diff --git a/tools/testing/selftests/kdbus/test-policy.c b/tools/testing/selftests/kdbus/test-policy.c deleted file mode 100644 index 96d20d5e9..000000000 --- a/tools/testing/selftests/kdbus/test-policy.c +++ /dev/null @@ -1,80 +0,0 @@ -#include <errno.h> -#include <stdio.h> -#include <string.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stdint.h> -#include <stdbool.h> -#include <unistd.h> - -#include "kdbus-test.h" -#include "kdbus-util.h" -#include "kdbus-enum.h" - -int kdbus_test_policy(struct kdbus_test_env *env) -{ - struct kdbus_conn *conn_a, *conn_b; - struct kdbus_policy_access access; - int ret; - - /* Invalid name */ - conn_a = kdbus_hello_registrar(env->buspath, ".example.a", - NULL, 0, KDBUS_HELLO_POLICY_HOLDER); - ASSERT_RETURN(conn_a == NULL); - - conn_a = kdbus_hello_registrar(env->buspath, "example", - NULL, 0, KDBUS_HELLO_POLICY_HOLDER); - ASSERT_RETURN(conn_a == NULL); - - conn_a = kdbus_hello_registrar(env->buspath, "com.example.a", - NULL, 0, KDBUS_HELLO_POLICY_HOLDER); - ASSERT_RETURN(conn_a); - - conn_b = kdbus_hello_registrar(env->buspath, "com.example.b", - NULL, 0, KDBUS_HELLO_POLICY_HOLDER); - ASSERT_RETURN(conn_b); - - /* - * Verify there cannot be any duplicate entries, except for specific vs. - * wildcard entries. - */ - - access = (struct kdbus_policy_access){ - .type = KDBUS_POLICY_ACCESS_USER, - .id = geteuid(), - .access = KDBUS_POLICY_SEE, - }; - - ret = kdbus_conn_update_policy(conn_a, "com.example.a", &access, 1); - ASSERT_RETURN(ret == 0); - - ret = kdbus_conn_update_policy(conn_b, "com.example.a", &access, 1); - ASSERT_RETURN(ret == -EEXIST); - - ret = kdbus_conn_update_policy(conn_b, "com.example.a.*", &access, 1); - ASSERT_RETURN(ret == 0); - - ret = kdbus_conn_update_policy(conn_a, "com.example.a.*", &access, 1); - ASSERT_RETURN(ret == -EEXIST); - - ret = kdbus_conn_update_policy(conn_a, "com.example.*", &access, 1); - ASSERT_RETURN(ret == 0); - - ret = kdbus_conn_update_policy(conn_b, "com.example.a", &access, 1); - ASSERT_RETURN(ret == 0); - - ret = kdbus_conn_update_policy(conn_b, "com.example.*", &access, 1); - ASSERT_RETURN(ret == -EEXIST); - - /* Invalid name */ - ret = kdbus_conn_update_policy(conn_b, ".example.*", &access, 1); - ASSERT_RETURN(ret == -EINVAL); - - ret = kdbus_conn_update_policy(conn_b, "example", &access, 1); - ASSERT_RETURN(ret == -EINVAL); - - kdbus_conn_free(conn_b); - kdbus_conn_free(conn_a); - - return TEST_OK; -} diff --git a/tools/testing/selftests/kdbus/test-sync.c b/tools/testing/selftests/kdbus/test-sync.c deleted file mode 100644 index 0655a545f..000000000 --- a/tools/testing/selftests/kdbus/test-sync.c +++ /dev/null @@ -1,369 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <stdint.h> -#include <errno.h> -#include <assert.h> -#include <pthread.h> -#include <stdbool.h> -#include <signal.h> -#include <sys/wait.h> -#include <sys/eventfd.h> - -#include "kdbus-api.h" -#include "kdbus-test.h" -#include "kdbus-util.h" -#include "kdbus-enum.h" - -static struct kdbus_conn *conn_a, *conn_b; -static unsigned int cookie = 0xdeadbeef; - -static void nop_handler(int sig) {} - -static int interrupt_sync(struct kdbus_conn *conn_src, - struct kdbus_conn *conn_dst) -{ - pid_t pid; - int ret, status; - struct kdbus_msg *msg = NULL; - struct sigaction sa = { - .sa_handler = nop_handler, - .sa_flags = SA_NOCLDSTOP|SA_RESTART, - }; - - cookie++; - pid = fork(); - ASSERT_RETURN_VAL(pid >= 0, pid); - - if (pid == 0) { - ret = sigaction(SIGINT, &sa, NULL); - ASSERT_EXIT(ret == 0); - - ret = kdbus_msg_send_sync(conn_dst, NULL, cookie, - KDBUS_MSG_EXPECT_REPLY, - 100000000ULL, 0, conn_src->id, -1); - ASSERT_EXIT(ret == -ETIMEDOUT); - - _exit(EXIT_SUCCESS); - } - - ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL); - ASSERT_RETURN(ret == 0 && msg->cookie == cookie); - - kdbus_msg_free(msg); - - ret = kill(pid, SIGINT); - ASSERT_RETURN_VAL(ret == 0, ret); - - ret = waitpid(pid, &status, 0); - ASSERT_RETURN_VAL(ret >= 0, ret); - - if (WIFSIGNALED(status)) - return TEST_ERR; - - ret = kdbus_msg_recv_poll(conn_src, 100, NULL, NULL); - ASSERT_RETURN(ret == -ETIMEDOUT); - - return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR; -} - -static int close_epipe_sync(const char *bus) -{ - pid_t pid; - int ret, status; - struct kdbus_conn *conn_src; - struct kdbus_conn *conn_dst; - struct kdbus_msg *msg = NULL; - - conn_src = kdbus_hello(bus, 0, NULL, 0); - ASSERT_RETURN(conn_src); - - ret = kdbus_add_match_empty(conn_src); - ASSERT_RETURN(ret == 0); - - conn_dst = kdbus_hello(bus, 0, NULL, 0); - ASSERT_RETURN(conn_dst); - - cookie++; - pid = fork(); - ASSERT_RETURN_VAL(pid >= 0, pid); - - if (pid == 0) { - uint64_t dst_id; - - /* close our reference */ - dst_id = conn_dst->id; - kdbus_conn_free(conn_dst); - - ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL); - ASSERT_EXIT(ret == 0 && msg->cookie == cookie); - ASSERT_EXIT(msg->src_id == dst_id); - - cookie++; - ret = kdbus_msg_send_sync(conn_src, NULL, cookie, - KDBUS_MSG_EXPECT_REPLY, - 100000000ULL, 0, dst_id, -1); - ASSERT_EXIT(ret == -EPIPE); - - _exit(EXIT_SUCCESS); - } - - ret = kdbus_msg_send(conn_dst, NULL, cookie, 0, 0, 0, - KDBUS_DST_ID_BROADCAST); - ASSERT_RETURN(ret == 0); - - cookie++; - ret = kdbus_msg_recv_poll(conn_dst, 100, &msg, NULL); - ASSERT_RETURN(ret == 0 && msg->cookie == cookie); - - kdbus_msg_free(msg); - - /* destroy connection */ - kdbus_conn_free(conn_dst); - kdbus_conn_free(conn_src); - - ret = waitpid(pid, &status, 0); - ASSERT_RETURN_VAL(ret >= 0, ret); - - if (!WIFEXITED(status)) - return TEST_ERR; - - return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR; -} - -static int cancel_fd_sync(struct kdbus_conn *conn_src, - struct kdbus_conn *conn_dst) -{ - pid_t pid; - int cancel_fd; - int ret, status; - uint64_t counter = 1; - struct kdbus_msg *msg = NULL; - - cancel_fd = eventfd(0, 0); - ASSERT_RETURN_VAL(cancel_fd >= 0, cancel_fd); - - cookie++; - pid = fork(); - ASSERT_RETURN_VAL(pid >= 0, pid); - - if (pid == 0) { - ret = kdbus_msg_send_sync(conn_dst, NULL, cookie, - KDBUS_MSG_EXPECT_REPLY, - 100000000ULL, 0, conn_src->id, - cancel_fd); - ASSERT_EXIT(ret == -ECANCELED); - - _exit(EXIT_SUCCESS); - } - - ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL); - ASSERT_RETURN(ret == 0 && msg->cookie == cookie); - - kdbus_msg_free(msg); - - ret = write(cancel_fd, &counter, sizeof(counter)); - ASSERT_RETURN(ret == sizeof(counter)); - - ret = waitpid(pid, &status, 0); - ASSERT_RETURN_VAL(ret >= 0, ret); - - if (WIFSIGNALED(status)) - return TEST_ERR; - - return (status == EXIT_SUCCESS) ? TEST_OK : TEST_ERR; -} - -static int no_cancel_sync(struct kdbus_conn *conn_src, - struct kdbus_conn *conn_dst) -{ - pid_t pid; - int cancel_fd; - int ret, status; - struct kdbus_msg *msg = NULL; - - /* pass eventfd, but never signal it so it shouldn't have any effect */ - - cancel_fd = eventfd(0, 0); - ASSERT_RETURN_VAL(cancel_fd >= 0, cancel_fd); - - cookie++; - pid = fork(); - ASSERT_RETURN_VAL(pid >= 0, pid); - - if (pid == 0) { - ret = kdbus_msg_send_sync(conn_dst, NULL, cookie, - KDBUS_MSG_EXPECT_REPLY, - 100000000ULL, 0, conn_src->id, - cancel_fd); - ASSERT_EXIT(ret == 0); - - _exit(EXIT_SUCCESS); - } - - ret = kdbus_msg_recv_poll(conn_src, 100, &msg, NULL); - ASSERT_RETURN_VAL(ret == 0 && msg->cookie == cookie, -1); - - kdbus_msg_free(msg); - - ret = kdbus_msg_send_reply(conn_src, cookie, conn_dst->id); - ASSERT_RETURN_VAL(ret >= 0, ret); - - ret = waitpid(pid, &status, 0); - ASSERT_RETURN_VAL(ret >= 0, ret); - - if (WIFSIGNALED(status)) - return -1; - - return (status == EXIT_SUCCESS) ? 0 : -1; -} - -static void *run_thread_reply(void *data) -{ - int ret; - unsigned long status = TEST_OK; - - ret = kdbus_msg_recv_poll(conn_a, 3000, NULL, NULL); - if (ret < 0) - goto exit_thread; - - kdbus_printf("Thread received message, sending reply ...\n"); - - /* using an unknown cookie must fail */ - ret = kdbus_msg_send_reply(conn_a, ~cookie, conn_b->id); - if (ret != -EBADSLT) { - status = TEST_ERR; - goto exit_thread; - } - - ret = kdbus_msg_send_reply(conn_a, cookie, conn_b->id); - if (ret != 0) { - status = TEST_ERR; - goto exit_thread; - } - -exit_thread: - pthread_exit(NULL); - return (void *) status; -} - -int kdbus_test_sync_reply(struct kdbus_test_env *env) -{ - unsigned long status; - pthread_t thread; - int ret; - - conn_a = kdbus_hello(env->buspath, 0, NULL, 0); - conn_b = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn_a && conn_b); - - pthread_create(&thread, NULL, run_thread_reply, NULL); - - ret = kdbus_msg_send_sync(conn_b, NULL, cookie, - KDBUS_MSG_EXPECT_REPLY, - 5000000000ULL, 0, conn_a->id, -1); - - pthread_join(thread, (void *) &status); - ASSERT_RETURN(status == 0); - ASSERT_RETURN(ret == 0); - - ret = interrupt_sync(conn_a, conn_b); - ASSERT_RETURN(ret == 0); - - ret = close_epipe_sync(env->buspath); - ASSERT_RETURN(ret == 0); - - ret = cancel_fd_sync(conn_a, conn_b); - ASSERT_RETURN(ret == 0); - - ret = no_cancel_sync(conn_a, conn_b); - ASSERT_RETURN(ret == 0); - - kdbus_printf("-- closing bus connections\n"); - - kdbus_conn_free(conn_a); - kdbus_conn_free(conn_b); - - return TEST_OK; -} - -#define BYEBYE_ME ((void*)0L) -#define BYEBYE_THEM ((void*)1L) - -static void *run_thread_byebye(void *data) -{ - struct kdbus_cmd cmd_byebye = { .size = sizeof(cmd_byebye) }; - int ret; - - ret = kdbus_msg_recv_poll(conn_a, 3000, NULL, NULL); - if (ret == 0) { - kdbus_printf("Thread received message, invoking BYEBYE ...\n"); - kdbus_msg_recv(conn_a, NULL, NULL); - if (data == BYEBYE_ME) - kdbus_cmd_byebye(conn_b->fd, &cmd_byebye); - else if (data == BYEBYE_THEM) - kdbus_cmd_byebye(conn_a->fd, &cmd_byebye); - } - - pthread_exit(NULL); - return NULL; -} - -int kdbus_test_sync_byebye(struct kdbus_test_env *env) -{ - pthread_t thread; - int ret; - - /* - * This sends a synchronous message to a thread, which waits until it - * received the message and then invokes BYEBYE on the *ORIGINAL* - * connection. That is, on the same connection that synchronously waits - * for an reply. - * This should properly wake the connection up and cause ECONNRESET as - * the connection is disconnected now. - * - * The second time, we do the same but invoke BYEBYE on the *TARGET* - * connection. This should also wake up the synchronous sender as the - * reply cannot be sent by a disconnected target. - */ - - conn_a = kdbus_hello(env->buspath, 0, NULL, 0); - conn_b = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn_a && conn_b); - - pthread_create(&thread, NULL, run_thread_byebye, BYEBYE_ME); - - ret = kdbus_msg_send_sync(conn_b, NULL, cookie, - KDBUS_MSG_EXPECT_REPLY, - 5000000000ULL, 0, conn_a->id, -1); - - ASSERT_RETURN(ret == -ECONNRESET); - - pthread_join(thread, NULL); - - kdbus_conn_free(conn_a); - kdbus_conn_free(conn_b); - - conn_a = kdbus_hello(env->buspath, 0, NULL, 0); - conn_b = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn_a && conn_b); - - pthread_create(&thread, NULL, run_thread_byebye, BYEBYE_THEM); - - ret = kdbus_msg_send_sync(conn_b, NULL, cookie, - KDBUS_MSG_EXPECT_REPLY, - 5000000000ULL, 0, conn_a->id, -1); - - ASSERT_RETURN(ret == -EPIPE); - - pthread_join(thread, NULL); - - kdbus_conn_free(conn_a); - kdbus_conn_free(conn_b); - - return TEST_OK; -} diff --git a/tools/testing/selftests/kdbus/test-timeout.c b/tools/testing/selftests/kdbus/test-timeout.c deleted file mode 100644 index cfd193066..000000000 --- a/tools/testing/selftests/kdbus/test-timeout.c +++ /dev/null @@ -1,99 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <fcntl.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <stdint.h> -#include <errno.h> -#include <assert.h> -#include <poll.h> -#include <stdbool.h> - -#include "kdbus-api.h" -#include "kdbus-test.h" -#include "kdbus-util.h" -#include "kdbus-enum.h" - -int timeout_msg_recv(struct kdbus_conn *conn, uint64_t *expected) -{ - struct kdbus_cmd_recv recv = { .size = sizeof(recv) }; - struct kdbus_msg *msg; - int ret; - - ret = kdbus_cmd_recv(conn->fd, &recv); - if (ret < 0) { - kdbus_printf("error receiving message: %d (%m)\n", ret); - return ret; - } - - msg = (struct kdbus_msg *)(conn->buf + recv.msg.offset); - - ASSERT_RETURN_VAL(msg->payload_type == KDBUS_PAYLOAD_KERNEL, -EINVAL); - ASSERT_RETURN_VAL(msg->src_id == KDBUS_SRC_ID_KERNEL, -EINVAL); - ASSERT_RETURN_VAL(msg->dst_id == conn->id, -EINVAL); - - *expected &= ~(1ULL << msg->cookie_reply); - kdbus_printf("Got message timeout for cookie %llu\n", - msg->cookie_reply); - - ret = kdbus_free(conn, recv.msg.offset); - if (ret < 0) - return ret; - - return 0; -} - -int kdbus_test_timeout(struct kdbus_test_env *env) -{ - struct kdbus_conn *conn_a, *conn_b; - struct pollfd fd; - int ret, i, n_msgs = 4; - uint64_t expected = 0; - uint64_t cookie = 0xdeadbeef; - - conn_a = kdbus_hello(env->buspath, 0, NULL, 0); - conn_b = kdbus_hello(env->buspath, 0, NULL, 0); - ASSERT_RETURN(conn_a && conn_b); - - fd.fd = conn_b->fd; - - /* - * send messages that expect a reply (within 100 msec), - * but never answer it. - */ - for (i = 0; i < n_msgs; i++, cookie++) { - kdbus_printf("Sending message with cookie %llu ...\n", - (unsigned long long)cookie); - ASSERT_RETURN(kdbus_msg_send(conn_b, NULL, cookie, - KDBUS_MSG_EXPECT_REPLY, - (i + 1) * 100ULL * 1000000ULL, 0, - conn_a->id) == 0); - expected |= 1ULL << cookie; - } - - for (;;) { - fd.events = POLLIN | POLLPRI | POLLHUP; - fd.revents = 0; - - ret = poll(&fd, 1, (n_msgs + 1) * 100); - if (ret == 0) - kdbus_printf("--- timeout\n"); - if (ret <= 0) - break; - - if (fd.revents & POLLIN) - ASSERT_RETURN(!timeout_msg_recv(conn_b, &expected)); - - if (expected == 0) - break; - } - - ASSERT_RETURN(expected == 0); - - kdbus_conn_free(conn_a); - kdbus_conn_free(conn_b); - - return TEST_OK; -} |