diff options
Diffstat (limited to 'tools/testing/selftests/kdbus/test-policy-priv.c')
-rw-r--r-- | tools/testing/selftests/kdbus/test-policy-priv.c | 1285 |
1 files changed, 0 insertions, 1285 deletions
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; -} |