542 lines · c
1// SPDX-License-Identifier: GPL-2.02 3#define _GNU_SOURCE4#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 427 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 39static 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 56static 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 "freeze_notification",69 };70 71 change_mountns(_metadata);72 73 EXPECT_NE(mkdtemp(binderfs_mntpt), NULL) {74 TH_LOG("%s - Failed to create binderfs mountpoint",75 strerror(errno));76 goto out;77 }78 79 ret = mount(NULL, binderfs_mntpt, "binder", 0, 0);80 EXPECT_EQ(ret, 0) {81 if (errno == ENODEV)82 SKIP(goto out, "binderfs missing");83 TH_LOG("%s - Failed to mount binderfs", strerror(errno));84 goto rmdir;85 }86 87 /* success: binderfs mounted */88 89 memcpy(device.name, "my-binder", strlen("my-binder"));90 91 snprintf(device_path, sizeof(device_path), "%s/binder-control", binderfs_mntpt);92 fd = open(device_path, O_RDONLY | O_CLOEXEC);93 EXPECT_GE(fd, 0) {94 TH_LOG("%s - Failed to open binder-control device",95 strerror(errno));96 goto umount;97 }98 99 ret = ioctl(fd, BINDER_CTL_ADD, &device);100 saved_errno = errno;101 close(fd);102 errno = saved_errno;103 EXPECT_GE(ret, 0) {104 TH_LOG("%s - Failed to allocate new binder device",105 strerror(errno));106 goto umount;107 }108 109 TH_LOG("Allocated new binder device with major %d, minor %d, and name %s",110 device.major, device.minor, device.name);111 112 /* success: binder device allocation */113 114 snprintf(device_path, sizeof(device_path), "%s/my-binder", binderfs_mntpt);115 fd = open(device_path, O_CLOEXEC | O_RDONLY);116 EXPECT_GE(fd, 0) {117 TH_LOG("%s - Failed to open my-binder device",118 strerror(errno));119 goto umount;120 }121 122 ret = ioctl(fd, BINDER_VERSION, &version);123 saved_errno = errno;124 close(fd);125 errno = saved_errno;126 EXPECT_GE(ret, 0) {127 TH_LOG("%s - Failed to open perform BINDER_VERSION request",128 strerror(errno));129 goto umount;130 }131 132 TH_LOG("Detected binder version: %d", version.protocol_version);133 134 /* success: binder transaction with binderfs binder device */135 136 ret = unlink(device_path);137 EXPECT_EQ(ret, 0) {138 TH_LOG("%s - Failed to delete binder device",139 strerror(errno));140 goto umount;141 }142 143 /* success: binder device removal */144 145 snprintf(device_path, sizeof(device_path), "%s/binder-control", binderfs_mntpt);146 ret = unlink(device_path);147 EXPECT_NE(ret, 0) {148 TH_LOG("Managed to delete binder-control device");149 goto umount;150 }151 EXPECT_EQ(errno, EPERM) {152 TH_LOG("%s - Failed to delete binder-control device but exited with unexpected error code",153 strerror(errno));154 goto umount;155 }156 157 /* success: binder-control device removal failed as expected */158 159 for (int i = 0; i < ARRAY_SIZE(binder_features); i++) {160 snprintf(device_path, sizeof(device_path), "%s/features/%s",161 binderfs_mntpt, binder_features[i]);162 fd = open(device_path, O_CLOEXEC | O_RDONLY);163 EXPECT_GE(fd, 0) {164 TH_LOG("%s - Failed to open binder feature: %s",165 strerror(errno), binder_features[i]);166 goto umount;167 }168 close(fd);169 }170 171 /* success: binder feature files found */172 result = 0;173 174umount:175 ret = umount2(binderfs_mntpt, MNT_DETACH);176 EXPECT_EQ(ret, 0) {177 TH_LOG("%s - Failed to unmount binderfs", strerror(errno));178 }179rmdir:180 ret = rmdir(binderfs_mntpt);181 EXPECT_EQ(ret, 0) {182 TH_LOG("%s - Failed to rmdir binderfs mount", strerror(errno));183 }184out:185 return result;186}187 188static int wait_for_pid(pid_t pid)189{190 int status, ret;191 192again:193 ret = waitpid(pid, &status, 0);194 if (ret == -1) {195 if (errno == EINTR)196 goto again;197 198 return -1;199 }200 201 if (!WIFEXITED(status))202 return -1;203 204 return WEXITSTATUS(status);205}206 207static int setid_userns_root(void)208{209 if (setuid(0))210 return -1;211 if (setgid(0))212 return -1;213 214 setfsuid(0);215 setfsgid(0);216 217 return 0;218}219 220enum idmap_type {221 UID_MAP,222 GID_MAP,223};224 225static ssize_t read_nointr(int fd, void *buf, size_t count)226{227 ssize_t ret;228again:229 ret = read(fd, buf, count);230 if (ret < 0 && errno == EINTR)231 goto again;232 233 return ret;234}235 236static ssize_t write_nointr(int fd, const void *buf, size_t count)237{238 ssize_t ret;239again:240 ret = write(fd, buf, count);241 if (ret < 0 && errno == EINTR)242 goto again;243 244 return ret;245}246 247static int write_id_mapping(enum idmap_type type, pid_t pid, const char *buf,248 size_t buf_size)249{250 int fd;251 int ret;252 char path[4096];253 254 if (type == GID_MAP) {255 int setgroups_fd;256 257 snprintf(path, sizeof(path), "/proc/%d/setgroups", pid);258 setgroups_fd = open(path, O_WRONLY | O_CLOEXEC | O_NOFOLLOW);259 if (setgroups_fd < 0 && errno != ENOENT)260 return -1;261 262 if (setgroups_fd >= 0) {263 ret = write_nointr(setgroups_fd, "deny", sizeof("deny") - 1);264 close_prot_errno_disarm(setgroups_fd);265 if (ret != sizeof("deny") - 1)266 return -1;267 }268 }269 270 switch (type) {271 case UID_MAP:272 ret = snprintf(path, sizeof(path), "/proc/%d/uid_map", pid);273 break;274 case GID_MAP:275 ret = snprintf(path, sizeof(path), "/proc/%d/gid_map", pid);276 break;277 default:278 return -1;279 }280 if (ret < 0 || ret >= sizeof(path))281 return -E2BIG;282 283 fd = open(path, O_WRONLY | O_CLOEXEC | O_NOFOLLOW);284 if (fd < 0)285 return -1;286 287 ret = write_nointr(fd, buf, buf_size);288 close_prot_errno_disarm(fd);289 if (ret != buf_size)290 return -1;291 292 return 0;293}294 295static void change_userns(struct __test_metadata *_metadata, int syncfds[2])296{297 int ret;298 char buf;299 300 close_prot_errno_disarm(syncfds[1]);301 302 ret = unshare(CLONE_NEWUSER);303 ASSERT_EQ(ret, 0) {304 TH_LOG("%s - Failed to unshare user namespace",305 strerror(errno));306 }307 308 ret = write_nointr(syncfds[0], "1", 1);309 ASSERT_EQ(ret, 1) {310 TH_LOG("write_nointr() failed");311 }312 313 ret = read_nointr(syncfds[0], &buf, 1);314 ASSERT_EQ(ret, 1) {315 TH_LOG("read_nointr() failed");316 }317 318 close_prot_errno_disarm(syncfds[0]);319 320 ASSERT_EQ(setid_userns_root(), 0) {321 TH_LOG("setid_userns_root() failed");322 }323}324 325static void change_idmaps(struct __test_metadata *_metadata, int syncfds[2], pid_t pid)326{327 int ret;328 char buf;329 char id_map[4096];330 331 close_prot_errno_disarm(syncfds[0]);332 333 ret = read_nointr(syncfds[1], &buf, 1);334 ASSERT_EQ(ret, 1) {335 TH_LOG("read_nointr() failed");336 }337 338 snprintf(id_map, sizeof(id_map), "0 %d 1\n", getuid());339 ret = write_id_mapping(UID_MAP, pid, id_map, strlen(id_map));340 ASSERT_EQ(ret, 0) {341 TH_LOG("write_id_mapping(UID_MAP) failed");342 }343 344 snprintf(id_map, sizeof(id_map), "0 %d 1\n", getgid());345 ret = write_id_mapping(GID_MAP, pid, id_map, strlen(id_map));346 ASSERT_EQ(ret, 0) {347 TH_LOG("write_id_mapping(GID_MAP) failed");348 }349 350 ret = write_nointr(syncfds[1], "1", 1);351 ASSERT_EQ(ret, 1) {352 TH_LOG("write_nointr() failed");353 }354 355 close_prot_errno_disarm(syncfds[1]);356}357 358struct __test_metadata *_thread_metadata;359static void *binder_version_thread(void *data)360{361 struct __test_metadata *_metadata = _thread_metadata;362 int fd = PTR_TO_INT(data);363 struct binder_version version = { 0 };364 int ret;365 366 ret = ioctl(fd, BINDER_VERSION, &version);367 if (ret < 0)368 TH_LOG("%s - Failed to open perform BINDER_VERSION request\n",369 strerror(errno));370 371 pthread_exit(data);372}373 374/*375 * Regression test:376 * 2669b8b0c798 ("binder: prevent UAF for binderfs devices")377 * f0fe2c0f050d ("binder: prevent UAF for binderfs devices II")378 * 211b64e4b5b6 ("binderfs: use refcount for binder control devices too")379 */380TEST(binderfs_stress)381{382 int fds[1000];383 int syncfds[2];384 pid_t pid;385 int fd, ret;386 size_t len;387 struct binderfs_device device = { 0 };388 char binderfs_mntpt[] = P_tmpdir "/binderfs_XXXXXX",389 device_path[sizeof(P_tmpdir "/binderfs_XXXXXX/") + BINDERFS_MAX_NAME];390 391 ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, syncfds);392 ASSERT_EQ(ret, 0) {393 TH_LOG("%s - Failed to create socket pair", strerror(errno));394 }395 396 pid = fork();397 ASSERT_GE(pid, 0) {398 TH_LOG("%s - Failed to fork", strerror(errno));399 close_prot_errno_disarm(syncfds[0]);400 close_prot_errno_disarm(syncfds[1]);401 }402 403 if (pid == 0) {404 int i, j, k, nthreads;405 pthread_attr_t attr;406 pthread_t threads[DEFAULT_THREADS];407 change_userns(_metadata, syncfds);408 change_mountns(_metadata);409 410 ASSERT_NE(mkdtemp(binderfs_mntpt), NULL) {411 TH_LOG("%s - Failed to create binderfs mountpoint",412 strerror(errno));413 }414 415 ret = mount(NULL, binderfs_mntpt, "binder", 0, 0);416 ASSERT_EQ(ret, 0) {417 TH_LOG("%s - Failed to mount binderfs, check if CONFIG_ANDROID_BINDERFS is enabled in the running kernel",418 strerror(errno));419 }420 421 for (int i = 0; i < ARRAY_SIZE(fds); i++) {422 423 snprintf(device_path, sizeof(device_path),424 "%s/binder-control", binderfs_mntpt);425 fd = open(device_path, O_RDONLY | O_CLOEXEC);426 ASSERT_GE(fd, 0) {427 TH_LOG("%s - Failed to open binder-control device",428 strerror(errno));429 }430 431 memset(&device, 0, sizeof(device));432 snprintf(device.name, sizeof(device.name), "%d", i);433 ret = ioctl(fd, BINDER_CTL_ADD, &device);434 close_prot_errno_disarm(fd);435 ASSERT_EQ(ret, 0) {436 TH_LOG("%s - Failed to allocate new binder device",437 strerror(errno));438 }439 440 snprintf(device_path, sizeof(device_path), "%s/%d",441 binderfs_mntpt, i);442 fds[i] = open(device_path, O_RDONLY | O_CLOEXEC);443 ASSERT_GE(fds[i], 0) {444 TH_LOG("%s - Failed to open binder device", strerror(errno));445 }446 }447 448 ret = umount2(binderfs_mntpt, MNT_DETACH);449 ASSERT_EQ(ret, 0) {450 TH_LOG("%s - Failed to unmount binderfs", strerror(errno));451 rmdir(binderfs_mntpt);452 }453 454 nthreads = get_nprocs_conf();455 if (nthreads > DEFAULT_THREADS)456 nthreads = DEFAULT_THREADS;457 458 _thread_metadata = _metadata;459 pthread_attr_init(&attr);460 for (k = 0; k < ARRAY_SIZE(fds); k++) {461 for (i = 0; i < nthreads; i++) {462 ret = pthread_create(&threads[i], &attr, binder_version_thread, INT_TO_PTR(fds[k]));463 if (ret) {464 TH_LOG("%s - Failed to create thread %d",465 strerror(errno), i);466 break;467 }468 }469 470 for (j = 0; j < i; j++) {471 void *fdptr = NULL;472 473 ret = pthread_join(threads[j], &fdptr);474 if (ret)475 TH_LOG("%s - Failed to join thread %d for fd %d",476 strerror(errno), j, PTR_TO_INT(fdptr));477 }478 }479 pthread_attr_destroy(&attr);480 481 for (k = 0; k < ARRAY_SIZE(fds); k++)482 close(fds[k]);483 484 exit(EXIT_SUCCESS);485 }486 487 change_idmaps(_metadata, syncfds, pid);488 489 ret = wait_for_pid(pid);490 ASSERT_EQ(ret, 0) {491 TH_LOG("wait_for_pid() failed");492 }493}494 495TEST(binderfs_test_privileged)496{497 if (geteuid() != 0)498 SKIP(return, "Tests are not run as root. Skipping privileged tests");499 500 if (__do_binderfs_test(_metadata))501 SKIP(return, "The Android binderfs filesystem is not available");502}503 504TEST(binderfs_test_unprivileged)505{506 int ret;507 int syncfds[2];508 pid_t pid;509 510 ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, syncfds);511 ASSERT_EQ(ret, 0) {512 TH_LOG("%s - Failed to create socket pair", strerror(errno));513 }514 515 pid = fork();516 ASSERT_GE(pid, 0) {517 close_prot_errno_disarm(syncfds[0]);518 close_prot_errno_disarm(syncfds[1]);519 TH_LOG("%s - Failed to fork", strerror(errno));520 }521 522 if (pid == 0) {523 change_userns(_metadata, syncfds);524 if (__do_binderfs_test(_metadata))525 exit(2);526 exit(EXIT_SUCCESS);527 }528 529 change_idmaps(_metadata, syncfds, pid);530 531 ret = wait_for_pid(pid);532 if (ret) {533 if (ret == 2)534 SKIP(return, "The Android binderfs filesystem is not available");535 ASSERT_EQ(ret, 0) {536 TH_LOG("wait_for_pid() failed");537 }538 }539}540 541TEST_HARNESS_MAIN542