]> Git Repo - linux.git/blob - tools/testing/selftests/filesystems/binderfs/binderfs_test.c
Linux 6.14-rc3
[linux.git] / tools / testing / selftests / filesystems / binderfs / binderfs_test.c
1 // SPDX-License-Identifier: GPL-2.0
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_harness.h"
25
26 #define DEFAULT_THREADS 4
27
28 #define PTR_TO_INT(p) ((int)((intptr_t)(p)))
29 #define INT_TO_PTR(u) ((void *)((intptr_t)(u)))
30
31 #define close_prot_errno_disarm(fd) \
32         if (fd >= 0) {              \
33                 int _e_ = errno;    \
34                 close(fd);          \
35                 errno = _e_;        \
36                 fd = -EBADF;        \
37         }
38
39 static void change_mountns(struct __test_metadata *_metadata)
40 {
41         int ret;
42
43         ret = unshare(CLONE_NEWNS);
44         ASSERT_EQ(ret, 0) {
45                 TH_LOG("%s - Failed to unshare mount namespace",
46                         strerror(errno));
47         }
48
49         ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0);
50         ASSERT_EQ(ret, 0) {
51                 TH_LOG("%s - Failed to mount / as private",
52                         strerror(errno));
53         }
54 }
55
56 static int __do_binderfs_test(struct __test_metadata *_metadata)
57 {
58         int fd, ret, saved_errno, result = 1;
59         size_t len;
60         struct binderfs_device device = { 0 };
61         struct binder_version version = { 0 };
62         char binderfs_mntpt[] = P_tmpdir "/binderfs_XXXXXX",
63                 device_path[sizeof(P_tmpdir "/binderfs_XXXXXX/") + BINDERFS_MAX_NAME];
64         static const char * const binder_features[] = {
65                 "oneway_spam_detection",
66                 "extended_error",
67                 "freeze_notification",
68         };
69
70         change_mountns(_metadata);
71
72         EXPECT_NE(mkdtemp(binderfs_mntpt), NULL) {
73                 TH_LOG("%s - Failed to create binderfs mountpoint",
74                         strerror(errno));
75                 goto out;
76         }
77
78         ret = mount(NULL, binderfs_mntpt, "binder", 0, 0);
79         EXPECT_EQ(ret, 0) {
80                 if (errno == ENODEV)
81                         SKIP(goto out, "binderfs missing");
82                 TH_LOG("%s - Failed to mount binderfs", strerror(errno));
83                 goto rmdir;
84         }
85
86         /* success: binderfs mounted */
87
88         memcpy(device.name, "my-binder", strlen("my-binder"));
89
90         snprintf(device_path, sizeof(device_path), "%s/binder-control", binderfs_mntpt);
91         fd = open(device_path, O_RDONLY | O_CLOEXEC);
92         EXPECT_GE(fd, 0) {
93                 TH_LOG("%s - Failed to open binder-control device",
94                         strerror(errno));
95                 goto umount;
96         }
97
98         ret = ioctl(fd, BINDER_CTL_ADD, &device);
99         saved_errno = errno;
100         close(fd);
101         errno = saved_errno;
102         EXPECT_GE(ret, 0) {
103                 TH_LOG("%s - Failed to allocate new binder device",
104                         strerror(errno));
105                 goto umount;
106         }
107
108         TH_LOG("Allocated new binder device with major %d, minor %d, and name %s",
109                 device.major, device.minor, device.name);
110
111         /* success: binder device allocation */
112
113         snprintf(device_path, sizeof(device_path), "%s/my-binder", binderfs_mntpt);
114         fd = open(device_path, O_CLOEXEC | O_RDONLY);
115         EXPECT_GE(fd, 0) {
116                 TH_LOG("%s - Failed to open my-binder device",
117                         strerror(errno));
118                 goto umount;
119         }
120
121         ret = ioctl(fd, BINDER_VERSION, &version);
122         saved_errno = errno;
123         close(fd);
124         errno = saved_errno;
125         EXPECT_GE(ret, 0) {
126                 TH_LOG("%s - Failed to open perform BINDER_VERSION request",
127                         strerror(errno));
128                 goto umount;
129         }
130
131         TH_LOG("Detected binder version: %d", version.protocol_version);
132
133         /* success: binder transaction with binderfs binder device */
134
135         ret = unlink(device_path);
136         EXPECT_EQ(ret, 0) {
137                 TH_LOG("%s - Failed to delete binder device",
138                         strerror(errno));
139                 goto umount;
140         }
141
142         /* success: binder device removal */
143
144         snprintf(device_path, sizeof(device_path), "%s/binder-control", binderfs_mntpt);
145         ret = unlink(device_path);
146         EXPECT_NE(ret, 0) {
147                 TH_LOG("Managed to delete binder-control device");
148                 goto umount;
149         }
150         EXPECT_EQ(errno, EPERM) {
151                 TH_LOG("%s - Failed to delete binder-control device but exited with unexpected error code",
152                         strerror(errno));
153                 goto umount;
154         }
155
156         /* success: binder-control device removal failed as expected */
157
158         for (int i = 0; i < ARRAY_SIZE(binder_features); i++) {
159                 snprintf(device_path, sizeof(device_path), "%s/features/%s",
160                          binderfs_mntpt, binder_features[i]);
161                 fd = open(device_path, O_CLOEXEC | O_RDONLY);
162                 EXPECT_GE(fd, 0) {
163                         TH_LOG("%s - Failed to open binder feature: %s",
164                                 strerror(errno), binder_features[i]);
165                         goto umount;
166                 }
167                 close(fd);
168         }
169
170         /* success: binder feature files found */
171         result = 0;
172
173 umount:
174         ret = umount2(binderfs_mntpt, MNT_DETACH);
175         EXPECT_EQ(ret, 0) {
176                 TH_LOG("%s - Failed to unmount binderfs", strerror(errno));
177         }
178 rmdir:
179         ret = rmdir(binderfs_mntpt);
180         EXPECT_EQ(ret, 0) {
181                 TH_LOG("%s - Failed to rmdir binderfs mount", strerror(errno));
182         }
183 out:
184         return result;
185 }
186
187 static int wait_for_pid(pid_t pid)
188 {
189         int status, ret;
190
191 again:
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
206 static 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
219 enum idmap_type {
220         UID_MAP,
221         GID_MAP,
222 };
223
224 static ssize_t read_nointr(int fd, void *buf, size_t count)
225 {
226         ssize_t ret;
227 again:
228         ret = read(fd, buf, count);
229         if (ret < 0 && errno == EINTR)
230                 goto again;
231
232         return ret;
233 }
234
235 static ssize_t write_nointr(int fd, const void *buf, size_t count)
236 {
237         ssize_t ret;
238 again:
239         ret = write(fd, buf, count);
240         if (ret < 0 && errno == EINTR)
241                 goto again;
242
243         return ret;
244 }
245
246 static 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
294 static void change_userns(struct __test_metadata *_metadata, 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         ASSERT_EQ(ret, 0) {
303                 TH_LOG("%s - Failed to unshare user namespace",
304                         strerror(errno));
305         }
306
307         ret = write_nointr(syncfds[0], "1", 1);
308         ASSERT_EQ(ret, 1) {
309                 TH_LOG("write_nointr() failed");
310         }
311
312         ret = read_nointr(syncfds[0], &buf, 1);
313         ASSERT_EQ(ret, 1) {
314                 TH_LOG("read_nointr() failed");
315         }
316
317         close_prot_errno_disarm(syncfds[0]);
318
319         ASSERT_EQ(setid_userns_root(), 0) {
320                 TH_LOG("setid_userns_root() failed");
321         }
322 }
323
324 static void change_idmaps(struct __test_metadata *_metadata, int syncfds[2], pid_t pid)
325 {
326         int ret;
327         char buf;
328         char id_map[4096];
329
330         close_prot_errno_disarm(syncfds[0]);
331
332         ret = read_nointr(syncfds[1], &buf, 1);
333         ASSERT_EQ(ret, 1) {
334                 TH_LOG("read_nointr() failed");
335         }
336
337         snprintf(id_map, sizeof(id_map), "0 %d 1\n", getuid());
338         ret = write_id_mapping(UID_MAP, pid, id_map, strlen(id_map));
339         ASSERT_EQ(ret, 0) {
340                 TH_LOG("write_id_mapping(UID_MAP) failed");
341         }
342
343         snprintf(id_map, sizeof(id_map), "0 %d 1\n", getgid());
344         ret = write_id_mapping(GID_MAP, pid, id_map, strlen(id_map));
345         ASSERT_EQ(ret, 0) {
346                 TH_LOG("write_id_mapping(GID_MAP) failed");
347         }
348
349         ret = write_nointr(syncfds[1], "1", 1);
350         ASSERT_EQ(ret, 1) {
351                 TH_LOG("write_nointr() failed");
352         }
353
354         close_prot_errno_disarm(syncfds[1]);
355 }
356
357 struct __test_metadata *_thread_metadata;
358 static void *binder_version_thread(void *data)
359 {
360         struct __test_metadata *_metadata = _thread_metadata;
361         int fd = PTR_TO_INT(data);
362         struct binder_version version = { 0 };
363         int ret;
364
365         ret = ioctl(fd, BINDER_VERSION, &version);
366         if (ret < 0)
367                 TH_LOG("%s - Failed to open perform BINDER_VERSION request\n",
368                         strerror(errno));
369
370         pthread_exit(data);
371 }
372
373 /*
374  * Regression test:
375  * 2669b8b0c798 ("binder: prevent UAF for binderfs devices")
376  * f0fe2c0f050d ("binder: prevent UAF for binderfs devices II")
377  * 211b64e4b5b6 ("binderfs: use refcount for binder control devices too")
378  */
379 TEST(binderfs_stress)
380 {
381         int fds[1000];
382         int syncfds[2];
383         pid_t pid;
384         int fd, ret;
385         size_t len;
386         struct binderfs_device device = { 0 };
387         char binderfs_mntpt[] = P_tmpdir "/binderfs_XXXXXX",
388                 device_path[sizeof(P_tmpdir "/binderfs_XXXXXX/") + BINDERFS_MAX_NAME];
389
390         ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, syncfds);
391         ASSERT_EQ(ret, 0) {
392                 TH_LOG("%s - Failed to create socket pair", strerror(errno));
393         }
394
395         pid = fork();
396         ASSERT_GE(pid, 0) {
397                 TH_LOG("%s - Failed to fork", strerror(errno));
398                 close_prot_errno_disarm(syncfds[0]);
399                 close_prot_errno_disarm(syncfds[1]);
400         }
401
402         if (pid == 0) {
403                 int i, j, k, nthreads;
404                 pthread_attr_t attr;
405                 pthread_t threads[DEFAULT_THREADS];
406                 change_userns(_metadata, syncfds);
407                 change_mountns(_metadata);
408
409                 ASSERT_NE(mkdtemp(binderfs_mntpt), NULL) {
410                         TH_LOG("%s - Failed to create binderfs mountpoint",
411                                 strerror(errno));
412                 }
413
414                 ret = mount(NULL, binderfs_mntpt, "binder", 0, 0);
415                 ASSERT_EQ(ret, 0) {
416                         TH_LOG("%s - Failed to mount binderfs, check if CONFIG_ANDROID_BINDERFS is enabled in the running kernel",
417                                 strerror(errno));
418                 }
419
420                 for (int i = 0; i < ARRAY_SIZE(fds); i++) {
421
422                         snprintf(device_path, sizeof(device_path),
423                                  "%s/binder-control", binderfs_mntpt);
424                         fd = open(device_path, O_RDONLY | O_CLOEXEC);
425                         ASSERT_GE(fd, 0) {
426                                 TH_LOG("%s - Failed to open binder-control device",
427                                         strerror(errno));
428                         }
429
430                         memset(&device, 0, sizeof(device));
431                         snprintf(device.name, sizeof(device.name), "%d", i);
432                         ret = ioctl(fd, BINDER_CTL_ADD, &device);
433                         close_prot_errno_disarm(fd);
434                         ASSERT_EQ(ret, 0) {
435                                 TH_LOG("%s - Failed to allocate new binder device",
436                                         strerror(errno));
437                         }
438
439                         snprintf(device_path, sizeof(device_path), "%s/%d",
440                                  binderfs_mntpt, i);
441                         fds[i] = open(device_path, O_RDONLY | O_CLOEXEC);
442                         ASSERT_GE(fds[i], 0) {
443                                 TH_LOG("%s - Failed to open binder device", strerror(errno));
444                         }
445                 }
446
447                 ret = umount2(binderfs_mntpt, MNT_DETACH);
448                 ASSERT_EQ(ret, 0) {
449                         TH_LOG("%s - Failed to unmount binderfs", strerror(errno));
450                         rmdir(binderfs_mntpt);
451                 }
452
453                 nthreads = get_nprocs_conf();
454                 if (nthreads > DEFAULT_THREADS)
455                         nthreads = DEFAULT_THREADS;
456
457                 _thread_metadata = _metadata;
458                 pthread_attr_init(&attr);
459                 for (k = 0; k < ARRAY_SIZE(fds); k++) {
460                         for (i = 0; i < nthreads; i++) {
461                                 ret = pthread_create(&threads[i], &attr, binder_version_thread, INT_TO_PTR(fds[k]));
462                                 if (ret) {
463                                         TH_LOG("%s - Failed to create thread %d",
464                                                 strerror(errno), i);
465                                         break;
466                                 }
467                         }
468
469                         for (j = 0; j < i; j++) {
470                                 void *fdptr = NULL;
471
472                                 ret = pthread_join(threads[j], &fdptr);
473                                 if (ret)
474                                         TH_LOG("%s - Failed to join thread %d for fd %d",
475                                                 strerror(errno), j, PTR_TO_INT(fdptr));
476                         }
477                 }
478                 pthread_attr_destroy(&attr);
479
480                 for (k = 0; k < ARRAY_SIZE(fds); k++)
481                         close(fds[k]);
482
483                 exit(EXIT_SUCCESS);
484         }
485
486         change_idmaps(_metadata, syncfds, pid);
487
488         ret = wait_for_pid(pid);
489         ASSERT_EQ(ret, 0) {
490                 TH_LOG("wait_for_pid() failed");
491         }
492 }
493
494 TEST(binderfs_test_privileged)
495 {
496         if (geteuid() != 0)
497                 SKIP(return, "Tests are not run as root. Skipping privileged tests");
498
499         if (__do_binderfs_test(_metadata))
500                 SKIP(return, "The Android binderfs filesystem is not available");
501 }
502
503 TEST(binderfs_test_unprivileged)
504 {
505         int ret;
506         int syncfds[2];
507         pid_t pid;
508
509         ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, syncfds);
510         ASSERT_EQ(ret, 0) {
511                 TH_LOG("%s - Failed to create socket pair", strerror(errno));
512         }
513
514         pid = fork();
515         ASSERT_GE(pid, 0) {
516                 close_prot_errno_disarm(syncfds[0]);
517                 close_prot_errno_disarm(syncfds[1]);
518                 TH_LOG("%s - Failed to fork", strerror(errno));
519         }
520
521         if (pid == 0) {
522                 change_userns(_metadata, syncfds);
523                 if (__do_binderfs_test(_metadata))
524                         exit(2);
525                 exit(EXIT_SUCCESS);
526         }
527
528         change_idmaps(_metadata, syncfds, pid);
529
530         ret = wait_for_pid(pid);
531         if (ret) {
532                 if (ret == 2)
533                         SKIP(return, "The Android binderfs filesystem is not available");
534                 ASSERT_EQ(ret, 0) {
535                         TH_LOG("wait_for_pid() failed");
536                 }
537         }
538 }
539
540 TEST_HARNESS_MAIN
This page took 0.063887 seconds and 4 git commands to generate.