1
2
3#define _GNU_SOURCE
4#include <errno.h>
5#include <fcntl.h>
6#include <pthread.h>
7#include <sched.h>
8#include <stdbool.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/fsuid.h>
13#include <sys/ioctl.h>
14#include <sys/mount.h>
15#include <sys/socket.h>
16#include <sys/stat.h>
17#include <sys/sysinfo.h>
18#include <sys/types.h>
19#include <sys/wait.h>
20#include <unistd.h>
21#include <linux/android/binder.h>
22#include <linux/android/binderfs.h>
23
24#include "../../kselftest.h"
25#include "../../kselftest_harness.h"
26
27#define DEFAULT_THREADS 4
28
29#define PTR_TO_INT(p) ((int)((intptr_t)(p)))
30#define INT_TO_PTR(u) ((void *)((intptr_t)(u)))
31
32#define close_prot_errno_disarm(fd) \
33 if (fd >= 0) { \
34 int _e_ = errno; \
35 close(fd); \
36 errno = _e_; \
37 fd = -EBADF; \
38 }
39
40#define log_exit(format, ...) \
41 ({ \
42 fprintf(stderr, format "\n", ##__VA_ARGS__); \
43 exit(EXIT_FAILURE); \
44 })
45
46static void change_mountns(void)
47{
48 int ret;
49
50 ret = unshare(CLONE_NEWNS);
51 if (ret < 0)
52 ksft_exit_fail_msg("%s - Failed to unshare mount namespace\n",
53 strerror(errno));
54
55 ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0);
56 if (ret < 0)
57 ksft_exit_fail_msg("%s - Failed to mount / as private\n",
58 strerror(errno));
59}
60
61static void rmdir_protect_errno(const char *dir)
62{
63 int saved_errno = errno;
64 (void)rmdir(dir);
65 errno = saved_errno;
66}
67
68static int __do_binderfs_test(void)
69{
70 int fd, ret, saved_errno;
71 size_t len;
72 ssize_t wret;
73 struct binderfs_device device = { 0 };
74 struct binder_version version = { 0 };
75 char binderfs_mntpt[] = P_tmpdir "/binderfs_XXXXXX",
76 device_path[sizeof(P_tmpdir "/binderfs_XXXXXX/") + BINDERFS_MAX_NAME];
77
78 change_mountns();
79
80 if (!mkdtemp(binderfs_mntpt))
81 ksft_exit_fail_msg(
82 "%s - Failed to create binderfs mountpoint\n",
83 strerror(errno));
84
85 ret = mount(NULL, binderfs_mntpt, "binder", 0, 0);
86 if (ret < 0) {
87 if (errno != ENODEV)
88 ksft_exit_fail_msg("%s - Failed to mount binderfs\n",
89 strerror(errno));
90
91 rmdir_protect_errno(binderfs_mntpt);
92 return 1;
93 }
94
95
96 ksft_inc_pass_cnt();
97
98 memcpy(device.name, "my-binder", strlen("my-binder"));
99
100 snprintf(device_path, sizeof(device_path), "%s/binder-control", binderfs_mntpt);
101 fd = open(device_path, O_RDONLY | O_CLOEXEC);
102 if (fd < 0)
103 ksft_exit_fail_msg(
104 "%s - Failed to open binder-control device\n",
105 strerror(errno));
106
107 ret = ioctl(fd, BINDER_CTL_ADD, &device);
108 saved_errno = errno;
109 close(fd);
110 errno = saved_errno;
111 if (ret < 0) {
112 rmdir_protect_errno(binderfs_mntpt);
113 ksft_exit_fail_msg(
114 "%s - Failed to allocate new binder device\n",
115 strerror(errno));
116 }
117
118 ksft_print_msg(
119 "Allocated new binder device with major %d, minor %d, and name %s\n",
120 device.major, device.minor, device.name);
121
122
123 ksft_inc_pass_cnt();
124
125 snprintf(device_path, sizeof(device_path), "%s/my-binder", binderfs_mntpt);
126 fd = open(device_path, O_CLOEXEC | O_RDONLY);
127 if (fd < 0) {
128 rmdir_protect_errno(binderfs_mntpt);
129 ksft_exit_fail_msg("%s - Failed to open my-binder device\n",
130 strerror(errno));
131 }
132
133 ret = ioctl(fd, BINDER_VERSION, &version);
134 saved_errno = errno;
135 close(fd);
136 errno = saved_errno;
137 if (ret < 0) {
138 rmdir_protect_errno(binderfs_mntpt);
139 ksft_exit_fail_msg(
140 "%s - Failed to open perform BINDER_VERSION request\n",
141 strerror(errno));
142 }
143
144 ksft_print_msg("Detected binder version: %d\n",
145 version.protocol_version);
146
147
148 ksft_inc_pass_cnt();
149
150 ret = unlink(device_path);
151 if (ret < 0) {
152 rmdir_protect_errno(binderfs_mntpt);
153 ksft_exit_fail_msg("%s - Failed to delete binder device\n",
154 strerror(errno));
155 }
156
157
158 ksft_inc_pass_cnt();
159
160 snprintf(device_path, sizeof(device_path), "%s/binder-control", binderfs_mntpt);
161 ret = unlink(device_path);
162 if (!ret) {
163 rmdir_protect_errno(binderfs_mntpt);
164 ksft_exit_fail_msg("Managed to delete binder-control device\n");
165 } else if (errno != EPERM) {
166 rmdir_protect_errno(binderfs_mntpt);
167 ksft_exit_fail_msg(
168 "%s - Failed to delete binder-control device but exited with unexpected error code\n",
169 strerror(errno));
170 }
171
172
173 ksft_inc_xfail_cnt();
174
175on_error:
176 ret = umount2(binderfs_mntpt, MNT_DETACH);
177 rmdir_protect_errno(binderfs_mntpt);
178 if (ret < 0)
179 ksft_exit_fail_msg("%s - Failed to unmount binderfs\n",
180 strerror(errno));
181
182
183 ksft_inc_pass_cnt();
184 return 0;
185}
186
187static int wait_for_pid(pid_t pid)
188{
189 int status, ret;
190
191again:
192 ret = waitpid(pid, &status, 0);
193 if (ret == -1) {
194 if (errno == EINTR)
195 goto again;
196
197 return -1;
198 }
199
200 if (!WIFEXITED(status))
201 return -1;
202
203 return WEXITSTATUS(status);
204}
205
206static int setid_userns_root(void)
207{
208 if (setuid(0))
209 return -1;
210 if (setgid(0))
211 return -1;
212
213 setfsuid(0);
214 setfsgid(0);
215
216 return 0;
217}
218
219enum idmap_type {
220 UID_MAP,
221 GID_MAP,
222};
223
224static ssize_t read_nointr(int fd, void *buf, size_t count)
225{
226 ssize_t ret;
227again:
228 ret = read(fd, buf, count);
229 if (ret < 0 && errno == EINTR)
230 goto again;
231
232 return ret;
233}
234
235static ssize_t write_nointr(int fd, const void *buf, size_t count)
236{
237 ssize_t ret;
238again:
239 ret = write(fd, buf, count);
240 if (ret < 0 && errno == EINTR)
241 goto again;
242
243 return ret;
244}
245
246static int write_id_mapping(enum idmap_type type, pid_t pid, const char *buf,
247 size_t buf_size)
248{
249 int fd;
250 int ret;
251 char path[4096];
252
253 if (type == GID_MAP) {
254 int setgroups_fd;
255
256 snprintf(path, sizeof(path), "/proc/%d/setgroups", pid);
257 setgroups_fd = open(path, O_WRONLY | O_CLOEXEC | O_NOFOLLOW);
258 if (setgroups_fd < 0 && errno != ENOENT)
259 return -1;
260
261 if (setgroups_fd >= 0) {
262 ret = write_nointr(setgroups_fd, "deny", sizeof("deny") - 1);
263 close_prot_errno_disarm(setgroups_fd);
264 if (ret != sizeof("deny") - 1)
265 return -1;
266 }
267 }
268
269 switch (type) {
270 case UID_MAP:
271 ret = snprintf(path, sizeof(path), "/proc/%d/uid_map", pid);
272 break;
273 case GID_MAP:
274 ret = snprintf(path, sizeof(path), "/proc/%d/gid_map", pid);
275 break;
276 default:
277 return -1;
278 }
279 if (ret < 0 || ret >= sizeof(path))
280 return -E2BIG;
281
282 fd = open(path, O_WRONLY | O_CLOEXEC | O_NOFOLLOW);
283 if (fd < 0)
284 return -1;
285
286 ret = write_nointr(fd, buf, buf_size);
287 close_prot_errno_disarm(fd);
288 if (ret != buf_size)
289 return -1;
290
291 return 0;
292}
293
294static void change_userns(int syncfds[2])
295{
296 int ret;
297 char buf;
298
299 close_prot_errno_disarm(syncfds[1]);
300
301 ret = unshare(CLONE_NEWUSER);
302 if (ret < 0)
303 ksft_exit_fail_msg("%s - Failed to unshare user namespace\n",
304 strerror(errno));
305
306 ret = write_nointr(syncfds[0], "1", 1);
307 if (ret != 1)
308 ksft_exit_fail_msg("write_nointr() failed\n");
309
310 ret = read_nointr(syncfds[0], &buf, 1);
311 if (ret != 1)
312 ksft_exit_fail_msg("read_nointr() failed\n");
313
314 close_prot_errno_disarm(syncfds[0]);
315
316 if (setid_userns_root())
317 ksft_exit_fail_msg("setid_userns_root() failed");
318}
319
320static void change_idmaps(int syncfds[2], pid_t pid)
321{
322 int ret;
323 char buf;
324 char id_map[4096];
325
326 close_prot_errno_disarm(syncfds[0]);
327
328 ret = read_nointr(syncfds[1], &buf, 1);
329 if (ret != 1)
330 ksft_exit_fail_msg("read_nointr() failed\n");
331
332 snprintf(id_map, sizeof(id_map), "0 %d 1\n", getuid());
333 ret = write_id_mapping(UID_MAP, pid, id_map, strlen(id_map));
334 if (ret)
335 ksft_exit_fail_msg("write_id_mapping(UID_MAP) failed");
336
337 snprintf(id_map, sizeof(id_map), "0 %d 1\n", getgid());
338 ret = write_id_mapping(GID_MAP, pid, id_map, strlen(id_map));
339 if (ret)
340 ksft_exit_fail_msg("write_id_mapping(GID_MAP) failed");
341
342 ret = write_nointr(syncfds[1], "1", 1);
343 if (ret != 1)
344 ksft_exit_fail_msg("write_nointr() failed");
345
346 close_prot_errno_disarm(syncfds[1]);
347}
348
349static void *binder_version_thread(void *data)
350{
351 int fd = PTR_TO_INT(data);
352 struct binder_version version = { 0 };
353 int ret;
354
355 ret = ioctl(fd, BINDER_VERSION, &version);
356 if (ret < 0)
357 ksft_print_msg("%s - Failed to open perform BINDER_VERSION request\n", strerror(errno));
358
359 pthread_exit(data);
360}
361
362
363
364
365
366
367
368TEST(binderfs_stress)
369{
370 int fds[1000];
371 int syncfds[2];
372 pid_t pid;
373 int fd, ret;
374 size_t len;
375 struct binderfs_device device = { 0 };
376 char binderfs_mntpt[] = P_tmpdir "/binderfs_XXXXXX",
377 device_path[sizeof(P_tmpdir "/binderfs_XXXXXX/") + BINDERFS_MAX_NAME];
378
379 ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, syncfds);
380 if (ret < 0)
381 ksft_exit_fail_msg("%s - Failed to create socket pair", strerror(errno));
382
383 pid = fork();
384 if (pid < 0) {
385 close_prot_errno_disarm(syncfds[0]);
386 close_prot_errno_disarm(syncfds[1]);
387 ksft_exit_fail_msg("%s - Failed to fork", strerror(errno));
388 }
389
390 if (pid == 0) {
391 int i, j, k, nthreads;
392 pthread_attr_t attr;
393 pthread_t threads[DEFAULT_THREADS];
394 change_userns(syncfds);
395 change_mountns();
396
397 if (!mkdtemp(binderfs_mntpt))
398 log_exit("%s - Failed to create binderfs mountpoint\n",
399 strerror(errno));
400
401 ret = mount(NULL, binderfs_mntpt, "binder", 0, 0);
402 if (ret < 0)
403 log_exit("%s - Failed to mount binderfs\n", strerror(errno));
404
405 for (int i = 0; i < ARRAY_SIZE(fds); i++) {
406
407 snprintf(device_path, sizeof(device_path),
408 "%s/binder-control", binderfs_mntpt);
409 fd = open(device_path, O_RDONLY | O_CLOEXEC);
410 if (fd < 0)
411 log_exit("%s - Failed to open binder-control device\n", strerror(errno));
412
413 memset(&device, 0, sizeof(device));
414 snprintf(device.name, sizeof(device.name), "%d", i);
415 ret = ioctl(fd, BINDER_CTL_ADD, &device);
416 close_prot_errno_disarm(fd);
417 if (ret < 0)
418 log_exit("%s - Failed to allocate new binder device\n", strerror(errno));
419
420 snprintf(device_path, sizeof(device_path), "%s/%d",
421 binderfs_mntpt, i);
422 fds[i] = open(device_path, O_RDONLY | O_CLOEXEC);
423 if (fds[i] < 0)
424 log_exit("%s - Failed to open binder device\n", strerror(errno));
425 }
426
427 ret = umount2(binderfs_mntpt, MNT_DETACH);
428 rmdir_protect_errno(binderfs_mntpt);
429 if (ret < 0)
430 log_exit("%s - Failed to unmount binderfs\n", strerror(errno));
431
432 nthreads = get_nprocs_conf();
433 if (nthreads > DEFAULT_THREADS)
434 nthreads = DEFAULT_THREADS;
435
436 pthread_attr_init(&attr);
437 for (k = 0; k < ARRAY_SIZE(fds); k++) {
438 for (i = 0; i < nthreads; i++) {
439 ret = pthread_create(&threads[i], &attr, binder_version_thread, INT_TO_PTR(fds[k]));
440 if (ret) {
441 ksft_print_msg("%s - Failed to create thread %d\n", strerror(errno), i);
442 break;
443 }
444 }
445
446 for (j = 0; j < i; j++) {
447 void *fdptr = NULL;
448
449 ret = pthread_join(threads[j], &fdptr);
450 if (ret)
451 ksft_print_msg("%s - Failed to join thread %d for fd %d\n", strerror(errno), j, PTR_TO_INT(fdptr));
452 }
453 }
454 pthread_attr_destroy(&attr);
455
456 for (k = 0; k < ARRAY_SIZE(fds); k++)
457 close(fds[k]);
458
459 exit(EXIT_SUCCESS);
460 }
461
462 change_idmaps(syncfds, pid);
463
464 ret = wait_for_pid(pid);
465 if (ret)
466 ksft_exit_fail_msg("wait_for_pid() failed");
467}
468
469TEST(binderfs_test_privileged)
470{
471 if (geteuid() != 0)
472 XFAIL(return, "Tests are not run as root. Skipping privileged tests");
473
474 if (__do_binderfs_test() == 1)
475 XFAIL(return, "The Android binderfs filesystem is not available");
476}
477
478TEST(binderfs_test_unprivileged)
479{
480 int ret;
481 int syncfds[2];
482 pid_t pid;
483
484 ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, syncfds);
485 if (ret < 0)
486 ksft_exit_fail_msg("%s - Failed to create socket pair", strerror(errno));
487
488 pid = fork();
489 if (pid < 0) {
490 close_prot_errno_disarm(syncfds[0]);
491 close_prot_errno_disarm(syncfds[1]);
492 ksft_exit_fail_msg("%s - Failed to fork", strerror(errno));
493 }
494
495 if (pid == 0) {
496 change_userns(syncfds);
497 if (__do_binderfs_test() == 1)
498 exit(2);
499 exit(EXIT_SUCCESS);
500 }
501
502 change_idmaps(syncfds, pid);
503
504 ret = wait_for_pid(pid);
505 if (ret) {
506 if (ret == 2)
507 XFAIL(return, "The Android binderfs filesystem is not available");
508 else
509 ksft_exit_fail_msg("wait_for_pid() failed");
510 }
511}
512
513TEST_HARNESS_MAIN
514