1 /* 2 * Check decoding of poll syscall. 3 * 4 * Copyright (c) 2016-2018 Dmitry V. Levin <ldv (at) altlinux.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "tests.h" 31 #include <asm/unistd.h> 32 33 #ifdef __NR_poll 34 35 # include <assert.h> 36 # include <errno.h> 37 # include <poll.h> 38 # include <stdio.h> 39 # include <stdlib.h> 40 # include <string.h> 41 # include <unistd.h> 42 43 #define PRINT_EVENT(flag, member) \ 44 do { \ 45 if (member & flag) { \ 46 if (member != pfd->member) \ 47 tprintf("|"); \ 48 tprintf(#flag); \ 49 member &= ~flag; \ 50 } \ 51 } while (0) 52 53 static void 54 print_pollfd_entering(const struct pollfd *const pfd) 55 { 56 tprintf("{fd=%d", pfd->fd); 57 if (pfd->fd >= 0) { 58 tprintf(", events="); 59 short events = pfd->events; 60 61 if (pfd->events) { 62 PRINT_EVENT(POLLIN, events); 63 PRINT_EVENT(POLLPRI, events); 64 PRINT_EVENT(POLLOUT, events); 65 #ifdef POLLRDNORM 66 PRINT_EVENT(POLLRDNORM, events); 67 #endif 68 #ifdef POLLWRNORM 69 PRINT_EVENT(POLLWRNORM, events); 70 #endif 71 #ifdef POLLRDBAND 72 PRINT_EVENT(POLLRDBAND, events); 73 #endif 74 #ifdef POLLWRBAND 75 PRINT_EVENT(POLLWRBAND, events); 76 #endif 77 PRINT_EVENT(POLLERR, events); 78 PRINT_EVENT(POLLHUP, events); 79 PRINT_EVENT(POLLNVAL, events); 80 } else 81 tprintf("0"); 82 } 83 tprintf("}"); 84 } 85 86 static void 87 print_pollfd_array_entering(const struct pollfd *const pfd, 88 const unsigned int size, 89 const unsigned int valid, 90 const unsigned int abbrev) 91 { 92 tprintf("["); 93 unsigned int i; 94 for (i = 0; i < size; ++i) { 95 if (i) 96 tprintf(", "); 97 if (i >= valid) { 98 tprintf("%p", &pfd[i]); 99 break; 100 } 101 if (i >= abbrev) { 102 tprintf("..."); 103 break; 104 } 105 print_pollfd_entering(&pfd[i]); 106 } 107 tprintf("]"); 108 } 109 110 static void 111 print_pollfd_exiting(const struct pollfd *const pfd, 112 unsigned int *const seen, 113 const unsigned int abbrev) 114 { 115 if (!pfd->revents || pfd->fd < 0 || *seen > abbrev) 116 return; 117 118 if (*seen) 119 tprintf(", "); 120 ++(*seen); 121 122 if (*seen > abbrev) { 123 tprintf("..."); 124 return; 125 } 126 tprintf("{fd=%d, revents=", pfd->fd); 127 short revents = pfd->revents; 128 129 PRINT_EVENT(POLLIN, revents); 130 PRINT_EVENT(POLLPRI, revents); 131 PRINT_EVENT(POLLOUT, revents); 132 #ifdef POLLRDNORM 133 PRINT_EVENT(POLLRDNORM, revents); 134 #endif 135 #ifdef POLLWRNORM 136 PRINT_EVENT(POLLWRNORM, revents); 137 #endif 138 #ifdef POLLRDBAND 139 PRINT_EVENT(POLLRDBAND, revents); 140 #endif 141 #ifdef POLLWRBAND 142 PRINT_EVENT(POLLWRBAND, revents); 143 #endif 144 PRINT_EVENT(POLLERR, revents); 145 PRINT_EVENT(POLLHUP, revents); 146 PRINT_EVENT(POLLNVAL, revents); 147 tprintf("}"); 148 } 149 150 static void 151 print_pollfd_array_exiting(const struct pollfd *const pfd, 152 const unsigned int size, 153 const unsigned int abbrev) 154 { 155 tprintf("["); 156 unsigned int seen = 0; 157 unsigned int i; 158 for (i = 0; i < size; ++i) 159 print_pollfd_exiting(&pfd[i], &seen, abbrev); 160 tprintf("]"); 161 } 162 163 int 164 main(int ac, char **av) 165 { 166 # ifdef PATH_TRACING_FD 167 skip_if_unavailable("/proc/self/fd/"); 168 # endif 169 170 tprintf("%s", ""); 171 172 assert(syscall(__NR_poll, NULL, 42, 0) == -1); 173 if (ENOSYS == errno) 174 perror_msg_and_skip("poll"); 175 176 # ifndef PATH_TRACING_FD 177 tprintf("poll(NULL, 42, 0) = -1 EFAULT (%m)\n"); 178 # endif 179 180 int fds[2]; 181 if (pipe(fds) || pipe(fds)) 182 perror_msg_and_fail("pipe"); 183 184 const unsigned int abbrev = (ac > 1) ? atoi(av[1]) : -1; 185 const struct pollfd pfds0[] = { 186 { .fd = 0, .events = POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND }, 187 { .fd = 1, .events = POLLOUT | POLLWRNORM | POLLWRBAND }, 188 { .fd = fds[0], .events = POLLIN | POLLPRI }, 189 { .fd = fds[1], .events = POLLOUT }, 190 { .fd = 2, .events = POLLOUT | POLLWRBAND } 191 }; 192 struct pollfd *const tail_fds0 = tail_memdup(pfds0, sizeof(pfds0)); 193 const int timeout = 42; 194 int rc = syscall(__NR_poll, tail_fds0, 0, timeout); 195 assert(rc == 0); 196 197 # ifndef PATH_TRACING_FD 198 tprintf("poll([], 0, %d) = %d (Timeout)\n", timeout, rc); 199 # endif 200 201 rc = syscall(__NR_poll, tail_fds0, ARRAY_SIZE(pfds0), timeout); 202 assert(rc == 3); 203 204 # ifndef PATH_TRACING_FD 205 tprintf("poll("); 206 print_pollfd_array_entering(tail_fds0, ARRAY_SIZE(pfds0), 207 ARRAY_SIZE(pfds0), abbrev); 208 tprintf(", %u, %d) = %d (", 209 (unsigned int) ARRAY_SIZE(pfds0), timeout, rc); 210 print_pollfd_array_exiting(tail_fds0, ARRAY_SIZE(pfds0), abbrev); 211 tprintf(")\n"); 212 # endif /* !PATH_TRACING_FD */ 213 214 tail_fds0[0].fd = -1; 215 tail_fds0[2].fd = -3; 216 tail_fds0[4].events = 0; 217 rc = syscall(__NR_poll, tail_fds0, ARRAY_SIZE(pfds0), timeout); 218 assert(rc == 2); 219 220 # ifndef PATH_TRACING_FD 221 tprintf("poll("); 222 print_pollfd_array_entering(tail_fds0, ARRAY_SIZE(pfds0), 223 ARRAY_SIZE(pfds0), abbrev); 224 tprintf(", %u, %d) = %d (", 225 (unsigned int) ARRAY_SIZE(pfds0), timeout, rc); 226 print_pollfd_array_exiting(tail_fds0, ARRAY_SIZE(pfds0), abbrev); 227 tprintf(")\n"); 228 # endif /* !PATH_TRACING_FD */ 229 230 tail_fds0[1].fd = -2; 231 tail_fds0[4].fd = -5; 232 rc = syscall(__NR_poll, tail_fds0, ARRAY_SIZE(pfds0), timeout); 233 assert(rc == 1); 234 235 # ifndef PATH_TRACING_FD 236 tprintf("poll("); 237 print_pollfd_array_entering(tail_fds0, ARRAY_SIZE(pfds0), 238 ARRAY_SIZE(pfds0), abbrev); 239 tprintf(", %u, %d) = %d (", 240 (unsigned int) ARRAY_SIZE(pfds0), timeout, rc); 241 print_pollfd_array_exiting(tail_fds0, ARRAY_SIZE(pfds0), abbrev); 242 tprintf(")\n"); 243 # endif /* !PATH_TRACING_FD */ 244 245 struct pollfd pfds1[] = { 246 { .fd = 1, .events = POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND }, 247 { .fd = 0, .events = POLLOUT | POLLWRNORM | POLLWRBAND } 248 }; 249 struct pollfd *const tail_fds1 = tail_memdup(pfds1, sizeof(pfds1)); 250 rc = syscall(__NR_poll, tail_fds1, ARRAY_SIZE(pfds1), timeout); 251 assert(rc == 0); 252 253 # ifndef PATH_TRACING_FD 254 tprintf("poll("); 255 print_pollfd_array_entering(tail_fds1, ARRAY_SIZE(pfds1), 256 ARRAY_SIZE(pfds1), abbrev); 257 tprintf(", %u, %d) = %d (Timeout)\n", 258 (unsigned int) ARRAY_SIZE(pfds1), timeout, rc); 259 # endif /* !PATH_TRACING_FD */ 260 261 const void *const efault = tail_fds0 + ARRAY_SIZE(pfds0); 262 rc = syscall(__NR_poll, efault, 1, 0); 263 assert(rc == -1); 264 265 # ifndef PATH_TRACING_FD 266 tprintf("poll(%p, 1, 0) = -1 EFAULT (%m)\n", efault); 267 # endif 268 269 const unsigned int valid = 1; 270 const void *const epfds = tail_fds0 + ARRAY_SIZE(pfds0) - valid; 271 rc = syscall(__NR_poll, epfds, valid + 1, 0); 272 assert(rc == -1); 273 274 # ifndef PATH_TRACING_FD 275 tprintf("poll("); 276 print_pollfd_array_entering(epfds, valid + 1, valid, abbrev); 277 errno = EFAULT; 278 tprintf(", %u, 0) = -1 EFAULT (%m)\n", valid + 1); 279 # endif /* !PATH_TRACING_FD */ 280 281 # ifdef PATH_TRACING_FD 282 memcpy(tail_fds0, pfds0, sizeof(pfds0)); 283 tail_fds0[4].fd = PATH_TRACING_FD; 284 285 rc = syscall(__NR_poll, tail_fds0, ARRAY_SIZE(pfds0), timeout); 286 assert(rc == 3); 287 288 tprintf("poll("); 289 print_pollfd_array_entering(tail_fds0, ARRAY_SIZE(pfds0), 290 ARRAY_SIZE(pfds0), abbrev); 291 tprintf(", %u, %d) = %d (", 292 (unsigned int) ARRAY_SIZE(pfds0), timeout, rc); 293 print_pollfd_array_exiting(tail_fds0, ARRAY_SIZE(pfds0), abbrev); 294 tprintf(")\n"); 295 296 rc = syscall(__NR_poll, epfds, valid + 1, 0); 297 assert(rc == -1); 298 299 /* the 1st pollfd element is readable and contains PATH_TRACING_FD */ 300 tprintf("poll("); 301 print_pollfd_array_entering(epfds, valid + 1, valid, abbrev); 302 errno = EFAULT; 303 tprintf(", %u, 0) = -1 EFAULT (%m)\n", valid + 1); 304 # endif /* PATH_TRACING_FD */ 305 306 tprintf("+++ exited with 0 +++\n"); 307 return 0; 308 } 309 310 #else 311 312 SKIP_MAIN_UNDEFINED("__NR_poll") 313 314 #endif 315