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