1 /* 2 * Copyright (c) 2015-2016 Dmitry V. Levin <ldv (at) altlinux.org> 3 * Copyright (c) 2015-2017 The strace developers. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Based on test by Dr. David Alan Gilbert <dave (at) treblig.org> 31 */ 32 33 #include "tests.h" 34 #include "nsig.h" 35 #include <assert.h> 36 #include <stdio.h> 37 #include <unistd.h> 38 #include <sys/select.h> 39 #include <asm/unistd.h> 40 #include <sys/time.h> 41 42 #ifdef __NR_pselect6 43 44 static fd_set set[3][0x1000000 / sizeof(fd_set)]; 45 46 static void 47 handler(int signo) 48 { 49 } 50 51 int main(int ac, char **av) 52 { 53 int fds[2]; 54 struct { 55 struct timespec ts; 56 int pad[2]; 57 } tm_in = { 58 .ts = { .tv_sec = 0xc0de1, .tv_nsec = 0xc0de2 }, 59 .pad = { 0xdeadbeef, 0xbadc0ded } 60 }, tm = tm_in; 61 sigset_t mask; 62 const struct sigaction act = { .sa_handler = handler }; 63 const struct itimerval itv = { .it_value.tv_usec = 111111 }; 64 65 sigemptyset(&mask); 66 sigaddset(&mask, SIGHUP); 67 sigaddset(&mask, SIGCHLD); 68 69 if (pipe(fds)) 70 perror_msg_and_fail("pipe"); 71 72 /* 73 * Start with a nice simple pselect. 74 */ 75 FD_SET(fds[0], set[0]); 76 FD_SET(fds[1], set[0]); 77 FD_SET(fds[0], set[1]); 78 FD_SET(fds[1], set[1]); 79 FD_SET(1, set[2]); 80 FD_SET(2, set[2]); 81 int rc = pselect(fds[1] + 1, set[0], set[1], set[2], NULL, NULL); 82 if (rc < 0) 83 perror_msg_and_skip("pselect"); 84 assert(rc == 1); 85 printf("pselect6(%d, [%d %d], [%d %d], [1 2], NULL, {NULL, %u}) " 86 "= 1 (out [%d])\n", 87 fds[1] + 1, fds[0], fds[1], 88 fds[0], fds[1], 89 NSIG_BYTES, fds[1]); 90 91 /* 92 * Another simple one, with a timeout. 93 */ 94 FD_SET(1, set[1]); 95 FD_SET(2, set[1]); 96 FD_SET(fds[0], set[1]); 97 FD_SET(fds[1], set[1]); 98 assert(syscall(__NR_pselect6, fds[1] + 1, NULL, set[1], NULL, &tm.ts, NULL) == 3); 99 printf("pselect6(%d, NULL, [1 2 %d %d], NULL" 100 ", {tv_sec=%lld, tv_nsec=%llu}, NULL) = 3 (out [1 2 %d]" 101 ", left {tv_sec=%lld, tv_nsec=%llu})\n", 102 fds[1] + 1, fds[0], fds[1], (long long) tm_in.ts.tv_sec, 103 zero_extend_signed_to_ull(tm_in.ts.tv_nsec), 104 fds[1], (long long) tm.ts.tv_sec, 105 zero_extend_signed_to_ull(tm.ts.tv_nsec)); 106 107 /* 108 * Now the crash case that trinity found, negative nfds 109 * but with a pointer to a large chunk of valid memory. 110 */ 111 FD_ZERO(set[0]); 112 FD_SET(fds[1], set[0]); 113 assert(pselect(-1, NULL, set[0], NULL, NULL, &mask) == -1); 114 printf("pselect6(-1, NULL, %p, NULL, NULL, {[HUP CHLD], %u}) " 115 "= -1 EINVAL (%m)\n", set[0], NSIG_BYTES); 116 117 /* 118 * Another variant, with nfds exceeding FD_SETSIZE limit. 119 */ 120 FD_ZERO(set[0]); 121 FD_SET(fds[0], set[0]); 122 FD_ZERO(set[1]); 123 tm.ts.tv_sec = 0; 124 tm.ts.tv_nsec = 123; 125 assert(pselect(FD_SETSIZE + 1, set[0], set[1], NULL, &tm.ts, &mask) == 0); 126 printf("pselect6(%d, [%d], [], NULL, {tv_sec=0, tv_nsec=123}" 127 ", {[HUP CHLD], %u}) = 0 (Timeout)\n", 128 FD_SETSIZE + 1, fds[0], NSIG_BYTES); 129 130 /* 131 * See how timeouts are decoded. 132 */ 133 tm.ts.tv_sec = 0xdeadbeefU; 134 tm.ts.tv_nsec = 0xfacefeedU; 135 assert(pselect(0, NULL, NULL, NULL, &tm.ts, NULL) == -1); 136 printf("pselect6(0, NULL, NULL, NULL" 137 ", {tv_sec=%lld, tv_nsec=%llu}, {NULL, %u}) = %s\n", 138 (long long) tm.ts.tv_sec, 139 zero_extend_signed_to_ull(tm.ts.tv_nsec), 140 NSIG_BYTES, sprintrc(-1)); 141 142 tm.ts.tv_sec = (time_t) 0xcafef00ddeadbeefLL; 143 tm.ts.tv_nsec = (long) 0xbadc0dedfacefeedLL; 144 assert(pselect(0, NULL, NULL, NULL, &tm.ts, NULL) == -1); 145 printf("pselect6(0, NULL, NULL, NULL" 146 ", {tv_sec=%lld, tv_nsec=%llu}, {NULL, %u}) = %s\n", 147 (long long) tm.ts.tv_sec, 148 zero_extend_signed_to_ull(tm.ts.tv_nsec), 149 NSIG_BYTES, sprintrc(-1)); 150 151 assert(sigaction(SIGALRM, &act, NULL) == 0); 152 assert(setitimer(ITIMER_REAL, &itv, NULL) == 0); 153 154 tm.ts.tv_sec = 0; 155 tm.ts.tv_nsec = 222222222; 156 assert(pselect(0, NULL, NULL, NULL, &tm.ts, &mask) == -1); 157 printf("pselect6(0, NULL, NULL, NULL, {tv_sec=0, tv_nsec=222222222}" 158 ", {[HUP CHLD], %u})" 159 " = ? ERESTARTNOHAND (To be restarted if no handler)\n", 160 NSIG_BYTES); 161 puts("--- SIGALRM {si_signo=SIGALRM, si_code=SI_KERNEL} ---"); 162 163 puts("+++ exited with 0 +++"); 164 return 0; 165 } 166 167 #else 168 169 SKIP_MAIN_UNDEFINED("__NR_pselect6") 170 171 #endif 172