vscode: Add configurations to run the executables under the debugger
[lttng-tools.git] / tests / regression / kernel / select_poll_epoll.cpp
1 /*
2 * Copyright (C) 2016 Julien Desfossez <jdesfossez@efficios.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
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
16 #include <common/compat/time.hpp>
17 #include <common/error.hpp>
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <limits.h>
22 #include <poll.h>
23 #include <popt.h>
24 #include <pthread.h>
25 #include <signal.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/epoll.h>
31 #include <sys/mman.h>
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
40 #define BUF_SIZE 256
41 #define NB_FD 1
42 #define MAX_FDS 2047
43 #define NR_ITER 1000 /* for stress-tests */
44
45 #define MIN_NR_FDS 5 /* the minimum number of open FDs required for the test to run */
46 #define BIG_SELECT_FD 1022
47
48 #define MSEC_PER_USEC 1000
49 #define MSEC_PER_NSEC (MSEC_PER_USEC * 1000)
50
51 static int timeout; /* seconds, -1 to disable */
52 static volatile int stop_thread;
53 static int wait_fd;
54
55 /* Used by logging utils. */
56 int lttng_opt_quiet, lttng_opt_verbose, lttng_opt_mi;
57
58 static void run_working_cases(FILE *validation_output_file);
59 static void test_ppoll_big(FILE *validation_output_file);
60 static void pselect_invalid_pointer(FILE *validation_output_file);
61 static void pselect_invalid_fd(FILE *validation_output_file);
62 static void ppoll_fds_ulong_max(FILE *validation_output_file);
63 static void ppoll_fds_buffer_overflow(FILE *validation_output_file);
64 static void epoll_pwait_invalid_pointer(FILE *validation_output_file);
65 static void epoll_pwait_int_max(FILE *validation_output_file);
66 static void ppoll_concurrent_write(FILE *validation_output_file);
67 static void epoll_pwait_concurrent_munmap(FILE *validation_output_file);
68
69 typedef void (*test_case_cb)(FILE *output_file);
70
71 namespace {
72 const struct test_case {
73 test_case_cb run;
74 bool produces_validation_info;
75 int timeout;
76 const char *name;
77 const char *description;
78 } test_cases[] = {
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" },
137 };
138
139 struct ppoll_thread_data {
140 struct pollfd *ufds;
141 int value;
142 };
143 } /* namespace */
144
145 static void test_select_big(void)
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) {
159 PERROR("dup2");
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 {
170 ret = select(fd2 + 1, &rfds, &wfds, &exfds, NULL);
171 }
172
173 if (ret == -1) {
174 PERROR("select()");
175 } else if (ret) {
176 ret = read(wait_fd, buf, BUF_SIZE);
177 if (ret < 0) {
178 PERROR("[select] read");
179 }
180 }
181
182 ret = close(BIG_SELECT_FD);
183 if (ret) {
184 PERROR("close");
185 }
186
187 end:
188 return;
189 }
190
191 static void test_pselect_generic(long int syscall_id)
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) {
205 ret = syscall(syscall_id, 1, &rfds, NULL, NULL, &tv, NULL);
206 } else {
207 ret = syscall(syscall_id, 1, &rfds, NULL, NULL, NULL, NULL);
208 }
209
210 if (ret == -1) {
211 PERROR("pselect()");
212 } else if (ret) {
213 ret = read(wait_fd, buf, BUF_SIZE);
214 if (ret < 0) {
215 PERROR("[pselect] read");
216 }
217 }
218 }
219
220 static void test_pselect(void)
221 {
222 test_pselect_generic(SYS_pselect6);
223 }
224
225 static void test_select(void)
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) {
239 ret = select(1, &rfds, NULL, NULL, &tv);
240 } else {
241 ret = select(1, &rfds, NULL, NULL, NULL);
242 }
243
244 if (ret == -1) {
245 PERROR("select()");
246 } else if (ret) {
247 ret = read(wait_fd, buf, BUF_SIZE);
248 if (ret < 0) {
249 PERROR("[select] read");
250 }
251 }
252 }
253
254 static void test_poll(void)
255 {
256 struct pollfd ufds[NB_FD];
257 char buf[BUF_SIZE];
258 int ret;
259
260 ufds[0].fd = wait_fd;
261 ufds[0].events = POLLIN | POLLPRI;
262
263 ret = poll(ufds, 1, timeout);
264
265 if (ret < 0) {
266 PERROR("poll");
267 } else if (ret > 0) {
268 ret = read(wait_fd, buf, BUF_SIZE);
269 if (ret < 0) {
270 PERROR("[poll] read");
271 }
272 }
273 }
274
275 static void test_ppoll_generic(long int syscall_id)
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;
283 ufds[0].events = POLLIN | POLLPRI;
284
285 if (timeout > 0) {
286 ts.tv_sec = 0;
287 ts.tv_nsec = timeout * MSEC_PER_NSEC;
288 ret = syscall(syscall_id, ufds, 1, &ts, NULL);
289 } else {
290 ret = syscall(syscall_id, ufds, 1, NULL, NULL);
291 }
292
293 if (ret < 0) {
294 PERROR("ppoll");
295 } else if (ret > 0) {
296 ret = read(wait_fd, buf, BUF_SIZE);
297 if (ret < 0) {
298 PERROR("[ppoll] read");
299 }
300 }
301 }
302
303 static void test_ppoll(void)
304 {
305 test_ppoll_generic(SYS_ppoll);
306 }
307
308 static void test_ppoll_big(FILE *validation_output_file __attribute__((unused)))
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) {
317 PERROR("dup");
318 }
319 ufds[i].fd = fds[i];
320 ufds[i].events = POLLIN | POLLPRI;
321 }
322
323 ret = ppoll(ufds, MAX_FDS, NULL, NULL);
324
325 if (ret < 0) {
326 PERROR("ppoll");
327 } else if (ret > 0) {
328 ret = read(wait_fd, buf, BUF_SIZE);
329 if (ret < 0) {
330 PERROR("[ppoll] read");
331 }
332 }
333
334 for (i = 0; i < MAX_FDS; i++) {
335 ret = close(fds[i]);
336 if (ret != 0) {
337 PERROR("close");
338 }
339 }
340
341 return;
342 }
343
344 static void test_epoll(FILE *validation_output_file)
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) {
352 PERROR("[epoll] create");
353 goto end;
354 }
355
356 ret = fprintf(validation_output_file, ", \"epoll_wait_fd\": %i", epollfd);
357 if (ret < 0) {
358 PERROR("[epoll] Failed to write test validation output");
359 goto error;
360 }
361
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) {
366 PERROR("[epoll] add");
367 goto error;
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) {
377 ret = read(wait_fd, buf, BUF_SIZE);
378 if (ret < 0) {
379 PERROR("[epoll] read");
380 }
381 } else if (ret != 0) {
382 PERROR("epoll_wait");
383 }
384
385 error:
386 ret = close(epollfd);
387 if (ret) {
388 PERROR("close");
389 }
390 end:
391 return;
392 }
393
394 static void test_epoll_pwait(FILE *validation_output_file)
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) {
402 PERROR("[epoll_pwait] create");
403 goto end;
404 }
405
406 ret = fprintf(validation_output_file, ", \"epoll_pwait_fd\": %i", epollfd);
407 if (ret < 0) {
408 PERROR("[epoll_pwait] Failed to write test validation output");
409 goto error;
410 }
411
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) {
416 PERROR("[epoll_pwait] add");
417 goto error;
418 }
419
420 if (timeout > 0) {
421 ret = epoll_pwait(epollfd, &epoll_event, 1, timeout, NULL);
422 } else {
423 ret = epoll_pwait(epollfd, &epoll_event, 1, -1, NULL);
424 }
425
426 if (ret == 1) {
427 ret = read(wait_fd, buf, BUF_SIZE);
428 if (ret < 0) {
429 PERROR("[epoll_pwait] read");
430 }
431 } else if (ret != 0) {
432 PERROR("epoll_pwait");
433 }
434
435 error:
436 ret = close(epollfd);
437 if (ret) {
438 PERROR("close");
439 }
440 end:
441 return;
442 }
443
444 static void run_working_cases(FILE *validation_output_file)
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) {
457 PERROR("pipe");
458 goto end;
459 }
460 wait_fd = pipe_fds[0];
461 }
462 test_select();
463 #ifdef sys_pselect6_time64
464 test_pselect_time64();
465 #else
466 test_pselect();
467 #endif /* sys_pselect6_time64 */
468 test_select_big();
469 test_poll();
470 test_ppoll();
471 #ifdef sys_ppoll_time64
472 test_ppoll_time64();
473 #else
474 test_ppoll();
475 #endif /* sys_ppoll_time64 */
476
477 ret = fprintf(validation_output_file, "{\"pid\": %i", getpid());
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);
485
486 if (timeout > 0) {
487 ret = close(pipe_fds[0]);
488 if (ret) {
489 PERROR("close");
490 }
491 ret = close(pipe_fds[1]);
492 if (ret) {
493 PERROR("close");
494 }
495 }
496
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
503 end:
504 return;
505 }
506
507 /*
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.
511 */
512 static void generic_ppoll_fds_ulong_max(long int syscall_id)
513 {
514 struct pollfd ufds[NB_FD];
515 char buf[BUF_SIZE];
516 int ret;
517
518 ufds[0].fd = wait_fd;
519 ufds[0].events = POLLIN | POLLPRI;
520
521 /* ppoll and/or ppoll_time64 are used, depending on platform support. */
522 ret = syscall(syscall_id, ufds, ULONG_MAX, NULL, NULL);
523 if (ret < 0) {
524 /* Expected error. */
525 } else if (ret > 0) {
526 ret = read(wait_fd, buf, BUF_SIZE);
527 if (ret < 0) {
528 PERROR("Failed to read from wait file descriptor");
529 }
530 }
531 }
532
533 /*
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.
537 */
538 static void generic_ppoll_fds_buffer_overflow(long int syscall_id)
539 {
540 struct pollfd ufds[NB_FD];
541 char buf[BUF_SIZE];
542 int ret;
543
544 ufds[0].fd = wait_fd;
545 ufds[0].events = POLLIN | POLLPRI;
546
547 /* ppoll and/or ppoll_time64 are used, depending on platform support. */
548 ret = syscall(syscall_id, ufds, 100, NULL, NULL);
549 if (ret < 0) {
550 PERROR("Failed to wait using ppoll/ppoll_time64");
551 } else if (ret > 0) {
552 ret = read(wait_fd, buf, BUF_SIZE);
553 if (ret < 0) {
554 PERROR("Failed to read from wait file descriptor");
555 }
556 }
557 }
558
559 static 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
568 static 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
577 /*
578 * Pass an invalid file descriptor to pselect6(). The syscall should return
579 * -EBADF. The recorded event should contain a "ret = -EBADF (-9)".
580 */
581 static void generic_invalid_fd(long int syscall_id)
582 {
583 fd_set rfds;
584 int ret;
585 int fd;
586 char buf[BUF_SIZE];
587
588 /*
589 * Open a file, close it and use the closed FD in the pselect6 call.
590 */
591 fd = open("/dev/null", O_RDONLY);
592 if (fd == -1) {
593 PERROR("Failed to open /dev/null");
594 goto error;
595 }
596
597 ret = close(fd);
598 if (ret == -1) {
599 PERROR("Failed to close /dev/null file descriptor");
600 goto error;
601 }
602
603 FD_ZERO(&rfds);
604 FD_SET(fd, &rfds);
605
606 ret = syscall(syscall_id, fd + 1, &rfds, NULL, NULL, NULL, NULL);
607 if (ret == -1) {
608 /* Expected error. */
609 } else if (ret) {
610 ret = read(wait_fd, buf, BUF_SIZE);
611 if (ret < 0) {
612 PERROR("Failed to read from wait file descriptor");
613 }
614 }
615 error:
616 return;
617 }
618
619 /*
620 * Invalid pointer as writefds, should output a ppoll event
621 * with 0 FDs.
622 */
623 static void generic_invalid_pointer(int syscall_id)
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
633 ret = syscall(syscall_id, 1, &rfds, (fd_set *) invalid, NULL, NULL, NULL);
634 if (ret == -1) {
635 /* Expected error. */
636 } else if (ret) {
637 ret = read(wait_fd, buf, BUF_SIZE);
638 if (ret < 0) {
639 PERROR("Failed to read from wait file descriptor");
640 }
641 }
642 }
643
644 static 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 */
657 static 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
666 /*
667 * Pass an invalid pointer to epoll_pwait, should fail with
668 * "Bad address", the event returns 0 FDs.
669 */
670 static void epoll_pwait_invalid_pointer(FILE *validation_output_file)
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) {
679 PERROR("[epoll_pwait] create");
680 goto end;
681 }
682
683 ret = fprintf(validation_output_file, "{\"epollfd\": %i, \"pid\": %i }", epollfd, getpid());
684 if (ret < 0) {
685 PERROR("[epoll_pwait] Failed to write test validation output");
686 goto error;
687 }
688
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) {
693 PERROR("[epoll_pwait] add");
694 goto error;
695 }
696
697 ret = syscall(SYS_epoll_pwait, epollfd, (struct epoll_event *) invalid, 1, -1, NULL);
698
699 if (ret == 1) {
700 ret = read(wait_fd, buf, BUF_SIZE);
701 if (ret < 0) {
702 PERROR("[epoll_pwait] read");
703 }
704 } else if (ret != 0) {
705 /* Expected error. */
706 }
707
708 error:
709 ret = close(epollfd);
710 if (ret) {
711 PERROR("close");
712 }
713 end:
714 return;
715 }
716
717 /*
718 * Set maxevents to INT_MAX, should output "Invalid argument"
719 * The event should return an empty array.
720 */
721 static void epoll_pwait_int_max(FILE *validation_output_file)
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) {
729 PERROR("[epoll_pwait] create");
730 goto end;
731 }
732
733 ret = fprintf(validation_output_file, "{\"epollfd\": %i, \"pid\": %i }", epollfd, getpid());
734 if (ret < 0) {
735 PERROR("[epoll_pwait] Failed to write test validation output");
736 goto error;
737 }
738
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) {
743 PERROR("[epoll_pwait] add");
744 goto error;
745 }
746
747 ret = syscall(SYS_epoll_pwait, epollfd, &epoll_event, INT_MAX, -1, NULL);
748
749 if (ret == 1) {
750 ret = read(wait_fd, buf, BUF_SIZE);
751 if (ret < 0) {
752 PERROR("[epoll_pwait] read");
753 }
754 } else if (ret != 0) {
755 /* Expected error. */
756 }
757
758 error:
759 ret = close(epollfd);
760 if (ret) {
761 PERROR("close");
762 }
763 end:
764 return;
765 }
766
767 static void *ppoll_writer(void *arg)
768 {
769 struct ppoll_thread_data *data = (struct ppoll_thread_data *) arg;
770
771 while (!stop_thread) {
772 memset(data->ufds, data->value, MAX_FDS * sizeof(struct pollfd));
773 usleep(100);
774 }
775
776 return NULL;
777 }
778
779 static void do_ppoll(int *fds, struct pollfd *ufds)
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];
790 ufds[i].events = POLLIN | POLLPRI;
791 }
792
793 ret = ppoll(ufds, MAX_FDS, &ts, NULL);
794
795 if (ret < 0) {
796 PERROR("ppoll");
797 } else if (ret > 0) {
798 ret = read(wait_fd, buf, BUF_SIZE);
799 if (ret < 0) {
800 PERROR("[ppoll] read");
801 }
802 }
803 }
804
805 static void stress_ppoll(int *fds, int value)
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;
816 ret = pthread_create(&writer, NULL, &ppoll_writer, (void *) &thread_data);
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;
825 ret = pthread_join(writer, NULL);
826 if (ret) {
827 fprintf(stderr, "[error] pthread_join\n");
828 goto end;
829 }
830 end:
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 */
846 static void ppoll_concurrent_write(FILE *validation_output_file __attribute__((unused)))
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) {
853 PERROR("dup");
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) {
864 PERROR("close");
865 }
866 }
867
868 return;
869 }
870
871 static void *epoll_pwait_writer(void *addr)
872 {
873 srand(time(NULL));
874
875 while (!stop_thread) {
876 usleep(rand() % 30);
877 munmap(addr, MAX_FDS * sizeof(struct epoll_event));
878 }
879
880 return NULL;
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 */
888 static void epoll_pwait_concurrent_munmap(FILE *validation_output_file)
889 {
890 int ret, epollfd, i, fds[MAX_FDS];
891 char buf[BUF_SIZE];
892 struct epoll_event *epoll_event;
893 pthread_t writer;
894
895 for (i = 0; i < MAX_FDS; i++) {
896 fds[i] = -1;
897 }
898 epollfd = epoll_create(MAX_FDS);
899 if (epollfd < 0) {
900 PERROR("[epoll_pwait] create");
901 goto end;
902 }
903
904 ret = fprintf(validation_output_file, "{\"epollfd\": %i, \"pid\": %i }", epollfd, getpid());
905 if (ret < 0) {
906 PERROR("[epoll_pwait] Failed to write test validation output");
907 goto error;
908 }
909
910 epoll_event = (struct epoll_event *) mmap(NULL,
911 MAX_FDS * sizeof(struct epoll_event),
912 PROT_READ | PROT_WRITE,
913 MAP_PRIVATE | MAP_ANONYMOUS,
914 -1,
915 0);
916 if (epoll_event == MAP_FAILED) {
917 PERROR("mmap");
918 goto error;
919 }
920
921 for (i = 0; i < MAX_FDS; i++) {
922 fds[i] = dup(wait_fd);
923 if (fds[i] < 0) {
924 PERROR("dup");
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) {
930 PERROR("[epoll_pwait] add");
931 goto error_unmap;
932 }
933 }
934 stop_thread = 0;
935 ret = pthread_create(&writer, NULL, &epoll_pwait_writer, (void *) epoll_event);
936 if (ret != 0) {
937 fprintf(stderr, "[error] pthread_create\n");
938 goto error_unmap;
939 }
940
941 ret = epoll_pwait(epollfd, epoll_event, 1, 1, NULL);
942
943 if (ret == 1) {
944 ret = read(wait_fd, buf, BUF_SIZE);
945 if (ret < 0) {
946 PERROR("[epoll_pwait] read");
947 }
948 } else if (ret != 0) {
949 /* Expected error. */
950 }
951
952 stop_thread = 1;
953 ret = pthread_join(writer, NULL);
954 if (ret) {
955 fprintf(stderr, "[error] pthread_join\n");
956 goto error_unmap;
957 }
958 error_unmap:
959 for (i = 0; i < MAX_FDS; i++) {
960 ret = close(fds[i]);
961 if (ret != 0) {
962 PERROR("close");
963 }
964 }
965
966 ret = munmap(epoll_event, MAX_FDS * sizeof(struct epoll_event));
967 if (ret != 0) {
968 PERROR("munmap");
969 }
970
971 error:
972 ret = close(epollfd);
973 if (ret) {
974 PERROR("close");
975 }
976 end:
977 return;
978 }
979
980 static 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
992 static void print_test_syscalls(void)
993 {
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 }
1028 }
1029
1030 int main(int argc, const char **argv)
1031 {
1032 int c, ret;
1033 const char *test_name;
1034 poptContext optCon;
1035 struct rlimit open_lim;
1036 FILE *test_validation_output_file = NULL;
1037 const char *test_validation_output_file_path = NULL;
1038 struct poptOption optionsTable[] = {
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 },
1048 { "validation-file",
1049 'o',
1050 POPT_ARG_STRING,
1051 &test_validation_output_file_path,
1052 0,
1053 "Test case output",
1054 NULL },
1055 POPT_AUTOHELP{ NULL, 0, 0, NULL, 0, NULL, NULL }
1056 };
1057 const struct test_case *test_case;
1058 size_t test_case_id;
1059
1060 optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
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) {
1071 switch (c) {
1072 case 'l':
1073 print_list();
1074 goto end;
1075 case 's':
1076 print_test_syscalls();
1077 goto end;
1078 }
1079 }
1080
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'",
1090 test_validation_output_file_path);
1091 ret = -1;
1092 goto end;
1093 }
1094
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) {
1100 PERROR("setrlimit");
1101 goto end;
1102 }
1103
1104 /*
1105 * Some tests might segfault, but we need the getpid() to be output
1106 * for the validation, disabling the buffering on the validation file
1107 * works.
1108 */
1109 setbuf(test_validation_output_file, NULL);
1110 wait_fd = STDIN_FILENO;
1111
1112 /* Test case id is 1-based. */
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)) {
1120 poptPrintUsage(optCon, stderr, 0);
1121 ret = -1;
1122 goto end;
1123 }
1124
1125 test_case = &test_cases[test_case_id];
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 */
1133 ret = fprintf(test_validation_output_file, "{\"pid\": %i }", getpid());
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
1142 end:
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 }
1150 poptFreeContext(optCon);
1151 return ret;
1152 }
This page took 0.086709 seconds and 4 git commands to generate.