~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/filesystems/binderfs/binderfs_test.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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         ssize_t wret;
 61         struct binderfs_device device = { 0 };
 62         struct binder_version version = { 0 };
 63         char binderfs_mntpt[] = P_tmpdir "/binderfs_XXXXXX",
 64                 device_path[sizeof(P_tmpdir "/binderfs_XXXXXX/") + BINDERFS_MAX_NAME];
 65         static const char * const binder_features[] = {
 66                 "oneway_spam_detection",
 67                 "extended_error",
 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
541 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php