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