Home | History | Annotate | Download | only in tests
      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
     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
     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
     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
    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
    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
    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 
    152 TEST(os_wrappers_socket_cloexec)
    153 {
    154 	/* normal case */
    155 	init_fallbacks(0);
    156 	do_os_wrappers_socket_cloexec(0);
    157 }
    158 
    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
    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 
    192 TEST(os_wrappers_dupfd_cloexec)
    193 {
    194 	init_fallbacks(0);
    195 	do_os_wrappers_dupfd_cloexec(0);
    196 }
    197 
    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
    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
    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
    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
    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 
    325 TEST(os_wrappers_recvmsg_cloexec)
    326 {
    327 	init_fallbacks(0);
    328 	do_os_wrappers_recvmsg_cloexec(0);
    329 }
    330 
    331 TEST(os_wrappers_recvmsg_cloexec_fallback)
    332 {
    333 	init_fallbacks(1);
    334 	do_os_wrappers_recvmsg_cloexec(1);
    335 }
    336 
    337 static void
    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 
    357 TEST(os_wrappers_epoll_create_cloexec)
    358 {
    359 	init_fallbacks(0);
    360 	do_os_wrappers_epoll_create_cloexec(1);
    361 }
    362 
    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