1 /*
2 * This file is part of pselect6* strace tests.
3 *
4 * Copyright (c) 2015-2021 Dmitry V. Levin <ldv@strace.io>
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 /*
11 * Based on test by Dr. David Alan Gilbert <dave@treblig.org>
12 */
13
14 #include "nsig.h"
15 #include <assert.h>
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <sys/select.h>
19 #include <sys/time.h>
20 #include "kernel_timespec.h"
21
22 static const char *errstr;
23
24 static long
25 pselect6(const unsigned int nfds,
26 void *const rfds,
27 void *const wfds,
28 void *const efds,
29 void *const timeout,
30 void *const sigmask)
31 {
32 static const kernel_ulong_t fill =
33 (kernel_ulong_t) 0xdefaced00000000ULL;
34 const kernel_ulong_t arg1 = nfds | fill;
35 const kernel_ulong_t arg2 = f8ill_ptr_to_kulong(rfds);
36 const kernel_ulong_t arg3 = f8ill_ptr_to_kulong(wfds);
37 const kernel_ulong_t arg4 = f8ill_ptr_to_kulong(efds);
38 const kernel_ulong_t arg5 = f8ill_ptr_to_kulong(timeout);
39 const kernel_ulong_t arg6 = f8ill_ptr_to_kulong(sigmask);
40 const long rc = syscall(SYSCALL_NR, arg1, arg2, arg3, arg4, arg5, arg6);
41 errstr = sprintrc(rc);
42 return rc;
43 }
44
45 static fd_set set[3][0x1000000 / sizeof(fd_set)];
46
47 static void
48 handler(int signo)
49 {
50 }
51
52 struct sigset_argpack {
53 kernel_ulong_t p, size;
54 };
55
56 int main(int ac, char **av)
57 {
58 static const pselect6_timespec_t ts_in = {
59 .tv_sec = 0xc0de1, .tv_nsec = 0xc0de2
60 };
61 pselect6_timespec_t *const ts = tail_memdup(&ts_in, sizeof(ts_in));
62
63 sigset_t mask;
64 sigemptyset(&mask);
65 sigaddset(&mask, SIGHUP);
66 sigaddset(&mask, SIGCHLD);
67
68 TAIL_ALLOC_OBJECT_CONST_PTR(struct sigset_argpack, sigmask_arg);
69 sigmask_arg->p = (uintptr_t) &mask;
70 sigmask_arg->size = NSIG_BYTES;
71
72 TAIL_ALLOC_OBJECT_CONST_PTR(struct sigset_argpack, nullmask_arg);
73 nullmask_arg->p = 0;
74 nullmask_arg->size = NSIG_BYTES;
75
76 int fds[2];
77 if (pipe(fds))
78 perror_msg_and_fail("pipe");
79
80 /*
81 * Start with a nice simple pselect6.
82 */
83 FD_SET(fds[0], set[0]);
84 FD_SET(fds[1], set[0]);
85 FD_SET(fds[0], set[1]);
86 FD_SET(fds[1], set[1]);
87 FD_SET(1, set[2]);
88 FD_SET(2, set[2]);
89 int rc = pselect6(fds[1] + 1, set[0], set[1], set[2], NULL, nullmask_arg);
90 if (rc < 0)
91 perror_msg_and_skip("pselect6");
92 assert(rc == 1);
93 printf("%s(%d, [%d %d], [%d %d], [1 2], NULL"
94 ", {sigmask=NULL, sigsetsize=%u}) = 1 (out [%d])\n",
95 SYSCALL_NAME, fds[1] + 1, fds[0], fds[1],
96 fds[0], fds[1],
97 NSIG_BYTES, fds[1]);
98
99 /*
100 * Another simple one, with a timeout.
101 */
102 FD_SET(1, set[1]);
103 FD_SET(2, set[1]);
104 FD_SET(fds[0], set[1]);
105 FD_SET(fds[1], set[1]);
106 assert(pselect6(fds[1] + 1, NULL, set[1], NULL, ts, NULL) == 3);
107 printf("%s(%d, NULL, [1 2 %d %d], NULL"
108 ", {tv_sec=%lld, tv_nsec=%llu}, NULL) = 3 (out [1 2 %d]"
109 ", left {tv_sec=%lld, tv_nsec=%llu})\n",
110 SYSCALL_NAME,
111 fds[1] + 1, fds[0], fds[1], (long long) ts_in.tv_sec,
112 zero_extend_signed_to_ull(ts_in.tv_nsec),
113 fds[1], (long long) ts->tv_sec,
114 zero_extend_signed_to_ull(ts->tv_nsec));
115
116 /*
117 * Now the crash case that trinity found, negative nfds
118 * but with a pointer to a large chunk of valid memory.
119 */
120 FD_ZERO(set[0]);
121 FD_SET(fds[1], set[0]);
122 assert(pselect6(-1, NULL, set[0], NULL, NULL, sigmask_arg) == -1);
123 printf("%s(-1, NULL, %p, NULL, NULL"
124 ", {sigmask=[HUP CHLD], sigsetsize=%u}) = %s\n",
125 SYSCALL_NAME, set[0], NSIG_BYTES, errstr);
126
127 /*
128 * Another variant, with nfds exceeding FD_SETSIZE limit.
129 */
130 FD_ZERO(set[0]);
131 FD_SET(fds[0], set[0]);
132 FD_ZERO(set[1]);
133 ts->tv_sec = 0;
134 ts->tv_nsec = 123;
135 assert(pselect6(FD_SETSIZE + 1, set[0], set[1], NULL, ts, sigmask_arg) == 0);
136 printf("%s(%d, [%d], [], NULL, {tv_sec=0, tv_nsec=123}"
137 ", {sigmask=[HUP CHLD], sigsetsize=%u}) = 0 (Timeout)\n",
138 SYSCALL_NAME, FD_SETSIZE + 1, fds[0], NSIG_BYTES);
139
140 /*
141 * See how timeouts are decoded.
142 */
143 ts->tv_sec = 0xdeadbeefU;
144 ts->tv_nsec = 0xfacefeedU;
145 assert(pselect6(0, NULL, NULL, NULL, ts, nullmask_arg) == -1);
146 printf("%s(0, NULL, NULL, NULL, {tv_sec=%lld, tv_nsec=%llu}"
147 ", {sigmask=NULL, sigsetsize=%u}) = %s\n",
148 SYSCALL_NAME, (long long) ts->tv_sec,
149 zero_extend_signed_to_ull(ts->tv_nsec),
150 NSIG_BYTES, errstr);
151
152 ts->tv_sec = (typeof(ts->tv_sec)) 0xcafef00ddeadbeefLL;
153 ts->tv_nsec = (typeof(ts->tv_nsec)) 0xbadc0dedfacefeedLL;
154 assert(pselect6(0, NULL, NULL, NULL, ts, nullmask_arg) == -1);
155 printf("%s(0, NULL, NULL, NULL, {tv_sec=%lld, tv_nsec=%llu}"
156 ", {sigmask=NULL, sigsetsize=%u}) = %s\n",
157 SYSCALL_NAME, (long long) ts->tv_sec,
158 zero_extend_signed_to_ull(ts->tv_nsec),
159 NSIG_BYTES, errstr);
160
161 const struct sigaction act = { .sa_handler = handler };
162 if (sigaction(SIGALRM, &act, NULL))
163 perror_msg_and_fail("sigaction SIGALRM");
164
165 const struct itimerval itv = { .it_value.tv_usec = 111111 };
166 if (setitimer(ITIMER_REAL, &itv, NULL))
167 perror_msg_and_fail("setitimer ITIMER_REAL");
168
169 ts->tv_sec = 0;
170 ts->tv_nsec = 222222222;
171 assert(pselect6(0, NULL, NULL, NULL, ts, sigmask_arg) == -1);
172 printf("%s(0, NULL, NULL, NULL, {tv_sec=0, tv_nsec=222222222}"
173 ", {sigmask=[HUP CHLD], sigsetsize=%u})"
174 " = ? ERESTARTNOHAND (To be restarted if no handler)\n",
175 SYSCALL_NAME, NSIG_BYTES);
176 puts("--- SIGALRM {si_signo=SIGALRM, si_code=SI_KERNEL} ---");
177
178 puts("+++ exited with 0 +++");
179 return 0;
180 }