2 * Test metadata in new namespaces. Even if our tests can run
3 * in a namespaced setup, this test is necessary so we can inspect
4 * metadata on the same kdbusfs but between multiple namespaces
20 #include <sys/prctl.h>
21 #include <sys/eventfd.h>
22 #include <sys/syscall.h>
23 #include <sys/capability.h>
24 #include <linux/sched.h>
26 #include "kdbus-test.h"
27 #include "kdbus-util.h"
28 #include "kdbus-enum.h"
30 static const struct kdbus_creds privileged_creds = {};
32 static const struct kdbus_creds unmapped_creds = {
43 static const struct kdbus_pids unmapped_pids = {};
45 /* Get only the first item */
46 static struct kdbus_item *kdbus_get_item(struct kdbus_msg *msg,
49 struct kdbus_item *item;
51 KDBUS_ITEM_FOREACH(item, msg, items)
52 if (item->type == type)
58 static int kdbus_match_kdbus_creds(struct kdbus_msg *msg,
59 const struct kdbus_creds *expected_creds)
61 struct kdbus_item *item;
63 item = kdbus_get_item(msg, KDBUS_ITEM_CREDS);
66 ASSERT_RETURN(memcmp(&item->creds, expected_creds,
67 sizeof(struct kdbus_creds)) == 0);
72 static int kdbus_match_kdbus_pids(struct kdbus_msg *msg,
73 const struct kdbus_pids *expected_pids)
75 struct kdbus_item *item;
77 item = kdbus_get_item(msg, KDBUS_ITEM_PIDS);
80 ASSERT_RETURN(memcmp(&item->pids, expected_pids,
81 sizeof(struct kdbus_pids)) == 0);
86 static int __kdbus_clone_userns_test(const char *bus,
87 struct kdbus_conn *conn,
93 struct kdbus_msg *msg = NULL;
94 const struct kdbus_item *item;
95 uint64_t cookie = time(NULL) ^ 0xdeadbeef;
96 struct kdbus_conn *unpriv_conn = NULL;
97 struct kdbus_pids parent_pids = {
103 ret = drop_privileges(UNPRIV_UID, UNPRIV_GID);
104 ASSERT_EXIT(ret == 0);
106 unpriv_conn = kdbus_hello(bus, 0, NULL, 0);
107 ASSERT_EXIT(unpriv_conn);
109 ret = kdbus_add_match_empty(unpriv_conn);
110 ASSERT_EXIT(ret == 0);
113 * ping privileged connection from this new unprivileged
117 ret = kdbus_msg_send(unpriv_conn, NULL, cookie, 0, 0,
118 0, conn->id, 0, NULL);
119 ASSERT_EXIT(ret == 0);
122 * Since we just dropped privileges, the dumpable flag
123 * was just cleared which makes the /proc/$clone_child/uid_map
124 * to be owned by root, hence any userns uid mapping will fail
125 * with -EPERM since the mapping will be done by uid 65534.
127 * To avoid this set the dumpable flag again which makes
128 * procfs update the /proc/$clone_child/ inodes owner to 65534.
130 * Using this we will be able write to /proc/$clone_child/uid_map
131 * as uid 65534 and map the uid 65534 to 0 inside the user namespace.
133 ret = prctl(PR_SET_DUMPABLE, SUID_DUMP_USER);
134 ASSERT_EXIT(ret == 0);
136 /* Make child privileged in its new userns and run tests */
138 ret = RUN_CLONE_CHILD(&clone_ret,
139 SIGCHLD | CLONE_NEWUSER | CLONE_NEWPID,
140 ({ 0; /* Clone setup, nothing */ }),
142 eventfd_t event_status = 0;
143 struct kdbus_conn *userns_conn;
145 /* ping connection from the new user namespace */
146 userns_conn = kdbus_hello(bus, 0, NULL, 0);
147 ASSERT_EXIT(userns_conn);
149 ret = kdbus_add_match_empty(userns_conn);
150 ASSERT_EXIT(ret == 0);
153 ret = kdbus_msg_send(userns_conn, NULL, cookie,
154 0, 0, 0, conn->id, 0, NULL);
155 ASSERT_EXIT(ret == 0);
157 /* Parent did send */
158 ret = eventfd_read(signal_fd, &event_status);
159 ASSERT_RETURN(ret >= 0 && event_status == 1);
162 * Receive from privileged connection
164 kdbus_printf("Privileged → unprivileged/privileged "
166 "(different userns and pidns):\n");
167 ret = kdbus_msg_recv_poll(userns_conn, 300, &msg, NULL);
168 ASSERT_EXIT(ret == 0);
169 ASSERT_EXIT(msg->dst_id == userns_conn->id);
171 /* Different namespaces no CAPS */
172 item = kdbus_get_item(msg, KDBUS_ITEM_CAPS);
173 ASSERT_EXIT(item == NULL);
175 /* uid/gid not mapped, so we have unpriv cached creds */
176 ret = kdbus_match_kdbus_creds(msg, &unmapped_creds);
177 ASSERT_EXIT(ret == 0);
180 * Diffent pid namepsaces. This is the child pidns
181 * so it should not see its parent kdbus_pids
183 ret = kdbus_match_kdbus_pids(msg, &unmapped_pids);
184 ASSERT_EXIT(ret == 0);
190 * Receive broadcast from privileged connection
192 kdbus_printf("Privileged → unprivileged/privileged "
194 "(different userns and pidns):\n");
195 ret = kdbus_msg_recv_poll(userns_conn, 300, &msg, NULL);
196 ASSERT_EXIT(ret == 0);
197 ASSERT_EXIT(msg->dst_id == KDBUS_DST_ID_BROADCAST);
199 /* Different namespaces no CAPS */
200 item = kdbus_get_item(msg, KDBUS_ITEM_CAPS);
201 ASSERT_EXIT(item == NULL);
203 /* uid/gid not mapped, so we have unpriv cached creds */
204 ret = kdbus_match_kdbus_creds(msg, &unmapped_creds);
205 ASSERT_EXIT(ret == 0);
208 * Diffent pid namepsaces. This is the child pidns
209 * so it should not see its parent kdbus_pids
211 ret = kdbus_match_kdbus_pids(msg, &unmapped_pids);
212 ASSERT_EXIT(ret == 0);
216 kdbus_conn_free(userns_conn);
219 /* Parent setup map child uid/gid */
220 ret = userns_map_uid_gid(pid, "0 65534 1", "0 65534 1");
221 ASSERT_EXIT(ret == 0);
224 /* Unprivileged was not able to create user namespace */
225 if (clone_ret == -EPERM) {
226 kdbus_printf("-- CLONE_NEWUSER TEST Failed for "
227 "uid: %u\n -- Make sure that your kernel "
228 "do not allow CLONE_NEWUSER for "
229 "unprivileged users\n", UNPRIV_UID);
234 ASSERT_EXIT(ret == 0);
238 * Receive from privileged connection
240 kdbus_printf("\nPrivileged → unprivileged (same namespaces):\n");
241 ret = kdbus_msg_recv_poll(unpriv_conn, 300, &msg, NULL);
243 ASSERT_EXIT(ret == 0);
244 ASSERT_EXIT(msg->dst_id == unpriv_conn->id);
246 /* will get the privileged creds */
247 ret = kdbus_match_kdbus_creds(msg, &privileged_creds);
248 ASSERT_EXIT(ret == 0);
250 /* Same pidns so will get the kdbus_pids */
251 ret = kdbus_match_kdbus_pids(msg, &parent_pids);
252 ASSERT_RETURN(ret == 0);
258 * Receive broadcast from privileged connection
260 kdbus_printf("\nPrivileged → unprivileged (same namespaces):\n");
261 ret = kdbus_msg_recv_poll(unpriv_conn, 300, &msg, NULL);
263 ASSERT_EXIT(ret == 0);
264 ASSERT_EXIT(msg->dst_id == KDBUS_DST_ID_BROADCAST);
266 /* will get the privileged creds */
267 ret = kdbus_match_kdbus_creds(msg, &privileged_creds);
268 ASSERT_EXIT(ret == 0);
270 ret = kdbus_match_kdbus_pids(msg, &parent_pids);
271 ASSERT_RETURN(ret == 0);
276 kdbus_conn_free(unpriv_conn);
281 static int kdbus_clone_userns_test(const char *bus,
282 struct kdbus_conn *conn)
288 uint64_t unpriv_conn_id = 0;
289 uint64_t userns_conn_id = 0;
290 struct kdbus_msg *msg;
291 const struct kdbus_item *item;
292 struct kdbus_pids expected_pids;
293 struct kdbus_conn *monitor = NULL;
295 kdbus_printf("STARTING TEST 'metadata-ns'.\n");
297 monitor = kdbus_hello(bus, KDBUS_HELLO_MONITOR, NULL, 0);
298 ASSERT_EXIT(monitor);
301 * parent will signal to child that is in its
302 * userns to read its queue
304 efd = eventfd(0, EFD_CLOEXEC);
305 ASSERT_RETURN_VAL(efd >= 0, efd);
310 ASSERT_RETURN_VAL(pid >= 0, -errno);
313 ret = prctl(PR_SET_PDEATHSIG, SIGKILL);
314 ASSERT_EXIT_VAL(ret == 0, -errno);
316 ret = __kdbus_clone_userns_test(bus, conn, ppid, efd);
321 /* Phase 1) privileged receives from unprivileged */
324 * Receive from the unprivileged child
326 kdbus_printf("\nUnprivileged → privileged (same namespaces):\n");
327 ret = kdbus_msg_recv_poll(conn, 300, &msg, NULL);
328 ASSERT_RETURN(ret == 0);
330 unpriv_conn_id = msg->src_id;
332 /* Unprivileged user */
333 ret = kdbus_match_kdbus_creds(msg, &unmapped_creds);
334 ASSERT_RETURN(ret == 0);
336 /* Set the expected creds_pids */
337 expected_pids = (struct kdbus_pids) {
342 ret = kdbus_match_kdbus_pids(msg, &expected_pids);
343 ASSERT_RETURN(ret == 0);
349 * Receive from the unprivileged that is in his own
353 kdbus_printf("\nUnprivileged/privileged in its userns → privileged "
354 "(different userns and pidns)\n");
355 ret = kdbus_msg_recv_poll(conn, 300, &msg, NULL);
356 if (ret == -ETIMEDOUT)
357 /* perhaps unprivileged userns is not allowed */
360 ASSERT_RETURN(ret == 0);
362 userns_conn_id = msg->src_id;
364 /* We do not share the userns, os no KDBUS_ITEM_CAPS */
365 item = kdbus_get_item(msg, KDBUS_ITEM_CAPS);
366 ASSERT_RETURN(item == NULL);
369 * Compare received items, creds must be translated into
370 * the receiver user namespace, so the user is unprivileged
372 ret = kdbus_match_kdbus_creds(msg, &unmapped_creds);
373 ASSERT_RETURN(ret == 0);
376 * We should have the kdbus_pids since we are the parent
379 item = kdbus_get_item(msg, KDBUS_ITEM_PIDS);
382 ASSERT_RETURN(memcmp(&item->pids, &unmapped_pids,
383 sizeof(struct kdbus_pids)) != 0);
386 * Parent pid of the unprivileged/privileged in its userns
387 * is the unprivileged child pid that was forked here.
389 ASSERT_RETURN((uint64_t)pid == item->pids.ppid);
394 /* Phase 2) Privileged connection sends now 3 packets */
397 * Sending to unprivileged connections a unicast
399 ret = kdbus_msg_send(conn, NULL, 0xdeadbeef, 0, 0,
400 0, unpriv_conn_id, 0, NULL);
401 ASSERT_RETURN(ret == 0);
403 /* signal to child that is in its userns */
404 ret = eventfd_write(efd, 1);
405 ASSERT_EXIT(ret == 0);
408 * Sending to unprivileged/privilged in its userns
409 * connections a unicast
411 ret = kdbus_msg_send(conn, NULL, 0xdeadbeef, 0, 0,
412 0, userns_conn_id, 0, NULL);
413 ASSERT_RETURN(ret == 0);
416 * Sending to unprivileged connections a broadcast
418 ret = kdbus_msg_send(conn, NULL, 0xdeadbeef, 0, 0,
419 0, KDBUS_DST_ID_BROADCAST, 0, NULL);
420 ASSERT_RETURN(ret == 0);
424 ret = waitpid(pid, &status, 0);
425 ASSERT_RETURN(ret >= 0);
427 ASSERT_RETURN(WIFEXITED(status))
428 ASSERT_RETURN(!WEXITSTATUS(status));
430 /* Dump monitor queue */
431 kdbus_printf("\n\nMonitor queue:\n");
433 ret = kdbus_msg_recv_poll(monitor, 100, &msg, NULL);
437 if (msg->payload_type == KDBUS_PAYLOAD_DBUS) {
439 * Parent pidns should see all the
442 item = kdbus_get_item(msg, KDBUS_ITEM_PIDS);
445 ASSERT_RETURN(item->pids.pid != 0 &&
446 item->pids.tid != 0 &&
447 item->pids.ppid != 0);
453 kdbus_conn_free(monitor);
459 int kdbus_test_metadata_ns(struct kdbus_test_env *env)
462 struct kdbus_conn *holder, *conn;
463 struct kdbus_policy_access policy_access = {
464 /* Allow world so we can inspect metadata in namespace */
465 .type = KDBUS_POLICY_ACCESS_WORLD,
467 .access = KDBUS_POLICY_TALK,
471 * We require user-namespaces and all uids/gids
472 * should be mapped (we can just require the necessary ones)
474 if (!config_user_ns_is_enabled() ||
475 !all_uids_gids_are_mapped())
478 ret = test_is_capable(CAP_SETUID, CAP_SETGID, CAP_SYS_ADMIN, -1);
479 ASSERT_RETURN(ret >= 0);
481 /* no enough privileges, SKIP test */
485 holder = kdbus_hello_registrar(env->buspath, "com.example.metadata",
487 KDBUS_HELLO_POLICY_HOLDER);
488 ASSERT_RETURN(holder);
490 conn = kdbus_hello(env->buspath, 0, NULL, 0);
493 ret = kdbus_add_match_empty(conn);
494 ASSERT_RETURN(ret == 0);
496 ret = kdbus_name_acquire(conn, "com.example.metadata", NULL);
497 ASSERT_EXIT(ret >= 0);
499 ret = kdbus_clone_userns_test(env->buspath, conn);
500 ASSERT_RETURN(ret == 0);
502 kdbus_conn_free(holder);
503 kdbus_conn_free(conn);