kdbus: the driver, original and non-working
[platform/kernel/linux-rpi.git] / tools / testing / selftests / kdbus / test-metadata-ns.c
1 /*
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
5  */
6
7 #include <stdio.h>
8 #include <string.h>
9 #include <sched.h>
10 #include <time.h>
11 #include <fcntl.h>
12 #include <stdlib.h>
13 #include <stddef.h>
14 #include <unistd.h>
15 #include <stdint.h>
16 #include <errno.h>
17 #include <assert.h>
18 #include <signal.h>
19 #include <sys/wait.h>
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>
25
26 #include "kdbus-test.h"
27 #include "kdbus-util.h"
28 #include "kdbus-enum.h"
29
30 static const struct kdbus_creds privileged_creds = {};
31
32 static const struct kdbus_creds unmapped_creds = {
33         .uid    = UNPRIV_UID,
34         .euid   = UNPRIV_UID,
35         .suid   = UNPRIV_UID,
36         .fsuid  = UNPRIV_UID,
37         .gid    = UNPRIV_GID,
38         .egid   = UNPRIV_GID,
39         .sgid   = UNPRIV_GID,
40         .fsgid  = UNPRIV_GID,
41 };
42
43 static const struct kdbus_pids unmapped_pids = {};
44
45 /* Get only the first item */
46 static struct kdbus_item *kdbus_get_item(struct kdbus_msg *msg,
47                                          uint64_t type)
48 {
49         struct kdbus_item *item;
50
51         KDBUS_ITEM_FOREACH(item, msg, items)
52                 if (item->type == type)
53                         return item;
54
55         return NULL;
56 }
57
58 static int kdbus_match_kdbus_creds(struct kdbus_msg *msg,
59                                    const struct kdbus_creds *expected_creds)
60 {
61         struct kdbus_item *item;
62
63         item = kdbus_get_item(msg, KDBUS_ITEM_CREDS);
64         ASSERT_RETURN(item);
65
66         ASSERT_RETURN(memcmp(&item->creds, expected_creds,
67                              sizeof(struct kdbus_creds)) == 0);
68
69         return 0;
70 }
71
72 static int kdbus_match_kdbus_pids(struct kdbus_msg *msg,
73                                   const struct kdbus_pids *expected_pids)
74 {
75         struct kdbus_item *item;
76
77         item = kdbus_get_item(msg, KDBUS_ITEM_PIDS);
78         ASSERT_RETURN(item);
79
80         ASSERT_RETURN(memcmp(&item->pids, expected_pids,
81                              sizeof(struct kdbus_pids)) == 0);
82
83         return 0;
84 }
85
86 static int __kdbus_clone_userns_test(const char *bus,
87                                      struct kdbus_conn *conn,
88                                      uint64_t grandpa_pid,
89                                      int signal_fd)
90 {
91         int clone_ret;
92         int ret;
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 = {
98                 .pid = getppid(),
99                 .tid = getppid(),
100                 .ppid = grandpa_pid,
101         };
102
103         ret = drop_privileges(UNPRIV_UID, UNPRIV_GID);
104         ASSERT_EXIT(ret == 0);
105
106         unpriv_conn = kdbus_hello(bus, 0, NULL, 0);
107         ASSERT_EXIT(unpriv_conn);
108
109         ret = kdbus_add_match_empty(unpriv_conn);
110         ASSERT_EXIT(ret == 0);
111
112         /*
113          * ping privileged connection from this new unprivileged
114          * one
115          */
116
117         ret = kdbus_msg_send(unpriv_conn, NULL, cookie, 0, 0,
118                              0, conn->id, 0, NULL);
119         ASSERT_EXIT(ret == 0);
120
121         /*
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.
126          *
127          * To avoid this set the dumpable flag again which makes
128          * procfs update the /proc/$clone_child/ inodes owner to 65534.
129          *
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.
132          */
133         ret = prctl(PR_SET_DUMPABLE, SUID_DUMP_USER);
134         ASSERT_EXIT(ret == 0);
135
136         /* Make child privileged in its new userns and run tests */
137
138         ret = RUN_CLONE_CHILD(&clone_ret,
139                               SIGCHLD | CLONE_NEWUSER | CLONE_NEWPID,
140         ({ 0;  /* Clone setup, nothing */ }),
141         ({
142                 eventfd_t event_status = 0;
143                 struct kdbus_conn *userns_conn;
144
145                 /* ping connection from the new user namespace */
146                 userns_conn = kdbus_hello(bus, 0, NULL, 0);
147                 ASSERT_EXIT(userns_conn);
148
149                 ret = kdbus_add_match_empty(userns_conn);
150                 ASSERT_EXIT(ret == 0);
151
152                 cookie++;
153                 ret = kdbus_msg_send(userns_conn, NULL, cookie,
154                                      0, 0, 0, conn->id, 0, NULL);
155                 ASSERT_EXIT(ret == 0);
156
157                 /* Parent did send */
158                 ret = eventfd_read(signal_fd, &event_status);
159                 ASSERT_RETURN(ret >= 0 && event_status == 1);
160
161                 /*
162                  * Receive from privileged connection
163                  */
164                 kdbus_printf("Privileged → unprivileged/privileged "
165                              "in its userns "
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);
170
171                 /* Different namespaces no CAPS */
172                 item = kdbus_get_item(msg, KDBUS_ITEM_CAPS);
173                 ASSERT_EXIT(item == NULL);
174
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);
178
179                 /*
180                  * Diffent pid namepsaces. This is the child pidns
181                  * so it should not see its parent kdbus_pids
182                  */
183                 ret = kdbus_match_kdbus_pids(msg, &unmapped_pids);
184                 ASSERT_EXIT(ret == 0);
185
186                 kdbus_msg_free(msg);
187
188
189                 /*
190                  * Receive broadcast from privileged connection
191                  */
192                 kdbus_printf("Privileged → unprivileged/privileged "
193                              "in its userns "
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);
198
199                 /* Different namespaces no CAPS */
200                 item = kdbus_get_item(msg, KDBUS_ITEM_CAPS);
201                 ASSERT_EXIT(item == NULL);
202
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);
206
207                 /*
208                  * Diffent pid namepsaces. This is the child pidns
209                  * so it should not see its parent kdbus_pids
210                  */
211                 ret = kdbus_match_kdbus_pids(msg, &unmapped_pids);
212                 ASSERT_EXIT(ret == 0);
213
214                 kdbus_msg_free(msg);
215
216                 kdbus_conn_free(userns_conn);
217         }),
218         ({
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);
222         }),
223         ({ 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);
230                 ret = 0;
231                 goto out;
232         }
233
234         ASSERT_EXIT(ret == 0);
235
236
237         /*
238          * Receive from privileged connection
239          */
240         kdbus_printf("\nPrivileged → unprivileged (same namespaces):\n");
241         ret = kdbus_msg_recv_poll(unpriv_conn, 300, &msg, NULL);
242
243         ASSERT_EXIT(ret == 0);
244         ASSERT_EXIT(msg->dst_id == unpriv_conn->id);
245
246         /* will get the privileged creds */
247         ret = kdbus_match_kdbus_creds(msg, &privileged_creds);
248         ASSERT_EXIT(ret == 0);
249
250         /* Same pidns so will get the kdbus_pids */
251         ret = kdbus_match_kdbus_pids(msg, &parent_pids);
252         ASSERT_RETURN(ret == 0);
253
254         kdbus_msg_free(msg);
255
256
257         /*
258          * Receive broadcast from privileged connection
259          */
260         kdbus_printf("\nPrivileged → unprivileged (same namespaces):\n");
261         ret = kdbus_msg_recv_poll(unpriv_conn, 300, &msg, NULL);
262
263         ASSERT_EXIT(ret == 0);
264         ASSERT_EXIT(msg->dst_id == KDBUS_DST_ID_BROADCAST);
265
266         /* will get the privileged creds */
267         ret = kdbus_match_kdbus_creds(msg, &privileged_creds);
268         ASSERT_EXIT(ret == 0);
269
270         ret = kdbus_match_kdbus_pids(msg, &parent_pids);
271         ASSERT_RETURN(ret == 0);
272
273         kdbus_msg_free(msg);
274
275 out:
276         kdbus_conn_free(unpriv_conn);
277
278         return ret;
279 }
280
281 static int kdbus_clone_userns_test(const char *bus,
282                                    struct kdbus_conn *conn)
283 {
284         int ret;
285         int status;
286         int efd = -1;
287         pid_t pid, ppid;
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;
294
295         kdbus_printf("STARTING TEST 'metadata-ns'.\n");
296
297         monitor = kdbus_hello(bus, KDBUS_HELLO_MONITOR, NULL, 0);
298         ASSERT_EXIT(monitor);
299
300         /*
301          * parent will signal to child that is in its
302          * userns to read its queue
303          */
304         efd = eventfd(0, EFD_CLOEXEC);
305         ASSERT_RETURN_VAL(efd >= 0, efd);
306
307         ppid = getppid();
308
309         pid = fork();
310         ASSERT_RETURN_VAL(pid >= 0, -errno);
311
312         if (pid == 0) {
313                 ret = prctl(PR_SET_PDEATHSIG, SIGKILL);
314                 ASSERT_EXIT_VAL(ret == 0, -errno);
315
316                 ret = __kdbus_clone_userns_test(bus, conn, ppid, efd);
317                 _exit(ret);
318         }
319
320
321         /* Phase 1) privileged receives from unprivileged */
322
323         /*
324          * Receive from the unprivileged child
325          */
326         kdbus_printf("\nUnprivileged → privileged (same namespaces):\n");
327         ret = kdbus_msg_recv_poll(conn, 300, &msg, NULL);
328         ASSERT_RETURN(ret == 0);
329
330         unpriv_conn_id = msg->src_id;
331
332         /* Unprivileged user */
333         ret = kdbus_match_kdbus_creds(msg, &unmapped_creds);
334         ASSERT_RETURN(ret == 0);
335
336         /* Set the expected creds_pids */
337         expected_pids = (struct kdbus_pids) {
338                 .pid = pid,
339                 .tid = pid,
340                 .ppid = getpid(),
341         };
342         ret = kdbus_match_kdbus_pids(msg, &expected_pids);
343         ASSERT_RETURN(ret == 0);
344
345         kdbus_msg_free(msg);
346
347
348         /*
349          * Receive from the unprivileged that is in his own
350          * userns and pidns
351          */
352
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 */
358                 goto wait;
359
360         ASSERT_RETURN(ret == 0);
361
362         userns_conn_id = msg->src_id;
363
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);
367
368         /*
369          * Compare received items, creds must be translated into
370          * the receiver user namespace, so the user is unprivileged
371          */
372         ret = kdbus_match_kdbus_creds(msg, &unmapped_creds);
373         ASSERT_RETURN(ret == 0);
374
375         /*
376          * We should have the kdbus_pids since we are the parent
377          * pidns
378          */
379         item = kdbus_get_item(msg, KDBUS_ITEM_PIDS);
380         ASSERT_RETURN(item);
381
382         ASSERT_RETURN(memcmp(&item->pids, &unmapped_pids,
383                              sizeof(struct kdbus_pids)) != 0);
384
385         /*
386          * Parent pid of the unprivileged/privileged in its userns
387          * is the unprivileged child pid that was forked here.
388          */
389         ASSERT_RETURN((uint64_t)pid == item->pids.ppid);
390
391         kdbus_msg_free(msg);
392
393
394         /* Phase 2) Privileged connection sends now 3 packets */
395
396         /*
397          * Sending to unprivileged connections a unicast
398          */
399         ret = kdbus_msg_send(conn, NULL, 0xdeadbeef, 0, 0,
400                              0, unpriv_conn_id, 0, NULL);
401         ASSERT_RETURN(ret == 0);
402
403         /* signal to child that is in its userns */
404         ret = eventfd_write(efd, 1);
405         ASSERT_EXIT(ret == 0);
406
407         /*
408          * Sending to unprivileged/privilged in its userns
409          * connections a unicast
410          */
411         ret = kdbus_msg_send(conn, NULL, 0xdeadbeef, 0, 0,
412                              0, userns_conn_id, 0, NULL);
413         ASSERT_RETURN(ret == 0);
414
415         /*
416          * Sending to unprivileged connections a broadcast
417          */
418         ret = kdbus_msg_send(conn, NULL, 0xdeadbeef, 0, 0,
419                              0, KDBUS_DST_ID_BROADCAST, 0, NULL);
420         ASSERT_RETURN(ret == 0);
421
422
423 wait:
424         ret = waitpid(pid, &status, 0);
425         ASSERT_RETURN(ret >= 0);
426
427         ASSERT_RETURN(WIFEXITED(status))
428         ASSERT_RETURN(!WEXITSTATUS(status));
429
430         /* Dump monitor queue */
431         kdbus_printf("\n\nMonitor queue:\n");
432         for (;;) {
433                 ret = kdbus_msg_recv_poll(monitor, 100, &msg, NULL);
434                 if (ret < 0)
435                         break;
436
437                 if (msg->payload_type == KDBUS_PAYLOAD_DBUS) {
438                         /*
439                          * Parent pidns should see all the
440                          * pids
441                          */
442                         item = kdbus_get_item(msg, KDBUS_ITEM_PIDS);
443                         ASSERT_RETURN(item);
444
445                         ASSERT_RETURN(item->pids.pid != 0 &&
446                                       item->pids.tid != 0 &&
447                                       item->pids.ppid != 0);
448                 }
449
450                 kdbus_msg_free(msg);
451         }
452
453         kdbus_conn_free(monitor);
454         close(efd);
455
456         return 0;
457 }
458
459 int kdbus_test_metadata_ns(struct kdbus_test_env *env)
460 {
461         int ret;
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,
466                 .id = geteuid(),
467                 .access = KDBUS_POLICY_TALK,
468         };
469
470         /*
471          * We require user-namespaces and all uids/gids
472          * should be mapped (we can just require the necessary ones)
473          */
474         if (!config_user_ns_is_enabled() ||
475             !all_uids_gids_are_mapped())
476                 return TEST_SKIP;
477
478         ret = test_is_capable(CAP_SETUID, CAP_SETGID, CAP_SYS_ADMIN, -1);
479         ASSERT_RETURN(ret >= 0);
480
481         /* no enough privileges, SKIP test */
482         if (!ret)
483                 return TEST_SKIP;
484
485         holder = kdbus_hello_registrar(env->buspath, "com.example.metadata",
486                                        &policy_access, 1,
487                                        KDBUS_HELLO_POLICY_HOLDER);
488         ASSERT_RETURN(holder);
489
490         conn = kdbus_hello(env->buspath, 0, NULL, 0);
491         ASSERT_RETURN(conn);
492
493         ret = kdbus_add_match_empty(conn);
494         ASSERT_RETURN(ret == 0);
495
496         ret = kdbus_name_acquire(conn, "com.example.metadata", NULL);
497         ASSERT_EXIT(ret >= 0);
498
499         ret = kdbus_clone_userns_test(env->buspath, conn);
500         ASSERT_RETURN(ret == 0);
501
502         kdbus_conn_free(holder);
503         kdbus_conn_free(conn);
504
505         return TEST_OK;
506 }