1 /*
2 * Copyright © 2012 Collabora, Ltd.
3 * Copyright © 2012 Intel Corporation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 */
26
27 #define _GNU_SOURCE
28
29 #include <stdlib.h>
30 #include <stdint.h>
31 #include <assert.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/stat.h>
35 #include <unistd.h>
36 #include <dlfcn.h>
37 #include <errno.h>
38 #include <stdarg.h>
39 #include <fcntl.h>
40 #include <stdio.h>
41 #include <sys/epoll.h>
42
43 #include "wayland-private.h"
44 #include "test-runner.h"
45 #include "wayland-os.h"
46
47 static int fall_back;
48
49 static int (*real_socket)(int, int, int);
50 static int wrapped_calls_socket;
51
52 static int (*real_fcntl)(int, int, ...);
53 static int wrapped_calls_fcntl;
54
55 static ssize_t (*real_recvmsg)(int, struct msghdr *, int);
56 static int wrapped_calls_recvmsg;
57
58 static int (*real_epoll_create1)(int);
59 static int wrapped_calls_epoll_create1;
60
61 static void
init_fallbacks(int do_fallbacks)62 init_fallbacks(int do_fallbacks)
63 {
64 fall_back = do_fallbacks;
65 real_socket = dlsym(RTLD_NEXT, "socket");
66 real_fcntl = dlsym(RTLD_NEXT, "fcntl");
67 real_recvmsg = dlsym(RTLD_NEXT, "recvmsg");
68 real_epoll_create1 = dlsym(RTLD_NEXT, "epoll_create1");
69 }
70
71 __attribute__ ((visibility("default"))) int
socket(int domain,int type,int protocol)72 socket(int domain, int type, int protocol)
73 {
74 wrapped_calls_socket++;
75
76 if (fall_back && (type & SOCK_CLOEXEC)) {
77 errno = EINVAL;
78 return -1;
79 }
80
81 return real_socket(domain, type, protocol);
82 }
83
84 __attribute__ ((visibility("default"))) int
fcntl(int fd,int cmd,...)85 fcntl(int fd, int cmd, ...)
86 {
87 va_list ap;
88 void *arg;
89
90 wrapped_calls_fcntl++;
91
92 if (fall_back && (cmd == F_DUPFD_CLOEXEC)) {
93 errno = EINVAL;
94 return -1;
95 }
96
97 va_start(ap, cmd);
98 arg = va_arg(ap, void*);
99 va_end(ap);
100
101 return real_fcntl(fd, cmd, arg);
102 }
103
104 __attribute__ ((visibility("default"))) ssize_t
recvmsg(int sockfd,struct msghdr * msg,int flags)105 recvmsg(int sockfd, struct msghdr *msg, int flags)
106 {
107 wrapped_calls_recvmsg++;
108
109 if (fall_back && (flags & MSG_CMSG_CLOEXEC)) {
110 errno = EINVAL;
111 return -1;
112 }
113
114 return real_recvmsg(sockfd, msg, flags);
115 }
116
117 __attribute__ ((visibility("default"))) int
epoll_create1(int flags)118 epoll_create1(int flags)
119 {
120 wrapped_calls_epoll_create1++;
121
122 if (fall_back) {
123 wrapped_calls_epoll_create1++; /* epoll_create() not wrapped */
124 errno = EINVAL;
125 return -1;
126 }
127
128 return real_epoll_create1(flags);
129 }
130
131 static void
do_os_wrappers_socket_cloexec(int n)132 do_os_wrappers_socket_cloexec(int n)
133 {
134 int fd;
135 int nr_fds;
136
137 nr_fds = count_open_fds();
138
139 /* simply create a socket that closes on exec */
140 fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0);
141 assert(fd >= 0);
142
143 /*
144 * Must have 2 calls if falling back, but must also allow
145 * falling back without a forced fallback.
146 */
147 assert(wrapped_calls_socket > n);
148
149 exec_fd_leak_check(nr_fds);
150 }
151
TEST(os_wrappers_socket_cloexec)152 TEST(os_wrappers_socket_cloexec)
153 {
154 /* normal case */
155 init_fallbacks(0);
156 do_os_wrappers_socket_cloexec(0);
157 }
158
TEST(os_wrappers_socket_cloexec_fallback)159 TEST(os_wrappers_socket_cloexec_fallback)
160 {
161 /* forced fallback */
162 init_fallbacks(1);
163 do_os_wrappers_socket_cloexec(1);
164 }
165
166 static void
do_os_wrappers_dupfd_cloexec(int n)167 do_os_wrappers_dupfd_cloexec(int n)
168 {
169 int base_fd;
170 int fd;
171 int nr_fds;
172
173 nr_fds = count_open_fds();
174
175 base_fd = socket(PF_LOCAL, SOCK_STREAM, 0);
176 assert(base_fd >= 0);
177
178 fd = wl_os_dupfd_cloexec(base_fd, 13);
179 assert(fd >= 13);
180
181 close(base_fd);
182
183 /*
184 * Must have 4 calls if falling back, but must also allow
185 * falling back without a forced fallback.
186 */
187 assert(wrapped_calls_fcntl > n);
188
189 exec_fd_leak_check(nr_fds);
190 }
191
TEST(os_wrappers_dupfd_cloexec)192 TEST(os_wrappers_dupfd_cloexec)
193 {
194 init_fallbacks(0);
195 do_os_wrappers_dupfd_cloexec(0);
196 }
197
TEST(os_wrappers_dupfd_cloexec_fallback)198 TEST(os_wrappers_dupfd_cloexec_fallback)
199 {
200 init_fallbacks(1);
201 do_os_wrappers_dupfd_cloexec(3);
202 }
203
204 struct marshal_data {
205 struct wl_connection *read_connection;
206 struct wl_connection *write_connection;
207 int s[2];
208 uint32_t read_mask;
209 uint32_t write_mask;
210 union {
211 int h[3];
212 } value;
213 int nr_fds_begin;
214 int nr_fds_conn;
215 int wrapped_calls;
216 };
217
218 static void
setup_marshal_data(struct marshal_data * data)219 setup_marshal_data(struct marshal_data *data)
220 {
221 assert(socketpair(AF_UNIX,
222 SOCK_STREAM | SOCK_CLOEXEC, 0, data->s) == 0);
223
224 data->read_connection = wl_connection_create(data->s[0]);
225 assert(data->read_connection);
226
227 data->write_connection = wl_connection_create(data->s[1]);
228 assert(data->write_connection);
229 }
230
231 static void
marshal_demarshal(struct marshal_data * data,void (* func)(void),int size,const char * format,...)232 marshal_demarshal(struct marshal_data *data,
233 void (*func)(void), int size, const char *format, ...)
234 {
235 struct wl_closure *closure;
236 static const int opcode = 4444;
237 static struct wl_object sender = { NULL, NULL, 1234 };
238 struct wl_message message = { "test", format, NULL };
239 struct wl_map objects;
240 struct wl_object object = { NULL, &func, 1234 };
241 va_list ap;
242 uint32_t msg[1] = { 1234 };
243
244 va_start(ap, format);
245 closure = wl_closure_vmarshal(&sender, opcode, ap, &message);
246 va_end(ap);
247
248 assert(closure);
249 assert(wl_closure_send(closure, data->write_connection) == 0);
250 wl_closure_destroy(closure);
251 assert(wl_connection_flush(data->write_connection) == size);
252
253 assert(wl_connection_read(data->read_connection) == size);
254
255 wl_map_init(&objects, WL_MAP_SERVER_SIDE);
256 object.id = msg[0];
257 closure = wl_connection_demarshal(data->read_connection,
258 size, &objects, &message);
259 assert(closure);
260 wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER, &object, 0, data);
261 wl_closure_destroy(closure);
262 }
263
264 static void
validate_recvmsg_h(struct marshal_data * data,struct wl_object * object,int fd1,int fd2,int fd3)265 validate_recvmsg_h(struct marshal_data *data,
266 struct wl_object *object, int fd1, int fd2, int fd3)
267 {
268 struct stat buf1, buf2;
269
270 assert(fd1 >= 0);
271 assert(fd2 >= 0);
272 assert(fd3 >= 0);
273
274 assert(fd1 != data->value.h[0]);
275 assert(fd2 != data->value.h[1]);
276 assert(fd3 != data->value.h[2]);
277
278 assert(fstat(fd3, &buf1) == 0);
279 assert(fstat(data->value.h[2], &buf2) == 0);
280 assert(buf1.st_dev == buf2.st_dev);
281 assert(buf1.st_ino == buf2.st_ino);
282
283 /* close the original file descriptors */
284 close(data->value.h[0]);
285 close(data->value.h[1]);
286 close(data->value.h[2]);
287
288 /* the dup'd (received) fds should still be open */
289 assert(count_open_fds() == data->nr_fds_conn + 3);
290
291 /*
292 * Must have 2 calls if falling back, but must also allow
293 * falling back without a forced fallback.
294 */
295 assert(wrapped_calls_recvmsg > data->wrapped_calls);
296
297 if (data->wrapped_calls == 0 && wrapped_calls_recvmsg > 1)
298 printf("recvmsg fell back unforced.\n");
299
300 /* all fds opened during the test in any way should be gone on exec */
301 exec_fd_leak_check(data->nr_fds_begin);
302 }
303
304 static void
do_os_wrappers_recvmsg_cloexec(int n)305 do_os_wrappers_recvmsg_cloexec(int n)
306 {
307 struct marshal_data data;
308
309 data.nr_fds_begin = count_open_fds();
310 data.wrapped_calls = n;
311
312 setup_marshal_data(&data);
313 data.nr_fds_conn = count_open_fds();
314
315 assert(pipe(data.value.h) >= 0);
316
317 data.value.h[2] = open("/dev/zero", O_RDONLY);
318 assert(data.value.h[2] >= 0);
319
320 marshal_demarshal(&data, (void *) validate_recvmsg_h,
321 8, "hhh", data.value.h[0], data.value.h[1],
322 data.value.h[2]);
323 }
324
TEST(os_wrappers_recvmsg_cloexec)325 TEST(os_wrappers_recvmsg_cloexec)
326 {
327 init_fallbacks(0);
328 do_os_wrappers_recvmsg_cloexec(0);
329 }
330
TEST(os_wrappers_recvmsg_cloexec_fallback)331 TEST(os_wrappers_recvmsg_cloexec_fallback)
332 {
333 init_fallbacks(1);
334 do_os_wrappers_recvmsg_cloexec(1);
335 }
336
337 static void
do_os_wrappers_epoll_create_cloexec(int n)338 do_os_wrappers_epoll_create_cloexec(int n)
339 {
340 int fd;
341 int nr_fds;
342
343 nr_fds = count_open_fds();
344
345 fd = wl_os_epoll_create_cloexec();
346 assert(fd >= 0);
347
348 #ifdef EPOLL_CLOEXEC
349 assert(wrapped_calls_epoll_create1 == n);
350 #else
351 printf("No epoll_create1.\n");
352 #endif
353
354 exec_fd_leak_check(nr_fds);
355 }
356
TEST(os_wrappers_epoll_create_cloexec)357 TEST(os_wrappers_epoll_create_cloexec)
358 {
359 init_fallbacks(0);
360 do_os_wrappers_epoll_create_cloexec(1);
361 }
362
TEST(os_wrappers_epoll_create_cloexec_fallback)363 TEST(os_wrappers_epoll_create_cloexec_fallback)
364 {
365 init_fallbacks(1);
366 do_os_wrappers_epoll_create_cloexec(2);
367 }
368
369 /* FIXME: add tests for wl_os_accept_cloexec() */
370