2 * Copyright (C) 2016 Julien Desfossez <jdesfossez@efficios.com>
4 * SPDX-License-Identifier: GPL-2.0-only
9 * This test voluntarily does buffer overflows and stack overruns, disable
10 * source fortification.
12 #ifdef _FORTIFY_SOURCE
13 #undef _FORTIFY_SOURCE
16 #include <common/compat/time.hpp>
17 #include <common/error.hpp>
29 #include <sys/epoll.h>
31 #include <sys/resource.h>
32 #include <sys/select.h>
34 #include <sys/syscall.h>
36 #include <sys/types.h>
42 #define NR_ITER 1000 /* for stress-tests */
44 #define MIN_NR_FDS 5 /* the minimum number of open FDs required for the test to run */
45 #define BIG_SELECT_FD 1022
47 #define MSEC_PER_USEC 1000
48 #define MSEC_PER_NSEC (MSEC_PER_USEC * 1000)
50 static int timeout
; /* seconds, -1 to disable */
51 static volatile int stop_thread
;
54 /* Used by logging utils. */
55 int lttng_opt_quiet
, lttng_opt_verbose
, lttng_opt_mi
;
57 static void run_working_cases(FILE *validation_output_file
);
58 static void pselect_invalid_fd(FILE *validation_output_file
);
59 static void test_ppoll_big(FILE *validation_output_file
);
60 static void ppoll_fds_buffer_overflow(FILE *validation_output_file
);
61 static void pselect_invalid_pointer(FILE *validation_output_file
);
62 static void ppoll_fds_ulong_max(FILE *validation_output_file
);
63 static void epoll_pwait_invalid_pointer(FILE *validation_output_file
);
64 static void epoll_pwait_int_max(FILE *validation_output_file
);
65 static void ppoll_concurrent_write(FILE *validation_output_file
);
66 static void epoll_pwait_concurrent_munmap(FILE *validation_output_file
);
68 using test_case_cb
= void (*)(FILE *);
71 const struct test_case
{
73 bool produces_validation_info
;
76 { .run
= run_working_cases
, .produces_validation_info
= true, .timeout
= -1 },
77 { .run
= run_working_cases
, .produces_validation_info
= true, .timeout
= 1 },
78 { .run
= pselect_invalid_fd
, .produces_validation_info
= false, .timeout
= 0 },
79 { .run
= test_ppoll_big
, .produces_validation_info
= false, .timeout
= 0 },
80 { .run
= ppoll_fds_buffer_overflow
, .produces_validation_info
= false, .timeout
= 0 },
81 { .run
= pselect_invalid_pointer
, .produces_validation_info
= false, .timeout
= 0 },
82 { .run
= ppoll_fds_ulong_max
, .produces_validation_info
= false, .timeout
= 0 },
83 { .run
= epoll_pwait_invalid_pointer
, .produces_validation_info
= true, .timeout
= 0 },
84 { .run
= epoll_pwait_int_max
, .produces_validation_info
= true, .timeout
= 0 },
85 { .run
= ppoll_concurrent_write
, .produces_validation_info
= false, .timeout
= 0 },
86 { .run
= epoll_pwait_concurrent_munmap
, .produces_validation_info
= true, .timeout
= 0 },
89 struct ppoll_thread_data
{
95 static void test_select_big()
97 fd_set rfds
, wfds
, exfds
;
107 fd2
= dup2(wait_fd
, BIG_SELECT_FD
);
115 tv
.tv_usec
= timeout
* MSEC_PER_USEC
;
118 ret
= select(fd2
+ 1, &rfds
, &wfds
, &exfds
, &tv
);
120 ret
= select(fd2
+ 1, &rfds
, &wfds
, &exfds
, nullptr);
126 ret
= read(wait_fd
, buf
, BUF_SIZE
);
128 PERROR("[select] read");
132 ret
= close(BIG_SELECT_FD
);
141 static void test_pselect()
149 FD_SET(wait_fd
, &rfds
);
152 tv
.tv_nsec
= timeout
* MSEC_PER_NSEC
;
155 ret
= pselect(1, &rfds
, nullptr, nullptr, &tv
, nullptr);
157 ret
= pselect(1, &rfds
, nullptr, nullptr, nullptr, nullptr);
163 ret
= read(wait_fd
, buf
, BUF_SIZE
);
165 PERROR("[pselect] read");
170 static void test_select()
178 FD_SET(wait_fd
, &rfds
);
181 tv
.tv_usec
= timeout
* MSEC_PER_USEC
;
184 ret
= select(1, &rfds
, nullptr, nullptr, &tv
);
186 ret
= select(1, &rfds
, nullptr, nullptr, nullptr);
192 ret
= read(wait_fd
, buf
, BUF_SIZE
);
194 PERROR("[select] read");
199 static void test_poll()
201 struct pollfd ufds
[NB_FD
];
205 ufds
[0].fd
= wait_fd
;
206 ufds
[0].events
= POLLIN
| POLLPRI
;
208 ret
= poll(ufds
, 1, timeout
);
212 } else if (ret
> 0) {
213 ret
= read(wait_fd
, buf
, BUF_SIZE
);
215 PERROR("[poll] read");
220 static void test_ppoll()
222 struct pollfd ufds
[NB_FD
];
227 ufds
[0].fd
= wait_fd
;
228 ufds
[0].events
= POLLIN
| POLLPRI
;
232 ts
.tv_nsec
= timeout
* MSEC_PER_NSEC
;
233 ret
= ppoll(ufds
, 1, &ts
, nullptr);
235 ret
= ppoll(ufds
, 1, nullptr, nullptr);
240 } else if (ret
> 0) {
241 ret
= read(wait_fd
, buf
, BUF_SIZE
);
243 PERROR("[ppoll] read");
248 static void test_ppoll_big(FILE *validation_output_file
__attribute__((unused
)))
250 struct pollfd ufds
[MAX_FDS
];
252 int ret
, i
, fds
[MAX_FDS
];
254 for (i
= 0; i
< MAX_FDS
; i
++) {
255 fds
[i
] = dup(wait_fd
);
260 ufds
[i
].events
= POLLIN
| POLLPRI
;
263 ret
= ppoll(ufds
, MAX_FDS
, nullptr, nullptr);
267 } else if (ret
> 0) {
268 ret
= read(wait_fd
, buf
, BUF_SIZE
);
270 PERROR("[ppoll] read");
274 for (i
= 0; i
< MAX_FDS
; i
++) {
284 static void test_epoll(FILE *validation_output_file
)
288 struct epoll_event epoll_event
;
290 epollfd
= epoll_create(NB_FD
);
292 PERROR("[epoll] create");
296 ret
= fprintf(validation_output_file
, ", \"epoll_wait_fd\": %i", epollfd
);
298 PERROR("[epoll] Failed to write test validation output");
302 epoll_event
.events
= EPOLLIN
| EPOLLPRI
| EPOLLET
;
303 epoll_event
.data
.fd
= wait_fd
;
304 ret
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, wait_fd
, &epoll_event
);
306 PERROR("[epoll] add");
311 ret
= epoll_wait(epollfd
, &epoll_event
, 1, timeout
);
313 ret
= epoll_wait(epollfd
, &epoll_event
, 1, -1);
317 ret
= read(wait_fd
, buf
, BUF_SIZE
);
319 PERROR("[epoll] read");
321 } else if (ret
!= 0) {
322 PERROR("epoll_wait");
326 ret
= close(epollfd
);
334 static void test_epoll_pwait(FILE *validation_output_file
)
338 struct epoll_event epoll_event
;
340 epollfd
= epoll_create(NB_FD
);
342 PERROR("[epoll_pwait] create");
346 ret
= fprintf(validation_output_file
, ", \"epoll_pwait_fd\": %i", epollfd
);
348 PERROR("[epoll_pwait] Failed to write test validation output");
352 epoll_event
.events
= EPOLLIN
| EPOLLPRI
| EPOLLET
;
353 epoll_event
.data
.fd
= wait_fd
;
354 ret
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, wait_fd
, &epoll_event
);
356 PERROR("[epoll_pwait] add");
361 ret
= epoll_pwait(epollfd
, &epoll_event
, 1, timeout
, nullptr);
363 ret
= epoll_pwait(epollfd
, &epoll_event
, 1, -1, nullptr);
367 ret
= read(wait_fd
, buf
, BUF_SIZE
);
369 PERROR("[epoll_pwait] read");
371 } else if (ret
!= 0) {
372 PERROR("epoll_pwait");
376 ret
= close(epollfd
);
384 static void run_working_cases(FILE *validation_output_file
)
391 * We need an input pipe for some cases and stdin might
392 * have random data, so we create a dummy pipe for this
393 * test to make sure we are running under clean conditions.
395 ret
= pipe(pipe_fds
);
400 wait_fd
= pipe_fds
[0];
408 ret
= fprintf(validation_output_file
, "{ \"pid\": %i", getpid());
410 PERROR("Failed to write pid to test validation file");
414 test_epoll(validation_output_file
);
415 test_epoll_pwait(validation_output_file
);
418 ret
= close(pipe_fds
[0]);
422 ret
= close(pipe_fds
[1]);
428 ret
= fputs(" }", validation_output_file
);
430 PERROR("Failed to close JSON dictionary in test validation file");
439 * Ask for 100 FDs in a buffer for allocated for only 1 FD, should
440 * segfault (eventually with a "*** stack smashing detected ***" message).
441 * The event should contain an array of 100 FDs filled with garbage.
443 static void ppoll_fds_buffer_overflow(FILE *validation_output_file
__attribute__((unused
)))
445 struct pollfd ufds
[NB_FD
];
449 ufds
[0].fd
= wait_fd
;
450 ufds
[0].events
= POLLIN
| POLLPRI
;
452 ret
= syscall(SYS_ppoll
, ufds
, 100, NULL
, NULL
);
456 } else if (ret
> 0) {
457 ret
= read(wait_fd
, buf
, BUF_SIZE
);
459 PERROR("[ppoll] read");
465 * Ask for ULONG_MAX FDs in a buffer for allocated for only 1 FD, should
466 * cleanly fail with a "Invalid argument".
467 * The event should contain an empty array of FDs and overflow = 1.
469 static void ppoll_fds_ulong_max(FILE *validation_output_file
__attribute__((unused
)))
471 struct pollfd ufds
[NB_FD
];
475 ufds
[0].fd
= wait_fd
;
476 ufds
[0].events
= POLLIN
| POLLPRI
;
478 ret
= syscall(SYS_ppoll
, ufds
, ULONG_MAX
, NULL
, NULL
);
480 /* Expected error. */
481 } else if (ret
> 0) {
482 ret
= read(wait_fd
, buf
, BUF_SIZE
);
484 PERROR("[ppoll] read");
490 * Pass an invalid file descriptor to pselect6(). The syscall should return
491 * -EBADF. The recorded event should contain a "ret = -EBADF (-9)".
493 static void pselect_invalid_fd(FILE *validation_output_file
__attribute__((unused
)))
501 * Open a file, close it and use the closed FD in the pselect6 call.
503 fd
= open("/dev/null", O_RDONLY
);
518 ret
= syscall(SYS_pselect6
, fd
+ 1, &rfds
, NULL
, NULL
, NULL
, NULL
);
520 /* Expected error. */
522 ret
= read(wait_fd
, buf
, BUF_SIZE
);
524 PERROR("[pselect] read");
532 * Invalid pointer as writefds, should output a ppoll event
535 static void pselect_invalid_pointer(FILE *validation_output_file
__attribute__((unused
)))
540 void *invalid
= (void *) 0x42;
543 FD_SET(wait_fd
, &rfds
);
545 ret
= syscall(SYS_pselect6
, 1, &rfds
, (fd_set
*) invalid
, NULL
, NULL
, NULL
);
547 /* Expected error. */
549 ret
= read(wait_fd
, buf
, BUF_SIZE
);
551 PERROR("[pselect] read");
557 * Pass an invalid pointer to epoll_pwait, should fail with
558 * "Bad address", the event returns 0 FDs.
560 static void epoll_pwait_invalid_pointer(FILE *validation_output_file
)
564 struct epoll_event epoll_event
;
565 void *invalid
= (void *) 0x42;
567 epollfd
= epoll_create(NB_FD
);
569 PERROR("[epoll_pwait] create");
574 validation_output_file
, "{ \"epollfd\": %i, \"pid\": %i }", epollfd
, getpid());
576 PERROR("[epoll_pwait] Failed to write test validation output");
580 epoll_event
.events
= EPOLLIN
| EPOLLPRI
| EPOLLET
;
581 epoll_event
.data
.fd
= wait_fd
;
582 ret
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, wait_fd
, &epoll_event
);
584 PERROR("[epoll_pwait] add");
588 ret
= syscall(SYS_epoll_pwait
, epollfd
, (struct epoll_event
*) invalid
, 1, -1, NULL
);
591 ret
= read(wait_fd
, buf
, BUF_SIZE
);
593 PERROR("[epoll_pwait] read");
595 } else if (ret
!= 0) {
596 /* Expected error. */
600 ret
= close(epollfd
);
609 * Set maxevents to INT_MAX, should output "Invalid argument"
610 * The event should return an empty array.
612 static void epoll_pwait_int_max(FILE *validation_output_file
)
616 struct epoll_event epoll_event
;
618 epollfd
= epoll_create(NB_FD
);
620 PERROR("[epoll_pwait] create");
625 validation_output_file
, "{ \"epollfd\": %i, \"pid\": %i }", epollfd
, getpid());
627 PERROR("[epoll_pwait] Failed to write test validation output");
631 epoll_event
.events
= EPOLLIN
| EPOLLPRI
| EPOLLET
;
632 epoll_event
.data
.fd
= wait_fd
;
633 ret
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, wait_fd
, &epoll_event
);
635 PERROR("[epoll_pwait] add");
639 ret
= syscall(SYS_epoll_pwait
, epollfd
, &epoll_event
, INT_MAX
, -1, NULL
);
642 ret
= read(wait_fd
, buf
, BUF_SIZE
);
644 PERROR("[epoll_pwait] read");
646 } else if (ret
!= 0) {
647 /* Expected error. */
651 ret
= close(epollfd
);
659 static void *ppoll_writer(void *arg
)
661 struct ppoll_thread_data
*data
= (struct ppoll_thread_data
*) arg
;
663 while (!stop_thread
) {
664 memset(data
->ufds
, data
->value
, MAX_FDS
* sizeof(struct pollfd
));
671 static void do_ppoll(int *fds
, struct pollfd
*ufds
)
678 ts
.tv_nsec
= 1 * MSEC_PER_NSEC
;
680 for (i
= 0; i
< MAX_FDS
; i
++) {
682 ufds
[i
].events
= POLLIN
| POLLPRI
;
685 ret
= ppoll(ufds
, MAX_FDS
, &ts
, nullptr);
689 } else if (ret
> 0) {
690 ret
= read(wait_fd
, buf
, BUF_SIZE
);
692 PERROR("[ppoll] read");
697 static void stress_ppoll(int *fds
, int value
)
701 struct ppoll_thread_data thread_data
;
702 struct pollfd ufds
[MAX_FDS
];
704 thread_data
.ufds
= ufds
;
705 thread_data
.value
= value
;
708 ret
= pthread_create(&writer
, nullptr, &ppoll_writer
, (void *) &thread_data
);
710 fprintf(stderr
, "[error] pthread_create\n");
713 for (iter
= 0; iter
< NR_ITER
; iter
++) {
717 ret
= pthread_join(writer
, nullptr);
719 fprintf(stderr
, "[error] pthread_join\n");
727 * 3 rounds of NR_ITER iterations with concurrent updates of the pollfd
731 * - memset to INT_MAX
732 * Waits for input, but also set a timeout in case the input FD is overwritten
733 * before entering in the syscall. We use MAX_FDS FDs (dup of stdin), so the
734 * resulting trace is big (20MB).
736 * ppoll should work as expected and the trace should be readable at the end.
738 static void ppoll_concurrent_write(FILE *validation_output_file
__attribute__((unused
)))
740 int i
, ret
, fds
[MAX_FDS
];
742 for (i
= 0; i
< MAX_FDS
; i
++) {
743 fds
[i
] = dup(wait_fd
);
749 stress_ppoll(fds
, 0);
750 stress_ppoll(fds
, 1);
751 stress_ppoll(fds
, INT_MAX
);
753 for (i
= 0; i
< MAX_FDS
; i
++) {
763 static void *epoll_pwait_writer(void *addr
)
765 srand(time(nullptr));
767 while (!stop_thread
) {
769 munmap(addr
, MAX_FDS
* sizeof(struct epoll_event
));
776 * epoll_pwait on MAX_FDS fds while a concurrent thread munmaps the
777 * buffer allocated for the returned data. This should randomly segfault.
778 * The trace should be readable and no kernel OOPS should occur.
780 static void epoll_pwait_concurrent_munmap(FILE *validation_output_file
)
782 int ret
, epollfd
, i
, fds
[MAX_FDS
];
784 struct epoll_event
*epoll_event
;
787 for (i
= 0; i
< MAX_FDS
; i
++) {
790 epollfd
= epoll_create(MAX_FDS
);
792 PERROR("[epoll_pwait] create");
797 validation_output_file
, "{ \"epollfd\": %i, \"pid\": %i }", epollfd
, getpid());
799 PERROR("[epoll_pwait] Failed to write test validation output");
803 epoll_event
= (struct epoll_event
*) mmap(nullptr,
804 MAX_FDS
* sizeof(struct epoll_event
),
805 PROT_READ
| PROT_WRITE
,
806 MAP_PRIVATE
| MAP_ANONYMOUS
,
809 if (epoll_event
== MAP_FAILED
) {
814 for (i
= 0; i
< MAX_FDS
; i
++) {
815 fds
[i
] = dup(wait_fd
);
819 epoll_event
[i
].events
= EPOLLIN
| EPOLLPRI
| EPOLLET
;
820 epoll_event
[i
].data
.fd
= fds
[i
];
821 ret
= epoll_ctl(epollfd
, EPOLL_CTL_ADD
, fds
[i
], epoll_event
);
823 PERROR("[epoll_pwait] add");
828 ret
= pthread_create(&writer
, nullptr, &epoll_pwait_writer
, (void *) epoll_event
);
830 fprintf(stderr
, "[error] pthread_create\n");
834 ret
= epoll_pwait(epollfd
, epoll_event
, 1, 1, nullptr);
837 ret
= read(wait_fd
, buf
, BUF_SIZE
);
839 PERROR("[epoll_pwait] read");
841 } else if (ret
!= 0) {
842 /* Expected error. */
846 ret
= pthread_join(writer
, nullptr);
848 fprintf(stderr
, "[error] pthread_join\n");
852 for (i
= 0; i
< MAX_FDS
; i
++) {
859 ret
= munmap(epoll_event
, MAX_FDS
* sizeof(struct epoll_event
));
865 ret
= close(epollfd
);
873 static void print_list()
875 fprintf(stderr
, "Test list (-t X):\n");
877 "\t1: Working cases for select, pselect6, poll, ppoll "
878 "and epoll, waiting for input\n");
880 "\t2: Timeout cases (1ms) for select, pselect6, poll, "
881 "ppoll and epoll\n");
882 fprintf(stderr
, "\t3: pselect with an invalid fd\n");
883 fprintf(stderr
, "\t4: ppoll with %d FDs\n", MAX_FDS
);
885 "\t5: ppoll buffer overflow, should segfault, waits "
888 "\t6: pselect with an invalid pointer, waits for "
890 fprintf(stderr
, "\t7: ppoll with ulong_max fds, waits for input\n");
892 "\t8: epoll_pwait with an invalid pointer, waits for "
895 "\t9: epoll_pwait with maxevents set to INT_MAX, "
896 "waits for input\n");
898 "\t10: ppoll with concurrent updates of the structure "
899 "from user-space, stress test (3000 iterations), "
900 "waits for input + timeout 1ms\n");
902 "\t11: epoll_pwait with concurrent munmap of the buffer "
903 "from user-space, should randomly segfault, run "
904 "multiple times, waits for input + timeout 1ms\n");
907 int main(int argc
, const char **argv
)
909 int c
, ret
, test
= -1;
911 struct rlimit open_lim
;
912 FILE *test_validation_output_file
= nullptr;
913 const char *test_validation_output_file_path
= nullptr;
914 struct poptOption optionsTable
[] = {
915 { "test", 't', POPT_ARG_INT
, &test
, 0, "Test to run", nullptr },
916 { "list", 'l', 0, nullptr, 'l', "List of tests (-t X)", nullptr },
920 &test_validation_output_file_path
,
924 POPT_AUTOHELP
{ nullptr, 0, 0, nullptr, 0, nullptr, nullptr }
926 const struct test_case
*test_case
;
928 optCon
= poptGetContext(nullptr, argc
, argv
, optionsTable
, 0);
931 poptPrintUsage(optCon
, stderr
, 0);
938 while ((c
= poptGetNextOpt(optCon
)) >= 0) {
946 if (!test_validation_output_file_path
) {
947 fprintf(stderr
, "A test validation file path is required (--validation-file/-o)\n");
952 test_validation_output_file
= fopen(test_validation_output_file_path
, "w+");
953 if (!test_validation_output_file
) {
954 PERROR("Failed to create test validation output file at '%s'",
955 test_validation_output_file_path
);
960 open_lim
.rlim_cur
= MAX_FDS
+ MIN_NR_FDS
;
961 open_lim
.rlim_max
= MAX_FDS
+ MIN_NR_FDS
;
963 ret
= setrlimit(RLIMIT_NOFILE
, &open_lim
);
970 * Some tests might segfault, but we need the getpid() to be output
971 * for the validation, disabling the buffering on the validation file
974 setbuf(test_validation_output_file
, nullptr);
975 wait_fd
= STDIN_FILENO
;
977 /* Test case id is 1-based. */
978 if (test
< 1 || test
> ARRAY_SIZE(test_cases
)) {
979 poptPrintUsage(optCon
, stderr
, 0);
983 test_case
= &test_cases
[test
- 1];
985 timeout
= test_case
->timeout
;
986 if (!test_case
->produces_validation_info
) {
988 * All test cases need to provide, at minimum, the pid of the
991 ret
= fprintf(test_validation_output_file
, "{ \"pid\": %i }", getpid());
993 PERROR("Failed to write application pid to test validation file");
998 test_case
->run(test_validation_output_file
);
1001 if (test_validation_output_file
) {
1002 const int close_ret
= fclose(test_validation_output_file
);
1005 PERROR("Failed to close test output file");
1008 poptFreeContext(optCon
);