summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/kdbus/test-policy-priv.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/testing/selftests/kdbus/test-policy-priv.c')
-rw-r--r--tools/testing/selftests/kdbus/test-policy-priv.c1285
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;
-}