Tests: Add test to check shared-memory FD leaks after relayd dies
[lttng-tools.git] / tests / regression / kernel / select_poll_epoll.cpp
CommitLineData
9d16b343
MJ
1/*
2 * Copyright (C) 2016 Julien Desfossez <jdesfossez@efficios.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
fbf606d7
MJ
8/*
9 * This test voluntarily does buffer overflows and stack overruns, disable
10 * source fortification.
11 */
12#ifdef _FORTIFY_SOURCE
13#undef _FORTIFY_SOURCE
14#endif
15
28ab034a
JG
16#include <common/compat/time.hpp>
17#include <common/error.hpp>
18
2a2ac572 19#include <errno.h>
c9e313bc
SM
20#include <fcntl.h>
21#include <limits.h>
a0b1f42c 22#include <poll.h>
c9e313bc
SM
23#include <popt.h>
24#include <pthread.h>
a0b1f42c 25#include <signal.h>
c9e313bc
SM
26#include <stddef.h>
27#include <stdio.h>
a0b1f42c
JD
28#include <stdlib.h>
29#include <string.h>
a0b1f42c 30#include <sys/epoll.h>
a0b1f42c 31#include <sys/mman.h>
c9e313bc
SM
32#include <sys/resource.h>
33#include <sys/select.h>
34#include <sys/stat.h>
35#include <sys/syscall.h>
36#include <sys/time.h>
37#include <sys/types.h>
38#include <unistd.h>
39
a0b1f42c 40#define BUF_SIZE 256
28ab034a
JG
41#define NB_FD 1
42#define MAX_FDS 2047
43#define NR_ITER 1000 /* for stress-tests */
a0b1f42c 44
28ab034a 45#define MIN_NR_FDS 5 /* the minimum number of open FDs required for the test to run */
a0b1f42c
JD
46#define BIG_SELECT_FD 1022
47
48#define MSEC_PER_USEC 1000
49#define MSEC_PER_NSEC (MSEC_PER_USEC * 1000)
50
51static int timeout; /* seconds, -1 to disable */
44a411a6 52static volatile int stop_thread;
a0b1f42c
JD
53static int wait_fd;
54
d40c2620
JG
55/* Used by logging utils. */
56int lttng_opt_quiet, lttng_opt_verbose, lttng_opt_mi;
57
58static void run_working_cases(FILE *validation_output_file);
d40c2620 59static void test_ppoll_big(FILE *validation_output_file);
d40c2620 60static void pselect_invalid_pointer(FILE *validation_output_file);
2a2ac572 61static void pselect_invalid_fd(FILE *validation_output_file);
d40c2620 62static void ppoll_fds_ulong_max(FILE *validation_output_file);
2a2ac572 63static void ppoll_fds_buffer_overflow(FILE *validation_output_file);
d40c2620
JG
64static void epoll_pwait_invalid_pointer(FILE *validation_output_file);
65static void epoll_pwait_int_max(FILE *validation_output_file);
66static void ppoll_concurrent_write(FILE *validation_output_file);
67static void epoll_pwait_concurrent_munmap(FILE *validation_output_file);
68
2a2ac572 69typedef void (*test_case_cb)(FILE *output_file);
d40c2620 70
f1494934
JG
71namespace {
72const struct test_case {
d40c2620
JG
73 test_case_cb run;
74 bool produces_validation_info;
75 int timeout;
2a2ac572
JG
76 const char *name;
77 const char *description;
28ab034a 78} test_cases[] = {
2a2ac572
JG
79 { .run = run_working_cases,
80 .produces_validation_info = true,
81 .timeout = -1,
82 .name = "working_cases",
83 .description =
84 "Working cases for select, pselect6, poll, ppoll and epoll, waiting for input" },
85 { .run = run_working_cases,
86 .produces_validation_info = true,
87 .timeout = 1,
88 .name = "working_cases_timeout",
89 .description = "Timeout cases (1ms) for select, pselect6, poll, ppoll and epoll" },
90 { .run = test_ppoll_big,
91 .produces_validation_info = false,
92 .timeout = 0,
93 .name = "ppoll_big",
94 .description = "ppoll with " XSTR(MAX_FDS) " FDs" },
95 { .run = epoll_pwait_invalid_pointer,
96 .produces_validation_info = true,
97 .timeout = 0,
98 .name = "epoll_pwait_invalid_pointer",
99 .description = "epoll_pwait with an invalid pointer, waits for input" },
100 { .run = epoll_pwait_int_max,
101 .produces_validation_info = true,
102 .timeout = 0,
103 .name = "epoll_pwait_int_max",
104 .description = "epoll_pwait with maxevents set to INT_MAX waits for input" },
105 { .run = ppoll_concurrent_write,
106 .produces_validation_info = false,
107 .timeout = 0,
108 .name = "ppoll_concurrent_write",
109 .description =
110 "ppoll with concurrent updates of the structure from user-space, stress test (3000 iterations) waits for input + timeout 1ms" },
111 { .run = epoll_pwait_concurrent_munmap,
112 .produces_validation_info = true,
113 .timeout = 0,
114 .name = "epoll_pwait_concurrent_munmap",
115 .description =
116 "epoll_pwait with concurrent munmap of the buffer from user-space, should randomly segfault, run multiple times, waits for input + timeout 1ms" },
117 { .run = pselect_invalid_pointer,
118 .produces_validation_info = false,
119 .timeout = 0,
120 .name = "pselect_invalid_pointer",
121 .description = "pselect with an invalid pointer, waits for input" },
122 { .run = pselect_invalid_fd,
123 .produces_validation_info = false,
124 .timeout = 0,
125 .name = "pselect_invalid_fd",
126 .description = "pselect with an invalid fd" },
127 { .run = ppoll_fds_ulong_max,
128 .produces_validation_info = false,
129 .timeout = 0,
130 .name = "ppoll_fds_ulong_max",
131 .description = "ppoll with ulong_max fds, waits for input" },
132 { .run = ppoll_fds_buffer_overflow,
133 .produces_validation_info = false,
134 .timeout = 0,
135 .name = "ppoll_fds_buffer_overflow",
136 .description = "ppoll buffer overflow, should segfault, waits for input" },
d40c2620
JG
137};
138
a0b1f42c
JD
139struct ppoll_thread_data {
140 struct pollfd *ufds;
141 int value;
142};
f1494934 143} /* namespace */
a0b1f42c 144
2a2ac572 145static void test_select_big(void)
a0b1f42c
JD
146{
147 fd_set rfds, wfds, exfds;
148 struct timeval tv;
149 int ret;
150 int fd2;
151 char buf[BUF_SIZE];
152
153 FD_ZERO(&rfds);
154 FD_ZERO(&wfds);
155 FD_ZERO(&exfds);
156
157 fd2 = dup2(wait_fd, BIG_SELECT_FD);
158 if (fd2 < 0) {
d40c2620 159 PERROR("dup2");
a0b1f42c
JD
160 goto end;
161 }
162 FD_SET(fd2, &rfds);
163
164 tv.tv_sec = 0;
165 tv.tv_usec = timeout * MSEC_PER_USEC;
166
167 if (timeout > 0) {
168 ret = select(fd2 + 1, &rfds, &wfds, &exfds, &tv);
169 } else {
2a2ac572 170 ret = select(fd2 + 1, &rfds, &wfds, &exfds, NULL);
a0b1f42c
JD
171 }
172
173 if (ret == -1) {
d40c2620 174 PERROR("select()");
a0b1f42c 175 } else if (ret) {
a0b1f42c
JD
176 ret = read(wait_fd, buf, BUF_SIZE);
177 if (ret < 0) {
d40c2620 178 PERROR("[select] read");
a0b1f42c 179 }
a0b1f42c
JD
180 }
181
182 ret = close(BIG_SELECT_FD);
183 if (ret) {
d40c2620 184 PERROR("close");
a0b1f42c
JD
185 }
186
187end:
188 return;
189}
190
2a2ac572 191static void test_pselect_generic(long int syscall_id)
a0b1f42c
JD
192{
193 fd_set rfds;
194 struct timespec tv;
195 int ret;
196 char buf[BUF_SIZE];
197
198 FD_ZERO(&rfds);
199 FD_SET(wait_fd, &rfds);
200
201 tv.tv_sec = 0;
202 tv.tv_nsec = timeout * MSEC_PER_NSEC;
203
204 if (timeout > 0) {
2a2ac572 205 ret = syscall(syscall_id, 1, &rfds, NULL, NULL, &tv, NULL);
a0b1f42c 206 } else {
2a2ac572 207 ret = syscall(syscall_id, 1, &rfds, NULL, NULL, NULL, NULL);
a0b1f42c
JD
208 }
209
210 if (ret == -1) {
d40c2620 211 PERROR("pselect()");
a0b1f42c 212 } else if (ret) {
a0b1f42c
JD
213 ret = read(wait_fd, buf, BUF_SIZE);
214 if (ret < 0) {
d40c2620 215 PERROR("[pselect] read");
a0b1f42c 216 }
a0b1f42c 217 }
a0b1f42c
JD
218}
219
2a2ac572
JG
220static void test_pselect(void)
221{
222 test_pselect_generic(SYS_pselect6);
223}
224
225static void test_select(void)
a0b1f42c
JD
226{
227 fd_set rfds;
228 struct timeval tv;
229 int ret;
230 char buf[BUF_SIZE];
231
232 FD_ZERO(&rfds);
233 FD_SET(wait_fd, &rfds);
234
235 tv.tv_sec = 0;
236 tv.tv_usec = timeout * MSEC_PER_USEC;
237
238 if (timeout > 0) {
2a2ac572 239 ret = select(1, &rfds, NULL, NULL, &tv);
a0b1f42c 240 } else {
2a2ac572 241 ret = select(1, &rfds, NULL, NULL, NULL);
a0b1f42c
JD
242 }
243
244 if (ret == -1) {
d40c2620 245 PERROR("select()");
a0b1f42c 246 } else if (ret) {
a0b1f42c
JD
247 ret = read(wait_fd, buf, BUF_SIZE);
248 if (ret < 0) {
d40c2620 249 PERROR("[select] read");
a0b1f42c 250 }
a0b1f42c 251 }
a0b1f42c
JD
252}
253
2a2ac572 254static void test_poll(void)
a0b1f42c
JD
255{
256 struct pollfd ufds[NB_FD];
257 char buf[BUF_SIZE];
258 int ret;
259
260 ufds[0].fd = wait_fd;
28ab034a 261 ufds[0].events = POLLIN | POLLPRI;
a0b1f42c
JD
262
263 ret = poll(ufds, 1, timeout);
264
265 if (ret < 0) {
d40c2620 266 PERROR("poll");
a0b1f42c 267 } else if (ret > 0) {
a0b1f42c
JD
268 ret = read(wait_fd, buf, BUF_SIZE);
269 if (ret < 0) {
d40c2620 270 PERROR("[poll] read");
a0b1f42c 271 }
a0b1f42c
JD
272 }
273}
274
2a2ac572 275static void test_ppoll_generic(long int syscall_id)
a0b1f42c
JD
276{
277 struct pollfd ufds[NB_FD];
278 char buf[BUF_SIZE];
279 int ret;
280 struct timespec ts;
281
282 ufds[0].fd = wait_fd;
28ab034a 283 ufds[0].events = POLLIN | POLLPRI;
a0b1f42c
JD
284
285 if (timeout > 0) {
286 ts.tv_sec = 0;
287 ts.tv_nsec = timeout * MSEC_PER_NSEC;
2a2ac572 288 ret = syscall(syscall_id, ufds, 1, &ts, NULL);
a0b1f42c 289 } else {
2a2ac572 290 ret = syscall(syscall_id, ufds, 1, NULL, NULL);
a0b1f42c
JD
291 }
292
a0b1f42c 293 if (ret < 0) {
d40c2620 294 PERROR("ppoll");
a0b1f42c 295 } else if (ret > 0) {
a0b1f42c
JD
296 ret = read(wait_fd, buf, BUF_SIZE);
297 if (ret < 0) {
d40c2620 298 PERROR("[ppoll] read");
a0b1f42c 299 }
a0b1f42c
JD
300 }
301}
302
2a2ac572
JG
303static void test_ppoll(void)
304{
305 test_ppoll_generic(SYS_ppoll);
306}
307
28ab034a 308static void test_ppoll_big(FILE *validation_output_file __attribute__((unused)))
a0b1f42c
JD
309{
310 struct pollfd ufds[MAX_FDS];
311 char buf[BUF_SIZE];
312 int ret, i, fds[MAX_FDS];
313
314 for (i = 0; i < MAX_FDS; i++) {
315 fds[i] = dup(wait_fd);
316 if (fds[i] < 0) {
d40c2620 317 PERROR("dup");
a0b1f42c
JD
318 }
319 ufds[i].fd = fds[i];
28ab034a 320 ufds[i].events = POLLIN | POLLPRI;
a0b1f42c
JD
321 }
322
2a2ac572 323 ret = ppoll(ufds, MAX_FDS, NULL, NULL);
a0b1f42c
JD
324
325 if (ret < 0) {
d40c2620 326 PERROR("ppoll");
a0b1f42c 327 } else if (ret > 0) {
a0b1f42c
JD
328 ret = read(wait_fd, buf, BUF_SIZE);
329 if (ret < 0) {
d40c2620 330 PERROR("[ppoll] read");
a0b1f42c 331 }
a0b1f42c
JD
332 }
333
334 for (i = 0; i < MAX_FDS; i++) {
335 ret = close(fds[i]);
336 if (ret != 0) {
d40c2620 337 PERROR("close");
a0b1f42c
JD
338 }
339 }
340
341 return;
342}
343
28ab034a 344static void test_epoll(FILE *validation_output_file)
a0b1f42c
JD
345{
346 int ret, epollfd;
347 char buf[BUF_SIZE];
348 struct epoll_event epoll_event;
349
350 epollfd = epoll_create(NB_FD);
351 if (epollfd < 0) {
d40c2620 352 PERROR("[epoll] create");
a0b1f42c
JD
353 goto end;
354 }
355
28ab034a 356 ret = fprintf(validation_output_file, ", \"epoll_wait_fd\": %i", epollfd);
d40c2620
JG
357 if (ret < 0) {
358 PERROR("[epoll] Failed to write test validation output");
359 goto error;
360 }
361
a0b1f42c
JD
362 epoll_event.events = EPOLLIN | EPOLLPRI | EPOLLET;
363 epoll_event.data.fd = wait_fd;
364 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, wait_fd, &epoll_event);
365 if (ret < 0) {
d40c2620 366 PERROR("[epoll] add");
5305e823 367 goto error;
a0b1f42c
JD
368 }
369
370 if (timeout > 0) {
371 ret = epoll_wait(epollfd, &epoll_event, 1, timeout);
372 } else {
373 ret = epoll_wait(epollfd, &epoll_event, 1, -1);
374 }
375
376 if (ret == 1) {
a0b1f42c
JD
377 ret = read(wait_fd, buf, BUF_SIZE);
378 if (ret < 0) {
d40c2620 379 PERROR("[epoll] read");
a0b1f42c 380 }
d40c2620
JG
381 } else if (ret != 0) {
382 PERROR("epoll_wait");
a0b1f42c
JD
383 }
384
5305e823 385error:
6d52f14d
FD
386 ret = close(epollfd);
387 if (ret) {
d40c2620 388 PERROR("close");
6d52f14d 389 }
a0b1f42c
JD
390end:
391 return;
392}
393
28ab034a 394static void test_epoll_pwait(FILE *validation_output_file)
a0b1f42c
JD
395{
396 int ret, epollfd;
397 char buf[BUF_SIZE];
398 struct epoll_event epoll_event;
399
400 epollfd = epoll_create(NB_FD);
401 if (epollfd < 0) {
d40c2620 402 PERROR("[epoll_pwait] create");
a0b1f42c
JD
403 goto end;
404 }
405
28ab034a 406 ret = fprintf(validation_output_file, ", \"epoll_pwait_fd\": %i", epollfd);
d40c2620
JG
407 if (ret < 0) {
408 PERROR("[epoll_pwait] Failed to write test validation output");
409 goto error;
410 }
411
a0b1f42c
JD
412 epoll_event.events = EPOLLIN | EPOLLPRI | EPOLLET;
413 epoll_event.data.fd = wait_fd;
414 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, wait_fd, &epoll_event);
415 if (ret < 0) {
d40c2620 416 PERROR("[epoll_pwait] add");
5305e823 417 goto error;
a0b1f42c
JD
418 }
419
420 if (timeout > 0) {
2a2ac572 421 ret = epoll_pwait(epollfd, &epoll_event, 1, timeout, NULL);
a0b1f42c 422 } else {
2a2ac572 423 ret = epoll_pwait(epollfd, &epoll_event, 1, -1, NULL);
a0b1f42c
JD
424 }
425
426 if (ret == 1) {
a0b1f42c
JD
427 ret = read(wait_fd, buf, BUF_SIZE);
428 if (ret < 0) {
d40c2620 429 PERROR("[epoll_pwait] read");
a0b1f42c 430 }
d40c2620
JG
431 } else if (ret != 0) {
432 PERROR("epoll_pwait");
a0b1f42c
JD
433 }
434
5305e823 435error:
6d52f14d
FD
436 ret = close(epollfd);
437 if (ret) {
d40c2620 438 PERROR("close");
6d52f14d 439 }
a0b1f42c
JD
440end:
441 return;
442}
443
28ab034a 444static void run_working_cases(FILE *validation_output_file)
a0b1f42c
JD
445{
446 int ret;
447 int pipe_fds[2];
448
449 if (timeout > 0) {
450 /*
451 * We need an input pipe for some cases and stdin might
452 * have random data, so we create a dummy pipe for this
453 * test to make sure we are running under clean conditions.
454 */
455 ret = pipe(pipe_fds);
456 if (ret != 0) {
d40c2620 457 PERROR("pipe");
a0b1f42c
JD
458 goto end;
459 }
460 wait_fd = pipe_fds[0];
461 }
462 test_select();
2a2ac572
JG
463#ifdef sys_pselect6_time64
464 test_pselect_time64();
465#else
a0b1f42c 466 test_pselect();
2a2ac572 467#endif /* sys_pselect6_time64 */
a0b1f42c
JD
468 test_select_big();
469 test_poll();
470 test_ppoll();
2a2ac572
JG
471#ifdef sys_ppoll_time64
472 test_ppoll_time64();
473#else
474 test_ppoll();
475#endif /* sys_ppoll_time64 */
d40c2620 476
2a2ac572 477 ret = fprintf(validation_output_file, "{\"pid\": %i", getpid());
d40c2620
JG
478 if (ret < 0) {
479 PERROR("Failed to write pid to test validation file");
480 goto end;
481 }
482
483 test_epoll(validation_output_file);
484 test_epoll_pwait(validation_output_file);
a0b1f42c
JD
485
486 if (timeout > 0) {
487 ret = close(pipe_fds[0]);
488 if (ret) {
d40c2620 489 PERROR("close");
a0b1f42c
JD
490 }
491 ret = close(pipe_fds[1]);
492 if (ret) {
d40c2620 493 PERROR("close");
a0b1f42c
JD
494 }
495 }
496
d40c2620
JG
497 ret = fputs(" }", validation_output_file);
498 if (ret < 0) {
499 PERROR("Failed to close JSON dictionary in test validation file");
500 goto end;
501 }
502
a0b1f42c
JD
503end:
504 return;
505}
506
507/*
2a2ac572
JG
508 * Ask for ULONG_MAX FDs in a buffer for allocated for only 1 FD, should
509 * cleanly fail with a "Invalid argument".
510 * The event should contain an empty array of FDs and overflow = 1.
a0b1f42c 511 */
2a2ac572 512static void generic_ppoll_fds_ulong_max(long int syscall_id)
a0b1f42c
JD
513{
514 struct pollfd ufds[NB_FD];
515 char buf[BUF_SIZE];
516 int ret;
517
518 ufds[0].fd = wait_fd;
28ab034a 519 ufds[0].events = POLLIN | POLLPRI;
a0b1f42c 520
2a2ac572
JG
521 /* ppoll and/or ppoll_time64 are used, depending on platform support. */
522 ret = syscall(syscall_id, ufds, ULONG_MAX, NULL, NULL);
a0b1f42c 523 if (ret < 0) {
2a2ac572 524 /* Expected error. */
a0b1f42c 525 } else if (ret > 0) {
a0b1f42c
JD
526 ret = read(wait_fd, buf, BUF_SIZE);
527 if (ret < 0) {
2a2ac572 528 PERROR("Failed to read from wait file descriptor");
a0b1f42c 529 }
a0b1f42c 530 }
a0b1f42c
JD
531}
532
533/*
2a2ac572
JG
534 * Ask for 100 FDs in a buffer for allocated for only 1 FD, should
535 * segfault (eventually with a "*** stack smashing detected ***" message).
536 * The event should contain an array of 100 FDs filled with garbage.
a0b1f42c 537 */
2a2ac572 538static void generic_ppoll_fds_buffer_overflow(long int syscall_id)
a0b1f42c
JD
539{
540 struct pollfd ufds[NB_FD];
541 char buf[BUF_SIZE];
542 int ret;
543
544 ufds[0].fd = wait_fd;
28ab034a 545 ufds[0].events = POLLIN | POLLPRI;
a0b1f42c 546
2a2ac572
JG
547 /* ppoll and/or ppoll_time64 are used, depending on platform support. */
548 ret = syscall(syscall_id, ufds, 100, NULL, NULL);
a0b1f42c 549 if (ret < 0) {
2a2ac572 550 PERROR("Failed to wait using ppoll/ppoll_time64");
a0b1f42c 551 } else if (ret > 0) {
a0b1f42c
JD
552 ret = read(wait_fd, buf, BUF_SIZE);
553 if (ret < 0) {
2a2ac572 554 PERROR("Failed to read from wait file descriptor");
a0b1f42c 555 }
a0b1f42c 556 }
a0b1f42c
JD
557}
558
2a2ac572
JG
559static void ppoll_fds_ulong_max(FILE *validation_output_file __attribute__((unused)))
560{
561#ifdef SYS_ppoll_time64
562 generic_ppoll_fds_ulong_max(SYS_ppoll_time64);
563#else
564 generic_ppoll_fds_ulong_max(SYS_ppoll);
565#endif /* SYS_ppoll_time64 */
566}
567
568static void ppoll_fds_buffer_overflow(FILE *validation_output_file __attribute__((unused)))
569{
570#ifdef SYS_ppoll_time64
571 generic_ppoll_fds_buffer_overflow(SYS_ppoll_time64);
572#else
573 generic_ppoll_fds_buffer_overflow(SYS_ppoll);
574#endif /* SYS_ppoll_time64 */
575}
576
a0b1f42c 577/*
8b3b99e2
FD
578 * Pass an invalid file descriptor to pselect6(). The syscall should return
579 * -EBADF. The recorded event should contain a "ret = -EBADF (-9)".
a0b1f42c 580 */
2a2ac572 581static void generic_invalid_fd(long int syscall_id)
a0b1f42c 582{
8b3b99e2 583 fd_set rfds;
a0b1f42c 584 int ret;
8b3b99e2 585 int fd;
a0b1f42c
JD
586 char buf[BUF_SIZE];
587
588 /*
8b3b99e2 589 * Open a file, close it and use the closed FD in the pselect6 call.
a0b1f42c 590 */
8b3b99e2
FD
591 fd = open("/dev/null", O_RDONLY);
592 if (fd == -1) {
2a2ac572 593 PERROR("Failed to open /dev/null");
8b3b99e2
FD
594 goto error;
595 }
596
597 ret = close(fd);
598 if (ret == -1) {
2a2ac572 599 PERROR("Failed to close /dev/null file descriptor");
8b3b99e2 600 goto error;
a0b1f42c 601 }
e593ee02 602
8b3b99e2
FD
603 FD_ZERO(&rfds);
604 FD_SET(fd, &rfds);
a0b1f42c 605
2a2ac572 606 ret = syscall(syscall_id, fd + 1, &rfds, NULL, NULL, NULL, NULL);
a0b1f42c 607 if (ret == -1) {
d40c2620 608 /* Expected error. */
a0b1f42c 609 } else if (ret) {
a0b1f42c
JD
610 ret = read(wait_fd, buf, BUF_SIZE);
611 if (ret < 0) {
2a2ac572 612 PERROR("Failed to read from wait file descriptor");
a0b1f42c 613 }
a0b1f42c 614 }
8b3b99e2
FD
615error:
616 return;
a0b1f42c
JD
617}
618
619/*
620 * Invalid pointer as writefds, should output a ppoll event
621 * with 0 FDs.
622 */
2a2ac572 623static void generic_invalid_pointer(int syscall_id)
a0b1f42c
JD
624{
625 fd_set rfds;
626 int ret;
627 char buf[BUF_SIZE];
628 void *invalid = (void *) 0x42;
629
630 FD_ZERO(&rfds);
631 FD_SET(wait_fd, &rfds);
632
2a2ac572 633 ret = syscall(syscall_id, 1, &rfds, (fd_set *) invalid, NULL, NULL, NULL);
a0b1f42c 634 if (ret == -1) {
d40c2620 635 /* Expected error. */
a0b1f42c 636 } else if (ret) {
a0b1f42c
JD
637 ret = read(wait_fd, buf, BUF_SIZE);
638 if (ret < 0) {
2a2ac572 639 PERROR("Failed to read from wait file descriptor");
a0b1f42c 640 }
a0b1f42c 641 }
a0b1f42c
JD
642}
643
2a2ac572
JG
644static void pselect_invalid_fd(FILE *validation_output_file __attribute__((unused)))
645{
646#ifdef SYS_pselect6_time64
647 generic_invalid_fd(SYS_pselect6_time64);
648#else
649 generic_invalid_fd(SYS_pselect6);
650#endif /* SYS_pselect6_time64 */
651}
652
653/*
654 * Invalid pointer as writefds, should output a ppoll event
655 * with 0 FDs.
656 */
657static void pselect_invalid_pointer(FILE *validation_output_file __attribute__((unused)))
658{
659#ifdef SYS_pselect6_time64
660 generic_invalid_pointer(SYS_pselect6_time64);
661#else
662 generic_invalid_pointer(SYS_pselect6);
663#endif /* SYS_pselect6_time64 */
664}
665
a0b1f42c
JD
666/*
667 * Pass an invalid pointer to epoll_pwait, should fail with
668 * "Bad address", the event returns 0 FDs.
669 */
28ab034a 670static void epoll_pwait_invalid_pointer(FILE *validation_output_file)
a0b1f42c
JD
671{
672 int ret, epollfd;
673 char buf[BUF_SIZE];
674 struct epoll_event epoll_event;
675 void *invalid = (void *) 0x42;
676
677 epollfd = epoll_create(NB_FD);
678 if (epollfd < 0) {
d40c2620 679 PERROR("[epoll_pwait] create");
a0b1f42c
JD
680 goto end;
681 }
682
2a2ac572 683 ret = fprintf(validation_output_file, "{\"epollfd\": %i, \"pid\": %i }", epollfd, getpid());
d40c2620
JG
684 if (ret < 0) {
685 PERROR("[epoll_pwait] Failed to write test validation output");
686 goto error;
687 }
688
a0b1f42c
JD
689 epoll_event.events = EPOLLIN | EPOLLPRI | EPOLLET;
690 epoll_event.data.fd = wait_fd;
691 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, wait_fd, &epoll_event);
692 if (ret < 0) {
d40c2620 693 PERROR("[epoll_pwait] add");
5305e823 694 goto error;
a0b1f42c
JD
695 }
696
28ab034a 697 ret = syscall(SYS_epoll_pwait, epollfd, (struct epoll_event *) invalid, 1, -1, NULL);
a0b1f42c
JD
698
699 if (ret == 1) {
a0b1f42c
JD
700 ret = read(wait_fd, buf, BUF_SIZE);
701 if (ret < 0) {
d40c2620 702 PERROR("[epoll_pwait] read");
a0b1f42c 703 }
d40c2620
JG
704 } else if (ret != 0) {
705 /* Expected error. */
a0b1f42c
JD
706 }
707
5305e823 708error:
6d52f14d
FD
709 ret = close(epollfd);
710 if (ret) {
d40c2620 711 PERROR("close");
6d52f14d 712 }
a0b1f42c
JD
713end:
714 return;
715}
716
717/*
718 * Set maxevents to INT_MAX, should output "Invalid argument"
719 * The event should return an empty array.
720 */
28ab034a 721static void epoll_pwait_int_max(FILE *validation_output_file)
a0b1f42c
JD
722{
723 int ret, epollfd;
724 char buf[BUF_SIZE];
725 struct epoll_event epoll_event;
726
727 epollfd = epoll_create(NB_FD);
728 if (epollfd < 0) {
d40c2620 729 PERROR("[epoll_pwait] create");
a0b1f42c
JD
730 goto end;
731 }
732
2a2ac572 733 ret = fprintf(validation_output_file, "{\"epollfd\": %i, \"pid\": %i }", epollfd, getpid());
d40c2620
JG
734 if (ret < 0) {
735 PERROR("[epoll_pwait] Failed to write test validation output");
736 goto error;
737 }
738
a0b1f42c
JD
739 epoll_event.events = EPOLLIN | EPOLLPRI | EPOLLET;
740 epoll_event.data.fd = wait_fd;
741 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, wait_fd, &epoll_event);
742 if (ret < 0) {
d40c2620 743 PERROR("[epoll_pwait] add");
5305e823 744 goto error;
a0b1f42c
JD
745 }
746
28ab034a 747 ret = syscall(SYS_epoll_pwait, epollfd, &epoll_event, INT_MAX, -1, NULL);
a0b1f42c
JD
748
749 if (ret == 1) {
a0b1f42c
JD
750 ret = read(wait_fd, buf, BUF_SIZE);
751 if (ret < 0) {
d40c2620 752 PERROR("[epoll_pwait] read");
a0b1f42c 753 }
d40c2620
JG
754 } else if (ret != 0) {
755 /* Expected error. */
a0b1f42c
JD
756 }
757
5305e823 758error:
6d52f14d
FD
759 ret = close(epollfd);
760 if (ret) {
d40c2620 761 PERROR("close");
6d52f14d 762 }
a0b1f42c
JD
763end:
764 return;
765}
766
28ab034a 767static void *ppoll_writer(void *arg)
a0b1f42c
JD
768{
769 struct ppoll_thread_data *data = (struct ppoll_thread_data *) arg;
770
771 while (!stop_thread) {
28ab034a 772 memset(data->ufds, data->value, MAX_FDS * sizeof(struct pollfd));
a0b1f42c
JD
773 usleep(100);
774 }
775
2a2ac572 776 return NULL;
a0b1f42c
JD
777}
778
28ab034a 779static void do_ppoll(int *fds, struct pollfd *ufds)
a0b1f42c
JD
780{
781 int i, ret;
782 struct timespec ts;
783 char buf[BUF_SIZE];
784
785 ts.tv_sec = 0;
786 ts.tv_nsec = 1 * MSEC_PER_NSEC;
787
788 for (i = 0; i < MAX_FDS; i++) {
789 ufds[i].fd = fds[i];
28ab034a 790 ufds[i].events = POLLIN | POLLPRI;
a0b1f42c
JD
791 }
792
2a2ac572 793 ret = ppoll(ufds, MAX_FDS, &ts, NULL);
a0b1f42c
JD
794
795 if (ret < 0) {
d40c2620 796 PERROR("ppoll");
a0b1f42c 797 } else if (ret > 0) {
a0b1f42c
JD
798 ret = read(wait_fd, buf, BUF_SIZE);
799 if (ret < 0) {
d40c2620 800 PERROR("[ppoll] read");
a0b1f42c 801 }
a0b1f42c
JD
802 }
803}
804
28ab034a 805static void stress_ppoll(int *fds, int value)
a0b1f42c
JD
806{
807 pthread_t writer;
808 int iter, ret;
809 struct ppoll_thread_data thread_data;
810 struct pollfd ufds[MAX_FDS];
811
812 thread_data.ufds = ufds;
813 thread_data.value = value;
814
815 stop_thread = 0;
2a2ac572 816 ret = pthread_create(&writer, NULL, &ppoll_writer, (void *) &thread_data);
a0b1f42c
JD
817 if (ret != 0) {
818 fprintf(stderr, "[error] pthread_create\n");
819 goto end;
820 }
821 for (iter = 0; iter < NR_ITER; iter++) {
822 do_ppoll(fds, ufds);
823 }
824 stop_thread = 1;
2a2ac572 825 ret = pthread_join(writer, NULL);
9d558571
JG
826 if (ret) {
827 fprintf(stderr, "[error] pthread_join\n");
828 goto end;
829 }
a0b1f42c
JD
830end:
831 return;
832}
833
834/*
835 * 3 rounds of NR_ITER iterations with concurrent updates of the pollfd
836 * structure:
837 * - memset to 0
838 * - memset to 1
839 * - memset to INT_MAX
840 * Waits for input, but also set a timeout in case the input FD is overwritten
841 * before entering in the syscall. We use MAX_FDS FDs (dup of stdin), so the
842 * resulting trace is big (20MB).
843 *
844 * ppoll should work as expected and the trace should be readable at the end.
845 */
28ab034a 846static void ppoll_concurrent_write(FILE *validation_output_file __attribute__((unused)))
a0b1f42c
JD
847{
848 int i, ret, fds[MAX_FDS];
849
850 for (i = 0; i < MAX_FDS; i++) {
851 fds[i] = dup(wait_fd);
852 if (fds[i] < 0) {
d40c2620 853 PERROR("dup");
a0b1f42c
JD
854 }
855 }
856
857 stress_ppoll(fds, 0);
858 stress_ppoll(fds, 1);
859 stress_ppoll(fds, INT_MAX);
860
861 for (i = 0; i < MAX_FDS; i++) {
862 ret = close(fds[i]);
863 if (ret != 0) {
d40c2620 864 PERROR("close");
a0b1f42c
JD
865 }
866 }
867
868 return;
869}
870
28ab034a 871static void *epoll_pwait_writer(void *addr)
a0b1f42c 872{
2a2ac572 873 srand(time(NULL));
a0b1f42c
JD
874
875 while (!stop_thread) {
876 usleep(rand() % 30);
877 munmap(addr, MAX_FDS * sizeof(struct epoll_event));
878 }
879
2a2ac572 880 return NULL;
a0b1f42c
JD
881}
882
883/*
884 * epoll_pwait on MAX_FDS fds while a concurrent thread munmaps the
885 * buffer allocated for the returned data. This should randomly segfault.
886 * The trace should be readable and no kernel OOPS should occur.
887 */
28ab034a 888static void epoll_pwait_concurrent_munmap(FILE *validation_output_file)
a0b1f42c
JD
889{
890 int ret, epollfd, i, fds[MAX_FDS];
891 char buf[BUF_SIZE];
892 struct epoll_event *epoll_event;
a0b1f42c
JD
893 pthread_t writer;
894
7f6288c8
JG
895 for (i = 0; i < MAX_FDS; i++) {
896 fds[i] = -1;
897 }
a0b1f42c
JD
898 epollfd = epoll_create(MAX_FDS);
899 if (epollfd < 0) {
d40c2620 900 PERROR("[epoll_pwait] create");
a0b1f42c
JD
901 goto end;
902 }
903
2a2ac572 904 ret = fprintf(validation_output_file, "{\"epollfd\": %i, \"pid\": %i }", epollfd, getpid());
d40c2620
JG
905 if (ret < 0) {
906 PERROR("[epoll_pwait] Failed to write test validation output");
907 goto error;
908 }
909
2a2ac572 910 epoll_event = (struct epoll_event *) mmap(NULL,
28ab034a
JG
911 MAX_FDS * sizeof(struct epoll_event),
912 PROT_READ | PROT_WRITE,
913 MAP_PRIVATE | MAP_ANONYMOUS,
914 -1,
915 0);
a0b1f42c 916 if (epoll_event == MAP_FAILED) {
d40c2620 917 PERROR("mmap");
5305e823 918 goto error;
a0b1f42c
JD
919 }
920
921 for (i = 0; i < MAX_FDS; i++) {
922 fds[i] = dup(wait_fd);
923 if (fds[i] < 0) {
d40c2620 924 PERROR("dup");
a0b1f42c
JD
925 }
926 epoll_event[i].events = EPOLLIN | EPOLLPRI | EPOLLET;
927 epoll_event[i].data.fd = fds[i];
928 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, fds[i], epoll_event);
929 if (ret < 0) {
d40c2620 930 PERROR("[epoll_pwait] add");
5305e823 931 goto error_unmap;
a0b1f42c
JD
932 }
933 }
934 stop_thread = 0;
2a2ac572 935 ret = pthread_create(&writer, NULL, &epoll_pwait_writer, (void *) epoll_event);
d542c0ae
JG
936 if (ret != 0) {
937 fprintf(stderr, "[error] pthread_create\n");
5305e823 938 goto error_unmap;
d542c0ae 939 }
a0b1f42c 940
2a2ac572 941 ret = epoll_pwait(epollfd, epoll_event, 1, 1, NULL);
a0b1f42c
JD
942
943 if (ret == 1) {
a0b1f42c
JD
944 ret = read(wait_fd, buf, BUF_SIZE);
945 if (ret < 0) {
d40c2620 946 PERROR("[epoll_pwait] read");
a0b1f42c 947 }
d40c2620
JG
948 } else if (ret != 0) {
949 /* Expected error. */
a0b1f42c
JD
950 }
951
952 stop_thread = 1;
2a2ac572 953 ret = pthread_join(writer, NULL);
9d558571
JG
954 if (ret) {
955 fprintf(stderr, "[error] pthread_join\n");
5305e823 956 goto error_unmap;
9d558571 957 }
5305e823 958error_unmap:
a0b1f42c
JD
959 for (i = 0; i < MAX_FDS; i++) {
960 ret = close(fds[i]);
961 if (ret != 0) {
d40c2620 962 PERROR("close");
a0b1f42c
JD
963 }
964 }
965
36bc42d9 966 ret = munmap(epoll_event, MAX_FDS * sizeof(struct epoll_event));
a0b1f42c 967 if (ret != 0) {
d40c2620 968 PERROR("munmap");
a0b1f42c
JD
969 }
970
5305e823 971error:
6d52f14d
FD
972 ret = close(epollfd);
973 if (ret) {
d40c2620 974 PERROR("close");
6d52f14d 975 }
a0b1f42c
JD
976end:
977 return;
978}
979
2a2ac572
JG
980static void print_list(void)
981{
982 printf("Test list (-t X):\n");
983
984 for (size_t test_id = 0; test_id < ARRAY_SIZE(test_cases); test_id++) {
985 printf("\t%zu: %s - %s\n",
986 test_id + 1,
987 test_cases[test_id].name,
988 test_cases[test_id].description);
989 }
990}
991
992static void print_test_syscalls(void)
a0b1f42c 993{
2a2ac572
JG
994 const char *supported_syscalls[] = {
995#ifdef SYS_select
996 "select",
997#endif
998#if defined SYS_pselect6_time64 && defined SYS_pselect6
999 "pselect6",
1000 "pselect6_time32",
1001#elif defined SYS_pselect6_time32 ^ defined SYS_pselect6
1002 "pselect6",
1003#endif /* SYS_pselect6_time64 && defined SYS_pselect6 */
1004#ifdef SYS_poll
1005 "poll",
1006#endif
1007#if defined SYS_ppoll && defined SYS_ppoll_time64
1008 "ppoll",
1009 "ppoll_time32",
1010#elif defined SYS_ppoll ^ defined SYS_ppoll_time64
1011 "ppoll",
1012#endif /* defined SYS_ppoll && defined SYS_ppoll_time64 */
1013#ifdef SYS_epoll_ctl
1014 "epoll_ctl",
1015#endif
1016#ifdef SYS_epoll_wait
1017 "epoll_wait",
1018#endif
1019#ifdef SYS_epoll_pwait
1020 "epoll_pwait",
1021#endif
1022 };
1023
1024 for (size_t i = 0; i < ARRAY_SIZE(supported_syscalls); i++) {
1025 fputs(supported_syscalls[i], stdout);
1026 fputs(i != ARRAY_SIZE(supported_syscalls) - 1 ? "," : "\n", stdout);
1027 }
a0b1f42c
JD
1028}
1029
1030int main(int argc, const char **argv)
1031{
2a2ac572
JG
1032 int c, ret;
1033 const char *test_name;
a0b1f42c
JD
1034 poptContext optCon;
1035 struct rlimit open_lim;
2a2ac572
JG
1036 FILE *test_validation_output_file = NULL;
1037 const char *test_validation_output_file_path = NULL;
a0b1f42c 1038 struct poptOption optionsTable[] = {
2a2ac572
JG
1039 { "test", 't', POPT_ARG_STRING, &test_name, 0, "Name of test to run", NULL },
1040 { "list-tests", 'l', 0, 0, 'l', "List tests (-t X)", NULL },
1041 { "list-supported-test-syscalls",
1042 's',
1043 0,
1044 0,
1045 's',
1046 "List supported test syscalls",
1047 NULL },
28ab034a
JG
1048 { "validation-file",
1049 'o',
1050 POPT_ARG_STRING,
1051 &test_validation_output_file_path,
1052 0,
1053 "Test case output",
2a2ac572
JG
1054 NULL },
1055 POPT_AUTOHELP{ NULL, 0, 0, NULL, 0, NULL, NULL }
a0b1f42c 1056 };
d40c2620 1057 const struct test_case *test_case;
2a2ac572 1058 size_t test_case_id;
a0b1f42c 1059
2a2ac572 1060 optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
a0b1f42c
JD
1061
1062 if (argc < 2) {
1063 poptPrintUsage(optCon, stderr, 0);
1064 ret = -1;
1065 goto end;
1066 }
1067
1068 ret = 0;
1069
1070 while ((c = poptGetNextOpt(optCon)) >= 0) {
d40c2620 1071 switch (c) {
a0b1f42c
JD
1072 case 'l':
1073 print_list();
1074 goto end;
2a2ac572
JG
1075 case 's':
1076 print_test_syscalls();
1077 goto end;
a0b1f42c
JD
1078 }
1079 }
1080
d40c2620
JG
1081 if (!test_validation_output_file_path) {
1082 fprintf(stderr, "A test validation file path is required (--validation-file/-o)\n");
1083 ret = -1;
1084 goto end;
1085 }
1086
1087 test_validation_output_file = fopen(test_validation_output_file_path, "w+");
1088 if (!test_validation_output_file) {
1089 PERROR("Failed to create test validation output file at '%s'",
28ab034a 1090 test_validation_output_file_path);
d40c2620
JG
1091 ret = -1;
1092 goto end;
1093 }
1094
a0b1f42c
JD
1095 open_lim.rlim_cur = MAX_FDS + MIN_NR_FDS;
1096 open_lim.rlim_max = MAX_FDS + MIN_NR_FDS;
1097
1098 ret = setrlimit(RLIMIT_NOFILE, &open_lim);
1099 if (ret < 0) {
d40c2620 1100 PERROR("setrlimit");
a0b1f42c
JD
1101 goto end;
1102 }
1103
1104 /*
1105 * Some tests might segfault, but we need the getpid() to be output
d40c2620
JG
1106 * for the validation, disabling the buffering on the validation file
1107 * works.
a0b1f42c 1108 */
2a2ac572 1109 setbuf(test_validation_output_file, NULL);
a0b1f42c
JD
1110 wait_fd = STDIN_FILENO;
1111
d40c2620 1112 /* Test case id is 1-based. */
2a2ac572
JG
1113 for (test_case_id = 0; test_case_id < ARRAY_SIZE(test_cases); test_case_id++) {
1114 if (!strcmp(test_cases[test_case_id].name, test_name)) {
1115 break;
1116 }
1117 }
1118
1119 if (test_case_id == ARRAY_SIZE(test_cases)) {
a0b1f42c
JD
1120 poptPrintUsage(optCon, stderr, 0);
1121 ret = -1;
2a2ac572 1122 goto end;
a0b1f42c
JD
1123 }
1124
2a2ac572 1125 test_case = &test_cases[test_case_id];
d40c2620
JG
1126
1127 timeout = test_case->timeout;
1128 if (!test_case->produces_validation_info) {
1129 /*
1130 * All test cases need to provide, at minimum, the pid of the
1131 * test application.
1132 */
2a2ac572 1133 ret = fprintf(test_validation_output_file, "{\"pid\": %i }", getpid());
d40c2620
JG
1134 if (ret < 0) {
1135 PERROR("Failed to write application pid to test validation file");
1136 goto end;
1137 }
1138 }
1139
1140 test_case->run(test_validation_output_file);
1141
a0b1f42c 1142end:
d40c2620
JG
1143 if (test_validation_output_file) {
1144 const int close_ret = fclose(test_validation_output_file);
1145
1146 if (close_ret) {
1147 PERROR("Failed to close test output file");
1148 }
1149 }
a0b1f42c
JD
1150 poptFreeContext(optCon);
1151 return ret;
1152}
This page took 0.106395 seconds and 4 git commands to generate.