OSDN Git Service

Merge tag 'clk-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[uclinux-h8/linux.git] / tools / testing / selftests / filesystems / binderfs / binderfs_test.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 #define _GNU_SOURCE
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <sched.h>
7 #include <stdbool.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/ioctl.h>
12 #include <sys/mount.h>
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16 #include <linux/android/binder.h>
17 #include <linux/android/binderfs.h>
18 #include "../../kselftest.h"
19
20 static ssize_t write_nointr(int fd, const void *buf, size_t count)
21 {
22         ssize_t ret;
23 again:
24         ret = write(fd, buf, count);
25         if (ret < 0 && errno == EINTR)
26                 goto again;
27
28         return ret;
29 }
30
31 static void write_to_file(const char *filename, const void *buf, size_t count,
32                           int allowed_errno)
33 {
34         int fd, saved_errno;
35         ssize_t ret;
36
37         fd = open(filename, O_WRONLY | O_CLOEXEC);
38         if (fd < 0)
39                 ksft_exit_fail_msg("%s - Failed to open file %s\n",
40                                    strerror(errno), filename);
41
42         ret = write_nointr(fd, buf, count);
43         if (ret < 0) {
44                 if (allowed_errno && (errno == allowed_errno)) {
45                         close(fd);
46                         return;
47                 }
48
49                 goto on_error;
50         }
51
52         if ((size_t)ret != count)
53                 goto on_error;
54
55         close(fd);
56         return;
57
58 on_error:
59         saved_errno = errno;
60         close(fd);
61         errno = saved_errno;
62
63         if (ret < 0)
64                 ksft_exit_fail_msg("%s - Failed to write to file %s\n",
65                                    strerror(errno), filename);
66
67         ksft_exit_fail_msg("Failed to write to file %s\n", filename);
68 }
69
70 static void change_to_userns(void)
71 {
72         int ret;
73         uid_t uid;
74         gid_t gid;
75         /* {g,u}id_map files only allow a max of 4096 bytes written to them */
76         char idmap[4096];
77
78         uid = getuid();
79         gid = getgid();
80
81         ret = unshare(CLONE_NEWUSER);
82         if (ret < 0)
83                 ksft_exit_fail_msg("%s - Failed to unshare user namespace\n",
84                                    strerror(errno));
85
86         write_to_file("/proc/self/setgroups", "deny", strlen("deny"), ENOENT);
87
88         ret = snprintf(idmap, sizeof(idmap), "0 %d 1", uid);
89         if (ret < 0 || (size_t)ret >= sizeof(idmap))
90                 ksft_exit_fail_msg("%s - Failed to prepare uid mapping\n",
91                                    strerror(errno));
92
93         write_to_file("/proc/self/uid_map", idmap, strlen(idmap), 0);
94
95         ret = snprintf(idmap, sizeof(idmap), "0 %d 1", gid);
96         if (ret < 0 || (size_t)ret >= sizeof(idmap))
97                 ksft_exit_fail_msg("%s - Failed to prepare uid mapping\n",
98                                    strerror(errno));
99
100         write_to_file("/proc/self/gid_map", idmap, strlen(idmap), 0);
101
102         ret = setgid(0);
103         if (ret)
104                 ksft_exit_fail_msg("%s - Failed to setgid(0)\n",
105                                    strerror(errno));
106
107         ret = setuid(0);
108         if (ret)
109                 ksft_exit_fail_msg("%s - Failed to setgid(0)\n",
110                                    strerror(errno));
111 }
112
113 static void change_to_mountns(void)
114 {
115         int ret;
116
117         ret = unshare(CLONE_NEWNS);
118         if (ret < 0)
119                 ksft_exit_fail_msg("%s - Failed to unshare mount namespace\n",
120                                    strerror(errno));
121
122         ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0);
123         if (ret < 0)
124                 ksft_exit_fail_msg("%s - Failed to mount / as private\n",
125                                    strerror(errno));
126 }
127
128 static void rmdir_protect_errno(const char *dir)
129 {
130         int saved_errno = errno;
131         (void)rmdir(dir);
132         errno = saved_errno;
133 }
134
135 static void __do_binderfs_test(void)
136 {
137         int fd, ret, saved_errno;
138         size_t len;
139         ssize_t wret;
140         bool keep = false;
141         struct binderfs_device device = { 0 };
142         struct binder_version version = { 0 };
143
144         change_to_mountns();
145
146         ret = mkdir("/dev/binderfs", 0755);
147         if (ret < 0) {
148                 if (errno != EEXIST)
149                         ksft_exit_fail_msg(
150                                 "%s - Failed to create binderfs mountpoint\n",
151                                 strerror(errno));
152
153                 keep = true;
154         }
155
156         ret = mount(NULL, "/dev/binderfs", "binder", 0, 0);
157         if (ret < 0) {
158                 if (errno != ENODEV)
159                         ksft_exit_fail_msg("%s - Failed to mount binderfs\n",
160                                            strerror(errno));
161
162                 keep ? : rmdir_protect_errno("/dev/binderfs");
163                 ksft_exit_skip(
164                         "The Android binderfs filesystem is not available\n");
165         }
166
167         /* binderfs mount test passed */
168         ksft_inc_pass_cnt();
169
170         memcpy(device.name, "my-binder", strlen("my-binder"));
171
172         fd = open("/dev/binderfs/binder-control", O_RDONLY | O_CLOEXEC);
173         if (fd < 0)
174                 ksft_exit_fail_msg(
175                         "%s - Failed to open binder-control device\n",
176                         strerror(errno));
177
178         ret = ioctl(fd, BINDER_CTL_ADD, &device);
179         saved_errno = errno;
180         close(fd);
181         errno = saved_errno;
182         if (ret < 0) {
183                 keep ? : rmdir_protect_errno("/dev/binderfs");
184                 ksft_exit_fail_msg(
185                         "%s - Failed to allocate new binder device\n",
186                         strerror(errno));
187         }
188
189         ksft_print_msg(
190                 "Allocated new binder device with major %d, minor %d, and name %s\n",
191                 device.major, device.minor, device.name);
192
193         /* binder device allocation test passed */
194         ksft_inc_pass_cnt();
195
196         fd = open("/dev/binderfs/my-binder", O_CLOEXEC | O_RDONLY);
197         if (fd < 0) {
198                 keep ? : rmdir_protect_errno("/dev/binderfs");
199                 ksft_exit_fail_msg("%s - Failed to open my-binder device\n",
200                                    strerror(errno));
201         }
202
203         ret = ioctl(fd, BINDER_VERSION, &version);
204         saved_errno = errno;
205         close(fd);
206         errno = saved_errno;
207         if (ret < 0) {
208                 keep ? : rmdir_protect_errno("/dev/binderfs");
209                 ksft_exit_fail_msg(
210                         "%s - Failed to open perform BINDER_VERSION request\n",
211                         strerror(errno));
212         }
213
214         ksft_print_msg("Detected binder version: %d\n",
215                        version.protocol_version);
216
217         /* binder transaction with binderfs binder device passed */
218         ksft_inc_pass_cnt();
219
220         ret = unlink("/dev/binderfs/my-binder");
221         if (ret < 0) {
222                 keep ? : rmdir_protect_errno("/dev/binderfs");
223                 ksft_exit_fail_msg("%s - Failed to delete binder device\n",
224                                    strerror(errno));
225         }
226
227         /* binder device removal passed */
228         ksft_inc_pass_cnt();
229
230         ret = unlink("/dev/binderfs/binder-control");
231         if (!ret) {
232                 keep ? : rmdir_protect_errno("/dev/binderfs");
233                 ksft_exit_fail_msg("Managed to delete binder-control device\n");
234         } else if (errno != EPERM) {
235                 keep ? : rmdir_protect_errno("/dev/binderfs");
236                 ksft_exit_fail_msg(
237                         "%s - Failed to delete binder-control device but exited with unexpected error code\n",
238                         strerror(errno));
239         }
240
241         /* binder-control device removal failed as expected */
242         ksft_inc_xfail_cnt();
243
244 on_error:
245         ret = umount2("/dev/binderfs", MNT_DETACH);
246         keep ?: rmdir_protect_errno("/dev/binderfs");
247         if (ret < 0)
248                 ksft_exit_fail_msg("%s - Failed to unmount binderfs\n",
249                                    strerror(errno));
250
251         /* binderfs unmount test passed */
252         ksft_inc_pass_cnt();
253 }
254
255 static void binderfs_test_privileged()
256 {
257         if (geteuid() != 0)
258                 ksft_print_msg(
259                         "Tests are not run as root. Skipping privileged tests\n");
260         else
261                 __do_binderfs_test();
262 }
263
264 static void binderfs_test_unprivileged()
265 {
266         change_to_userns();
267         __do_binderfs_test();
268 }
269
270 int main(int argc, char *argv[])
271 {
272         binderfs_test_privileged();
273         binderfs_test_unprivileged();
274         ksft_exit_pass();
275 }