Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

binderfs: add stress test for binderfs binder devices

This adds a stress test that should hopefully help us catch regressions
for [1], [2], and [3].

[1]: 2669b8b0c798 ("binder: prevent UAF for binderfs devices")
[2]: f0fe2c0f050d ("binder: prevent UAF for binderfs devices II")
[3]: 211b64e4b5b6 ("binderfs: use refcount for binder control devices too")
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Link: https://lore.kernel.org/r/20200313152420.138777-3-christian.brauner@ubuntu.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Christian Brauner and committed by
Greg Kroah-Hartman
e48d1174 ad29ace2

+334 -94
+1 -1
tools/testing/selftests/filesystems/binderfs/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 3 - CFLAGS += -I../../../../../usr/include/ 3 + CFLAGS += -I../../../../../usr/include/ -pthread 4 4 TEST_GEN_PROGS := binderfs_test 5 5 6 6 binderfs_test: binderfs_test.c ../../kselftest.h ../../kselftest_harness.h
+333 -93
tools/testing/selftests/filesystems/binderfs/binderfs_test.c
··· 3 3 #define _GNU_SOURCE 4 4 #include <errno.h> 5 5 #include <fcntl.h> 6 + #include <pthread.h> 6 7 #include <sched.h> 7 8 #include <stdbool.h> 8 9 #include <stdio.h> 9 10 #include <stdlib.h> 10 11 #include <string.h> 12 + #include <sys/fsuid.h> 11 13 #include <sys/ioctl.h> 12 14 #include <sys/mount.h> 15 + #include <sys/socket.h> 13 16 #include <sys/stat.h> 17 + #include <sys/sysinfo.h> 14 18 #include <sys/types.h> 19 + #include <sys/wait.h> 15 20 #include <unistd.h> 16 21 #include <linux/android/binder.h> 17 22 #include <linux/android/binderfs.h> ··· 24 19 #include "../../kselftest.h" 25 20 #include "../../kselftest_harness.h" 26 21 27 - static ssize_t write_nointr(int fd, const void *buf, size_t count) 28 - { 29 - ssize_t ret; 30 - again: 31 - ret = write(fd, buf, count); 32 - if (ret < 0 && errno == EINTR) 33 - goto again; 22 + #define DEFAULT_THREADS 4 34 23 35 - return ret; 36 - } 24 + #define PTR_TO_INT(p) ((int)((intptr_t)(p))) 25 + #define INT_TO_PTR(u) ((void *)((intptr_t)(u))) 37 26 38 - static void write_to_file(const char *filename, const void *buf, size_t count, 39 - int allowed_errno) 40 - { 41 - int fd, saved_errno; 42 - ssize_t ret; 43 - 44 - fd = open(filename, O_WRONLY | O_CLOEXEC); 45 - if (fd < 0) 46 - ksft_exit_fail_msg("%s - Failed to open file %s\n", 47 - strerror(errno), filename); 48 - 49 - ret = write_nointr(fd, buf, count); 50 - if (ret < 0) { 51 - if (allowed_errno && (errno == allowed_errno)) { 52 - close(fd); 53 - return; 54 - } 55 - 56 - goto on_error; 27 + #define close_prot_errno_disarm(fd) \ 28 + if (fd >= 0) { \ 29 + int _e_ = errno; \ 30 + close(fd); \ 31 + errno = _e_; \ 32 + fd = -EBADF; \ 57 33 } 58 34 59 - if ((size_t)ret != count) 60 - goto on_error; 35 + #define log_exit(format, ...) \ 36 + ({ \ 37 + fprintf(stderr, format "\n", ##__VA_ARGS__); \ 38 + exit(EXIT_FAILURE); \ 39 + }) 61 40 62 - close(fd); 63 - return; 64 - 65 - on_error: 66 - saved_errno = errno; 67 - close(fd); 68 - errno = saved_errno; 69 - 70 - if (ret < 0) 71 - ksft_exit_fail_msg("%s - Failed to write to file %s\n", 72 - strerror(errno), filename); 73 - 74 - ksft_exit_fail_msg("Failed to write to file %s\n", filename); 75 - } 76 - 77 - static void change_to_userns(void) 78 - { 79 - int ret; 80 - uid_t uid; 81 - gid_t gid; 82 - /* {g,u}id_map files only allow a max of 4096 bytes written to them */ 83 - char idmap[4096]; 84 - 85 - uid = getuid(); 86 - gid = getgid(); 87 - 88 - ret = unshare(CLONE_NEWUSER); 89 - if (ret < 0) 90 - ksft_exit_fail_msg("%s - Failed to unshare user namespace\n", 91 - strerror(errno)); 92 - 93 - write_to_file("/proc/self/setgroups", "deny", strlen("deny"), ENOENT); 94 - 95 - ret = snprintf(idmap, sizeof(idmap), "0 %d 1", uid); 96 - if (ret < 0 || (size_t)ret >= sizeof(idmap)) 97 - ksft_exit_fail_msg("%s - Failed to prepare uid mapping\n", 98 - strerror(errno)); 99 - 100 - write_to_file("/proc/self/uid_map", idmap, strlen(idmap), 0); 101 - 102 - ret = snprintf(idmap, sizeof(idmap), "0 %d 1", gid); 103 - if (ret < 0 || (size_t)ret >= sizeof(idmap)) 104 - ksft_exit_fail_msg("%s - Failed to prepare uid mapping\n", 105 - strerror(errno)); 106 - 107 - write_to_file("/proc/self/gid_map", idmap, strlen(idmap), 0); 108 - 109 - ret = setgid(0); 110 - if (ret) 111 - ksft_exit_fail_msg("%s - Failed to setgid(0)\n", 112 - strerror(errno)); 113 - 114 - ret = setuid(0); 115 - if (ret) 116 - ksft_exit_fail_msg("%s - Failed to setgid(0)\n", 117 - strerror(errno)); 118 - } 119 - 120 - static void change_to_mountns(void) 41 + static void change_mountns(void) 121 42 { 122 43 int ret; 123 44 ··· 75 144 char binderfs_mntpt[] = P_tmpdir "/binderfs_XXXXXX", 76 145 device_path[sizeof(P_tmpdir "/binderfs_XXXXXX/") + BINDERFS_MAX_NAME]; 77 146 78 - change_to_mountns(); 147 + change_mountns(); 79 148 80 149 if (!mkdtemp(binderfs_mntpt)) 81 150 ksft_exit_fail_msg( ··· 184 253 return 0; 185 254 } 186 255 256 + static int wait_for_pid(pid_t pid) 257 + { 258 + int status, ret; 259 + 260 + again: 261 + ret = waitpid(pid, &status, 0); 262 + if (ret == -1) { 263 + if (errno == EINTR) 264 + goto again; 265 + 266 + return -1; 267 + } 268 + 269 + if (!WIFEXITED(status)) 270 + return -1; 271 + 272 + return WEXITSTATUS(status); 273 + } 274 + 275 + static int setid_userns_root(void) 276 + { 277 + if (setuid(0)) 278 + return -1; 279 + if (setgid(0)) 280 + return -1; 281 + 282 + setfsuid(0); 283 + setfsgid(0); 284 + 285 + return 0; 286 + } 287 + 288 + enum idmap_type { 289 + UID_MAP, 290 + GID_MAP, 291 + }; 292 + 293 + static ssize_t read_nointr(int fd, void *buf, size_t count) 294 + { 295 + ssize_t ret; 296 + again: 297 + ret = read(fd, buf, count); 298 + if (ret < 0 && errno == EINTR) 299 + goto again; 300 + 301 + return ret; 302 + } 303 + 304 + static ssize_t write_nointr(int fd, const void *buf, size_t count) 305 + { 306 + ssize_t ret; 307 + again: 308 + ret = write(fd, buf, count); 309 + if (ret < 0 && errno == EINTR) 310 + goto again; 311 + 312 + return ret; 313 + } 314 + 315 + static int write_id_mapping(enum idmap_type type, pid_t pid, const char *buf, 316 + size_t buf_size) 317 + { 318 + int fd; 319 + int ret; 320 + char path[4096]; 321 + 322 + if (type == GID_MAP) { 323 + int setgroups_fd; 324 + 325 + snprintf(path, sizeof(path), "/proc/%d/setgroups", pid); 326 + setgroups_fd = open(path, O_WRONLY | O_CLOEXEC | O_NOFOLLOW); 327 + if (setgroups_fd < 0 && errno != ENOENT) 328 + return -1; 329 + 330 + if (setgroups_fd >= 0) { 331 + ret = write_nointr(setgroups_fd, "deny", sizeof("deny") - 1); 332 + close_prot_errno_disarm(setgroups_fd); 333 + if (ret != sizeof("deny") - 1) 334 + return -1; 335 + } 336 + } 337 + 338 + switch (type) { 339 + case UID_MAP: 340 + ret = snprintf(path, sizeof(path), "/proc/%d/uid_map", pid); 341 + break; 342 + case GID_MAP: 343 + ret = snprintf(path, sizeof(path), "/proc/%d/gid_map", pid); 344 + break; 345 + default: 346 + return -1; 347 + } 348 + if (ret < 0 || ret >= sizeof(path)) 349 + return -E2BIG; 350 + 351 + fd = open(path, O_WRONLY | O_CLOEXEC | O_NOFOLLOW); 352 + if (fd < 0) 353 + return -1; 354 + 355 + ret = write_nointr(fd, buf, buf_size); 356 + close_prot_errno_disarm(fd); 357 + if (ret != buf_size) 358 + return -1; 359 + 360 + return 0; 361 + } 362 + 363 + static void change_userns(int syncfds[2]) 364 + { 365 + int ret; 366 + char buf; 367 + 368 + close_prot_errno_disarm(syncfds[1]); 369 + 370 + ret = unshare(CLONE_NEWUSER); 371 + if (ret < 0) 372 + ksft_exit_fail_msg("%s - Failed to unshare user namespace\n", 373 + strerror(errno)); 374 + 375 + ret = write_nointr(syncfds[0], "1", 1); 376 + if (ret != 1) 377 + ksft_exit_fail_msg("write_nointr() failed\n"); 378 + 379 + ret = read_nointr(syncfds[0], &buf, 1); 380 + if (ret != 1) 381 + ksft_exit_fail_msg("read_nointr() failed\n"); 382 + 383 + close_prot_errno_disarm(syncfds[0]); 384 + 385 + if (setid_userns_root()) 386 + ksft_exit_fail_msg("setid_userns_root() failed"); 387 + } 388 + 389 + static void change_idmaps(int syncfds[2], pid_t pid) 390 + { 391 + int ret; 392 + char buf; 393 + char id_map[4096]; 394 + 395 + close_prot_errno_disarm(syncfds[0]); 396 + 397 + ret = read_nointr(syncfds[1], &buf, 1); 398 + if (ret != 1) 399 + ksft_exit_fail_msg("read_nointr() failed\n"); 400 + 401 + snprintf(id_map, sizeof(id_map), "0 %d 1\n", getuid()); 402 + ret = write_id_mapping(UID_MAP, pid, id_map, strlen(id_map)); 403 + if (ret) 404 + ksft_exit_fail_msg("write_id_mapping(UID_MAP) failed"); 405 + 406 + snprintf(id_map, sizeof(id_map), "0 %d 1\n", getgid()); 407 + ret = write_id_mapping(GID_MAP, pid, id_map, strlen(id_map)); 408 + if (ret) 409 + ksft_exit_fail_msg("write_id_mapping(GID_MAP) failed"); 410 + 411 + ret = write_nointr(syncfds[1], "1", 1); 412 + if (ret != 1) 413 + ksft_exit_fail_msg("write_nointr() failed"); 414 + 415 + close_prot_errno_disarm(syncfds[1]); 416 + } 417 + 418 + static void *binder_version_thread(void *data) 419 + { 420 + int fd = PTR_TO_INT(data); 421 + struct binder_version version = { 0 }; 422 + int ret; 423 + 424 + ret = ioctl(fd, BINDER_VERSION, &version); 425 + if (ret < 0) 426 + ksft_print_msg("%s - Failed to open perform BINDER_VERSION request\n", strerror(errno)); 427 + 428 + pthread_exit(data); 429 + } 430 + 431 + /* 432 + * Regression test: 433 + * 2669b8b0c798 ("binder: prevent UAF for binderfs devices") 434 + * f0fe2c0f050d ("binder: prevent UAF for binderfs devices II") 435 + * 211b64e4b5b6 ("binderfs: use refcount for binder control devices too") 436 + */ 437 + TEST(binderfs_stress) 438 + { 439 + int fds[1000]; 440 + int syncfds[2]; 441 + pid_t pid; 442 + int fd, ret; 443 + size_t len; 444 + struct binderfs_device device = { 0 }; 445 + char binderfs_mntpt[] = P_tmpdir "/binderfs_XXXXXX", 446 + device_path[sizeof(P_tmpdir "/binderfs_XXXXXX/") + BINDERFS_MAX_NAME]; 447 + 448 + ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, syncfds); 449 + if (ret < 0) 450 + ksft_exit_fail_msg("%s - Failed to create socket pair", strerror(errno)); 451 + 452 + pid = fork(); 453 + if (pid < 0) { 454 + close_prot_errno_disarm(syncfds[0]); 455 + close_prot_errno_disarm(syncfds[1]); 456 + ksft_exit_fail_msg("%s - Failed to fork", strerror(errno)); 457 + } 458 + 459 + if (pid == 0) { 460 + int i, j, k, nthreads; 461 + pthread_attr_t attr; 462 + pthread_t threads[DEFAULT_THREADS]; 463 + change_userns(syncfds); 464 + change_mountns(); 465 + 466 + if (!mkdtemp(binderfs_mntpt)) 467 + log_exit("%s - Failed to create binderfs mountpoint\n", 468 + strerror(errno)); 469 + 470 + ret = mount(NULL, binderfs_mntpt, "binder", 0, 0); 471 + if (ret < 0) 472 + log_exit("%s - Failed to mount binderfs\n", strerror(errno)); 473 + 474 + for (int i = 0; i < ARRAY_SIZE(fds); i++) { 475 + 476 + snprintf(device_path, sizeof(device_path), 477 + "%s/binder-control", binderfs_mntpt); 478 + fd = open(device_path, O_RDONLY | O_CLOEXEC); 479 + if (fd < 0) 480 + log_exit("%s - Failed to open binder-control device\n", strerror(errno)); 481 + 482 + memset(&device, 0, sizeof(device)); 483 + snprintf(device.name, sizeof(device.name), "%d", i); 484 + ret = ioctl(fd, BINDER_CTL_ADD, &device); 485 + close_prot_errno_disarm(fd); 486 + if (ret < 0) 487 + log_exit("%s - Failed to allocate new binder device\n", strerror(errno)); 488 + 489 + snprintf(device_path, sizeof(device_path), "%s/%d", 490 + binderfs_mntpt, i); 491 + fds[i] = open(device_path, O_RDONLY | O_CLOEXEC); 492 + if (fds[i] < 0) 493 + log_exit("%s - Failed to open binder device\n", strerror(errno)); 494 + } 495 + 496 + ret = umount2(binderfs_mntpt, MNT_DETACH); 497 + rmdir_protect_errno(binderfs_mntpt); 498 + if (ret < 0) 499 + log_exit("%s - Failed to unmount binderfs\n", strerror(errno)); 500 + 501 + nthreads = get_nprocs_conf(); 502 + if (nthreads > DEFAULT_THREADS) 503 + nthreads = DEFAULT_THREADS; 504 + 505 + pthread_attr_init(&attr); 506 + for (k = 0; k < ARRAY_SIZE(fds); k++) { 507 + for (i = 0; i < nthreads; i++) { 508 + ret = pthread_create(&threads[i], &attr, binder_version_thread, INT_TO_PTR(fds[k])); 509 + if (ret) { 510 + ksft_print_msg("%s - Failed to create thread %d\n", strerror(errno), i); 511 + break; 512 + } 513 + } 514 + 515 + for (j = 0; j < i; j++) { 516 + void *fdptr = NULL; 517 + 518 + ret = pthread_join(threads[j], &fdptr); 519 + if (ret) 520 + ksft_print_msg("%s - Failed to join thread %d for fd %d\n", strerror(errno), j, PTR_TO_INT(fdptr)); 521 + } 522 + } 523 + pthread_attr_destroy(&attr); 524 + 525 + for (k = 0; k < ARRAY_SIZE(fds); k++) 526 + close(fds[k]); 527 + 528 + exit(EXIT_SUCCESS); 529 + } 530 + 531 + change_idmaps(syncfds, pid); 532 + 533 + ret = wait_for_pid(pid); 534 + if (ret) 535 + ksft_exit_fail_msg("wait_for_pid() failed"); 536 + } 537 + 187 538 TEST(binderfs_test_privileged) 188 539 { 189 540 if (geteuid() != 0) ··· 477 264 478 265 TEST(binderfs_test_unprivileged) 479 266 { 480 - change_to_userns(); 267 + int ret; 268 + int syncfds[2]; 269 + pid_t pid; 481 270 482 - if (__do_binderfs_test() == 1) 483 - XFAIL(return, "The Android binderfs filesystem is not available"); 271 + ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, syncfds); 272 + if (ret < 0) 273 + ksft_exit_fail_msg("%s - Failed to create socket pair", strerror(errno)); 274 + 275 + pid = fork(); 276 + if (pid < 0) { 277 + close_prot_errno_disarm(syncfds[0]); 278 + close_prot_errno_disarm(syncfds[1]); 279 + ksft_exit_fail_msg("%s - Failed to fork", strerror(errno)); 280 + } 281 + 282 + if (pid == 0) { 283 + change_userns(syncfds); 284 + if (__do_binderfs_test() == 1) 285 + exit(2); 286 + exit(EXIT_SUCCESS); 287 + } 288 + 289 + change_idmaps(syncfds, pid); 290 + 291 + ret = wait_for_pid(pid); 292 + if (ret) { 293 + if (ret == 2) 294 + XFAIL(return, "The Android binderfs filesystem is not available"); 295 + else 296 + ksft_exit_fail_msg("wait_for_pid() failed"); 297 + } 484 298 } 485 299 486 300 TEST_HARNESS_MAIN