cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

binderfs_test.c (12402B)


      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
     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	};
     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
    173umount:
    174	ret = umount2(binderfs_mntpt, MNT_DETACH);
    175	EXPECT_EQ(ret, 0) {
    176		TH_LOG("%s - Failed to unmount binderfs", strerror(errno));
    177	}
    178rmdir:
    179	ret = rmdir(binderfs_mntpt);
    180	EXPECT_EQ(ret, 0) {
    181		TH_LOG("%s - Failed to rmdir binderfs mount", strerror(errno));
    182	}
    183out:
    184	return result;
    185}
    186
    187static int wait_for_pid(pid_t pid)
    188{
    189	int status, ret;
    190
    191again:
    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
    206static 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
    219enum idmap_type {
    220	UID_MAP,
    221	GID_MAP,
    222};
    223
    224static ssize_t read_nointr(int fd, void *buf, size_t count)
    225{
    226	ssize_t ret;
    227again:
    228	ret = read(fd, buf, count);
    229	if (ret < 0 && errno == EINTR)
    230		goto again;
    231
    232	return ret;
    233}
    234
    235static ssize_t write_nointr(int fd, const void *buf, size_t count)
    236{
    237	ssize_t ret;
    238again:
    239	ret = write(fd, buf, count);
    240	if (ret < 0 && errno == EINTR)
    241		goto again;
    242
    243	return ret;
    244}
    245
    246static 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
    294static 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
    324static 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
    357struct __test_metadata *_thread_metadata;
    358static 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 */
    379TEST(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
    494TEST(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
    503TEST(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
    540TEST_HARNESS_MAIN