Path: blob/master/tools/testing/selftests/filesystems/binderfs/binderfs_test.c
26302 views
// SPDX-License-Identifier: GPL-2.012#define _GNU_SOURCE3#include <errno.h>4#include <fcntl.h>5#include <pthread.h>6#include <sched.h>7#include <stdbool.h>8#include <stdio.h>9#include <stdlib.h>10#include <string.h>11#include <sys/fsuid.h>12#include <sys/ioctl.h>13#include <sys/mount.h>14#include <sys/socket.h>15#include <sys/stat.h>16#include <sys/sysinfo.h>17#include <sys/types.h>18#include <sys/wait.h>19#include <unistd.h>20#include <linux/android/binder.h>21#include <linux/android/binderfs.h>2223#include "../../kselftest_harness.h"2425#define DEFAULT_THREADS 42627#define PTR_TO_INT(p) ((int)((intptr_t)(p)))28#define INT_TO_PTR(u) ((void *)((intptr_t)(u)))2930#define close_prot_errno_disarm(fd) \31if (fd >= 0) { \32int _e_ = errno; \33close(fd); \34errno = _e_; \35fd = -EBADF; \36}3738static void change_mountns(struct __test_metadata *_metadata)39{40int ret;4142ret = unshare(CLONE_NEWNS);43ASSERT_EQ(ret, 0) {44TH_LOG("%s - Failed to unshare mount namespace",45strerror(errno));46}4748ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0);49ASSERT_EQ(ret, 0) {50TH_LOG("%s - Failed to mount / as private",51strerror(errno));52}53}5455static int __do_binderfs_test(struct __test_metadata *_metadata)56{57int fd, ret, saved_errno, result = 1;58size_t len;59struct binderfs_device device = { 0 };60struct binder_version version = { 0 };61char binderfs_mntpt[] = P_tmpdir "/binderfs_XXXXXX",62device_path[sizeof(P_tmpdir "/binderfs_XXXXXX/") + BINDERFS_MAX_NAME];63static const char * const binder_features[] = {64"oneway_spam_detection",65"extended_error",66"freeze_notification",67};6869change_mountns(_metadata);7071EXPECT_NE(mkdtemp(binderfs_mntpt), NULL) {72TH_LOG("%s - Failed to create binderfs mountpoint",73strerror(errno));74goto out;75}7677ret = mount(NULL, binderfs_mntpt, "binder", 0, 0);78EXPECT_EQ(ret, 0) {79if (errno == ENODEV)80SKIP(goto out, "binderfs missing");81TH_LOG("%s - Failed to mount binderfs", strerror(errno));82goto rmdir;83}8485/* success: binderfs mounted */8687memcpy(device.name, "my-binder", strlen("my-binder"));8889snprintf(device_path, sizeof(device_path), "%s/binder-control", binderfs_mntpt);90fd = open(device_path, O_RDONLY | O_CLOEXEC);91EXPECT_GE(fd, 0) {92TH_LOG("%s - Failed to open binder-control device",93strerror(errno));94goto umount;95}9697ret = ioctl(fd, BINDER_CTL_ADD, &device);98saved_errno = errno;99close(fd);100errno = saved_errno;101EXPECT_GE(ret, 0) {102TH_LOG("%s - Failed to allocate new binder device",103strerror(errno));104goto umount;105}106107TH_LOG("Allocated new binder device with major %d, minor %d, and name %s",108device.major, device.minor, device.name);109110/* success: binder device allocation */111112snprintf(device_path, sizeof(device_path), "%s/my-binder", binderfs_mntpt);113fd = open(device_path, O_CLOEXEC | O_RDONLY);114EXPECT_GE(fd, 0) {115TH_LOG("%s - Failed to open my-binder device",116strerror(errno));117goto umount;118}119120ret = ioctl(fd, BINDER_VERSION, &version);121saved_errno = errno;122close(fd);123errno = saved_errno;124EXPECT_GE(ret, 0) {125TH_LOG("%s - Failed to open perform BINDER_VERSION request",126strerror(errno));127goto umount;128}129130TH_LOG("Detected binder version: %d", version.protocol_version);131132/* success: binder transaction with binderfs binder device */133134ret = unlink(device_path);135EXPECT_EQ(ret, 0) {136TH_LOG("%s - Failed to delete binder device",137strerror(errno));138goto umount;139}140141/* success: binder device removal */142143snprintf(device_path, sizeof(device_path), "%s/binder-control", binderfs_mntpt);144ret = unlink(device_path);145EXPECT_NE(ret, 0) {146TH_LOG("Managed to delete binder-control device");147goto umount;148}149EXPECT_EQ(errno, EPERM) {150TH_LOG("%s - Failed to delete binder-control device but exited with unexpected error code",151strerror(errno));152goto umount;153}154155/* success: binder-control device removal failed as expected */156157for (int i = 0; i < ARRAY_SIZE(binder_features); i++) {158snprintf(device_path, sizeof(device_path), "%s/features/%s",159binderfs_mntpt, binder_features[i]);160fd = open(device_path, O_CLOEXEC | O_RDONLY);161EXPECT_GE(fd, 0) {162TH_LOG("%s - Failed to open binder feature: %s",163strerror(errno), binder_features[i]);164goto umount;165}166close(fd);167}168169/* success: binder feature files found */170result = 0;171172umount:173ret = umount2(binderfs_mntpt, MNT_DETACH);174EXPECT_EQ(ret, 0) {175TH_LOG("%s - Failed to unmount binderfs", strerror(errno));176}177rmdir:178ret = rmdir(binderfs_mntpt);179EXPECT_EQ(ret, 0) {180TH_LOG("%s - Failed to rmdir binderfs mount", strerror(errno));181}182out:183return result;184}185186static int wait_for_pid(pid_t pid)187{188int status, ret;189190again:191ret = waitpid(pid, &status, 0);192if (ret == -1) {193if (errno == EINTR)194goto again;195196return -1;197}198199if (!WIFEXITED(status))200return -1;201202return WEXITSTATUS(status);203}204205static int setid_userns_root(void)206{207if (setuid(0))208return -1;209if (setgid(0))210return -1;211212setfsuid(0);213setfsgid(0);214215return 0;216}217218enum idmap_type {219UID_MAP,220GID_MAP,221};222223static ssize_t read_nointr(int fd, void *buf, size_t count)224{225ssize_t ret;226again:227ret = read(fd, buf, count);228if (ret < 0 && errno == EINTR)229goto again;230231return ret;232}233234static ssize_t write_nointr(int fd, const void *buf, size_t count)235{236ssize_t ret;237again:238ret = write(fd, buf, count);239if (ret < 0 && errno == EINTR)240goto again;241242return ret;243}244245static int write_id_mapping(enum idmap_type type, pid_t pid, const char *buf,246size_t buf_size)247{248int fd;249int ret;250char path[4096];251252if (type == GID_MAP) {253int setgroups_fd;254255snprintf(path, sizeof(path), "/proc/%d/setgroups", pid);256setgroups_fd = open(path, O_WRONLY | O_CLOEXEC | O_NOFOLLOW);257if (setgroups_fd < 0 && errno != ENOENT)258return -1;259260if (setgroups_fd >= 0) {261ret = write_nointr(setgroups_fd, "deny", sizeof("deny") - 1);262close_prot_errno_disarm(setgroups_fd);263if (ret != sizeof("deny") - 1)264return -1;265}266}267268switch (type) {269case UID_MAP:270ret = snprintf(path, sizeof(path), "/proc/%d/uid_map", pid);271break;272case GID_MAP:273ret = snprintf(path, sizeof(path), "/proc/%d/gid_map", pid);274break;275default:276return -1;277}278if (ret < 0 || ret >= sizeof(path))279return -E2BIG;280281fd = open(path, O_WRONLY | O_CLOEXEC | O_NOFOLLOW);282if (fd < 0)283return -1;284285ret = write_nointr(fd, buf, buf_size);286close_prot_errno_disarm(fd);287if (ret != buf_size)288return -1;289290return 0;291}292293static void change_userns(struct __test_metadata *_metadata, int syncfds[2])294{295int ret;296char buf;297298close_prot_errno_disarm(syncfds[1]);299300ret = unshare(CLONE_NEWUSER);301ASSERT_EQ(ret, 0) {302TH_LOG("%s - Failed to unshare user namespace",303strerror(errno));304}305306ret = write_nointr(syncfds[0], "1", 1);307ASSERT_EQ(ret, 1) {308TH_LOG("write_nointr() failed");309}310311ret = read_nointr(syncfds[0], &buf, 1);312ASSERT_EQ(ret, 1) {313TH_LOG("read_nointr() failed");314}315316close_prot_errno_disarm(syncfds[0]);317318ASSERT_EQ(setid_userns_root(), 0) {319TH_LOG("setid_userns_root() failed");320}321}322323static void change_idmaps(struct __test_metadata *_metadata, int syncfds[2], pid_t pid)324{325int ret;326char buf;327char id_map[4096];328329close_prot_errno_disarm(syncfds[0]);330331ret = read_nointr(syncfds[1], &buf, 1);332ASSERT_EQ(ret, 1) {333TH_LOG("read_nointr() failed");334}335336snprintf(id_map, sizeof(id_map), "0 %d 1\n", getuid());337ret = write_id_mapping(UID_MAP, pid, id_map, strlen(id_map));338ASSERT_EQ(ret, 0) {339TH_LOG("write_id_mapping(UID_MAP) failed");340}341342snprintf(id_map, sizeof(id_map), "0 %d 1\n", getgid());343ret = write_id_mapping(GID_MAP, pid, id_map, strlen(id_map));344ASSERT_EQ(ret, 0) {345TH_LOG("write_id_mapping(GID_MAP) failed");346}347348ret = write_nointr(syncfds[1], "1", 1);349ASSERT_EQ(ret, 1) {350TH_LOG("write_nointr() failed");351}352353close_prot_errno_disarm(syncfds[1]);354}355356struct __test_metadata *_thread_metadata;357static void *binder_version_thread(void *data)358{359struct __test_metadata *_metadata = _thread_metadata;360int fd = PTR_TO_INT(data);361struct binder_version version = { 0 };362int ret;363364ret = ioctl(fd, BINDER_VERSION, &version);365if (ret < 0)366TH_LOG("%s - Failed to open perform BINDER_VERSION request\n",367strerror(errno));368369pthread_exit(data);370}371372/*373* Regression test:374* 2669b8b0c798 ("binder: prevent UAF for binderfs devices")375* f0fe2c0f050d ("binder: prevent UAF for binderfs devices II")376* 211b64e4b5b6 ("binderfs: use refcount for binder control devices too")377*/378TEST(binderfs_stress)379{380int fds[1000];381int syncfds[2];382pid_t pid;383int fd, ret;384size_t len;385struct binderfs_device device = { 0 };386char binderfs_mntpt[] = P_tmpdir "/binderfs_XXXXXX",387device_path[sizeof(P_tmpdir "/binderfs_XXXXXX/") + BINDERFS_MAX_NAME];388389ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, syncfds);390ASSERT_EQ(ret, 0) {391TH_LOG("%s - Failed to create socket pair", strerror(errno));392}393394pid = fork();395ASSERT_GE(pid, 0) {396TH_LOG("%s - Failed to fork", strerror(errno));397close_prot_errno_disarm(syncfds[0]);398close_prot_errno_disarm(syncfds[1]);399}400401if (pid == 0) {402int i, j, k, nthreads;403pthread_attr_t attr;404pthread_t threads[DEFAULT_THREADS];405change_userns(_metadata, syncfds);406change_mountns(_metadata);407408ASSERT_NE(mkdtemp(binderfs_mntpt), NULL) {409TH_LOG("%s - Failed to create binderfs mountpoint",410strerror(errno));411}412413ret = mount(NULL, binderfs_mntpt, "binder", 0, 0);414ASSERT_EQ(ret, 0) {415TH_LOG("%s - Failed to mount binderfs, check if CONFIG_ANDROID_BINDERFS is enabled in the running kernel",416strerror(errno));417}418419for (int i = 0; i < ARRAY_SIZE(fds); i++) {420421snprintf(device_path, sizeof(device_path),422"%s/binder-control", binderfs_mntpt);423fd = open(device_path, O_RDONLY | O_CLOEXEC);424ASSERT_GE(fd, 0) {425TH_LOG("%s - Failed to open binder-control device",426strerror(errno));427}428429memset(&device, 0, sizeof(device));430snprintf(device.name, sizeof(device.name), "%d", i);431ret = ioctl(fd, BINDER_CTL_ADD, &device);432close_prot_errno_disarm(fd);433ASSERT_EQ(ret, 0) {434TH_LOG("%s - Failed to allocate new binder device",435strerror(errno));436}437438snprintf(device_path, sizeof(device_path), "%s/%d",439binderfs_mntpt, i);440fds[i] = open(device_path, O_RDONLY | O_CLOEXEC);441ASSERT_GE(fds[i], 0) {442TH_LOG("%s - Failed to open binder device", strerror(errno));443}444}445446ret = umount2(binderfs_mntpt, MNT_DETACH);447ASSERT_EQ(ret, 0) {448TH_LOG("%s - Failed to unmount binderfs", strerror(errno));449rmdir(binderfs_mntpt);450}451452nthreads = get_nprocs_conf();453if (nthreads > DEFAULT_THREADS)454nthreads = DEFAULT_THREADS;455456_thread_metadata = _metadata;457pthread_attr_init(&attr);458for (k = 0; k < ARRAY_SIZE(fds); k++) {459for (i = 0; i < nthreads; i++) {460ret = pthread_create(&threads[i], &attr, binder_version_thread, INT_TO_PTR(fds[k]));461if (ret) {462TH_LOG("%s - Failed to create thread %d",463strerror(errno), i);464break;465}466}467468for (j = 0; j < i; j++) {469void *fdptr = NULL;470471ret = pthread_join(threads[j], &fdptr);472if (ret)473TH_LOG("%s - Failed to join thread %d for fd %d",474strerror(errno), j, PTR_TO_INT(fdptr));475}476}477pthread_attr_destroy(&attr);478479for (k = 0; k < ARRAY_SIZE(fds); k++)480close(fds[k]);481482exit(EXIT_SUCCESS);483}484485change_idmaps(_metadata, syncfds, pid);486487ret = wait_for_pid(pid);488ASSERT_EQ(ret, 0) {489TH_LOG("wait_for_pid() failed");490}491}492493TEST(binderfs_test_privileged)494{495if (geteuid() != 0)496SKIP(return, "Tests are not run as root. Skipping privileged tests");497498if (__do_binderfs_test(_metadata))499SKIP(return, "The Android binderfs filesystem is not available");500}501502TEST(binderfs_test_unprivileged)503{504int ret;505int syncfds[2];506pid_t pid;507508ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, syncfds);509ASSERT_EQ(ret, 0) {510TH_LOG("%s - Failed to create socket pair", strerror(errno));511}512513pid = fork();514ASSERT_GE(pid, 0) {515close_prot_errno_disarm(syncfds[0]);516close_prot_errno_disarm(syncfds[1]);517TH_LOG("%s - Failed to fork", strerror(errno));518}519520if (pid == 0) {521change_userns(_metadata, syncfds);522if (__do_binderfs_test(_metadata))523exit(2);524exit(EXIT_SUCCESS);525}526527change_idmaps(_metadata, syncfds, pid);528529ret = wait_for_pid(pid);530if (ret) {531if (ret == 2)532SKIP(return, "The Android binderfs filesystem is not available");533ASSERT_EQ(ret, 0) {534TH_LOG("wait_for_pid() failed");535}536}537}538539TEST_HARNESS_MAIN540541542