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.h"
25 #include "../../kselftest_harness.h"
26 
27 #define DEFAULT_THREADS 4
28 
29 #define PTR_TO_INT(p) ((int)((intptr_t)(p)))
30 #define INT_TO_PTR(u) ((void *)((intptr_t)(u)))
31 
32 #define close_prot_errno_disarm(fd) \
33 	if (fd >= 0) {              \
34 		int _e_ = errno;    \
35 		close(fd);          \
36 		errno = _e_;        \
37 		fd = -EBADF;        \
38 	}
39 
40 #define log_exit(format, ...)                                                  \
41 	({                                                                     \
42 		fprintf(stderr, format "\n", ##__VA_ARGS__);                   \
43 		exit(EXIT_FAILURE);                                            \
44 	})
45 
46 static void change_mountns(void)
47 {
48 	int ret;
49 
50 	ret = unshare(CLONE_NEWNS);
51 	if (ret < 0)
52 		ksft_exit_fail_msg("%s - Failed to unshare mount namespace\n",
53 				   strerror(errno));
54 
55 	ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0);
56 	if (ret < 0)
57 		ksft_exit_fail_msg("%s - Failed to mount / as private\n",
58 				   strerror(errno));
59 }
60 
61 static void rmdir_protect_errno(const char *dir)
62 {
63 	int saved_errno = errno;
64 	(void)rmdir(dir);
65 	errno = saved_errno;
66 }
67 
68 static int __do_binderfs_test(void)
69 {
70 	int fd, ret, saved_errno;
71 	size_t len;
72 	ssize_t wret;
73 	struct binderfs_device device = { 0 };
74 	struct binder_version version = { 0 };
75 	char binderfs_mntpt[] = P_tmpdir "/binderfs_XXXXXX",
76 		device_path[sizeof(P_tmpdir "/binderfs_XXXXXX/") + BINDERFS_MAX_NAME];
77 
78 	change_mountns();
79 
80 	if (!mkdtemp(binderfs_mntpt))
81 		ksft_exit_fail_msg(
82 			"%s - Failed to create binderfs mountpoint\n",
83 			strerror(errno));
84 
85 	ret = mount(NULL, binderfs_mntpt, "binder", 0, 0);
86 	if (ret < 0) {
87 		if (errno != ENODEV)
88 			ksft_exit_fail_msg("%s - Failed to mount binderfs\n",
89 					   strerror(errno));
90 
91 		rmdir_protect_errno(binderfs_mntpt);
92 		return 1;
93 	}
94 
95 	/* binderfs mount test passed */
96 	ksft_inc_pass_cnt();
97 
98 	memcpy(device.name, "my-binder", strlen("my-binder"));
99 
100 	snprintf(device_path, sizeof(device_path), "%s/binder-control", binderfs_mntpt);
101 	fd = open(device_path, O_RDONLY | O_CLOEXEC);
102 	if (fd < 0)
103 		ksft_exit_fail_msg(
104 			"%s - Failed to open binder-control device\n",
105 			strerror(errno));
106 
107 	ret = ioctl(fd, BINDER_CTL_ADD, &device);
108 	saved_errno = errno;
109 	close(fd);
110 	errno = saved_errno;
111 	if (ret < 0) {
112 		rmdir_protect_errno(binderfs_mntpt);
113 		ksft_exit_fail_msg(
114 			"%s - Failed to allocate new binder device\n",
115 			strerror(errno));
116 	}
117 
118 	ksft_print_msg(
119 		"Allocated new binder device with major %d, minor %d, and name %s\n",
120 		device.major, device.minor, device.name);
121 
122 	/* binder device allocation test passed */
123 	ksft_inc_pass_cnt();
124 
125 	snprintf(device_path, sizeof(device_path), "%s/my-binder", binderfs_mntpt);
126 	fd = open(device_path, O_CLOEXEC | O_RDONLY);
127 	if (fd < 0) {
128 		rmdir_protect_errno(binderfs_mntpt);
129 		ksft_exit_fail_msg("%s - Failed to open my-binder device\n",
130 				   strerror(errno));
131 	}
132 
133 	ret = ioctl(fd, BINDER_VERSION, &version);
134 	saved_errno = errno;
135 	close(fd);
136 	errno = saved_errno;
137 	if (ret < 0) {
138 		rmdir_protect_errno(binderfs_mntpt);
139 		ksft_exit_fail_msg(
140 			"%s - Failed to open perform BINDER_VERSION request\n",
141 			strerror(errno));
142 	}
143 
144 	ksft_print_msg("Detected binder version: %d\n",
145 		       version.protocol_version);
146 
147 	/* binder transaction with binderfs binder device passed */
148 	ksft_inc_pass_cnt();
149 
150 	ret = unlink(device_path);
151 	if (ret < 0) {
152 		rmdir_protect_errno(binderfs_mntpt);
153 		ksft_exit_fail_msg("%s - Failed to delete binder device\n",
154 				   strerror(errno));
155 	}
156 
157 	/* binder device removal passed */
158 	ksft_inc_pass_cnt();
159 
160 	snprintf(device_path, sizeof(device_path), "%s/binder-control", binderfs_mntpt);
161 	ret = unlink(device_path);
162 	if (!ret) {
163 		rmdir_protect_errno(binderfs_mntpt);
164 		ksft_exit_fail_msg("Managed to delete binder-control device\n");
165 	} else if (errno != EPERM) {
166 		rmdir_protect_errno(binderfs_mntpt);
167 		ksft_exit_fail_msg(
168 			"%s - Failed to delete binder-control device but exited with unexpected error code\n",
169 			strerror(errno));
170 	}
171 
172 	/* binder-control device removal failed as expected */
173 	ksft_inc_xfail_cnt();
174 
175 on_error:
176 	ret = umount2(binderfs_mntpt, MNT_DETACH);
177 	rmdir_protect_errno(binderfs_mntpt);
178 	if (ret < 0)
179 		ksft_exit_fail_msg("%s - Failed to unmount binderfs\n",
180 				   strerror(errno));
181 
182 	/* binderfs unmount test passed */
183 	ksft_inc_pass_cnt();
184 	return 0;
185 }
186 
187 static int wait_for_pid(pid_t pid)
188 {
189 	int status, ret;
190 
191 again:
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 
206 static 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 
219 enum idmap_type {
220 	UID_MAP,
221 	GID_MAP,
222 };
223 
224 static ssize_t read_nointr(int fd, void *buf, size_t count)
225 {
226 	ssize_t ret;
227 again:
228 	ret = read(fd, buf, count);
229 	if (ret < 0 && errno == EINTR)
230 		goto again;
231 
232 	return ret;
233 }
234 
235 static ssize_t write_nointr(int fd, const void *buf, size_t count)
236 {
237 	ssize_t ret;
238 again:
239 	ret = write(fd, buf, count);
240 	if (ret < 0 && errno == EINTR)
241 		goto again;
242 
243 	return ret;
244 }
245 
246 static 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 
294 static void change_userns(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 	if (ret < 0)
303 		ksft_exit_fail_msg("%s - Failed to unshare user namespace\n",
304 				   strerror(errno));
305 
306 	ret = write_nointr(syncfds[0], "1", 1);
307 	if (ret != 1)
308 		ksft_exit_fail_msg("write_nointr() failed\n");
309 
310 	ret = read_nointr(syncfds[0], &buf, 1);
311 	if (ret != 1)
312 		ksft_exit_fail_msg("read_nointr() failed\n");
313 
314 	close_prot_errno_disarm(syncfds[0]);
315 
316 	if (setid_userns_root())
317 		ksft_exit_fail_msg("setid_userns_root() failed");
318 }
319 
320 static void change_idmaps(int syncfds[2], pid_t pid)
321 {
322 	int ret;
323 	char buf;
324 	char id_map[4096];
325 
326 	close_prot_errno_disarm(syncfds[0]);
327 
328 	ret = read_nointr(syncfds[1], &buf, 1);
329 	if (ret != 1)
330 		ksft_exit_fail_msg("read_nointr() failed\n");
331 
332 	snprintf(id_map, sizeof(id_map), "0 %d 1\n", getuid());
333 	ret = write_id_mapping(UID_MAP, pid, id_map, strlen(id_map));
334 	if (ret)
335 		ksft_exit_fail_msg("write_id_mapping(UID_MAP) failed");
336 
337 	snprintf(id_map, sizeof(id_map), "0 %d 1\n", getgid());
338 	ret = write_id_mapping(GID_MAP, pid, id_map, strlen(id_map));
339 	if (ret)
340 		ksft_exit_fail_msg("write_id_mapping(GID_MAP) failed");
341 
342 	ret = write_nointr(syncfds[1], "1", 1);
343 	if (ret != 1)
344 		ksft_exit_fail_msg("write_nointr() failed");
345 
346 	close_prot_errno_disarm(syncfds[1]);
347 }
348 
349 static void *binder_version_thread(void *data)
350 {
351 	int fd = PTR_TO_INT(data);
352 	struct binder_version version = { 0 };
353 	int ret;
354 
355 	ret = ioctl(fd, BINDER_VERSION, &version);
356 	if (ret < 0)
357 		ksft_print_msg("%s - Failed to open perform BINDER_VERSION request\n", strerror(errno));
358 
359 	pthread_exit(data);
360 }
361 
362 /*
363  * Regression test:
364  * 2669b8b0c798 ("binder: prevent UAF for binderfs devices")
365  * f0fe2c0f050d ("binder: prevent UAF for binderfs devices II")
366  * 211b64e4b5b6 ("binderfs: use refcount for binder control devices too")
367  */
368 TEST(binderfs_stress)
369 {
370 	int fds[1000];
371 	int syncfds[2];
372 	pid_t pid;
373 	int fd, ret;
374 	size_t len;
375 	struct binderfs_device device = { 0 };
376 	char binderfs_mntpt[] = P_tmpdir "/binderfs_XXXXXX",
377 		device_path[sizeof(P_tmpdir "/binderfs_XXXXXX/") + BINDERFS_MAX_NAME];
378 
379 	ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, syncfds);
380 	if (ret < 0)
381 		ksft_exit_fail_msg("%s - Failed to create socket pair", strerror(errno));
382 
383 	pid = fork();
384 	if (pid < 0) {
385 		close_prot_errno_disarm(syncfds[0]);
386 		close_prot_errno_disarm(syncfds[1]);
387 		ksft_exit_fail_msg("%s - Failed to fork", strerror(errno));
388 	}
389 
390 	if (pid == 0) {
391 		int i, j, k, nthreads;
392 		pthread_attr_t attr;
393 		pthread_t threads[DEFAULT_THREADS];
394 		change_userns(syncfds);
395 		change_mountns();
396 
397 		if (!mkdtemp(binderfs_mntpt))
398 			log_exit("%s - Failed to create binderfs mountpoint\n",
399 				 strerror(errno));
400 
401 		ret = mount(NULL, binderfs_mntpt, "binder", 0, 0);
402 		if (ret < 0)
403 			log_exit("%s - Failed to mount binderfs\n", strerror(errno));
404 
405 		for (int i = 0; i < ARRAY_SIZE(fds); i++) {
406 
407 			snprintf(device_path, sizeof(device_path),
408 				 "%s/binder-control", binderfs_mntpt);
409 			fd = open(device_path, O_RDONLY | O_CLOEXEC);
410 			if (fd < 0)
411 				log_exit("%s - Failed to open binder-control device\n", strerror(errno));
412 
413 			memset(&device, 0, sizeof(device));
414 			snprintf(device.name, sizeof(device.name), "%d", i);
415 			ret = ioctl(fd, BINDER_CTL_ADD, &device);
416 			close_prot_errno_disarm(fd);
417 			if (ret < 0)
418 				log_exit("%s - Failed to allocate new binder device\n", strerror(errno));
419 
420 			snprintf(device_path, sizeof(device_path), "%s/%d",
421 				 binderfs_mntpt, i);
422 			fds[i] = open(device_path, O_RDONLY | O_CLOEXEC);
423 			if (fds[i] < 0)
424 				log_exit("%s - Failed to open binder device\n", strerror(errno));
425 		}
426 
427 		ret = umount2(binderfs_mntpt, MNT_DETACH);
428 		rmdir_protect_errno(binderfs_mntpt);
429 		if (ret < 0)
430 			log_exit("%s - Failed to unmount binderfs\n", strerror(errno));
431 
432 		nthreads = get_nprocs_conf();
433 		if (nthreads > DEFAULT_THREADS)
434 			nthreads = DEFAULT_THREADS;
435 
436 		pthread_attr_init(&attr);
437 		for (k = 0; k < ARRAY_SIZE(fds); k++) {
438 			for (i = 0; i < nthreads; i++) {
439 				ret = pthread_create(&threads[i], &attr, binder_version_thread, INT_TO_PTR(fds[k]));
440 				if (ret) {
441 					ksft_print_msg("%s - Failed to create thread %d\n", strerror(errno), i);
442 					break;
443 				}
444 			}
445 
446 			for (j = 0; j < i; j++) {
447 				void *fdptr = NULL;
448 
449 				ret = pthread_join(threads[j], &fdptr);
450 				if (ret)
451 					ksft_print_msg("%s - Failed to join thread %d for fd %d\n", strerror(errno), j, PTR_TO_INT(fdptr));
452 			}
453 		}
454 		pthread_attr_destroy(&attr);
455 
456 		for (k = 0; k < ARRAY_SIZE(fds); k++)
457 			close(fds[k]);
458 
459 		exit(EXIT_SUCCESS);
460 	}
461 
462 	change_idmaps(syncfds, pid);
463 
464 	ret = wait_for_pid(pid);
465 	if (ret)
466 		ksft_exit_fail_msg("wait_for_pid() failed");
467 }
468 
469 TEST(binderfs_test_privileged)
470 {
471 	if (geteuid() != 0)
472 		XFAIL(return, "Tests are not run as root. Skipping privileged tests");
473 
474 	if (__do_binderfs_test() == 1)
475 		XFAIL(return, "The Android binderfs filesystem is not available");
476 }
477 
478 TEST(binderfs_test_unprivileged)
479 {
480 	int ret;
481 	int syncfds[2];
482 	pid_t pid;
483 
484 	ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, syncfds);
485 	if (ret < 0)
486 		ksft_exit_fail_msg("%s - Failed to create socket pair", strerror(errno));
487 
488 	pid = fork();
489 	if (pid < 0) {
490 		close_prot_errno_disarm(syncfds[0]);
491 		close_prot_errno_disarm(syncfds[1]);
492 		ksft_exit_fail_msg("%s - Failed to fork", strerror(errno));
493 	}
494 
495 	if (pid == 0) {
496 		change_userns(syncfds);
497 		if (__do_binderfs_test() == 1)
498 			exit(2);
499 		exit(EXIT_SUCCESS);
500 	}
501 
502 	change_idmaps(syncfds, pid);
503 
504 	ret = wait_for_pid(pid);
505 	if (ret) {
506 		if (ret == 2)
507 			XFAIL(return, "The Android binderfs filesystem is not available");
508 		else
509 			ksft_exit_fail_msg("wait_for_pid() failed");
510 	}
511 }
512 
513 TEST_HARNESS_MAIN
514