1 /* 2 * Check decoding of mq_open, mq_timedsend, mq_notify, mq_timedreceive and 3 * mq_unlink syscalls. 4 * 5 * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr (at) gmail.com> 6 * Copyright (c) 2016-2017 The strace developers. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include "tests.h" 33 34 #include <asm/unistd.h> 35 36 #if defined __NR_mq_open && __NR_mq_timedsend && __NR_mq_timedreceive && \ 37 __NR_mq_notify && __NR_mq_unlink 38 39 # include <assert.h> 40 # include <errno.h> 41 # include <fcntl.h> 42 # include <inttypes.h> 43 # include <signal.h> 44 # include <stdbool.h> 45 # include <stdio.h> 46 # include <stdlib.h> 47 # include <string.h> 48 # include <time.h> 49 # include <unistd.h> 50 51 # include "sigevent.h" 52 53 # ifndef DUMPIO_READ 54 # define DUMPIO_READ 0 55 # endif 56 57 # ifndef DUMPIO_WRITE 58 # define DUMPIO_WRITE 0 59 # endif 60 61 static char *mq_name; 62 63 enum { 64 NUM_ATTRS = 8, 65 MSG_CUT = 8, 66 MSG_MAX_UNCUT = 32, 67 MSG_SIZE = 64, 68 MSG_START = 0x80, 69 }; 70 71 72 static void 73 printstr(unsigned char start, unsigned int count) 74 { 75 unsigned int i; 76 77 printf("\""); 78 for (i = 0; i < count; i++) { 79 printf("\\%hho", (unsigned char) (start + i)); 80 } 81 printf("\""); 82 } 83 84 #if DUMPIO_READ || DUMPIO_WRITE 85 static void 86 dumpstr(unsigned char start, unsigned int count) 87 { 88 unsigned int i; 89 unsigned int j; 90 91 for (i = 0; i < count; i++) { 92 if (i < count) { 93 if (!(i % 16)) 94 printf(" | %05x ", i); 95 if (!(i % 8)) 96 printf(" "); 97 98 printf("%02hhx ", (unsigned char) (start + i)); 99 } 100 101 if ((i % 16 == 15) || (i == (count - 1))) { 102 if (i % 16 != 15) 103 printf("%*s", 3 * (15 - i % 16) + 104 ((i + 8) % 16) / 8, " "); 105 106 printf(" "); 107 108 for (j = 0; j <= (i % 16); j++) 109 printf("."); 110 for (j = i % 16; j < 15; j++) 111 printf(" "); 112 113 printf(" |\n"); 114 115 } 116 } 117 } 118 #endif /* DUMPIO_READ || DUMPIO_WRITE */ 119 120 static void 121 cleanup(void) 122 { 123 long rc; 124 125 rc = syscall(__NR_mq_unlink, mq_name); 126 printf("mq_unlink(\"%s\") = %s\n", mq_name, sprintrc(rc)); 127 128 puts("+++ exited with 0 +++"); 129 } 130 131 static void 132 do_send(int fd, char *msg, unsigned int msg_size, struct timespec *tmout, 133 bool cropped) 134 { 135 long rc; 136 long saved_errno; 137 138 do { 139 rc = syscall(__NR_mq_timedsend, fd, msg, msg_size, 42, 140 tmout); 141 saved_errno = errno; 142 printf("mq_timedsend(%d, ", fd); 143 printstr(MSG_START, msg_size > MSG_MAX_UNCUT ? MSG_MAX_UNCUT : 144 msg_size); 145 if (cropped) 146 printf("..."); 147 errno = saved_errno; 148 printf(", %u, 42, {tv_sec=%lld, tv_nsec=%llu}) = %s\n", msg_size, 149 (long long) tmout->tv_sec, 150 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc)); 151 errno = saved_errno; 152 153 if (rc == -1) { 154 if (errno == EINTR) 155 continue; 156 perror_msg_and_skip("mq_timedsend"); 157 } 158 # if DUMPIO_WRITE 159 dumpstr(MSG_START, msg_size); 160 # endif 161 } while (rc); 162 } 163 164 static void 165 do_recv(int fd, char *msg, unsigned int msg_size, struct timespec *tmout, 166 bool cropped) 167 { 168 long rc; 169 long saved_errno; 170 unsigned prio; 171 172 do { 173 rc = syscall(__NR_mq_timedreceive, fd, msg, MSG_SIZE, &prio, 174 tmout); 175 saved_errno = errno; 176 printf("mq_timedreceive(%d, ", fd); 177 if (rc >= 0) { 178 printstr(MSG_START, rc > MSG_MAX_UNCUT ? MSG_MAX_UNCUT : 179 rc); 180 if (cropped) 181 printf("..."); 182 } else { 183 printf("%p", msg); 184 } 185 errno = saved_errno; 186 printf(", %u, [42], {tv_sec=%lld, tv_nsec=%llu}) = %s\n", MSG_SIZE, 187 (long long) tmout->tv_sec, 188 zero_extend_signed_to_ull(tmout->tv_nsec), sprintrc(rc)); 189 errno = saved_errno; 190 191 if (rc == -1) { 192 if (errno == EINTR) 193 continue; 194 perror_msg_and_skip("mq_timedreceive"); 195 } 196 if ((rc >= 0) && ((unsigned long) rc != msg_size)) 197 error_msg_and_skip("mq_timedreceive size mismatch" 198 ": expected %u, got %ld", 199 msg_size, rc); 200 # if DUMPIO_READ 201 dumpstr(MSG_START, rc); 202 # endif 203 } while (rc < 0); 204 } 205 206 int 207 main(void) 208 { 209 static const kernel_ulong_t bogus_zero = 210 (kernel_ulong_t) 0x8765432100000000ULL; 211 static const kernel_ulong_t bogus_oflags = 212 (kernel_ulong_t) 0xdefaced100000003ULL; 213 static const kernel_ulong_t bogus_mode = 214 (kernel_ulong_t) 0xdec0deadfacefeedULL; 215 static const kernel_ulong_t bogus_fd = 216 (kernel_ulong_t) 0xfeedfacedeadba5eULL; 217 static const kernel_ulong_t bogus_zero_size = 218 (sizeof(kernel_ulong_t) > sizeof(int)) ? (kernel_ulong_t) 0 : 219 (kernel_ulong_t) 0xface1e5500000000ULL; 220 static const kernel_ulong_t bogus_size = 221 (kernel_ulong_t) 0xbadc0dedda7a1057ULL; 222 static const kernel_ulong_t bogus_prio = 223 (kernel_ulong_t) 0xdec0ded1defaced3ULL; 224 static const struct timespec bogus_tmout_data = { 225 .tv_sec = (time_t) 0xdeadfacebeeff00dLL, 226 .tv_nsec = (long) 0xfacefee1deadfeedLL, 227 }; 228 static const struct timespec future_tmout_data = { 229 .tv_sec = (time_t) 0x7ea1fade7e57faceLL, 230 .tv_nsec = 999999999, 231 }; 232 struct_sigevent bogus_sev_data = { 233 .sigev_notify = 0xdefaced, 234 .sigev_signo = 0xfacefeed, 235 .sigev_value.sival_ptr = (unsigned long) 0xdeadbeefbadc0dedULL 236 }; 237 238 const char *errstr; 239 long rc; 240 kernel_long_t *bogus_attrs = tail_alloc(sizeof(*bogus_attrs) * 241 NUM_ATTRS); 242 char *msg = tail_alloc(MSG_SIZE); 243 TAIL_ALLOC_OBJECT_CONST_PTR(unsigned, bogus_prio_ptr); 244 struct timespec *bogus_tmout = tail_memdup(&bogus_tmout_data, 245 sizeof(*bogus_tmout)); 246 struct timespec *future_tmout = tail_memdup(&future_tmout_data, 247 sizeof(*future_tmout)); 248 struct_sigevent *bogus_sev = tail_memdup(&bogus_sev_data, 249 sizeof(*bogus_sev)); 250 int fd = -1; 251 252 253 fill_memory_ex(msg, MSG_SIZE, MSG_START, MSG_SIZE); 254 fill_memory_ex(bogus_attrs, sizeof(*bogus_attrs) * NUM_ATTRS, 255 0xbb, 0x70); 256 257 258 /* mq_open */ 259 260 /* Zero values, non-O_CREAT mode */ 261 rc = syscall(__NR_mq_open, NULL, bogus_zero, bogus_mode, NULL); 262 printf("mq_open(NULL, O_RDONLY) = %s\n", sprintrc(rc)); 263 264 /* O_CREAT parsing, other flags, bogs values */ 265 rc = syscall(__NR_mq_open, msg, O_CREAT | bogus_oflags, bogus_mode, 266 NULL); 267 printf("mq_open(%p, O_ACCMODE|O_CREAT, %#o, NULL) = %s\n", 268 msg, (unsigned short) bogus_mode, sprintrc(rc)); 269 270 /* Partially invalid attributes structure */ 271 rc = syscall(__NR_mq_open, msg, O_CREAT | bogus_oflags, bogus_mode, 272 bogus_attrs + 1); 273 printf("mq_open(%p, O_ACCMODE|O_CREAT, %#o, %p) = %s\n", 274 msg, (unsigned short) bogus_mode, bogus_attrs + 1, sprintrc(rc)); 275 276 /* Valid attributes structure */ 277 rc = syscall(__NR_mq_open, msg, O_CREAT | bogus_oflags, bogus_mode, 278 bogus_attrs); 279 printf("mq_open(%p, O_ACCMODE|O_CREAT, %#o, {mq_flags=%#llx" 280 ", mq_maxmsg=%lld, mq_msgsize=%lld, mq_curmsgs=%lld}) = %s\n", 281 msg, (unsigned short) bogus_mode, 282 (unsigned long long) (kernel_ulong_t) bogus_attrs[0], 283 (long long) bogus_attrs[1], 284 (long long) bogus_attrs[2], 285 (long long) bogus_attrs[3], sprintrc(rc)); 286 287 288 /* mq_timedsend */ 289 290 /* Zero values*/ 291 rc = syscall(__NR_mq_timedsend, bogus_zero, NULL, bogus_zero_size, 292 bogus_zero, NULL); 293 printf("mq_timedsend(0, NULL, 0, 0, NULL) = %s\n", sprintrc(rc)); 294 295 /* Invalid pointers */ 296 rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_SIZE, bogus_size, 297 bogus_prio, bogus_tmout + 1); 298 printf("mq_timedsend(%d, %p, %llu, %u, %p) = %s\n", 299 (int) bogus_fd, msg + MSG_SIZE, (unsigned long long) bogus_size, 300 (unsigned) bogus_prio, bogus_tmout + 1, sprintrc(rc)); 301 302 /* Partially invalid message (memory only partially available) */ 303 rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_SIZE - MSG_CUT, 304 MSG_SIZE, bogus_prio, bogus_tmout); 305 printf("mq_timedsend(%d, %p, %llu, %u, {tv_sec=%lld, tv_nsec=%llu})" 306 " = %s\n", 307 (int) bogus_fd, msg + MSG_SIZE - MSG_CUT, 308 (unsigned long long) MSG_SIZE, (unsigned) bogus_prio, 309 (long long) bogus_tmout->tv_sec, 310 zero_extend_signed_to_ull(bogus_tmout->tv_nsec), sprintrc(rc)); 311 312 /* Fully valid message, uncut */ 313 rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_SIZE - MSG_CUT, 314 MSG_CUT, bogus_prio, bogus_tmout); 315 errstr = sprintrc(rc); 316 printf("mq_timedsend(%d, ", (int) bogus_fd); 317 printstr(MSG_START + MSG_SIZE - MSG_CUT, MSG_CUT); 318 printf(", %llu, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n", 319 (unsigned long long) MSG_CUT, (unsigned) bogus_prio, 320 (long long) bogus_tmout->tv_sec, 321 zero_extend_signed_to_ull(bogus_tmout->tv_nsec), errstr); 322 323 /* Partially invalid message, cut at maxstrlen */ 324 rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_CUT, MSG_SIZE, 325 bogus_prio, bogus_tmout); 326 errstr = sprintrc(rc); 327 printf("mq_timedsend(%d, ", (int) bogus_fd); 328 printstr(MSG_START + MSG_CUT, MSG_MAX_UNCUT); 329 printf("..., %llu, %u, {tv_sec=%lld, tv_nsec=%llu}) = %s\n", 330 (unsigned long long) MSG_SIZE, (unsigned) bogus_prio, 331 (long long) bogus_tmout->tv_sec, 332 zero_extend_signed_to_ull(bogus_tmout->tv_nsec), errstr); 333 334 335 /* mq_timedreceive */ 336 337 /* Zero values */ 338 rc = syscall(__NR_mq_timedreceive, bogus_zero, NULL, bogus_zero_size, 339 NULL, NULL); 340 printf("mq_timedreceive(0, NULL, 0, NULL, NULL) = %s\n", sprintrc(rc)); 341 342 /* Invalid addresses */ 343 rc = syscall(__NR_mq_timedreceive, bogus_fd, msg + MSG_SIZE, bogus_size, 344 bogus_prio_ptr + 1, bogus_tmout + 1); 345 printf("mq_timedreceive(%d, %p, %llu, %p, %p) = %s\n", 346 (int) bogus_fd, msg + MSG_SIZE, (unsigned long long) bogus_size, 347 bogus_prio_ptr + 1, bogus_tmout + 1, sprintrc(rc)); 348 349 /* Invalid fd, valid msg pointer */ 350 rc = syscall(__NR_mq_timedreceive, bogus_fd, msg, bogus_size, 351 bogus_prio_ptr, bogus_tmout); 352 printf("mq_timedreceive(%d, %p, %llu, %p, {tv_sec=%lld, tv_nsec=%llu}) " 353 "= %s\n", 354 (int) bogus_fd, msg, (unsigned long long) bogus_size, 355 bogus_prio_ptr, (long long) bogus_tmout->tv_sec, 356 zero_extend_signed_to_ull(bogus_tmout->tv_nsec), sprintrc(rc)); 357 358 359 /* mq_notify */ 360 361 /* Zero values */ 362 rc = syscall(__NR_mq_notify, bogus_zero, NULL); 363 printf("mq_notify(0, NULL) = %s\n", sprintrc(rc)); 364 365 /* Invalid pointer */ 366 rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev + 1); 367 printf("mq_notify(%d, %p) = %s\n", 368 (int) bogus_fd, bogus_sev + 1, sprintrc(rc)); 369 370 /* Invalid SIGEV_* */ 371 rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev); 372 printf("mq_notify(%d, {sigev_value={sival_int=%d, sival_ptr=%#lx}" 373 ", sigev_signo=%u, sigev_notify=%#x /* SIGEV_??? */}) = %s\n", 374 (int) bogus_fd, bogus_sev->sigev_value.sival_int, 375 bogus_sev->sigev_value.sival_ptr, 376 bogus_sev->sigev_signo, bogus_sev->sigev_notify, 377 sprintrc(rc)); 378 379 /* SIGEV_NONE */ 380 bogus_sev->sigev_notify = SIGEV_NONE; 381 rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev); 382 printf("mq_notify(%d, {sigev_value={sival_int=%d, sival_ptr=%#lx}" 383 ", sigev_signo=%u, sigev_notify=SIGEV_NONE}) = %s\n", 384 (int) bogus_fd, bogus_sev->sigev_value.sival_int, 385 bogus_sev->sigev_value.sival_ptr, 386 bogus_sev->sigev_signo, sprintrc(rc)); 387 388 /* SIGEV_SIGNAL */ 389 bogus_sev->sigev_notify = SIGEV_SIGNAL; 390 bogus_sev->sigev_signo = SIGALRM; 391 rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev); 392 printf("mq_notify(%d, {sigev_value={sival_int=%d, sival_ptr=%#lx}" 393 ", sigev_signo=SIGALRM, sigev_notify=SIGEV_SIGNAL}) = %s\n", 394 (int) bogus_fd, bogus_sev->sigev_value.sival_int, 395 bogus_sev->sigev_value.sival_ptr, sprintrc(rc)); 396 397 /* SIGEV_THREAD */ 398 bogus_sev->sigev_notify = SIGEV_THREAD; 399 bogus_sev->sigev_un.sigev_thread.function = 400 (unsigned long) 0xdeadbeefbadc0dedULL; 401 bogus_sev->sigev_un.sigev_thread.attribute = 402 (unsigned long) 0xcafef00dfacefeedULL; 403 rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev); 404 printf("mq_notify(%d, {sigev_value={sival_int=%d, sival_ptr=%#lx}" 405 ", sigev_signo=SIGALRM, sigev_notify=SIGEV_THREAD" 406 ", sigev_notify_function=%#lx, sigev_notify_attributes=%#lx})" 407 " = %s\n", 408 (int) bogus_fd, bogus_sev->sigev_value.sival_int, 409 bogus_sev->sigev_value.sival_ptr, 410 bogus_sev->sigev_un.sigev_thread.function, 411 bogus_sev->sigev_un.sigev_thread.attribute, sprintrc(rc)); 412 413 /* mq_unlink */ 414 415 /* Zero values */ 416 rc = syscall(__NR_mq_unlink, NULL); 417 printf("mq_unlink(NULL) = %s\n", sprintrc(rc)); 418 419 /* Invalid ptr */ 420 rc = syscall(__NR_mq_unlink, msg + MSG_SIZE); 421 printf("mq_unlink(%p) = %s\n", msg + MSG_SIZE, sprintrc(rc)); 422 423 /* Long unterminated string */ 424 rc = syscall(__NR_mq_unlink, msg); 425 errstr = sprintrc(rc); 426 printf("mq_unlink(%p) = %s\n", msg, errstr); 427 428 429 /* Sending and receiving test */ 430 431 if (asprintf(&mq_name, "strace-mq_sendrecv-%u.sample", getpid()) < 0) 432 perror_msg_and_fail("asprintf"); 433 434 # if DUMPIO_READ || DUMPIO_WRITE 435 close(0); 436 # endif 437 bogus_attrs[1] = 2; 438 bogus_attrs[2] = MSG_SIZE; 439 fd = rc = syscall(__NR_mq_open, mq_name, 440 O_CREAT|O_RDWR|O_NONBLOCK, S_IRWXU, bogus_attrs); 441 errstr = sprintrc(rc); 442 if (rc < 0) 443 perror_msg_and_skip("mq_open"); 444 else 445 atexit(cleanup); 446 # if DUMPIO_READ || DUMPIO_WRITE 447 if (fd != 0) 448 error_msg_and_skip("mq_open returned fd other than 0"); 449 # endif 450 fill_memory_ex(bogus_attrs, sizeof(*bogus_attrs) * NUM_ATTRS, 451 0xbb, 0x70); 452 printf("mq_open(\"%s\", O_RDWR|O_CREAT|O_NONBLOCK, 0700" 453 ", {mq_flags=%#llx, mq_maxmsg=2, mq_msgsize=%u" 454 ", mq_curmsgs=%lld}) = %s\n", 455 mq_name, (unsigned long long) (kernel_ulong_t) bogus_attrs[0], 456 MSG_SIZE, (long long) bogus_attrs[3], errstr); 457 458 rc = syscall(__NR_mq_getsetattr, fd, NULL, bogus_attrs); 459 if (rc < 0) 460 perror_msg_and_skip("mq_getsetattr"); 461 if ((bogus_attrs[1] < 2) || (bogus_attrs[2] < MSG_SIZE)) 462 error_msg_and_skip("mq too small"); 463 464 do_send(fd, msg, MSG_CUT, future_tmout, false); 465 do_send(fd, msg, MSG_SIZE, future_tmout, true); 466 467 memset(msg, '\0', MSG_SIZE); 468 do_recv(fd, msg, MSG_CUT, future_tmout, false); 469 470 memset(msg, '\0', MSG_SIZE); 471 do_recv(fd, msg, MSG_SIZE, future_tmout, true); 472 473 return 0; 474 } 475 476 #else 477 478 SKIP_MAIN_UNDEFINED("__NR_mq_open && __NR_mq_timedsend && " 479 "__NR_mq_timedreceive && __NR_mq_notify && __NR_mq_unlink"); 480 481 #endif 482