brintos

brintos / linux-shallow public Read only

0
0
Text · 12.1 KiB · 319567f Raw
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