Run clang-format on the whole tree
[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
c9e313bc
SM
19#include <fcntl.h>
20#include <limits.h>
a0b1f42c 21#include <poll.h>
c9e313bc
SM
22#include <popt.h>
23#include <pthread.h>
a0b1f42c 24#include <signal.h>
c9e313bc
SM
25#include <stddef.h>
26#include <stdio.h>
a0b1f42c
JD
27#include <stdlib.h>
28#include <string.h>
a0b1f42c 29#include <sys/epoll.h>
a0b1f42c 30#include <sys/mman.h>
c9e313bc
SM
31#include <sys/resource.h>
32#include <sys/select.h>
33#include <sys/stat.h>
34#include <sys/syscall.h>
35#include <sys/time.h>
36#include <sys/types.h>
37#include <unistd.h>
38
a0b1f42c 39#define BUF_SIZE 256
28ab034a
JG
40#define NB_FD 1
41#define MAX_FDS 2047
42#define NR_ITER 1000 /* for stress-tests */
a0b1f42c 43
28ab034a 44#define MIN_NR_FDS 5 /* the minimum number of open FDs required for the test to run */
a0b1f42c
JD
45#define BIG_SELECT_FD 1022
46
47#define MSEC_PER_USEC 1000
48#define MSEC_PER_NSEC (MSEC_PER_USEC * 1000)
49
50static int timeout; /* seconds, -1 to disable */
44a411a6 51static volatile int stop_thread;
a0b1f42c
JD
52static int wait_fd;
53
d40c2620
JG
54/* Used by logging utils. */
55int lttng_opt_quiet, lttng_opt_verbose, lttng_opt_mi;
56
57static void run_working_cases(FILE *validation_output_file);
58static void pselect_invalid_fd(FILE *validation_output_file);
59static void test_ppoll_big(FILE *validation_output_file);
60static void ppoll_fds_buffer_overflow(FILE *validation_output_file);
61static void pselect_invalid_pointer(FILE *validation_output_file);
62static void ppoll_fds_ulong_max(FILE *validation_output_file);
63static void epoll_pwait_invalid_pointer(FILE *validation_output_file);
64static void epoll_pwait_int_max(FILE *validation_output_file);
65static void ppoll_concurrent_write(FILE *validation_output_file);
66static void epoll_pwait_concurrent_munmap(FILE *validation_output_file);
67
68typedef void (*test_case_cb)(FILE *output_file);
69
f1494934
JG
70namespace {
71const struct test_case {
d40c2620
JG
72 test_case_cb run;
73 bool produces_validation_info;
74 int timeout;
28ab034a 75} test_cases[] = {
d40c2620
JG
76 { .run = run_working_cases, .produces_validation_info = true, .timeout = -1 },
77 { .run = run_working_cases, .produces_validation_info = true, .timeout = 1 },
1c9a0b0e
MJ
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 },
d40c2620
JG
87};
88
a0b1f42c
JD
89struct ppoll_thread_data {
90 struct pollfd *ufds;
91 int value;
92};
f1494934 93} /* namespace */
a0b1f42c 94
28ab034a 95static void test_select_big(void)
a0b1f42c
JD
96{
97 fd_set rfds, wfds, exfds;
98 struct timeval tv;
99 int ret;
100 int fd2;
101 char buf[BUF_SIZE];
102
103 FD_ZERO(&rfds);
104 FD_ZERO(&wfds);
105 FD_ZERO(&exfds);
106
107 fd2 = dup2(wait_fd, BIG_SELECT_FD);
108 if (fd2 < 0) {
d40c2620 109 PERROR("dup2");
a0b1f42c
JD
110 goto end;
111 }
112 FD_SET(fd2, &rfds);
113
114 tv.tv_sec = 0;
115 tv.tv_usec = timeout * MSEC_PER_USEC;
116
117 if (timeout > 0) {
118 ret = select(fd2 + 1, &rfds, &wfds, &exfds, &tv);
119 } else {
120 ret = select(fd2 + 1, &rfds, &wfds, &exfds, NULL);
121 }
122
123 if (ret == -1) {
d40c2620 124 PERROR("select()");
a0b1f42c 125 } else if (ret) {
a0b1f42c
JD
126 ret = read(wait_fd, buf, BUF_SIZE);
127 if (ret < 0) {
d40c2620 128 PERROR("[select] read");
a0b1f42c 129 }
a0b1f42c
JD
130 }
131
132 ret = close(BIG_SELECT_FD);
133 if (ret) {
d40c2620 134 PERROR("close");
a0b1f42c
JD
135 }
136
137end:
138 return;
139}
140
28ab034a 141static void test_pselect(void)
a0b1f42c
JD
142{
143 fd_set rfds;
144 struct timespec tv;
145 int ret;
146 char buf[BUF_SIZE];
147
148 FD_ZERO(&rfds);
149 FD_SET(wait_fd, &rfds);
150
151 tv.tv_sec = 0;
152 tv.tv_nsec = timeout * MSEC_PER_NSEC;
153
154 if (timeout > 0) {
155 ret = pselect(1, &rfds, NULL, NULL, &tv, NULL);
156 } else {
157 ret = pselect(1, &rfds, NULL, NULL, NULL, NULL);
158 }
159
160 if (ret == -1) {
d40c2620 161 PERROR("pselect()");
a0b1f42c 162 } else if (ret) {
a0b1f42c
JD
163 ret = read(wait_fd, buf, BUF_SIZE);
164 if (ret < 0) {
d40c2620 165 PERROR("[pselect] read");
a0b1f42c 166 }
a0b1f42c 167 }
a0b1f42c
JD
168}
169
28ab034a 170static void test_select(void)
a0b1f42c
JD
171{
172 fd_set rfds;
173 struct timeval tv;
174 int ret;
175 char buf[BUF_SIZE];
176
177 FD_ZERO(&rfds);
178 FD_SET(wait_fd, &rfds);
179
180 tv.tv_sec = 0;
181 tv.tv_usec = timeout * MSEC_PER_USEC;
182
183 if (timeout > 0) {
184 ret = select(1, &rfds, NULL, NULL, &tv);
185 } else {
186 ret = select(1, &rfds, NULL, NULL, NULL);
187 }
188
189 if (ret == -1) {
d40c2620 190 PERROR("select()");
a0b1f42c 191 } else if (ret) {
a0b1f42c
JD
192 ret = read(wait_fd, buf, BUF_SIZE);
193 if (ret < 0) {
d40c2620 194 PERROR("[select] read");
a0b1f42c 195 }
a0b1f42c 196 }
a0b1f42c
JD
197}
198
28ab034a 199static void test_poll(void)
a0b1f42c
JD
200{
201 struct pollfd ufds[NB_FD];
202 char buf[BUF_SIZE];
203 int ret;
204
205 ufds[0].fd = wait_fd;
28ab034a 206 ufds[0].events = POLLIN | POLLPRI;
a0b1f42c
JD
207
208 ret = poll(ufds, 1, timeout);
209
210 if (ret < 0) {
d40c2620 211 PERROR("poll");
a0b1f42c 212 } else if (ret > 0) {
a0b1f42c
JD
213 ret = read(wait_fd, buf, BUF_SIZE);
214 if (ret < 0) {
d40c2620 215 PERROR("[poll] read");
a0b1f42c 216 }
a0b1f42c
JD
217 }
218}
219
28ab034a 220static void test_ppoll(void)
a0b1f42c
JD
221{
222 struct pollfd ufds[NB_FD];
223 char buf[BUF_SIZE];
224 int ret;
225 struct timespec ts;
226
227 ufds[0].fd = wait_fd;
28ab034a 228 ufds[0].events = POLLIN | POLLPRI;
a0b1f42c
JD
229
230 if (timeout > 0) {
231 ts.tv_sec = 0;
232 ts.tv_nsec = timeout * MSEC_PER_NSEC;
233 ret = ppoll(ufds, 1, &ts, NULL);
234 } else {
235 ret = ppoll(ufds, 1, NULL, NULL);
236 }
237
a0b1f42c 238 if (ret < 0) {
d40c2620 239 PERROR("ppoll");
a0b1f42c 240 } else if (ret > 0) {
a0b1f42c
JD
241 ret = read(wait_fd, buf, BUF_SIZE);
242 if (ret < 0) {
d40c2620 243 PERROR("[ppoll] read");
a0b1f42c 244 }
a0b1f42c
JD
245 }
246}
247
28ab034a 248static void test_ppoll_big(FILE *validation_output_file __attribute__((unused)))
a0b1f42c
JD
249{
250 struct pollfd ufds[MAX_FDS];
251 char buf[BUF_SIZE];
252 int ret, i, fds[MAX_FDS];
253
254 for (i = 0; i < MAX_FDS; i++) {
255 fds[i] = dup(wait_fd);
256 if (fds[i] < 0) {
d40c2620 257 PERROR("dup");
a0b1f42c
JD
258 }
259 ufds[i].fd = fds[i];
28ab034a 260 ufds[i].events = POLLIN | POLLPRI;
a0b1f42c
JD
261 }
262
263 ret = ppoll(ufds, MAX_FDS, NULL, NULL);
264
265 if (ret < 0) {
d40c2620 266 PERROR("ppoll");
a0b1f42c 267 } else if (ret > 0) {
a0b1f42c
JD
268 ret = read(wait_fd, buf, BUF_SIZE);
269 if (ret < 0) {
d40c2620 270 PERROR("[ppoll] read");
a0b1f42c 271 }
a0b1f42c
JD
272 }
273
274 for (i = 0; i < MAX_FDS; i++) {
275 ret = close(fds[i]);
276 if (ret != 0) {
d40c2620 277 PERROR("close");
a0b1f42c
JD
278 }
279 }
280
281 return;
282}
283
28ab034a 284static void test_epoll(FILE *validation_output_file)
a0b1f42c
JD
285{
286 int ret, epollfd;
287 char buf[BUF_SIZE];
288 struct epoll_event epoll_event;
289
290 epollfd = epoll_create(NB_FD);
291 if (epollfd < 0) {
d40c2620 292 PERROR("[epoll] create");
a0b1f42c
JD
293 goto end;
294 }
295
28ab034a 296 ret = fprintf(validation_output_file, ", \"epoll_wait_fd\": %i", epollfd);
d40c2620
JG
297 if (ret < 0) {
298 PERROR("[epoll] Failed to write test validation output");
299 goto error;
300 }
301
a0b1f42c
JD
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);
305 if (ret < 0) {
d40c2620 306 PERROR("[epoll] add");
5305e823 307 goto error;
a0b1f42c
JD
308 }
309
310 if (timeout > 0) {
311 ret = epoll_wait(epollfd, &epoll_event, 1, timeout);
312 } else {
313 ret = epoll_wait(epollfd, &epoll_event, 1, -1);
314 }
315
316 if (ret == 1) {
a0b1f42c
JD
317 ret = read(wait_fd, buf, BUF_SIZE);
318 if (ret < 0) {
d40c2620 319 PERROR("[epoll] read");
a0b1f42c 320 }
d40c2620
JG
321 } else if (ret != 0) {
322 PERROR("epoll_wait");
a0b1f42c
JD
323 }
324
5305e823 325error:
6d52f14d
FD
326 ret = close(epollfd);
327 if (ret) {
d40c2620 328 PERROR("close");
6d52f14d 329 }
a0b1f42c
JD
330end:
331 return;
332}
333
28ab034a 334static void test_epoll_pwait(FILE *validation_output_file)
a0b1f42c
JD
335{
336 int ret, epollfd;
337 char buf[BUF_SIZE];
338 struct epoll_event epoll_event;
339
340 epollfd = epoll_create(NB_FD);
341 if (epollfd < 0) {
d40c2620 342 PERROR("[epoll_pwait] create");
a0b1f42c
JD
343 goto end;
344 }
345
28ab034a 346 ret = fprintf(validation_output_file, ", \"epoll_pwait_fd\": %i", epollfd);
d40c2620
JG
347 if (ret < 0) {
348 PERROR("[epoll_pwait] Failed to write test validation output");
349 goto error;
350 }
351
a0b1f42c
JD
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);
355 if (ret < 0) {
d40c2620 356 PERROR("[epoll_pwait] add");
5305e823 357 goto error;
a0b1f42c
JD
358 }
359
360 if (timeout > 0) {
361 ret = epoll_pwait(epollfd, &epoll_event, 1, timeout, NULL);
362 } else {
363 ret = epoll_pwait(epollfd, &epoll_event, 1, -1, NULL);
364 }
365
366 if (ret == 1) {
a0b1f42c
JD
367 ret = read(wait_fd, buf, BUF_SIZE);
368 if (ret < 0) {
d40c2620 369 PERROR("[epoll_pwait] read");
a0b1f42c 370 }
d40c2620
JG
371 } else if (ret != 0) {
372 PERROR("epoll_pwait");
a0b1f42c
JD
373 }
374
5305e823 375error:
6d52f14d
FD
376 ret = close(epollfd);
377 if (ret) {
d40c2620 378 PERROR("close");
6d52f14d 379 }
a0b1f42c
JD
380end:
381 return;
382}
383
28ab034a 384static void run_working_cases(FILE *validation_output_file)
a0b1f42c
JD
385{
386 int ret;
387 int pipe_fds[2];
388
389 if (timeout > 0) {
390 /*
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.
394 */
395 ret = pipe(pipe_fds);
396 if (ret != 0) {
d40c2620 397 PERROR("pipe");
a0b1f42c
JD
398 goto end;
399 }
400 wait_fd = pipe_fds[0];
401 }
402 test_select();
403 test_pselect();
404 test_select_big();
405 test_poll();
406 test_ppoll();
d40c2620
JG
407
408 ret = fprintf(validation_output_file, "{ \"pid\": %i", getpid());
409 if (ret < 0) {
410 PERROR("Failed to write pid to test validation file");
411 goto end;
412 }
413
414 test_epoll(validation_output_file);
415 test_epoll_pwait(validation_output_file);
a0b1f42c
JD
416
417 if (timeout > 0) {
418 ret = close(pipe_fds[0]);
419 if (ret) {
d40c2620 420 PERROR("close");
a0b1f42c
JD
421 }
422 ret = close(pipe_fds[1]);
423 if (ret) {
d40c2620 424 PERROR("close");
a0b1f42c
JD
425 }
426 }
427
d40c2620
JG
428 ret = fputs(" }", validation_output_file);
429 if (ret < 0) {
430 PERROR("Failed to close JSON dictionary in test validation file");
431 goto end;
432 }
433
a0b1f42c
JD
434end:
435 return;
436}
437
438/*
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.
442 */
28ab034a 443static void ppoll_fds_buffer_overflow(FILE *validation_output_file __attribute__((unused)))
a0b1f42c
JD
444{
445 struct pollfd ufds[NB_FD];
446 char buf[BUF_SIZE];
447 int ret;
448
449 ufds[0].fd = wait_fd;
28ab034a 450 ufds[0].events = POLLIN | POLLPRI;
a0b1f42c
JD
451
452 ret = syscall(SYS_ppoll, ufds, 100, NULL, NULL);
453
454 if (ret < 0) {
d40c2620 455 PERROR("ppoll");
a0b1f42c 456 } else if (ret > 0) {
a0b1f42c
JD
457 ret = read(wait_fd, buf, BUF_SIZE);
458 if (ret < 0) {
d40c2620 459 PERROR("[ppoll] read");
a0b1f42c 460 }
a0b1f42c 461 }
a0b1f42c
JD
462}
463
464/*
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.
468 */
28ab034a 469static void ppoll_fds_ulong_max(FILE *validation_output_file __attribute__((unused)))
a0b1f42c
JD
470{
471 struct pollfd ufds[NB_FD];
472 char buf[BUF_SIZE];
473 int ret;
474
475 ufds[0].fd = wait_fd;
28ab034a 476 ufds[0].events = POLLIN | POLLPRI;
a0b1f42c
JD
477
478 ret = syscall(SYS_ppoll, ufds, ULONG_MAX, NULL, NULL);
a0b1f42c 479 if (ret < 0) {
d40c2620 480 /* Expected error. */
a0b1f42c 481 } else if (ret > 0) {
a0b1f42c
JD
482 ret = read(wait_fd, buf, BUF_SIZE);
483 if (ret < 0) {
d40c2620 484 PERROR("[ppoll] read");
a0b1f42c 485 }
a0b1f42c 486 }
a0b1f42c
JD
487}
488
489/*
8b3b99e2
FD
490 * Pass an invalid file descriptor to pselect6(). The syscall should return
491 * -EBADF. The recorded event should contain a "ret = -EBADF (-9)".
a0b1f42c 492 */
28ab034a 493static void pselect_invalid_fd(FILE *validation_output_file __attribute__((unused)))
a0b1f42c 494{
8b3b99e2 495 fd_set rfds;
a0b1f42c 496 int ret;
8b3b99e2 497 int fd;
a0b1f42c
JD
498 char buf[BUF_SIZE];
499
500 /*
8b3b99e2 501 * Open a file, close it and use the closed FD in the pselect6 call.
a0b1f42c 502 */
8b3b99e2
FD
503 fd = open("/dev/null", O_RDONLY);
504 if (fd == -1) {
d40c2620 505 PERROR("open");
8b3b99e2
FD
506 goto error;
507 }
508
509 ret = close(fd);
510 if (ret == -1) {
d40c2620 511 PERROR("close");
8b3b99e2 512 goto error;
a0b1f42c 513 }
e593ee02 514
8b3b99e2
FD
515 FD_ZERO(&rfds);
516 FD_SET(fd, &rfds);
a0b1f42c 517
8b3b99e2 518 ret = syscall(SYS_pselect6, fd + 1, &rfds, NULL, NULL, NULL, NULL);
a0b1f42c 519 if (ret == -1) {
d40c2620 520 /* Expected error. */
a0b1f42c 521 } else if (ret) {
a0b1f42c
JD
522 ret = read(wait_fd, buf, BUF_SIZE);
523 if (ret < 0) {
d40c2620 524 PERROR("[pselect] read");
a0b1f42c 525 }
a0b1f42c 526 }
8b3b99e2
FD
527error:
528 return;
a0b1f42c
JD
529}
530
531/*
532 * Invalid pointer as writefds, should output a ppoll event
533 * with 0 FDs.
534 */
28ab034a 535static void pselect_invalid_pointer(FILE *validation_output_file __attribute__((unused)))
a0b1f42c
JD
536{
537 fd_set rfds;
538 int ret;
539 char buf[BUF_SIZE];
540 void *invalid = (void *) 0x42;
541
542 FD_ZERO(&rfds);
543 FD_SET(wait_fd, &rfds);
544
28ab034a 545 ret = syscall(SYS_pselect6, 1, &rfds, (fd_set *) invalid, NULL, NULL, NULL);
a0b1f42c 546 if (ret == -1) {
d40c2620 547 /* Expected error. */
a0b1f42c 548 } else if (ret) {
a0b1f42c
JD
549 ret = read(wait_fd, buf, BUF_SIZE);
550 if (ret < 0) {
d40c2620 551 PERROR("[pselect] read");
a0b1f42c 552 }
a0b1f42c 553 }
a0b1f42c
JD
554}
555
556/*
557 * Pass an invalid pointer to epoll_pwait, should fail with
558 * "Bad address", the event returns 0 FDs.
559 */
28ab034a 560static void epoll_pwait_invalid_pointer(FILE *validation_output_file)
a0b1f42c
JD
561{
562 int ret, epollfd;
563 char buf[BUF_SIZE];
564 struct epoll_event epoll_event;
565 void *invalid = (void *) 0x42;
566
567 epollfd = epoll_create(NB_FD);
568 if (epollfd < 0) {
d40c2620 569 PERROR("[epoll_pwait] create");
a0b1f42c
JD
570 goto end;
571 }
572
28ab034a
JG
573 ret = fprintf(
574 validation_output_file, "{ \"epollfd\": %i, \"pid\": %i }", epollfd, getpid());
d40c2620
JG
575 if (ret < 0) {
576 PERROR("[epoll_pwait] Failed to write test validation output");
577 goto error;
578 }
579
a0b1f42c
JD
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);
583 if (ret < 0) {
d40c2620 584 PERROR("[epoll_pwait] add");
5305e823 585 goto error;
a0b1f42c
JD
586 }
587
28ab034a 588 ret = syscall(SYS_epoll_pwait, epollfd, (struct epoll_event *) invalid, 1, -1, NULL);
a0b1f42c
JD
589
590 if (ret == 1) {
a0b1f42c
JD
591 ret = read(wait_fd, buf, BUF_SIZE);
592 if (ret < 0) {
d40c2620 593 PERROR("[epoll_pwait] read");
a0b1f42c 594 }
d40c2620
JG
595 } else if (ret != 0) {
596 /* Expected error. */
a0b1f42c
JD
597 }
598
5305e823 599error:
6d52f14d
FD
600 ret = close(epollfd);
601 if (ret) {
d40c2620 602 PERROR("close");
6d52f14d 603 }
a0b1f42c
JD
604end:
605 return;
606}
607
608/*
609 * Set maxevents to INT_MAX, should output "Invalid argument"
610 * The event should return an empty array.
611 */
28ab034a 612static void epoll_pwait_int_max(FILE *validation_output_file)
a0b1f42c
JD
613{
614 int ret, epollfd;
615 char buf[BUF_SIZE];
616 struct epoll_event epoll_event;
617
618 epollfd = epoll_create(NB_FD);
619 if (epollfd < 0) {
d40c2620 620 PERROR("[epoll_pwait] create");
a0b1f42c
JD
621 goto end;
622 }
623
28ab034a
JG
624 ret = fprintf(
625 validation_output_file, "{ \"epollfd\": %i, \"pid\": %i }", epollfd, getpid());
d40c2620
JG
626 if (ret < 0) {
627 PERROR("[epoll_pwait] Failed to write test validation output");
628 goto error;
629 }
630
a0b1f42c
JD
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);
634 if (ret < 0) {
d40c2620 635 PERROR("[epoll_pwait] add");
5305e823 636 goto error;
a0b1f42c
JD
637 }
638
28ab034a 639 ret = syscall(SYS_epoll_pwait, epollfd, &epoll_event, INT_MAX, -1, NULL);
a0b1f42c
JD
640
641 if (ret == 1) {
a0b1f42c
JD
642 ret = read(wait_fd, buf, BUF_SIZE);
643 if (ret < 0) {
d40c2620 644 PERROR("[epoll_pwait] read");
a0b1f42c 645 }
d40c2620
JG
646 } else if (ret != 0) {
647 /* Expected error. */
a0b1f42c
JD
648 }
649
5305e823 650error:
6d52f14d
FD
651 ret = close(epollfd);
652 if (ret) {
d40c2620 653 PERROR("close");
6d52f14d 654 }
a0b1f42c
JD
655end:
656 return;
657}
658
28ab034a 659static void *ppoll_writer(void *arg)
a0b1f42c
JD
660{
661 struct ppoll_thread_data *data = (struct ppoll_thread_data *) arg;
662
663 while (!stop_thread) {
28ab034a 664 memset(data->ufds, data->value, MAX_FDS * sizeof(struct pollfd));
a0b1f42c
JD
665 usleep(100);
666 }
667
668 return NULL;
669}
670
28ab034a 671static void do_ppoll(int *fds, struct pollfd *ufds)
a0b1f42c
JD
672{
673 int i, ret;
674 struct timespec ts;
675 char buf[BUF_SIZE];
676
677 ts.tv_sec = 0;
678 ts.tv_nsec = 1 * MSEC_PER_NSEC;
679
680 for (i = 0; i < MAX_FDS; i++) {
681 ufds[i].fd = fds[i];
28ab034a 682 ufds[i].events = POLLIN | POLLPRI;
a0b1f42c
JD
683 }
684
685 ret = ppoll(ufds, MAX_FDS, &ts, NULL);
686
687 if (ret < 0) {
d40c2620 688 PERROR("ppoll");
a0b1f42c 689 } else if (ret > 0) {
a0b1f42c
JD
690 ret = read(wait_fd, buf, BUF_SIZE);
691 if (ret < 0) {
d40c2620 692 PERROR("[ppoll] read");
a0b1f42c 693 }
a0b1f42c
JD
694 }
695}
696
28ab034a 697static void stress_ppoll(int *fds, int value)
a0b1f42c
JD
698{
699 pthread_t writer;
700 int iter, ret;
701 struct ppoll_thread_data thread_data;
702 struct pollfd ufds[MAX_FDS];
703
704 thread_data.ufds = ufds;
705 thread_data.value = value;
706
707 stop_thread = 0;
708 ret = pthread_create(&writer, NULL, &ppoll_writer, (void *) &thread_data);
709 if (ret != 0) {
710 fprintf(stderr, "[error] pthread_create\n");
711 goto end;
712 }
713 for (iter = 0; iter < NR_ITER; iter++) {
714 do_ppoll(fds, ufds);
715 }
716 stop_thread = 1;
9d558571
JG
717 ret = pthread_join(writer, NULL);
718 if (ret) {
719 fprintf(stderr, "[error] pthread_join\n");
720 goto end;
721 }
a0b1f42c
JD
722end:
723 return;
724}
725
726/*
727 * 3 rounds of NR_ITER iterations with concurrent updates of the pollfd
728 * structure:
729 * - memset to 0
730 * - memset to 1
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).
735 *
736 * ppoll should work as expected and the trace should be readable at the end.
737 */
28ab034a 738static void ppoll_concurrent_write(FILE *validation_output_file __attribute__((unused)))
a0b1f42c
JD
739{
740 int i, ret, fds[MAX_FDS];
741
742 for (i = 0; i < MAX_FDS; i++) {
743 fds[i] = dup(wait_fd);
744 if (fds[i] < 0) {
d40c2620 745 PERROR("dup");
a0b1f42c
JD
746 }
747 }
748
749 stress_ppoll(fds, 0);
750 stress_ppoll(fds, 1);
751 stress_ppoll(fds, INT_MAX);
752
753 for (i = 0; i < MAX_FDS; i++) {
754 ret = close(fds[i]);
755 if (ret != 0) {
d40c2620 756 PERROR("close");
a0b1f42c
JD
757 }
758 }
759
760 return;
761}
762
28ab034a 763static void *epoll_pwait_writer(void *addr)
a0b1f42c
JD
764{
765 srand(time(NULL));
766
767 while (!stop_thread) {
768 usleep(rand() % 30);
769 munmap(addr, MAX_FDS * sizeof(struct epoll_event));
770 }
771
772 return NULL;
773}
774
775/*
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.
779 */
28ab034a 780static void epoll_pwait_concurrent_munmap(FILE *validation_output_file)
a0b1f42c
JD
781{
782 int ret, epollfd, i, fds[MAX_FDS];
783 char buf[BUF_SIZE];
784 struct epoll_event *epoll_event;
a0b1f42c
JD
785 pthread_t writer;
786
7f6288c8
JG
787 for (i = 0; i < MAX_FDS; i++) {
788 fds[i] = -1;
789 }
a0b1f42c
JD
790 epollfd = epoll_create(MAX_FDS);
791 if (epollfd < 0) {
d40c2620 792 PERROR("[epoll_pwait] create");
a0b1f42c
JD
793 goto end;
794 }
795
28ab034a
JG
796 ret = fprintf(
797 validation_output_file, "{ \"epollfd\": %i, \"pid\": %i }", epollfd, getpid());
d40c2620
JG
798 if (ret < 0) {
799 PERROR("[epoll_pwait] Failed to write test validation output");
800 goto error;
801 }
802
803 epoll_event = (struct epoll_event *) mmap(NULL,
28ab034a
JG
804 MAX_FDS * sizeof(struct epoll_event),
805 PROT_READ | PROT_WRITE,
806 MAP_PRIVATE | MAP_ANONYMOUS,
807 -1,
808 0);
a0b1f42c 809 if (epoll_event == MAP_FAILED) {
d40c2620 810 PERROR("mmap");
5305e823 811 goto error;
a0b1f42c
JD
812 }
813
814 for (i = 0; i < MAX_FDS; i++) {
815 fds[i] = dup(wait_fd);
816 if (fds[i] < 0) {
d40c2620 817 PERROR("dup");
a0b1f42c
JD
818 }
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);
822 if (ret < 0) {
d40c2620 823 PERROR("[epoll_pwait] add");
5305e823 824 goto error_unmap;
a0b1f42c
JD
825 }
826 }
827 stop_thread = 0;
28ab034a 828 ret = pthread_create(&writer, NULL, &epoll_pwait_writer, (void *) epoll_event);
d542c0ae
JG
829 if (ret != 0) {
830 fprintf(stderr, "[error] pthread_create\n");
5305e823 831 goto error_unmap;
d542c0ae 832 }
a0b1f42c
JD
833
834 ret = epoll_pwait(epollfd, epoll_event, 1, 1, NULL);
835
836 if (ret == 1) {
a0b1f42c
JD
837 ret = read(wait_fd, buf, BUF_SIZE);
838 if (ret < 0) {
d40c2620 839 PERROR("[epoll_pwait] read");
a0b1f42c 840 }
d40c2620
JG
841 } else if (ret != 0) {
842 /* Expected error. */
a0b1f42c
JD
843 }
844
845 stop_thread = 1;
9d558571
JG
846 ret = pthread_join(writer, NULL);
847 if (ret) {
848 fprintf(stderr, "[error] pthread_join\n");
5305e823 849 goto error_unmap;
9d558571 850 }
5305e823 851error_unmap:
a0b1f42c
JD
852 for (i = 0; i < MAX_FDS; i++) {
853 ret = close(fds[i]);
854 if (ret != 0) {
d40c2620 855 PERROR("close");
a0b1f42c
JD
856 }
857 }
858
36bc42d9 859 ret = munmap(epoll_event, MAX_FDS * sizeof(struct epoll_event));
a0b1f42c 860 if (ret != 0) {
d40c2620 861 PERROR("munmap");
a0b1f42c
JD
862 }
863
5305e823 864error:
6d52f14d
FD
865 ret = close(epollfd);
866 if (ret) {
d40c2620 867 PERROR("close");
6d52f14d 868 }
a0b1f42c
JD
869end:
870 return;
871}
872
28ab034a 873static void print_list(void)
a0b1f42c
JD
874{
875 fprintf(stderr, "Test list (-t X):\n");
28ab034a
JG
876 fprintf(stderr,
877 "\t1: Working cases for select, pselect6, poll, ppoll "
878 "and epoll, waiting for input\n");
879 fprintf(stderr,
880 "\t2: Timeout cases (1ms) for select, pselect6, poll, "
881 "ppoll and epoll\n");
8b3b99e2 882 fprintf(stderr, "\t3: pselect with an invalid fd\n");
a0b1f42c 883 fprintf(stderr, "\t4: ppoll with %d FDs\n", MAX_FDS);
28ab034a
JG
884 fprintf(stderr,
885 "\t5: ppoll buffer overflow, should segfault, waits "
886 "for input\n");
887 fprintf(stderr,
888 "\t6: pselect with an invalid pointer, waits for "
889 "input\n");
a0b1f42c 890 fprintf(stderr, "\t7: ppoll with ulong_max fds, waits for input\n");
28ab034a
JG
891 fprintf(stderr,
892 "\t8: epoll_pwait with an invalid pointer, waits for "
893 "input\n");
894 fprintf(stderr,
895 "\t9: epoll_pwait with maxevents set to INT_MAX, "
896 "waits for input\n");
897 fprintf(stderr,
898 "\t10: ppoll with concurrent updates of the structure "
899 "from user-space, stress test (3000 iterations), "
900 "waits for input + timeout 1ms\n");
901 fprintf(stderr,
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");
a0b1f42c
JD
905}
906
907int main(int argc, const char **argv)
908{
909 int c, ret, test = -1;
910 poptContext optCon;
911 struct rlimit open_lim;
d40c2620
JG
912 FILE *test_validation_output_file = NULL;
913 const char *test_validation_output_file_path = NULL;
a0b1f42c 914 struct poptOption optionsTable[] = {
28ab034a
JG
915 { "test", 't', POPT_ARG_INT, &test, 0, "Test to run", NULL },
916 { "list", 'l', 0, 0, 'l', "List of tests (-t X)", NULL },
917 { "validation-file",
918 'o',
919 POPT_ARG_STRING,
920 &test_validation_output_file_path,
921 0,
922 "Test case output",
923 NULL },
924 POPT_AUTOHELP{ NULL, 0, 0, NULL, 0, NULL, NULL }
a0b1f42c 925 };
d40c2620 926 const struct test_case *test_case;
a0b1f42c
JD
927
928 optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
929
930 if (argc < 2) {
931 poptPrintUsage(optCon, stderr, 0);
932 ret = -1;
933 goto end;
934 }
935
936 ret = 0;
937
938 while ((c = poptGetNextOpt(optCon)) >= 0) {
d40c2620 939 switch (c) {
a0b1f42c
JD
940 case 'l':
941 print_list();
942 goto end;
943 }
944 }
945
d40c2620
JG
946 if (!test_validation_output_file_path) {
947 fprintf(stderr, "A test validation file path is required (--validation-file/-o)\n");
948 ret = -1;
949 goto end;
950 }
951
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'",
28ab034a 955 test_validation_output_file_path);
d40c2620
JG
956 ret = -1;
957 goto end;
958 }
959
a0b1f42c
JD
960 open_lim.rlim_cur = MAX_FDS + MIN_NR_FDS;
961 open_lim.rlim_max = MAX_FDS + MIN_NR_FDS;
962
963 ret = setrlimit(RLIMIT_NOFILE, &open_lim);
964 if (ret < 0) {
d40c2620 965 PERROR("setrlimit");
a0b1f42c
JD
966 goto end;
967 }
968
969 /*
970 * Some tests might segfault, but we need the getpid() to be output
d40c2620
JG
971 * for the validation, disabling the buffering on the validation file
972 * works.
a0b1f42c 973 */
d40c2620 974 setbuf(test_validation_output_file, NULL);
a0b1f42c
JD
975 wait_fd = STDIN_FILENO;
976
d40c2620
JG
977 /* Test case id is 1-based. */
978 if (test < 1 || test > ARRAY_SIZE(test_cases)) {
a0b1f42c
JD
979 poptPrintUsage(optCon, stderr, 0);
980 ret = -1;
a0b1f42c
JD
981 }
982
d40c2620
JG
983 test_case = &test_cases[test - 1];
984
985 timeout = test_case->timeout;
986 if (!test_case->produces_validation_info) {
987 /*
988 * All test cases need to provide, at minimum, the pid of the
989 * test application.
990 */
991 ret = fprintf(test_validation_output_file, "{ \"pid\": %i }", getpid());
992 if (ret < 0) {
993 PERROR("Failed to write application pid to test validation file");
994 goto end;
995 }
996 }
997
998 test_case->run(test_validation_output_file);
999
a0b1f42c 1000end:
d40c2620
JG
1001 if (test_validation_output_file) {
1002 const int close_ret = fclose(test_validation_output_file);
1003
1004 if (close_ret) {
1005 PERROR("Failed to close test output file");
1006 }
1007 }
a0b1f42c
JD
1008 poptFreeContext(optCon);
1009 return ret;
1010}
This page took 0.096276 seconds and 4 git commands to generate.