2 * Check decoding of mq_open, mq_timedsend, mq_notify, mq_timedreceive and
5 * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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.
33 #include <asm/unistd.h>
35 #if defined __NR_mq_open && __NR_mq_timedsend && __NR_mq_timedreceive && \
36 __NR_mq_notify && __NR_mq_unlink
41 # include <inttypes.h>
50 # include "kernel_types.h"
51 # include "sigevent.h"
54 # define MQ_NAME "mq_sendrecv.sample"
58 # define DUMPIO_READ 0
62 # define DUMPIO_WRITE 0
76 printstr(unsigned char start, unsigned int count)
81 for (i = 0; i < count; i++) {
82 printf("\\%hho", (unsigned char) (start + i));
87 #if DUMPIO_READ || DUMPIO_WRITE
89 dumpstr(unsigned char start, unsigned int count)
94 for (i = 0; i < count; i++) {
97 printf(" | %05x ", i);
101 printf("%02hhx ", (unsigned char) (start + i));
104 if ((i % 16 == 15) || (i == (count - 1))) {
106 printf("%*s", 3 * (15 - i % 16) +
107 ((i + 8) % 16) / 8, " ");
111 for (j = 0; j <= (i % 16); j++)
113 for (j = i % 16; j < 15; j++)
121 #endif /* DUMPIO_READ || DUMPIO_WRITE */
128 rc = syscall(__NR_mq_unlink, MQ_NAME);
129 printf("mq_unlink(\"" MQ_NAME "\") = %s\n", sprintrc(rc));
131 puts("+++ exited with 0 +++");
135 do_send(int fd, char *msg, unsigned int msg_size, struct timespec *tmout,
142 rc = syscall(__NR_mq_timedsend, fd, msg, msg_size, 42,
145 printf("mq_timedsend(%d, ", fd);
146 printstr(MSG_START, msg_size > MSG_MAX_UNCUT ? MSG_MAX_UNCUT :
151 printf(", %u, 42, {tv_sec=%jd, tv_nsec=%jd}) = %s\n", msg_size,
152 (intmax_t) tmout->tv_sec, (intmax_t) tmout->tv_nsec,
159 perror_msg_and_skip("mq_timedsend");
162 dumpstr(MSG_START, msg_size);
168 do_recv(int fd, char *msg, unsigned int msg_size, struct timespec *tmout,
176 rc = syscall(__NR_mq_timedreceive, fd, msg, MSG_SIZE, &prio,
179 printf("mq_timedreceive(%d, ", fd);
181 printstr(MSG_START, rc > MSG_MAX_UNCUT ? MSG_MAX_UNCUT :
189 printf(", %u, [42], {tv_sec=%jd, tv_nsec=%jd}) = %s\n", MSG_SIZE,
190 (intmax_t) tmout->tv_sec,
191 (intmax_t) tmout->tv_nsec, sprintrc(rc));
197 perror_msg_and_skip("mq_timedreceive");
199 if ((rc >= 0) && ((unsigned long) rc != msg_size))
200 error_msg_and_skip("mq_timedreceive size mismatch"
201 ": expected %u, got %ld",
204 dumpstr(MSG_START, rc);
212 static const kernel_ulong_t bogus_zero =
213 (kernel_ulong_t) 0x8765432100000000ULL;
214 static const kernel_ulong_t bogus_oflags =
215 (kernel_ulong_t) 0xdefaced100000003ULL;
216 static const kernel_ulong_t bogus_mode =
217 (kernel_ulong_t) 0xdec0deadfacefeedULL;
218 static const kernel_ulong_t bogus_fd =
219 (kernel_ulong_t) 0xfeedfacedeadba5eULL;
220 static const kernel_ulong_t bogus_zero_size =
221 (sizeof(kernel_ulong_t) > sizeof(int)) ? (kernel_ulong_t) 0 :
222 (kernel_ulong_t) 0xface1e5500000000ULL;
223 static const kernel_ulong_t bogus_size =
224 (kernel_ulong_t) 0xbadc0dedda7a1057ULL;
225 static const kernel_ulong_t bogus_prio =
226 (kernel_ulong_t) 0xdec0ded1defaced3ULL;
227 static const struct timespec bogus_tmout_data = {
228 .tv_sec = (time_t) 0xdeadfacebeeff00dLL,
229 .tv_nsec = (long) 0xfacefee1deadfeedLL,
231 static const struct timespec future_tmout_data = {
232 .tv_sec = (time_t) 0x7ea1fade7e57faceLL,
233 .tv_nsec = 999999999,
235 struct_sigevent bogus_sev_data = {
236 .sigev_notify = 0xdefaced,
237 .sigev_signo = 0xfacefeed,
238 .sigev_value.sival_ptr = (unsigned long) 0xdeadbeefbadc0dedULL
243 kernel_long_t *bogus_attrs = tail_alloc(sizeof(*bogus_attrs) *
245 char *msg = tail_alloc(MSG_SIZE);
246 unsigned *bogus_prio_ptr = tail_alloc(sizeof(*bogus_prio_ptr));
247 struct timespec *bogus_tmout = tail_memdup(&bogus_tmout_data,
248 sizeof(*bogus_tmout));
249 struct timespec *future_tmout = tail_memdup(&future_tmout_data,
250 sizeof(*future_tmout));
251 struct_sigevent *bogus_sev = tail_memdup(&bogus_sev_data,
256 fill_memory_ex(msg, MSG_SIZE, MSG_START, MSG_SIZE);
257 fill_memory_ex((char *) bogus_attrs, sizeof(*bogus_attrs) * NUM_ATTRS,
263 /* Zero values, non-O_CREAT mode */
264 rc = syscall(__NR_mq_open, NULL, bogus_zero, bogus_mode, NULL);
265 printf("mq_open(NULL, O_RDONLY) = %s\n", sprintrc(rc));
267 /* O_CREAT parsing, other flags, bogs values */
268 rc = syscall(__NR_mq_open, msg, O_CREAT | bogus_oflags, bogus_mode,
270 printf("mq_open(%p, O_ACCMODE|O_CREAT, %#o, NULL) = %s\n",
271 msg, (unsigned short) bogus_mode, sprintrc(rc));
273 /* Partially invalid attributes structure */
274 rc = syscall(__NR_mq_open, msg, O_CREAT | bogus_oflags, bogus_mode,
276 printf("mq_open(%p, O_ACCMODE|O_CREAT, %#o, %p) = %s\n",
277 msg, (unsigned short) bogus_mode, bogus_attrs + 1, sprintrc(rc));
279 /* Valid attributes structure */
280 rc = syscall(__NR_mq_open, msg, O_CREAT | bogus_oflags, bogus_mode,
282 printf("mq_open(%p, O_ACCMODE|O_CREAT, %#o, {mq_flags=%#llx, "
283 "mq_maxmsg=%lld, mq_msgsize=%lld, mq_curmsgs=%lld}) = %s\n",
284 msg, (unsigned short) bogus_mode,
285 (unsigned long long) (kernel_ulong_t) bogus_attrs[0],
286 (long long) bogus_attrs[1],
287 (long long) bogus_attrs[2],
288 (long long) bogus_attrs[3], sprintrc(rc));
294 rc = syscall(__NR_mq_timedsend, bogus_zero, NULL, bogus_zero_size,
296 printf("mq_timedsend(0, NULL, 0, 0, NULL) = %s\n", sprintrc(rc));
298 /* Invalid pointers */
299 rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_SIZE, bogus_size,
300 bogus_prio, bogus_tmout + 1);
301 printf("mq_timedsend(%d, %p, %llu, %u, %p) = %s\n",
302 (int) bogus_fd, msg + MSG_SIZE, (unsigned long long) bogus_size,
303 (unsigned) bogus_prio, bogus_tmout + 1, sprintrc(rc));
305 /* Partially invalid message (memory only partially available) */
306 rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_SIZE - MSG_CUT,
307 MSG_SIZE, bogus_prio, bogus_tmout);
308 printf("mq_timedsend(%d, %p, %llu, %u, {tv_sec=%jd, tv_nsec=%jd}) = "
310 (int) bogus_fd, msg + MSG_SIZE - MSG_CUT,
311 (unsigned long long) MSG_SIZE, (unsigned) bogus_prio,
312 (intmax_t) bogus_tmout->tv_sec, (intmax_t) bogus_tmout->tv_nsec,
315 /* Fully valid message, uncut */
316 rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_SIZE - MSG_CUT,
317 MSG_CUT, bogus_prio, bogus_tmout);
318 errstr = sprintrc(rc);
319 printf("mq_timedsend(%d, ", (int) bogus_fd);
320 printstr(MSG_START + MSG_SIZE - MSG_CUT, MSG_CUT);
321 printf(", %llu, %u, {tv_sec=%jd, tv_nsec=%jd}) = %s\n",
322 (unsigned long long) MSG_CUT, (unsigned) bogus_prio,
323 (intmax_t) bogus_tmout->tv_sec, (intmax_t) bogus_tmout->tv_nsec,
326 /* Partially invalid message, cut at maxstrlen */
327 rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_CUT, MSG_SIZE,
328 bogus_prio, bogus_tmout);
329 errstr = sprintrc(rc);
330 printf("mq_timedsend(%d, ", (int) bogus_fd);
331 printstr(MSG_START + MSG_CUT, MSG_MAX_UNCUT);
332 printf("..., %llu, %u, {tv_sec=%jd, tv_nsec=%jd}) = %s\n",
333 (unsigned long long) MSG_SIZE, (unsigned) bogus_prio,
334 (intmax_t) bogus_tmout->tv_sec, (intmax_t) bogus_tmout->tv_nsec,
338 /* mq_timedreceive */
341 rc = syscall(__NR_mq_timedreceive, bogus_zero, NULL, bogus_zero_size,
343 printf("mq_timedreceive(0, NULL, 0, NULL, NULL) = %s\n", sprintrc(rc));
345 /* Invalid addresses */
346 rc = syscall(__NR_mq_timedreceive, bogus_fd, msg + MSG_SIZE, bogus_size,
347 bogus_prio_ptr + 1, bogus_tmout + 1);
348 printf("mq_timedreceive(%d, %p, %llu, %p, %p) = %s\n",
349 (int) bogus_fd, msg + MSG_SIZE, (unsigned long long) bogus_size,
350 bogus_prio_ptr + 1, bogus_tmout + 1, sprintrc(rc));
352 /* Invalid fd, valid msg pointer */
353 rc = syscall(__NR_mq_timedreceive, bogus_fd, msg, bogus_size,
354 bogus_prio_ptr, bogus_tmout);
355 printf("mq_timedreceive(%d, %p, %llu, %p, {tv_sec=%jd, tv_nsec=%jd}) = "
357 (int) bogus_fd, msg, (unsigned long long) bogus_size,
358 bogus_prio_ptr, (intmax_t) bogus_tmout->tv_sec,
359 (intmax_t) bogus_tmout->tv_nsec, sprintrc(rc));
365 rc = syscall(__NR_mq_notify, bogus_zero, NULL);
366 printf("mq_notify(0, NULL) = %s\n", sprintrc(rc));
368 /* Invalid pointer */
369 rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev + 1);
370 printf("mq_notify(%d, %p) = %s\n",
371 (int) bogus_fd, bogus_sev + 1, sprintrc(rc));
373 /* Invalid SIGEV_* */
374 rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev);
375 printf("mq_notify(%d, {sigev_value={sival_int=%d, sival_ptr=%#lx}"
376 ", sigev_signo=%u, sigev_notify=%#x /* SIGEV_??? */}) = %s\n",
377 (int) bogus_fd, bogus_sev->sigev_value.sival_int,
378 bogus_sev->sigev_value.sival_ptr,
379 bogus_sev->sigev_signo, bogus_sev->sigev_notify,
383 bogus_sev->sigev_notify = SIGEV_NONE;
384 rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev);
385 printf("mq_notify(%d, {sigev_value={sival_int=%d, sival_ptr=%#lx}, "
386 "sigev_signo=%u, sigev_notify=SIGEV_NONE}) = %s\n",
387 (int) bogus_fd, bogus_sev->sigev_value.sival_int,
388 bogus_sev->sigev_value.sival_ptr,
389 bogus_sev->sigev_signo, sprintrc(rc));
392 bogus_sev->sigev_notify = SIGEV_SIGNAL;
393 bogus_sev->sigev_signo = SIGALRM;
394 rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev);
395 printf("mq_notify(%d, {sigev_value={sival_int=%d, sival_ptr=%#lx}, "
396 "sigev_signo=SIGALRM, sigev_notify=SIGEV_SIGNAL}) = %s\n",
397 (int) bogus_fd, bogus_sev->sigev_value.sival_int,
398 bogus_sev->sigev_value.sival_ptr, sprintrc(rc));
401 bogus_sev->sigev_notify = SIGEV_THREAD;
402 bogus_sev->sigev_un.sigev_thread.function =
403 (unsigned long) 0xdeadbeefbadc0dedULL;
404 bogus_sev->sigev_un.sigev_thread.attribute =
405 (unsigned long) 0xcafef00dfacefeedULL;
406 rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev);
407 printf("mq_notify(%d, {sigev_value={sival_int=%d, sival_ptr=%#lx}, "
408 "sigev_signo=SIGALRM, sigev_notify=SIGEV_THREAD, "
409 "sigev_notify_function=%#lx, sigev_notify_attributes=%#lx}) = "
411 (int) bogus_fd, bogus_sev->sigev_value.sival_int,
412 bogus_sev->sigev_value.sival_ptr,
413 bogus_sev->sigev_un.sigev_thread.function,
414 bogus_sev->sigev_un.sigev_thread.attribute, sprintrc(rc));
419 rc = syscall(__NR_mq_unlink, NULL);
420 printf("mq_unlink(NULL) = %s\n", sprintrc(rc));
423 rc = syscall(__NR_mq_unlink, msg + MSG_SIZE);
424 printf("mq_unlink(%p) = %s\n", msg + MSG_SIZE, sprintrc(rc));
426 /* Long unterminated string */
427 rc = syscall(__NR_mq_unlink, msg);
428 errstr = sprintrc(rc);
429 printf("mq_unlink(%p) = %s\n", msg, errstr);
432 /* Sending and receiving test */
434 # if DUMPIO_READ || DUMPIO_WRITE
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);
443 perror_msg_and_skip("mq_open");
446 # if DUMPIO_READ || DUMPIO_WRITE
448 error_msg_and_skip("mq_open returned fd other than 0");
450 fill_memory_ex((char *) bogus_attrs, sizeof(*bogus_attrs) * NUM_ATTRS,
452 printf("mq_open(\"" MQ_NAME "\", O_RDWR|O_CREAT|O_NONBLOCK, "
453 "0700, {mq_flags=%#llx, mq_maxmsg=2, mq_msgsize=%u, "
454 "mq_curmsgs=%lld}) = %s\n",
455 (unsigned long long) (kernel_ulong_t) bogus_attrs[0], MSG_SIZE,
456 (long long) bogus_attrs[3], errstr);
458 rc = syscall(__NR_mq_getsetattr, fd, NULL, bogus_attrs);
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");
464 do_send(fd, msg, MSG_CUT, future_tmout, false);
465 do_send(fd, msg, MSG_SIZE, future_tmout, true);
467 memset(msg, '\0', MSG_SIZE);
468 do_recv(fd, msg, MSG_CUT, future_tmout, false);
470 memset(msg, '\0', MSG_SIZE);
471 do_recv(fd, msg, MSG_SIZE, future_tmout, true);
478 SKIP_MAIN_UNDEFINED("__NR_mq_open && __NR_mq_timedsend && "
479 "__NR_mq_timedreceive && __NR_mq_notify && __NR_mq_unlink");