175abec73SChristian Brauner // SPDX-License-Identifier: GPL-2.0
275abec73SChristian Brauner
375abec73SChristian Brauner #define _GNU_SOURCE
475abec73SChristian Brauner #include <errno.h>
575abec73SChristian Brauner #include <fcntl.h>
6e48d1174SChristian Brauner #include <pthread.h>
775abec73SChristian Brauner #include <sched.h>
875abec73SChristian Brauner #include <stdbool.h>
975abec73SChristian Brauner #include <stdio.h>
1075abec73SChristian Brauner #include <stdlib.h>
1175abec73SChristian Brauner #include <string.h>
12e48d1174SChristian Brauner #include <sys/fsuid.h>
1375abec73SChristian Brauner #include <sys/ioctl.h>
1475abec73SChristian Brauner #include <sys/mount.h>
15e48d1174SChristian Brauner #include <sys/socket.h>
1675abec73SChristian Brauner #include <sys/stat.h>
17e48d1174SChristian Brauner #include <sys/sysinfo.h>
1875abec73SChristian Brauner #include <sys/types.h>
19e48d1174SChristian Brauner #include <sys/wait.h>
2075abec73SChristian Brauner #include <unistd.h>
2175abec73SChristian Brauner #include <linux/android/binder.h>
2275abec73SChristian Brauner #include <linux/android/binderfs.h>
236e29225aSChristian Brauner
246e29225aSChristian Brauner #include "../../kselftest_harness.h"
2575abec73SChristian Brauner
26e48d1174SChristian Brauner #define DEFAULT_THREADS 4
2775abec73SChristian Brauner
28e48d1174SChristian Brauner #define PTR_TO_INT(p) ((int)((intptr_t)(p)))
29e48d1174SChristian Brauner #define INT_TO_PTR(u) ((void *)((intptr_t)(u)))
30e48d1174SChristian Brauner
31e48d1174SChristian Brauner #define close_prot_errno_disarm(fd) \
32e48d1174SChristian Brauner if (fd >= 0) { \
33e48d1174SChristian Brauner int _e_ = errno; \
34e48d1174SChristian Brauner close(fd); \
35e48d1174SChristian Brauner errno = _e_; \
36e48d1174SChristian Brauner fd = -EBADF; \
3775abec73SChristian Brauner }
3875abec73SChristian Brauner
change_mountns(struct __test_metadata * _metadata)39eaa163caSKees Cook static void change_mountns(struct __test_metadata *_metadata)
4075abec73SChristian Brauner {
4175abec73SChristian Brauner int ret;
4275abec73SChristian Brauner
4375abec73SChristian Brauner ret = unshare(CLONE_NEWNS);
44eaa163caSKees Cook ASSERT_EQ(ret, 0) {
45eaa163caSKees Cook TH_LOG("%s - Failed to unshare mount namespace",
4675abec73SChristian Brauner strerror(errno));
47eaa163caSKees Cook }
4875abec73SChristian Brauner
4975abec73SChristian Brauner ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0);
50eaa163caSKees Cook ASSERT_EQ(ret, 0) {
51eaa163caSKees Cook TH_LOG("%s - Failed to mount / as private",
5275abec73SChristian Brauner strerror(errno));
5375abec73SChristian Brauner }
5475abec73SChristian Brauner }
5575abec73SChristian Brauner
__do_binderfs_test(struct __test_metadata * _metadata)56eaa163caSKees Cook static int __do_binderfs_test(struct __test_metadata *_metadata)
5775abec73SChristian Brauner {
58eaa163caSKees Cook int fd, ret, saved_errno, result = 1;
5975abec73SChristian Brauner size_t len;
6075abec73SChristian Brauner ssize_t wret;
6175abec73SChristian Brauner struct binderfs_device device = { 0 };
6275abec73SChristian Brauner struct binder_version version = { 0 };
63ad29ace2SChristian Brauner char binderfs_mntpt[] = P_tmpdir "/binderfs_XXXXXX",
64ad29ace2SChristian Brauner device_path[sizeof(P_tmpdir "/binderfs_XXXXXX/") + BINDERFS_MAX_NAME];
6507e91341SCarlos Llamas static const char * const binder_features[] = {
6607e91341SCarlos Llamas "oneway_spam_detection",
67*d23386edSCarlos Llamas "extended_error",
6807e91341SCarlos Llamas };
6975abec73SChristian Brauner
70eaa163caSKees Cook change_mountns(_metadata);
7175abec73SChristian Brauner
72eaa163caSKees Cook EXPECT_NE(mkdtemp(binderfs_mntpt), NULL) {
73eaa163caSKees Cook TH_LOG("%s - Failed to create binderfs mountpoint",
7475abec73SChristian Brauner strerror(errno));
75eaa163caSKees Cook goto out;
7675abec73SChristian Brauner }
7775abec73SChristian Brauner
78eaa163caSKees Cook ret = mount(NULL, binderfs_mntpt, "binder", 0, 0);
79eaa163caSKees Cook EXPECT_EQ(ret, 0) {
80eaa163caSKees Cook if (errno == ENODEV)
817d764b68STommi Rantala SKIP(goto out, "binderfs missing");
82eaa163caSKees Cook TH_LOG("%s - Failed to mount binderfs", strerror(errno));
83eaa163caSKees Cook goto rmdir;
84eaa163caSKees Cook }
85eaa163caSKees Cook
86eaa163caSKees Cook /* success: binderfs mounted */
8775abec73SChristian Brauner
8875abec73SChristian Brauner memcpy(device.name, "my-binder", strlen("my-binder"));
8975abec73SChristian Brauner
90ad29ace2SChristian Brauner snprintf(device_path, sizeof(device_path), "%s/binder-control", binderfs_mntpt);
91ad29ace2SChristian Brauner fd = open(device_path, O_RDONLY | O_CLOEXEC);
92eaa163caSKees Cook EXPECT_GE(fd, 0) {
93eaa163caSKees Cook TH_LOG("%s - Failed to open binder-control device",
9475abec73SChristian Brauner strerror(errno));
95eaa163caSKees Cook goto umount;
96eaa163caSKees Cook }
9775abec73SChristian Brauner
9875abec73SChristian Brauner ret = ioctl(fd, BINDER_CTL_ADD, &device);
9975abec73SChristian Brauner saved_errno = errno;
10075abec73SChristian Brauner close(fd);
10175abec73SChristian Brauner errno = saved_errno;
102eaa163caSKees Cook EXPECT_GE(ret, 0) {
103eaa163caSKees Cook TH_LOG("%s - Failed to allocate new binder device",
10475abec73SChristian Brauner strerror(errno));
105eaa163caSKees Cook goto umount;
10675abec73SChristian Brauner }
10775abec73SChristian Brauner
108eaa163caSKees Cook TH_LOG("Allocated new binder device with major %d, minor %d, and name %s",
10975abec73SChristian Brauner device.major, device.minor, device.name);
11075abec73SChristian Brauner
111eaa163caSKees Cook /* success: binder device allocation */
11275abec73SChristian Brauner
113ad29ace2SChristian Brauner snprintf(device_path, sizeof(device_path), "%s/my-binder", binderfs_mntpt);
114ad29ace2SChristian Brauner fd = open(device_path, O_CLOEXEC | O_RDONLY);
115eaa163caSKees Cook EXPECT_GE(fd, 0) {
116eaa163caSKees Cook TH_LOG("%s - Failed to open my-binder device",
11775abec73SChristian Brauner strerror(errno));
118eaa163caSKees Cook goto umount;
11975abec73SChristian Brauner }
12075abec73SChristian Brauner
12175abec73SChristian Brauner ret = ioctl(fd, BINDER_VERSION, &version);
12275abec73SChristian Brauner saved_errno = errno;
12375abec73SChristian Brauner close(fd);
12475abec73SChristian Brauner errno = saved_errno;
125eaa163caSKees Cook EXPECT_GE(ret, 0) {
126eaa163caSKees Cook TH_LOG("%s - Failed to open perform BINDER_VERSION request",
12775abec73SChristian Brauner strerror(errno));
128eaa163caSKees Cook goto umount;
12975abec73SChristian Brauner }
13075abec73SChristian Brauner
131eaa163caSKees Cook TH_LOG("Detected binder version: %d", version.protocol_version);
13275abec73SChristian Brauner
133eaa163caSKees Cook /* success: binder transaction with binderfs binder device */
13475abec73SChristian Brauner
135ad29ace2SChristian Brauner ret = unlink(device_path);
136eaa163caSKees Cook EXPECT_EQ(ret, 0) {
137eaa163caSKees Cook TH_LOG("%s - Failed to delete binder device",
13875abec73SChristian Brauner strerror(errno));
139eaa163caSKees Cook goto umount;
14075abec73SChristian Brauner }
14175abec73SChristian Brauner
142eaa163caSKees Cook /* success: binder device removal */
14375abec73SChristian Brauner
144ad29ace2SChristian Brauner snprintf(device_path, sizeof(device_path), "%s/binder-control", binderfs_mntpt);
145ad29ace2SChristian Brauner ret = unlink(device_path);
146eaa163caSKees Cook EXPECT_NE(ret, 0) {
147eaa163caSKees Cook TH_LOG("Managed to delete binder-control device");
148eaa163caSKees Cook goto umount;
149eaa163caSKees Cook }
150eaa163caSKees Cook EXPECT_EQ(errno, EPERM) {
151eaa163caSKees Cook TH_LOG("%s - Failed to delete binder-control device but exited with unexpected error code",
15275abec73SChristian Brauner strerror(errno));
153eaa163caSKees Cook goto umount;
15475abec73SChristian Brauner }
15575abec73SChristian Brauner
156eaa163caSKees Cook /* success: binder-control device removal failed as expected */
15707e91341SCarlos Llamas
15807e91341SCarlos Llamas for (int i = 0; i < ARRAY_SIZE(binder_features); i++) {
15907e91341SCarlos Llamas snprintf(device_path, sizeof(device_path), "%s/features/%s",
16007e91341SCarlos Llamas binderfs_mntpt, binder_features[i]);
16107e91341SCarlos Llamas fd = open(device_path, O_CLOEXEC | O_RDONLY);
16207e91341SCarlos Llamas EXPECT_GE(fd, 0) {
16307e91341SCarlos Llamas TH_LOG("%s - Failed to open binder feature: %s",
16407e91341SCarlos Llamas strerror(errno), binder_features[i]);
16507e91341SCarlos Llamas goto umount;
16607e91341SCarlos Llamas }
16707e91341SCarlos Llamas close(fd);
16807e91341SCarlos Llamas }
16907e91341SCarlos Llamas
17007e91341SCarlos Llamas /* success: binder feature files found */
171eaa163caSKees Cook result = 0;
17275abec73SChristian Brauner
173eaa163caSKees Cook umount:
174ad29ace2SChristian Brauner ret = umount2(binderfs_mntpt, MNT_DETACH);
175eaa163caSKees Cook EXPECT_EQ(ret, 0) {
176eaa163caSKees Cook TH_LOG("%s - Failed to unmount binderfs", strerror(errno));
177eaa163caSKees Cook }
178eaa163caSKees Cook rmdir:
179eaa163caSKees Cook ret = rmdir(binderfs_mntpt);
180eaa163caSKees Cook EXPECT_EQ(ret, 0) {
181eaa163caSKees Cook TH_LOG("%s - Failed to rmdir binderfs mount", strerror(errno));
182eaa163caSKees Cook }
183eaa163caSKees Cook out:
184eaa163caSKees Cook return result;
18575abec73SChristian Brauner }
18675abec73SChristian Brauner
wait_for_pid(pid_t pid)187e48d1174SChristian Brauner static int wait_for_pid(pid_t pid)
188e48d1174SChristian Brauner {
189e48d1174SChristian Brauner int status, ret;
190e48d1174SChristian Brauner
191e48d1174SChristian Brauner again:
192e48d1174SChristian Brauner ret = waitpid(pid, &status, 0);
193e48d1174SChristian Brauner if (ret == -1) {
194e48d1174SChristian Brauner if (errno == EINTR)
195e48d1174SChristian Brauner goto again;
196e48d1174SChristian Brauner
197e48d1174SChristian Brauner return -1;
198e48d1174SChristian Brauner }
199e48d1174SChristian Brauner
200e48d1174SChristian Brauner if (!WIFEXITED(status))
201e48d1174SChristian Brauner return -1;
202e48d1174SChristian Brauner
203e48d1174SChristian Brauner return WEXITSTATUS(status);
204e48d1174SChristian Brauner }
205e48d1174SChristian Brauner
setid_userns_root(void)206e48d1174SChristian Brauner static int setid_userns_root(void)
207e48d1174SChristian Brauner {
208e48d1174SChristian Brauner if (setuid(0))
209e48d1174SChristian Brauner return -1;
210e48d1174SChristian Brauner if (setgid(0))
211e48d1174SChristian Brauner return -1;
212e48d1174SChristian Brauner
213e48d1174SChristian Brauner setfsuid(0);
214e48d1174SChristian Brauner setfsgid(0);
215e48d1174SChristian Brauner
216e48d1174SChristian Brauner return 0;
217e48d1174SChristian Brauner }
218e48d1174SChristian Brauner
219e48d1174SChristian Brauner enum idmap_type {
220e48d1174SChristian Brauner UID_MAP,
221e48d1174SChristian Brauner GID_MAP,
222e48d1174SChristian Brauner };
223e48d1174SChristian Brauner
read_nointr(int fd,void * buf,size_t count)224e48d1174SChristian Brauner static ssize_t read_nointr(int fd, void *buf, size_t count)
225e48d1174SChristian Brauner {
226e48d1174SChristian Brauner ssize_t ret;
227e48d1174SChristian Brauner again:
228e48d1174SChristian Brauner ret = read(fd, buf, count);
229e48d1174SChristian Brauner if (ret < 0 && errno == EINTR)
230e48d1174SChristian Brauner goto again;
231e48d1174SChristian Brauner
232e48d1174SChristian Brauner return ret;
233e48d1174SChristian Brauner }
234e48d1174SChristian Brauner
write_nointr(int fd,const void * buf,size_t count)235e48d1174SChristian Brauner static ssize_t write_nointr(int fd, const void *buf, size_t count)
236e48d1174SChristian Brauner {
237e48d1174SChristian Brauner ssize_t ret;
238e48d1174SChristian Brauner again:
239e48d1174SChristian Brauner ret = write(fd, buf, count);
240e48d1174SChristian Brauner if (ret < 0 && errno == EINTR)
241e48d1174SChristian Brauner goto again;
242e48d1174SChristian Brauner
243e48d1174SChristian Brauner return ret;
244e48d1174SChristian Brauner }
245e48d1174SChristian Brauner
write_id_mapping(enum idmap_type type,pid_t pid,const char * buf,size_t buf_size)246e48d1174SChristian Brauner static int write_id_mapping(enum idmap_type type, pid_t pid, const char *buf,
247e48d1174SChristian Brauner size_t buf_size)
248e48d1174SChristian Brauner {
249e48d1174SChristian Brauner int fd;
250e48d1174SChristian Brauner int ret;
251e48d1174SChristian Brauner char path[4096];
252e48d1174SChristian Brauner
253e48d1174SChristian Brauner if (type == GID_MAP) {
254e48d1174SChristian Brauner int setgroups_fd;
255e48d1174SChristian Brauner
256e48d1174SChristian Brauner snprintf(path, sizeof(path), "/proc/%d/setgroups", pid);
257e48d1174SChristian Brauner setgroups_fd = open(path, O_WRONLY | O_CLOEXEC | O_NOFOLLOW);
258e48d1174SChristian Brauner if (setgroups_fd < 0 && errno != ENOENT)
259e48d1174SChristian Brauner return -1;
260e48d1174SChristian Brauner
261e48d1174SChristian Brauner if (setgroups_fd >= 0) {
262e48d1174SChristian Brauner ret = write_nointr(setgroups_fd, "deny", sizeof("deny") - 1);
263e48d1174SChristian Brauner close_prot_errno_disarm(setgroups_fd);
264e48d1174SChristian Brauner if (ret != sizeof("deny") - 1)
265e48d1174SChristian Brauner return -1;
266e48d1174SChristian Brauner }
267e48d1174SChristian Brauner }
268e48d1174SChristian Brauner
269e48d1174SChristian Brauner switch (type) {
270e48d1174SChristian Brauner case UID_MAP:
271e48d1174SChristian Brauner ret = snprintf(path, sizeof(path), "/proc/%d/uid_map", pid);
272e48d1174SChristian Brauner break;
273e48d1174SChristian Brauner case GID_MAP:
274e48d1174SChristian Brauner ret = snprintf(path, sizeof(path), "/proc/%d/gid_map", pid);
275e48d1174SChristian Brauner break;
276e48d1174SChristian Brauner default:
277e48d1174SChristian Brauner return -1;
278e48d1174SChristian Brauner }
279e48d1174SChristian Brauner if (ret < 0 || ret >= sizeof(path))
280e48d1174SChristian Brauner return -E2BIG;
281e48d1174SChristian Brauner
282e48d1174SChristian Brauner fd = open(path, O_WRONLY | O_CLOEXEC | O_NOFOLLOW);
283e48d1174SChristian Brauner if (fd < 0)
284e48d1174SChristian Brauner return -1;
285e48d1174SChristian Brauner
286e48d1174SChristian Brauner ret = write_nointr(fd, buf, buf_size);
287e48d1174SChristian Brauner close_prot_errno_disarm(fd);
288e48d1174SChristian Brauner if (ret != buf_size)
289e48d1174SChristian Brauner return -1;
290e48d1174SChristian Brauner
291e48d1174SChristian Brauner return 0;
292e48d1174SChristian Brauner }
293e48d1174SChristian Brauner
change_userns(struct __test_metadata * _metadata,int syncfds[2])294eaa163caSKees Cook static void change_userns(struct __test_metadata *_metadata, int syncfds[2])
295e48d1174SChristian Brauner {
296e48d1174SChristian Brauner int ret;
297e48d1174SChristian Brauner char buf;
298e48d1174SChristian Brauner
299e48d1174SChristian Brauner close_prot_errno_disarm(syncfds[1]);
300e48d1174SChristian Brauner
301e48d1174SChristian Brauner ret = unshare(CLONE_NEWUSER);
302eaa163caSKees Cook ASSERT_EQ(ret, 0) {
303eaa163caSKees Cook TH_LOG("%s - Failed to unshare user namespace",
304e48d1174SChristian Brauner strerror(errno));
305eaa163caSKees Cook }
306e48d1174SChristian Brauner
307e48d1174SChristian Brauner ret = write_nointr(syncfds[0], "1", 1);
308eaa163caSKees Cook ASSERT_EQ(ret, 1) {
309eaa163caSKees Cook TH_LOG("write_nointr() failed");
310eaa163caSKees Cook }
311e48d1174SChristian Brauner
312e48d1174SChristian Brauner ret = read_nointr(syncfds[0], &buf, 1);
313eaa163caSKees Cook ASSERT_EQ(ret, 1) {
314eaa163caSKees Cook TH_LOG("read_nointr() failed");
315eaa163caSKees Cook }
316e48d1174SChristian Brauner
317e48d1174SChristian Brauner close_prot_errno_disarm(syncfds[0]);
318e48d1174SChristian Brauner
319eaa163caSKees Cook ASSERT_EQ(setid_userns_root(), 0) {
320eaa163caSKees Cook TH_LOG("setid_userns_root() failed");
321eaa163caSKees Cook }
322e48d1174SChristian Brauner }
323e48d1174SChristian Brauner
change_idmaps(struct __test_metadata * _metadata,int syncfds[2],pid_t pid)324eaa163caSKees Cook static void change_idmaps(struct __test_metadata *_metadata, int syncfds[2], pid_t pid)
325e48d1174SChristian Brauner {
326e48d1174SChristian Brauner int ret;
327e48d1174SChristian Brauner char buf;
328e48d1174SChristian Brauner char id_map[4096];
329e48d1174SChristian Brauner
330e48d1174SChristian Brauner close_prot_errno_disarm(syncfds[0]);
331e48d1174SChristian Brauner
332e48d1174SChristian Brauner ret = read_nointr(syncfds[1], &buf, 1);
333eaa163caSKees Cook ASSERT_EQ(ret, 1) {
334eaa163caSKees Cook TH_LOG("read_nointr() failed");
335eaa163caSKees Cook }
336e48d1174SChristian Brauner
337e48d1174SChristian Brauner snprintf(id_map, sizeof(id_map), "0 %d 1\n", getuid());
338e48d1174SChristian Brauner ret = write_id_mapping(UID_MAP, pid, id_map, strlen(id_map));
339eaa163caSKees Cook ASSERT_EQ(ret, 0) {
340eaa163caSKees Cook TH_LOG("write_id_mapping(UID_MAP) failed");
341eaa163caSKees Cook }
342e48d1174SChristian Brauner
343e48d1174SChristian Brauner snprintf(id_map, sizeof(id_map), "0 %d 1\n", getgid());
344e48d1174SChristian Brauner ret = write_id_mapping(GID_MAP, pid, id_map, strlen(id_map));
345eaa163caSKees Cook ASSERT_EQ(ret, 0) {
346eaa163caSKees Cook TH_LOG("write_id_mapping(GID_MAP) failed");
347eaa163caSKees Cook }
348e48d1174SChristian Brauner
349e48d1174SChristian Brauner ret = write_nointr(syncfds[1], "1", 1);
350eaa163caSKees Cook ASSERT_EQ(ret, 1) {
351eaa163caSKees Cook TH_LOG("write_nointr() failed");
352eaa163caSKees Cook }
353e48d1174SChristian Brauner
354e48d1174SChristian Brauner close_prot_errno_disarm(syncfds[1]);
355e48d1174SChristian Brauner }
356e48d1174SChristian Brauner
357eaa163caSKees Cook struct __test_metadata *_thread_metadata;
binder_version_thread(void * data)358e48d1174SChristian Brauner static void *binder_version_thread(void *data)
359e48d1174SChristian Brauner {
360eaa163caSKees Cook struct __test_metadata *_metadata = _thread_metadata;
361e48d1174SChristian Brauner int fd = PTR_TO_INT(data);
362e48d1174SChristian Brauner struct binder_version version = { 0 };
363e48d1174SChristian Brauner int ret;
364e48d1174SChristian Brauner
365e48d1174SChristian Brauner ret = ioctl(fd, BINDER_VERSION, &version);
366e48d1174SChristian Brauner if (ret < 0)
367eaa163caSKees Cook TH_LOG("%s - Failed to open perform BINDER_VERSION request\n",
368eaa163caSKees Cook strerror(errno));
369e48d1174SChristian Brauner
370e48d1174SChristian Brauner pthread_exit(data);
371e48d1174SChristian Brauner }
372e48d1174SChristian Brauner
373e48d1174SChristian Brauner /*
374e48d1174SChristian Brauner * Regression test:
375e48d1174SChristian Brauner * 2669b8b0c798 ("binder: prevent UAF for binderfs devices")
376e48d1174SChristian Brauner * f0fe2c0f050d ("binder: prevent UAF for binderfs devices II")
377e48d1174SChristian Brauner * 211b64e4b5b6 ("binderfs: use refcount for binder control devices too")
378e48d1174SChristian Brauner */
TEST(binderfs_stress)379e48d1174SChristian Brauner TEST(binderfs_stress)
380e48d1174SChristian Brauner {
381e48d1174SChristian Brauner int fds[1000];
382e48d1174SChristian Brauner int syncfds[2];
383e48d1174SChristian Brauner pid_t pid;
384e48d1174SChristian Brauner int fd, ret;
385e48d1174SChristian Brauner size_t len;
386e48d1174SChristian Brauner struct binderfs_device device = { 0 };
387e48d1174SChristian Brauner char binderfs_mntpt[] = P_tmpdir "/binderfs_XXXXXX",
388e48d1174SChristian Brauner device_path[sizeof(P_tmpdir "/binderfs_XXXXXX/") + BINDERFS_MAX_NAME];
389e48d1174SChristian Brauner
390e48d1174SChristian Brauner ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, syncfds);
391eaa163caSKees Cook ASSERT_EQ(ret, 0) {
392eaa163caSKees Cook TH_LOG("%s - Failed to create socket pair", strerror(errno));
393eaa163caSKees Cook }
394e48d1174SChristian Brauner
395e48d1174SChristian Brauner pid = fork();
396eaa163caSKees Cook ASSERT_GE(pid, 0) {
397eaa163caSKees Cook TH_LOG("%s - Failed to fork", strerror(errno));
398e48d1174SChristian Brauner close_prot_errno_disarm(syncfds[0]);
399e48d1174SChristian Brauner close_prot_errno_disarm(syncfds[1]);
400e48d1174SChristian Brauner }
401e48d1174SChristian Brauner
402e48d1174SChristian Brauner if (pid == 0) {
403e48d1174SChristian Brauner int i, j, k, nthreads;
404e48d1174SChristian Brauner pthread_attr_t attr;
405e48d1174SChristian Brauner pthread_t threads[DEFAULT_THREADS];
406eaa163caSKees Cook change_userns(_metadata, syncfds);
407eaa163caSKees Cook change_mountns(_metadata);
408e48d1174SChristian Brauner
409eaa163caSKees Cook ASSERT_NE(mkdtemp(binderfs_mntpt), NULL) {
410eaa163caSKees Cook TH_LOG("%s - Failed to create binderfs mountpoint",
411e48d1174SChristian Brauner strerror(errno));
412eaa163caSKees Cook }
413e48d1174SChristian Brauner
414e48d1174SChristian Brauner ret = mount(NULL, binderfs_mntpt, "binder", 0, 0);
415eaa163caSKees Cook ASSERT_EQ(ret, 0) {
416ea1d15a0SKarthik Alapati TH_LOG("%s - Failed to mount binderfs, check if CONFIG_ANDROID_BINDERFS is enabled in the running kernel",
417ea1d15a0SKarthik Alapati strerror(errno));
418eaa163caSKees Cook }
419e48d1174SChristian Brauner
420e48d1174SChristian Brauner for (int i = 0; i < ARRAY_SIZE(fds); i++) {
421e48d1174SChristian Brauner
422e48d1174SChristian Brauner snprintf(device_path, sizeof(device_path),
423e48d1174SChristian Brauner "%s/binder-control", binderfs_mntpt);
424e48d1174SChristian Brauner fd = open(device_path, O_RDONLY | O_CLOEXEC);
425eaa163caSKees Cook ASSERT_GE(fd, 0) {
426eaa163caSKees Cook TH_LOG("%s - Failed to open binder-control device",
427eaa163caSKees Cook strerror(errno));
428eaa163caSKees Cook }
429e48d1174SChristian Brauner
430e48d1174SChristian Brauner memset(&device, 0, sizeof(device));
431e48d1174SChristian Brauner snprintf(device.name, sizeof(device.name), "%d", i);
432e48d1174SChristian Brauner ret = ioctl(fd, BINDER_CTL_ADD, &device);
433e48d1174SChristian Brauner close_prot_errno_disarm(fd);
434eaa163caSKees Cook ASSERT_EQ(ret, 0) {
435eaa163caSKees Cook TH_LOG("%s - Failed to allocate new binder device",
436eaa163caSKees Cook strerror(errno));
437eaa163caSKees Cook }
438e48d1174SChristian Brauner
439e48d1174SChristian Brauner snprintf(device_path, sizeof(device_path), "%s/%d",
440e48d1174SChristian Brauner binderfs_mntpt, i);
441e48d1174SChristian Brauner fds[i] = open(device_path, O_RDONLY | O_CLOEXEC);
442eaa163caSKees Cook ASSERT_GE(fds[i], 0) {
443eaa163caSKees Cook TH_LOG("%s - Failed to open binder device", strerror(errno));
444eaa163caSKees Cook }
445e48d1174SChristian Brauner }
446e48d1174SChristian Brauner
447e48d1174SChristian Brauner ret = umount2(binderfs_mntpt, MNT_DETACH);
448eaa163caSKees Cook ASSERT_EQ(ret, 0) {
449eaa163caSKees Cook TH_LOG("%s - Failed to unmount binderfs", strerror(errno));
450eaa163caSKees Cook rmdir(binderfs_mntpt);
451eaa163caSKees Cook }
452e48d1174SChristian Brauner
453e48d1174SChristian Brauner nthreads = get_nprocs_conf();
454e48d1174SChristian Brauner if (nthreads > DEFAULT_THREADS)
455e48d1174SChristian Brauner nthreads = DEFAULT_THREADS;
456e48d1174SChristian Brauner
457eaa163caSKees Cook _thread_metadata = _metadata;
458e48d1174SChristian Brauner pthread_attr_init(&attr);
459e48d1174SChristian Brauner for (k = 0; k < ARRAY_SIZE(fds); k++) {
460e48d1174SChristian Brauner for (i = 0; i < nthreads; i++) {
461e48d1174SChristian Brauner ret = pthread_create(&threads[i], &attr, binder_version_thread, INT_TO_PTR(fds[k]));
462e48d1174SChristian Brauner if (ret) {
463eaa163caSKees Cook TH_LOG("%s - Failed to create thread %d",
464eaa163caSKees Cook strerror(errno), i);
465e48d1174SChristian Brauner break;
466e48d1174SChristian Brauner }
467e48d1174SChristian Brauner }
468e48d1174SChristian Brauner
469e48d1174SChristian Brauner for (j = 0; j < i; j++) {
470e48d1174SChristian Brauner void *fdptr = NULL;
471e48d1174SChristian Brauner
472e48d1174SChristian Brauner ret = pthread_join(threads[j], &fdptr);
473e48d1174SChristian Brauner if (ret)
474eaa163caSKees Cook TH_LOG("%s - Failed to join thread %d for fd %d",
475eaa163caSKees Cook strerror(errno), j, PTR_TO_INT(fdptr));
476e48d1174SChristian Brauner }
477e48d1174SChristian Brauner }
478e48d1174SChristian Brauner pthread_attr_destroy(&attr);
479e48d1174SChristian Brauner
480e48d1174SChristian Brauner for (k = 0; k < ARRAY_SIZE(fds); k++)
481e48d1174SChristian Brauner close(fds[k]);
482e48d1174SChristian Brauner
483e48d1174SChristian Brauner exit(EXIT_SUCCESS);
484e48d1174SChristian Brauner }
485e48d1174SChristian Brauner
486eaa163caSKees Cook change_idmaps(_metadata, syncfds, pid);
487e48d1174SChristian Brauner
488e48d1174SChristian Brauner ret = wait_for_pid(pid);
489eaa163caSKees Cook ASSERT_EQ(ret, 0) {
490eaa163caSKees Cook TH_LOG("wait_for_pid() failed");
491eaa163caSKees Cook }
492e48d1174SChristian Brauner }
493e48d1174SChristian Brauner
TEST(binderfs_test_privileged)4946e29225aSChristian Brauner TEST(binderfs_test_privileged)
49575abec73SChristian Brauner {
49675abec73SChristian Brauner if (geteuid() != 0)
4977d764b68STommi Rantala SKIP(return, "Tests are not run as root. Skipping privileged tests");
4986e29225aSChristian Brauner
499eaa163caSKees Cook if (__do_binderfs_test(_metadata))
5007d764b68STommi Rantala SKIP(return, "The Android binderfs filesystem is not available");
50175abec73SChristian Brauner }
50275abec73SChristian Brauner
TEST(binderfs_test_unprivileged)5036e29225aSChristian Brauner TEST(binderfs_test_unprivileged)
50475abec73SChristian Brauner {
505e48d1174SChristian Brauner int ret;
506e48d1174SChristian Brauner int syncfds[2];
507e48d1174SChristian Brauner pid_t pid;
5086e29225aSChristian Brauner
509e48d1174SChristian Brauner ret = socketpair(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, syncfds);
510eaa163caSKees Cook ASSERT_EQ(ret, 0) {
511eaa163caSKees Cook TH_LOG("%s - Failed to create socket pair", strerror(errno));
512eaa163caSKees Cook }
513e48d1174SChristian Brauner
514e48d1174SChristian Brauner pid = fork();
515eaa163caSKees Cook ASSERT_GE(pid, 0) {
516e48d1174SChristian Brauner close_prot_errno_disarm(syncfds[0]);
517e48d1174SChristian Brauner close_prot_errno_disarm(syncfds[1]);
518eaa163caSKees Cook TH_LOG("%s - Failed to fork", strerror(errno));
519e48d1174SChristian Brauner }
520e48d1174SChristian Brauner
521e48d1174SChristian Brauner if (pid == 0) {
522eaa163caSKees Cook change_userns(_metadata, syncfds);
523eaa163caSKees Cook if (__do_binderfs_test(_metadata))
524e48d1174SChristian Brauner exit(2);
525e48d1174SChristian Brauner exit(EXIT_SUCCESS);
526e48d1174SChristian Brauner }
527e48d1174SChristian Brauner
528eaa163caSKees Cook change_idmaps(_metadata, syncfds, pid);
529e48d1174SChristian Brauner
530e48d1174SChristian Brauner ret = wait_for_pid(pid);
531e48d1174SChristian Brauner if (ret) {
532e48d1174SChristian Brauner if (ret == 2)
5337d764b68STommi Rantala SKIP(return, "The Android binderfs filesystem is not available");
534eaa163caSKees Cook ASSERT_EQ(ret, 0) {
535eaa163caSKees Cook TH_LOG("wait_for_pid() failed");
536eaa163caSKees Cook }
537e48d1174SChristian Brauner }
53875abec73SChristian Brauner }
53975abec73SChristian Brauner
5406e29225aSChristian Brauner TEST_HARNESS_MAIN
541