kdbus: the driver, original and non-working
[platform/kernel/linux-exynos.git] / tools / testing / selftests / kdbus / test-connection.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <fcntl.h>
4 #include <stdlib.h>
5 #include <stddef.h>
6 #include <unistd.h>
7 #include <stdint.h>
8 #include <errno.h>
9 #include <assert.h>
10 #include <limits.h>
11 #include <sys/types.h>
12 #include <sys/capability.h>
13 #include <sys/mman.h>
14 #include <sys/syscall.h>
15 #include <sys/wait.h>
16 #include <stdbool.h>
17
18 #include "kdbus-api.h"
19 #include "kdbus-util.h"
20 #include "kdbus-enum.h"
21 #include "kdbus-test.h"
22
23 int kdbus_test_hello(struct kdbus_test_env *env)
24 {
25         struct kdbus_cmd_free cmd_free = {};
26         struct kdbus_cmd_hello hello;
27         int fd, ret;
28
29         memset(&hello, 0, sizeof(hello));
30
31         fd = open(env->buspath, O_RDWR|O_CLOEXEC);
32         ASSERT_RETURN(fd >= 0);
33
34         hello.flags = KDBUS_HELLO_ACCEPT_FD;
35         hello.attach_flags_send = _KDBUS_ATTACH_ALL;
36         hello.attach_flags_recv = _KDBUS_ATTACH_ALL;
37         hello.size = sizeof(struct kdbus_cmd_hello);
38         hello.pool_size = POOL_SIZE;
39
40         /* an unaligned hello must result in -EFAULT */
41         ret = kdbus_cmd_hello(fd, (struct kdbus_cmd_hello *) ((char *) &hello + 1));
42         ASSERT_RETURN(ret == -EFAULT);
43
44         /* a size of 0 must return EMSGSIZE */
45         hello.size = 1;
46         hello.flags = KDBUS_HELLO_ACCEPT_FD;
47         hello.attach_flags_send = _KDBUS_ATTACH_ALL;
48         ret = kdbus_cmd_hello(fd, &hello);
49         ASSERT_RETURN(ret == -EINVAL);
50
51         hello.size = sizeof(struct kdbus_cmd_hello);
52
53         /* check faulty flags */
54         hello.flags = 1ULL << 32;
55         hello.attach_flags_send = _KDBUS_ATTACH_ALL;
56         ret = kdbus_cmd_hello(fd, &hello);
57         ASSERT_RETURN(ret == -EINVAL);
58
59         /* check for faulty pool sizes */
60         hello.pool_size = 0;
61         hello.flags = KDBUS_HELLO_ACCEPT_FD;
62         hello.attach_flags_send = _KDBUS_ATTACH_ALL;
63         ret = kdbus_cmd_hello(fd, &hello);
64         ASSERT_RETURN(ret == -EINVAL);
65
66         hello.pool_size = 4097;
67         hello.attach_flags_send = _KDBUS_ATTACH_ALL;
68         ret = kdbus_cmd_hello(fd, &hello);
69         ASSERT_RETURN(ret == -EINVAL);
70
71         hello.pool_size = POOL_SIZE;
72
73         /*
74          * The connection created by the core requires ALL meta flags
75          * to be sent. An attempt to send less than that should result in
76          * -ECONNREFUSED.
77          */
78         hello.attach_flags_send = _KDBUS_ATTACH_ALL & ~KDBUS_ATTACH_TIMESTAMP;
79         ret = kdbus_cmd_hello(fd, &hello);
80         ASSERT_RETURN(ret == -ECONNREFUSED);
81
82         hello.attach_flags_send = _KDBUS_ATTACH_ALL;
83         hello.offset = (__u64)-1;
84
85         /* success test */
86         ret = kdbus_cmd_hello(fd, &hello);
87         ASSERT_RETURN(ret == 0);
88
89         /* The kernel should have returned some items */
90         ASSERT_RETURN(hello.offset != (__u64)-1);
91         cmd_free.size = sizeof(cmd_free);
92         cmd_free.offset = hello.offset;
93         ret = kdbus_cmd_free(fd, &cmd_free);
94         ASSERT_RETURN(ret >= 0);
95
96         close(fd);
97
98         fd = open(env->buspath, O_RDWR|O_CLOEXEC);
99         ASSERT_RETURN(fd >= 0);
100
101         /* no ACTIVATOR flag without a name */
102         hello.flags = KDBUS_HELLO_ACTIVATOR;
103         ret = kdbus_cmd_hello(fd, &hello);
104         ASSERT_RETURN(ret == -EINVAL);
105
106         close(fd);
107
108         return TEST_OK;
109 }
110
111 int kdbus_test_byebye(struct kdbus_test_env *env)
112 {
113         struct kdbus_conn *conn;
114         struct kdbus_cmd_recv cmd_recv = { .size = sizeof(cmd_recv) };
115         struct kdbus_cmd cmd_byebye = { .size = sizeof(cmd_byebye) };
116         int ret;
117
118         /* create a 2nd connection */
119         conn = kdbus_hello(env->buspath, 0, NULL, 0);
120         ASSERT_RETURN(conn != NULL);
121
122         ret = kdbus_add_match_empty(conn);
123         ASSERT_RETURN(ret == 0);
124
125         ret = kdbus_add_match_empty(env->conn);
126         ASSERT_RETURN(ret == 0);
127
128         /* send over 1st connection */
129         ret = kdbus_msg_send(env->conn, NULL, 0, 0, 0, 0,
130                              KDBUS_DST_ID_BROADCAST, 0, NULL);
131         ASSERT_RETURN(ret == 0);
132
133         /* say byebye on the 2nd, which must fail */
134         ret = kdbus_cmd_byebye(conn->fd, &cmd_byebye);
135         ASSERT_RETURN(ret == -EBUSY);
136
137         /* receive the message */
138         ret = kdbus_cmd_recv(conn->fd, &cmd_recv);
139         ASSERT_RETURN(ret == 0);
140
141         ret = kdbus_free(conn, cmd_recv.msg.offset);
142         ASSERT_RETURN(ret == 0);
143
144         /* and try again */
145         ret = kdbus_cmd_byebye(conn->fd, &cmd_byebye);
146         ASSERT_RETURN(ret == 0);
147
148         /* a 2nd try should result in -ECONNRESET */
149         ret = kdbus_cmd_byebye(conn->fd, &cmd_byebye);
150         ASSERT_RETURN(ret == -ECONNRESET);
151
152         kdbus_conn_free(conn);
153
154         return TEST_OK;
155 }
156
157 /* Get only the first item */
158 static struct kdbus_item *kdbus_get_item(struct kdbus_info *info,
159                                          uint64_t type)
160 {
161         struct kdbus_item *item;
162
163         KDBUS_ITEM_FOREACH(item, info, items)
164                 if (item->type == type)
165                         return item;
166
167         return NULL;
168 }
169
170 static unsigned int kdbus_count_item(struct kdbus_info *info,
171                                      uint64_t type)
172 {
173         unsigned int i = 0;
174         const struct kdbus_item *item;
175
176         KDBUS_ITEM_FOREACH(item, info, items)
177                 if (item->type == type)
178                         i++;
179
180         return i;
181 }
182
183 static int kdbus_fuzz_conn_info(struct kdbus_test_env *env, int capable)
184 {
185         int ret;
186         unsigned int cnt = 0;
187         uint64_t offset = 0;
188         uint64_t kdbus_flags_mask;
189         struct kdbus_info *info;
190         struct kdbus_conn *conn;
191         struct kdbus_conn *privileged;
192         const struct kdbus_item *item;
193         uint64_t valid_flags_set;
194         uint64_t invalid_flags_set;
195         uint64_t valid_flags = KDBUS_ATTACH_NAMES |
196                                KDBUS_ATTACH_CREDS |
197                                KDBUS_ATTACH_PIDS |
198                                KDBUS_ATTACH_CONN_DESCRIPTION;
199
200         uint64_t invalid_flags = KDBUS_ATTACH_NAMES     |
201                                  KDBUS_ATTACH_CREDS     |
202                                  KDBUS_ATTACH_PIDS      |
203                                  KDBUS_ATTACH_CAPS      |
204                                  KDBUS_ATTACH_CGROUP    |
205                                  KDBUS_ATTACH_CONN_DESCRIPTION;
206
207         struct kdbus_creds cached_creds;
208         uid_t ruid, euid, suid;
209         gid_t rgid, egid, sgid;
210
211         getresuid(&ruid, &euid, &suid);
212         getresgid(&rgid, &egid, &sgid);
213
214         cached_creds.uid = ruid;
215         cached_creds.euid = euid;
216         cached_creds.suid = suid;
217         cached_creds.fsuid = ruid;
218
219         cached_creds.gid = rgid;
220         cached_creds.egid = egid;
221         cached_creds.sgid = sgid;
222         cached_creds.fsgid = rgid;
223
224         struct kdbus_pids cached_pids = {
225                 .pid    = getpid(),
226                 .tid    = syscall(SYS_gettid),
227                 .ppid   = getppid(),
228         };
229
230         ret = kdbus_sysfs_get_parameter_mask(env->mask_param_path,
231                                              &kdbus_flags_mask);
232         ASSERT_RETURN(ret == 0);
233
234         valid_flags_set = valid_flags & kdbus_flags_mask;
235         invalid_flags_set = invalid_flags & kdbus_flags_mask;
236
237         ret = kdbus_conn_info(env->conn, env->conn->id, NULL,
238                               valid_flags, &offset);
239         ASSERT_RETURN(ret == 0);
240
241         info = (struct kdbus_info *)(env->conn->buf + offset);
242         ASSERT_RETURN(info->id == env->conn->id);
243
244         /* We do not have any well-known name */
245         item = kdbus_get_item(info, KDBUS_ITEM_NAME);
246         ASSERT_RETURN(item == NULL);
247
248         item = kdbus_get_item(info, KDBUS_ITEM_CONN_DESCRIPTION);
249         if (valid_flags_set & KDBUS_ATTACH_CONN_DESCRIPTION) {
250                 ASSERT_RETURN(item);
251         } else {
252                 ASSERT_RETURN(item == NULL);
253         }
254
255         kdbus_free(env->conn, offset);
256
257         conn = kdbus_hello(env->buspath, 0, NULL, 0);
258         ASSERT_RETURN(conn);
259
260         privileged = kdbus_hello(env->buspath, 0, NULL, 0);
261         ASSERT_RETURN(privileged);
262
263         ret = kdbus_conn_info(conn, conn->id, NULL, valid_flags, &offset);
264         ASSERT_RETURN(ret == 0);
265
266         info = (struct kdbus_info *)(conn->buf + offset);
267         ASSERT_RETURN(info->id == conn->id);
268
269         /* We do not have any well-known name */
270         item = kdbus_get_item(info, KDBUS_ITEM_NAME);
271         ASSERT_RETURN(item == NULL);
272
273         cnt = kdbus_count_item(info, KDBUS_ITEM_CREDS);
274         if (valid_flags_set & KDBUS_ATTACH_CREDS) {
275                 ASSERT_RETURN(cnt == 1);
276
277                 item = kdbus_get_item(info, KDBUS_ITEM_CREDS);
278                 ASSERT_RETURN(item);
279
280                 /* Compare received items with cached creds */
281                 ASSERT_RETURN(memcmp(&item->creds, &cached_creds,
282                                       sizeof(struct kdbus_creds)) == 0);
283         } else {
284                 ASSERT_RETURN(cnt == 0);
285         }
286
287         item = kdbus_get_item(info, KDBUS_ITEM_PIDS);
288         if (valid_flags_set & KDBUS_ATTACH_PIDS) {
289                 ASSERT_RETURN(item);
290
291                 /* Compare item->pids with cached PIDs */
292                 ASSERT_RETURN(item->pids.pid == cached_pids.pid &&
293                               item->pids.tid == cached_pids.tid &&
294                               item->pids.ppid == cached_pids.ppid);
295         } else {
296                 ASSERT_RETURN(item == NULL);
297         }
298
299         /* We did not request KDBUS_ITEM_CAPS */
300         item = kdbus_get_item(info, KDBUS_ITEM_CAPS);
301         ASSERT_RETURN(item == NULL);
302
303         kdbus_free(conn, offset);
304
305         ret = kdbus_name_acquire(conn, "com.example.a", NULL);
306         ASSERT_RETURN(ret >= 0);
307
308         ret = kdbus_conn_info(conn, conn->id, NULL, valid_flags, &offset);
309         ASSERT_RETURN(ret == 0);
310
311         info = (struct kdbus_info *)(conn->buf + offset);
312         ASSERT_RETURN(info->id == conn->id);
313
314         item = kdbus_get_item(info, KDBUS_ITEM_OWNED_NAME);
315         if (valid_flags_set & KDBUS_ATTACH_NAMES) {
316                 ASSERT_RETURN(item && !strcmp(item->name.name, "com.example.a"));
317         } else {
318                 ASSERT_RETURN(item == NULL);
319         }
320
321         kdbus_free(conn, offset);
322
323         ret = kdbus_conn_info(conn, 0, "com.example.a", valid_flags, &offset);
324         ASSERT_RETURN(ret == 0);
325
326         info = (struct kdbus_info *)(conn->buf + offset);
327         ASSERT_RETURN(info->id == conn->id);
328
329         kdbus_free(conn, offset);
330
331         /* does not have the necessary caps to drop to unprivileged */
332         if (!capable)
333                 goto continue_test;
334
335         ret = RUN_UNPRIVILEGED(UNPRIV_UID, UNPRIV_GID, ({
336                 ret = kdbus_conn_info(conn, conn->id, NULL,
337                                       valid_flags, &offset);
338                 ASSERT_EXIT(ret == 0);
339
340                 info = (struct kdbus_info *)(conn->buf + offset);
341                 ASSERT_EXIT(info->id == conn->id);
342
343                 if (valid_flags_set & KDBUS_ATTACH_NAMES) {
344                         item = kdbus_get_item(info, KDBUS_ITEM_OWNED_NAME);
345                         ASSERT_EXIT(item &&
346                                     strcmp(item->name.name,
347                                            "com.example.a") == 0);
348                 }
349
350                 if (valid_flags_set & KDBUS_ATTACH_CREDS) {
351                         item = kdbus_get_item(info, KDBUS_ITEM_CREDS);
352                         ASSERT_EXIT(item);
353
354                         /* Compare received items with cached creds */
355                         ASSERT_EXIT(memcmp(&item->creds, &cached_creds,
356                                     sizeof(struct kdbus_creds)) == 0);
357                 }
358
359                 if (valid_flags_set & KDBUS_ATTACH_PIDS) {
360                         item = kdbus_get_item(info, KDBUS_ITEM_PIDS);
361                         ASSERT_EXIT(item);
362
363                         /*
364                          * Compare item->pids with cached pids of
365                          * privileged one.
366                          *
367                          * cmd_info will always return cached pids.
368                          */
369                         ASSERT_EXIT(item->pids.pid == cached_pids.pid &&
370                                     item->pids.tid == cached_pids.tid);
371                 }
372
373                 kdbus_free(conn, offset);
374
375                 /*
376                  * Use invalid_flags and make sure that userspace
377                  * do not play with us.
378                  */
379                 ret = kdbus_conn_info(conn, conn->id, NULL,
380                                       invalid_flags, &offset);
381                 ASSERT_EXIT(ret == 0);
382
383                 /*
384                  * Make sure that we return only one creds item and
385                  * it points to the cached creds.
386                  */
387                 cnt = kdbus_count_item(info, KDBUS_ITEM_CREDS);
388                 if (invalid_flags_set & KDBUS_ATTACH_CREDS) {
389                         ASSERT_EXIT(cnt == 1);
390
391                         item = kdbus_get_item(info, KDBUS_ITEM_CREDS);
392                         ASSERT_EXIT(item);
393
394                         /* Compare received items with cached creds */
395                         ASSERT_EXIT(memcmp(&item->creds, &cached_creds,
396                                     sizeof(struct kdbus_creds)) == 0);
397                 } else {
398                         ASSERT_EXIT(cnt == 0);
399                 }
400
401                 if (invalid_flags_set & KDBUS_ATTACH_PIDS) {
402                         cnt = kdbus_count_item(info, KDBUS_ITEM_PIDS);
403                         ASSERT_EXIT(cnt == 1);
404
405                         item = kdbus_get_item(info, KDBUS_ITEM_PIDS);
406                         ASSERT_EXIT(item);
407
408                         /* Compare item->pids with cached pids */
409                         ASSERT_EXIT(item->pids.pid == cached_pids.pid &&
410                                     item->pids.tid == cached_pids.tid);
411                 }
412
413                 cnt = kdbus_count_item(info, KDBUS_ITEM_CGROUP);
414                 if (invalid_flags_set & KDBUS_ATTACH_CGROUP) {
415                         ASSERT_EXIT(cnt == 1);
416                 } else {
417                         ASSERT_EXIT(cnt == 0);
418                 }
419
420                 cnt = kdbus_count_item(info, KDBUS_ITEM_CAPS);
421                 if (invalid_flags_set & KDBUS_ATTACH_CAPS) {
422                         ASSERT_EXIT(cnt == 1);
423                 } else {
424                         ASSERT_EXIT(cnt == 0);
425                 }
426
427                 kdbus_free(conn, offset);
428         }),
429         ({ 0; }));
430         ASSERT_RETURN(ret == 0);
431
432 continue_test:
433
434         /* A second name */
435         ret = kdbus_name_acquire(conn, "com.example.b", NULL);
436         ASSERT_RETURN(ret >= 0);
437
438         ret = kdbus_conn_info(conn, conn->id, NULL, valid_flags, &offset);
439         ASSERT_RETURN(ret == 0);
440
441         info = (struct kdbus_info *)(conn->buf + offset);
442         ASSERT_RETURN(info->id == conn->id);
443
444         cnt = kdbus_count_item(info, KDBUS_ITEM_OWNED_NAME);
445         if (valid_flags_set & KDBUS_ATTACH_NAMES) {
446                 ASSERT_RETURN(cnt == 2);
447         } else {
448                 ASSERT_RETURN(cnt == 0);
449         }
450
451         kdbus_free(conn, offset);
452
453         ASSERT_RETURN(ret == 0);
454
455         return 0;
456 }
457
458 int kdbus_test_conn_info(struct kdbus_test_env *env)
459 {
460         int ret;
461         int have_caps;
462         struct {
463                 struct kdbus_cmd_info cmd_info;
464
465                 struct {
466                         uint64_t size;
467                         uint64_t type;
468                         char str[64];
469                 } name;
470         } buf;
471
472         buf.cmd_info.size = sizeof(struct kdbus_cmd_info);
473         buf.cmd_info.flags = 0;
474         buf.cmd_info.attach_flags = 0;
475         buf.cmd_info.id = env->conn->id;
476
477         ret = kdbus_conn_info(env->conn, env->conn->id, NULL, 0, NULL);
478         ASSERT_RETURN(ret == 0);
479
480         /* try to pass a name that is longer than the buffer's size */
481         buf.name.size = KDBUS_ITEM_HEADER_SIZE + 1;
482         buf.name.type = KDBUS_ITEM_NAME;
483         strcpy(buf.name.str, "foo.bar.bla");
484
485         buf.cmd_info.id = 0;
486         buf.cmd_info.size = sizeof(buf.cmd_info) + buf.name.size;
487         ret = kdbus_cmd_conn_info(env->conn->fd, (struct kdbus_cmd_info *) &buf);
488         ASSERT_RETURN(ret == -EINVAL);
489
490         /* Pass a non existent name */
491         ret = kdbus_conn_info(env->conn, 0, "non.existent.name", 0, NULL);
492         ASSERT_RETURN(ret == -ESRCH);
493
494         if (!all_uids_gids_are_mapped())
495                 return TEST_SKIP;
496
497         /* Test for caps here, so we run the previous test */
498         have_caps = test_is_capable(CAP_SETUID, CAP_SETGID, -1);
499         ASSERT_RETURN(have_caps >= 0);
500
501         ret = kdbus_fuzz_conn_info(env, have_caps);
502         ASSERT_RETURN(ret == 0);
503
504         /* Now if we have skipped some tests then let the user know */
505         if (!have_caps)
506                 return TEST_SKIP;
507
508         return TEST_OK;
509 }
510
511 int kdbus_test_conn_update(struct kdbus_test_env *env)
512 {
513         struct kdbus_conn *conn;
514         struct kdbus_msg *msg;
515         int found = 0;
516         int ret;
517
518         /*
519          * kdbus_hello() sets all attach flags. Receive a message by this
520          * connection, and make sure a timestamp item (just to pick one) is
521          * present.
522          */
523         conn = kdbus_hello(env->buspath, 0, NULL, 0);
524         ASSERT_RETURN(conn);
525
526         ret = kdbus_msg_send(env->conn, NULL, 0x12345678, 0, 0, 0, conn->id,
527                              0, NULL);
528         ASSERT_RETURN(ret == 0);
529
530         ret = kdbus_msg_recv(conn, &msg, NULL);
531         ASSERT_RETURN(ret == 0);
532
533         found = kdbus_item_in_message(msg, KDBUS_ITEM_TIMESTAMP);
534         ASSERT_RETURN(found == 1);
535
536         kdbus_msg_free(msg);
537
538         /*
539          * Now, modify the attach flags and repeat the action. The item must
540          * now be missing.
541          */
542         found = 0;
543
544         ret = kdbus_conn_update_attach_flags(conn,
545                                              _KDBUS_ATTACH_ALL,
546                                              _KDBUS_ATTACH_ALL &
547                                              ~KDBUS_ATTACH_TIMESTAMP);
548         ASSERT_RETURN(ret == 0);
549
550         ret = kdbus_msg_send(env->conn, NULL, 0x12345678, 0, 0, 0, conn->id,
551                              0, NULL);
552         ASSERT_RETURN(ret == 0);
553
554         ret = kdbus_msg_recv(conn, &msg, NULL);
555         ASSERT_RETURN(ret == 0);
556
557         found = kdbus_item_in_message(msg, KDBUS_ITEM_TIMESTAMP);
558         ASSERT_RETURN(found == 0);
559
560         /* Provide a bogus attach_flags value */
561         ret = kdbus_conn_update_attach_flags(conn,
562                                              _KDBUS_ATTACH_ALL + 1,
563                                              _KDBUS_ATTACH_ALL);
564         ASSERT_RETURN(ret == -EINVAL);
565
566         kdbus_msg_free(msg);
567
568         kdbus_conn_free(conn);
569
570         return TEST_OK;
571 }
572
573 int kdbus_test_writable_pool(struct kdbus_test_env *env)
574 {
575         struct kdbus_cmd_free cmd_free = {};
576         struct kdbus_cmd_hello hello;
577         int fd, ret;
578         void *map;
579
580         fd = open(env->buspath, O_RDWR | O_CLOEXEC);
581         ASSERT_RETURN(fd >= 0);
582
583         memset(&hello, 0, sizeof(hello));
584         hello.flags = KDBUS_HELLO_ACCEPT_FD;
585         hello.attach_flags_send = _KDBUS_ATTACH_ALL;
586         hello.attach_flags_recv = _KDBUS_ATTACH_ALL;
587         hello.size = sizeof(struct kdbus_cmd_hello);
588         hello.pool_size = POOL_SIZE;
589         hello.offset = (__u64)-1;
590
591         /* success test */
592         ret = kdbus_cmd_hello(fd, &hello);
593         ASSERT_RETURN(ret == 0);
594
595         /* The kernel should have returned some items */
596         ASSERT_RETURN(hello.offset != (__u64)-1);
597         cmd_free.size = sizeof(cmd_free);
598         cmd_free.offset = hello.offset;
599         ret = kdbus_cmd_free(fd, &cmd_free);
600         ASSERT_RETURN(ret >= 0);
601
602         /* pools cannot be mapped writable */
603         map = mmap(NULL, POOL_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
604         ASSERT_RETURN(map == MAP_FAILED);
605
606         /* pools can always be mapped readable */
607         map = mmap(NULL, POOL_SIZE, PROT_READ, MAP_SHARED, fd, 0);
608         ASSERT_RETURN(map != MAP_FAILED);
609
610         /* make sure we cannot change protection masks to writable */
611         ret = mprotect(map, POOL_SIZE, PROT_READ | PROT_WRITE);
612         ASSERT_RETURN(ret < 0);
613
614         munmap(map, POOL_SIZE);
615         close(fd);
616
617         return TEST_OK;
618 }