• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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