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 #include "../config.h"
27
28 #define _GNU_SOURCE
29
30 #include <stdlib.h>
31 #include <stdint.h>
32 #include <assert.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37 #include <dlfcn.h>
38 #include <errno.h>
39 #include <stdarg.h>
40 #include <fcntl.h>
41 #include <stdio.h>
42 #include <sys/epoll.h>
43
44 #include "wayland-private.h"
45 #include "test-runner.h"
46 #include "wayland-os.h"
47
48 static int fall_back;
49
50 /* Play nice with sanitizers
51 *
52 * Sanitizers need to intercept syscalls in the compiler run-time library. As
53 * this isn't a separate ELF object, the usual dlsym(RTLD_NEXT) approach won't
54 * work: there can only be one function named "socket" etc. To support this, the
55 * sanitizer library names its interceptors with the prefix __interceptor_ ("__"
56 * being reserved for the implementation) and then weakly aliases it to the real
57 * function. The functions we define below will override the weak alias, and we
58 * can call them by the __interceptor_ name directly. This allows the sanitizer
59 * to do its work before calling the next version of the function via dlsym.
60 *
61 * However! We also don't know which of these functions the sanitizer actually
62 * wants to override, so we have to declare our own weak symbols for
63 * __interceptor_ and check at run time if they linked to anything or not.
64 */
65
66 #define DECL(ret_type, func, ...) \
67 ret_type __interceptor_ ## func(__VA_ARGS__) __attribute__((weak)); \
68 static ret_type (*real_ ## func)(__VA_ARGS__); \
69 static int wrapped_calls_ ## func;
70
71 #define REAL(func) (__interceptor_ ## func) ? \
72 __interceptor_ ## func : \
73 (__typeof__(&__interceptor_ ## func))dlsym(RTLD_NEXT, #func)
74
75 DECL(int, socket, int, int, int);
76 DECL(int, fcntl, int, int, ...);
77 DECL(ssize_t, recvmsg, int, struct msghdr *, int);
78 DECL(int, epoll_create1, int);
79
80 static void
init_fallbacks(int do_fallbacks)81 init_fallbacks(int do_fallbacks)
82 {
83 fall_back = do_fallbacks;
84 real_socket = REAL(socket);
85 real_fcntl = REAL(fcntl);
86 real_recvmsg = REAL(recvmsg);
87 real_epoll_create1 = REAL(epoll_create1);
88 }
89
90 __attribute__ ((visibility("default"))) int
socket(int domain,int type,int protocol)91 socket(int domain, int type, int protocol)
92 {
93 wrapped_calls_socket++;
94
95 if (fall_back && (type & SOCK_CLOEXEC)) {
96 errno = EINVAL;
97 return -1;
98 }
99
100 return real_socket(domain, type, protocol);
101 }
102
103 __attribute__ ((visibility("default"))) int
104 (fcntl)(int fd, int cmd, ...)
105 {
106 va_list ap;
107 int arg;
108 int has_arg;
109
110 wrapped_calls_fcntl++;
111
112 if (fall_back && (cmd == F_DUPFD_CLOEXEC)) {
113 errno = EINVAL;
114 return -1;
115 }
116 switch (cmd) {
117 case F_DUPFD_CLOEXEC:
118 case F_DUPFD:
119 case F_SETFD:
120 va_start(ap, cmd);
121 arg = va_arg(ap, int);
122 has_arg = 1;
123 va_end(ap);
124 break;
125 case F_GETFD:
126 has_arg = 0;
127 break;
128 default:
129 fprintf(stderr, "Unexpected fctnl cmd %d\n", cmd);
130 abort();
131 }
132
133 if (has_arg) {
134 return real_fcntl(fd, cmd, arg);
135 }
136 return real_fcntl(fd, cmd);
137 }
138
139 __attribute__ ((visibility("default"))) ssize_t
recvmsg(int sockfd,struct msghdr * msg,int flags)140 recvmsg(int sockfd, struct msghdr *msg, int flags)
141 {
142 wrapped_calls_recvmsg++;
143
144 if (fall_back && (flags & MSG_CMSG_CLOEXEC)) {
145 errno = EINVAL;
146 return -1;
147 }
148
149 return real_recvmsg(sockfd, msg, flags);
150 }
151
152 __attribute__ ((visibility("default"))) int
epoll_create1(int flags)153 epoll_create1(int flags)
154 {
155 wrapped_calls_epoll_create1++;
156
157 if (fall_back) {
158 wrapped_calls_epoll_create1++; /* epoll_create() not wrapped */
159 errno = EINVAL;
160 return -1;
161 }
162
163 return real_epoll_create1(flags);
164 }
165
166 static void
do_os_wrappers_socket_cloexec(int n)167 do_os_wrappers_socket_cloexec(int n)
168 {
169 int fd;
170 int nr_fds;
171
172 nr_fds = count_open_fds();
173
174 /* simply create a socket that closes on exec */
175 fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0);
176 assert(fd >= 0);
177
178 /*
179 * Must have 2 calls if falling back, but must also allow
180 * falling back without a forced fallback.
181 */
182 assert(wrapped_calls_socket > n);
183
184 exec_fd_leak_check(nr_fds);
185 }
186
TEST(os_wrappers_socket_cloexec)187 TEST(os_wrappers_socket_cloexec)
188 {
189 /* normal case */
190 init_fallbacks(0);
191 do_os_wrappers_socket_cloexec(0);
192 }
193
TEST(os_wrappers_socket_cloexec_fallback)194 TEST(os_wrappers_socket_cloexec_fallback)
195 {
196 /* forced fallback */
197 init_fallbacks(1);
198 do_os_wrappers_socket_cloexec(1);
199 }
200
201 static void
do_os_wrappers_dupfd_cloexec(int n)202 do_os_wrappers_dupfd_cloexec(int n)
203 {
204 int base_fd;
205 int fd;
206 int nr_fds;
207
208 nr_fds = count_open_fds();
209
210 base_fd = socket(PF_LOCAL, SOCK_STREAM, 0);
211 assert(base_fd >= 0);
212
213 fd = wl_os_dupfd_cloexec(base_fd, 13);
214 assert(fd >= 13);
215
216 close(base_fd);
217
218 /*
219 * Must have 4 calls if falling back, but must also allow
220 * falling back without a forced fallback.
221 */
222 assert(wrapped_calls_fcntl > n);
223
224 exec_fd_leak_check(nr_fds);
225 }
226
TEST(os_wrappers_dupfd_cloexec)227 TEST(os_wrappers_dupfd_cloexec)
228 {
229 init_fallbacks(0);
230 do_os_wrappers_dupfd_cloexec(0);
231 }
232
TEST(os_wrappers_dupfd_cloexec_fallback)233 TEST(os_wrappers_dupfd_cloexec_fallback)
234 {
235 init_fallbacks(1);
236 do_os_wrappers_dupfd_cloexec(3);
237 }
238
239 struct marshal_data {
240 struct wl_connection *read_connection;
241 struct wl_connection *write_connection;
242 int s[2];
243 uint32_t read_mask;
244 uint32_t write_mask;
245 union {
246 int h[3];
247 } value;
248 int nr_fds_begin;
249 int nr_fds_conn;
250 int wrapped_calls;
251 };
252
253 static void
setup_marshal_data(struct marshal_data * data)254 setup_marshal_data(struct marshal_data *data)
255 {
256 assert(socketpair(AF_UNIX,
257 SOCK_STREAM | SOCK_CLOEXEC, 0, data->s) == 0);
258
259 data->read_connection = wl_connection_create(data->s[0]);
260 assert(data->read_connection);
261
262 data->write_connection = wl_connection_create(data->s[1]);
263 assert(data->write_connection);
264 }
265
266 static void
marshal_demarshal(struct marshal_data * data,void (* func)(void),int size,const char * format,...)267 marshal_demarshal(struct marshal_data *data,
268 void (*func)(void), int size, const char *format, ...)
269 {
270 struct wl_closure *closure;
271 static const int opcode = 4444;
272 static struct wl_object sender = { NULL, NULL, 1234 };
273 struct wl_message message = { "test", format, NULL };
274 struct wl_map objects;
275 struct wl_object object = { NULL, &func, 1234 };
276 va_list ap;
277 uint32_t msg[1] = { 1234 };
278
279 va_start(ap, format);
280 closure = wl_closure_vmarshal(&sender, opcode, ap, &message);
281 va_end(ap);
282
283 assert(closure);
284 assert(wl_closure_send(closure, data->write_connection) == 0);
285 wl_closure_destroy(closure);
286 assert(wl_connection_flush(data->write_connection) == size);
287
288 assert(wl_connection_read(data->read_connection) == size);
289
290 wl_map_init(&objects, WL_MAP_SERVER_SIDE);
291 object.id = msg[0];
292 closure = wl_connection_demarshal(data->read_connection,
293 size, &objects, &message);
294 assert(closure);
295 wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER, &object, 0, data);
296 wl_closure_destroy(closure);
297 }
298
299 static void
validate_recvmsg_h(struct marshal_data * data,struct wl_object * object,int fd1,int fd2,int fd3)300 validate_recvmsg_h(struct marshal_data *data,
301 struct wl_object *object, int fd1, int fd2, int fd3)
302 {
303 struct stat buf1, buf2;
304
305 assert(fd1 >= 0);
306 assert(fd2 >= 0);
307 assert(fd3 >= 0);
308
309 assert(fd1 != data->value.h[0]);
310 assert(fd2 != data->value.h[1]);
311 assert(fd3 != data->value.h[2]);
312
313 assert(fstat(fd3, &buf1) == 0);
314 assert(fstat(data->value.h[2], &buf2) == 0);
315 assert(buf1.st_dev == buf2.st_dev);
316 assert(buf1.st_ino == buf2.st_ino);
317
318 /* close the original file descriptors */
319 close(data->value.h[0]);
320 close(data->value.h[1]);
321 close(data->value.h[2]);
322
323 /* the dup'd (received) fds should still be open */
324 assert(count_open_fds() == data->nr_fds_conn + 3);
325
326 /*
327 * Must have 2 calls if falling back, but must also allow
328 * falling back without a forced fallback.
329 */
330 assert(wrapped_calls_recvmsg > data->wrapped_calls);
331
332 if (data->wrapped_calls == 0 && wrapped_calls_recvmsg > 1)
333 printf("recvmsg fell back unforced.\n");
334
335 /* all fds opened during the test in any way should be gone on exec */
336 exec_fd_leak_check(data->nr_fds_begin);
337 }
338
339 static void
do_os_wrappers_recvmsg_cloexec(int n)340 do_os_wrappers_recvmsg_cloexec(int n)
341 {
342 struct marshal_data data;
343
344 data.nr_fds_begin = count_open_fds();
345 #if HAVE_BROKEN_MSG_CMSG_CLOEXEC
346 /* We call the fallback directly on FreeBSD versions with a broken
347 * MSG_CMSG_CLOEXEC, so we don't call the local recvmsg() wrapper. */
348 data.wrapped_calls = 0;
349 #else
350 data.wrapped_calls = n;
351 #endif
352
353 setup_marshal_data(&data);
354 data.nr_fds_conn = count_open_fds();
355
356 assert(pipe(data.value.h) >= 0);
357
358 data.value.h[2] = open("/dev/zero", O_RDONLY);
359 assert(data.value.h[2] >= 0);
360
361 marshal_demarshal(&data, (void *) validate_recvmsg_h,
362 8, "hhh", data.value.h[0], data.value.h[1],
363 data.value.h[2]);
364 }
365
TEST(os_wrappers_recvmsg_cloexec)366 TEST(os_wrappers_recvmsg_cloexec)
367 {
368 init_fallbacks(0);
369 do_os_wrappers_recvmsg_cloexec(0);
370 }
371
TEST(os_wrappers_recvmsg_cloexec_fallback)372 TEST(os_wrappers_recvmsg_cloexec_fallback)
373 {
374 init_fallbacks(1);
375 do_os_wrappers_recvmsg_cloexec(1);
376 }
377
378 static void
do_os_wrappers_epoll_create_cloexec(int n)379 do_os_wrappers_epoll_create_cloexec(int n)
380 {
381 int fd;
382 int nr_fds;
383
384 nr_fds = count_open_fds();
385
386 fd = wl_os_epoll_create_cloexec();
387 assert(fd >= 0);
388
389 #ifdef EPOLL_CLOEXEC
390 assert(wrapped_calls_epoll_create1 == n);
391 #else
392 printf("No epoll_create1.\n");
393 #endif
394
395 exec_fd_leak_check(nr_fds);
396 }
397
TEST(os_wrappers_epoll_create_cloexec)398 TEST(os_wrappers_epoll_create_cloexec)
399 {
400 init_fallbacks(0);
401 do_os_wrappers_epoll_create_cloexec(1);
402 }
403
TEST(os_wrappers_epoll_create_cloexec_fallback)404 TEST(os_wrappers_epoll_create_cloexec_fallback)
405 {
406 init_fallbacks(1);
407 do_os_wrappers_epoll_create_cloexec(2);
408 }
409
410 /* FIXME: add tests for wl_os_accept_cloexec() */
411