diff options
author | Eugene Syromyatnikov <evgsyr@gmail.com> | 2016-10-27 10:18:44 +0300 |
---|---|---|
committer | Eugene Syromyatnikov <evgsyr@gmail.com> | 2016-11-09 04:27:53 +0300 |
commit | 62218efa6cfd382d9519ae7d93c427948aa89dfa (patch) | |
tree | b21a87bb5aac05278bf79af2e0847da313ab55c3 /tests/mq_sendrecv.c | |
parent | 64ac9ee78535ec3921445a213fdb2c5f4efc1083 (diff) | |
download | strace-62218efa6cfd382d9519ae7d93c427948aa89dfa.tar.gz |
tests: check decoding of mq_{notify,open,timedreceive,timedsend,unlink}
* tests/mq_sendrecv.c: New file.
* tests/mq_sendrecv-read.c: Likewise.
* tests/mq_sendrecv-write.c: Likewise.
* tests/mq_sendrecv.test: New test.
* tests/mq_sendrecv-read.test: Likewise.
* tests/mq_sendrecv-write.test: Likewise.
* tests/.gitignore: Add mq_sendrecv, mq_sendrecv-read,
and mq_sendrecv-write.
* tests/Makefile.am (check_PROGRAMS): Likewise.
(mq_sendrecv_LDADD, mq_sendrecv_read_LDADD, mq_sendrecv_write_LDADD):
New variables.
(DECODER_TESTS): Add mq_sendrecv.test, mq_sendrecv-read.test,
and mq_sendrecv-write.test.
Diffstat (limited to 'tests/mq_sendrecv.c')
-rw-r--r-- | tests/mq_sendrecv.c | 479 |
1 files changed, 479 insertions, 0 deletions
diff --git a/tests/mq_sendrecv.c b/tests/mq_sendrecv.c new file mode 100644 index 000000000..de6464b3f --- /dev/null +++ b/tests/mq_sendrecv.c @@ -0,0 +1,479 @@ +/* + * Check decoding of mq_open, mq_timedsend, mq_notify, mq_timedreceive and + * mq_unlink syscalls. + * + * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "tests.h" + +#include <asm/unistd.h> + +#if defined __NR_mq_open && __NR_mq_timedsend && __NR_mq_timedreceive && \ + __NR_mq_notify && __NR_mq_unlink + +# include <assert.h> +# include <errno.h> +# include <fcntl.h> +# include <inttypes.h> +# include <signal.h> +# include <stdbool.h> +# include <stdio.h> +# include <stdlib.h> +# include <string.h> +# include <time.h> +# include <unistd.h> + +# include "kernel_types.h" +# include "sigevent.h" + +# ifndef MQ_NAME +# define MQ_NAME "mq_sendrecv.sample" +# endif + +# ifndef DUMPIO_READ +# define DUMPIO_READ 0 +# endif + +# ifndef DUMPIO_WRITE +# define DUMPIO_WRITE 0 +# endif + + +enum { + NUM_ATTRS = 8, + MSG_CUT = 8, + MSG_MAX_UNCUT = 32, + MSG_SIZE = 64, + MSG_START = 0x80, +}; + + +static void +printstr(unsigned char start, unsigned int count) +{ + unsigned int i; + + printf("\""); + for (i = 0; i < count; i++) { + printf("\\%hho", (unsigned char) (start + i)); + } + printf("\""); +} + +#if DUMPIO_READ || DUMPIO_WRITE +static void +dumpstr(unsigned char start, unsigned int count) +{ + unsigned int i; + unsigned int j; + + for (i = 0; i < count; i++) { + if (i < count) { + if (!(i % 16)) + printf(" | %05x ", i); + if (!(i % 8)) + printf(" "); + + printf("%02hhx ", (unsigned char) (start + i)); + } + + if ((i % 16 == 15) || (i == (count - 1))) { + if (i % 16 != 15) + printf("%*s", 3 * (15 - i % 16) + + ((i + 8) % 16) / 8, " "); + + printf(" "); + + for (j = 0; j <= (i % 16); j++) + printf("."); + for (j = i % 16; j < 15; j++) + printf(" "); + + printf(" |\n"); + + } + } +} +#endif /* DUMPIO_READ || DUMPIO_WRITE */ + +static void +cleanup(void) +{ + long rc; + + rc = syscall(__NR_mq_unlink, MQ_NAME); + printf("mq_unlink(\"" MQ_NAME "\") = %s\n", sprintrc(rc)); + + puts("+++ exited with 0 +++"); +} + +static void +do_send(int fd, char *msg, unsigned int msg_size, struct timespec *tmout, + bool cropped) +{ + long rc; + long saved_errno; + + do { + rc = syscall(__NR_mq_timedsend, fd, msg, msg_size, 42, + tmout); + saved_errno = errno; + printf("mq_timedsend(%d, ", fd); + printstr(MSG_START, msg_size > MSG_MAX_UNCUT ? MSG_MAX_UNCUT : + msg_size); + if (cropped) + printf("..."); + errno = saved_errno; + printf(", %u, 42, {%jd, %jd}) = %s\n", msg_size, + (intmax_t) tmout->tv_sec, (intmax_t) tmout->tv_nsec, + sprintrc(rc)); + errno = saved_errno; + + if (rc == -1) { + if (errno == EINTR) + continue; + perror_msg_and_skip("mq_timedsend"); + } +# if DUMPIO_WRITE + dumpstr(MSG_START, msg_size); +# endif + } while (rc); +} + +static void +do_recv(int fd, char *msg, unsigned int msg_size, struct timespec *tmout, + bool cropped) +{ + long rc; + long saved_errno; + unsigned prio; + + do { + rc = syscall(__NR_mq_timedreceive, fd, msg, MSG_SIZE, &prio, + tmout); + saved_errno = errno; + printf("mq_timedreceive(%d, ", fd); + if (rc >= 0) { + printstr(MSG_START, rc > MSG_MAX_UNCUT ? MSG_MAX_UNCUT : + rc); + if (cropped) + printf("..."); + } else { + printf("%p", msg); + } + errno = saved_errno; + printf(", %u, [42], {%jd, %jd}) = %s\n", MSG_SIZE, + (intmax_t) tmout->tv_sec, + (intmax_t) tmout->tv_nsec, sprintrc(rc)); + errno = saved_errno; + + if (rc == -1) { + if (errno == EINTR) + continue; + perror_msg_and_skip("mq_timedreceive"); + } + if ((rc >= 0) && ((unsigned long) rc != msg_size)) + error_msg_and_skip("mq_timedreceive size mismatch" + ": expected %u, got %ld", + msg_size, rc); +# if DUMPIO_READ + dumpstr(MSG_START, rc); +# endif + } while (rc < 0); +} + +int +main(void) +{ + static const kernel_ulong_t bogus_zero = + (kernel_ulong_t) 0x8765432100000000ULL; + static const kernel_ulong_t bogus_oflags = + (kernel_ulong_t) 0xdefaced100000003ULL; + static const kernel_ulong_t bogus_mode = + (kernel_ulong_t) 0xdec0deadfacefeedULL; + static const kernel_ulong_t bogus_fd = + (kernel_ulong_t) 0xfeedfacedeadba5eULL; + static const kernel_ulong_t bogus_zero_size = + (sizeof(kernel_ulong_t) > sizeof(int)) ? (kernel_ulong_t) 0 : + (kernel_ulong_t) 0xface1e5500000000ULL; + static const kernel_ulong_t bogus_size = + (kernel_ulong_t) 0xbadc0dedda7a1057ULL; + static const kernel_ulong_t bogus_prio = + (kernel_ulong_t) 0xdec0ded1defaced3ULL; + static const struct timespec bogus_tmout_data = { + .tv_sec = (time_t) 0xdeadfacebeeff00dLL, + .tv_nsec = (long) 0xfacefee1deadfeedLL, + }; + static const struct timespec future_tmout_data = { + .tv_sec = (time_t) 0x7ea1fade7e57faceLL, + .tv_nsec = 999999999, + };; + struct_sigevent bogus_sev_data = { + .sigev_notify = 0xdefaced, + .sigev_signo = 0xfacefeed, + .sigev_value.sival_ptr = (unsigned long) 0xdeadbeefbadc0ded + }; + + const char *errstr; + long rc; + kernel_long_t *bogus_attrs = tail_alloc(sizeof(*bogus_attrs) * + NUM_ATTRS); + char *msg = tail_alloc(MSG_SIZE); + unsigned *bogus_prio_ptr = tail_alloc(sizeof(*bogus_prio_ptr)); + struct timespec *bogus_tmout = tail_memdup(&bogus_tmout_data, + sizeof(*bogus_tmout)); + struct timespec *future_tmout = tail_memdup(&future_tmout_data, + sizeof(*future_tmout)); + struct_sigevent *bogus_sev = tail_memdup(&bogus_sev_data, + sizeof(*bogus_sev)); + int fd = -1; + + + fill_memory_ex(msg, MSG_SIZE, MSG_START, MSG_SIZE); + fill_memory_ex((char *) bogus_attrs, sizeof(*bogus_attrs) * NUM_ATTRS, + 0xbb, 0x70); + + + /* mq_open */ + + /* Zero values, non-O_CREAT mode */ + rc = syscall(__NR_mq_open, NULL, bogus_zero, bogus_mode, NULL); + printf("mq_open(NULL, O_RDONLY) = %s\n", sprintrc(rc)); + + /* O_CREAT parsing, other flags, bogs values */ + rc = syscall(__NR_mq_open, msg, O_CREAT | bogus_oflags, bogus_mode, + NULL); + printf("mq_open(%p, O_ACCMODE|O_CREAT, %#o, NULL) = %s\n", + msg, (unsigned short) bogus_mode, sprintrc(rc)); + + /* Partially invalid attributes structure */ + rc = syscall(__NR_mq_open, msg, O_CREAT | bogus_oflags, bogus_mode, + bogus_attrs + 1); + printf("mq_open(%p, O_ACCMODE|O_CREAT, %#o, %p) = %s\n", + msg, (unsigned short) bogus_mode, bogus_attrs + 1, sprintrc(rc)); + + /* Valid attributes structure */ + rc = syscall(__NR_mq_open, msg, O_CREAT | bogus_oflags, bogus_mode, + bogus_attrs); + printf("mq_open(%p, O_ACCMODE|O_CREAT, %#o, {mq_flags=%#llx, " + "mq_maxmsg=%lld, mq_msgsize=%lld, mq_curmsgs=%lld}) = %s\n", + msg, (unsigned short) bogus_mode, + (unsigned long long) (kernel_ulong_t) bogus_attrs[0], + (long long) bogus_attrs[1], + (long long) bogus_attrs[2], + (long long) bogus_attrs[3], sprintrc(rc)); + + + /* mq_timedsend */ + + /* Zero values*/ + rc = syscall(__NR_mq_timedsend, bogus_zero, NULL, bogus_zero_size, + bogus_zero, NULL); + printf("mq_timedsend(0, NULL, 0, 0, NULL) = %s\n", sprintrc(rc)); + + /* Invalid pointers */ + rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_SIZE, bogus_size, + bogus_prio, bogus_tmout + 1); + printf("mq_timedsend(%d, %p, %llu, %u, %p) = %s\n", + (int) bogus_fd, msg + MSG_SIZE, (unsigned long long) bogus_size, + (unsigned) bogus_prio, bogus_tmout + 1, sprintrc(rc)); + + /* Partially invalid message (memory only partially available) */ + rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_SIZE - MSG_CUT, + MSG_SIZE, bogus_prio, bogus_tmout); + printf("mq_timedsend(%d, %p, %llu, %u, {%jd, %jd}) = %s\n", + (int) bogus_fd, msg + MSG_SIZE - MSG_CUT, + (unsigned long long) MSG_SIZE, (unsigned) bogus_prio, + (intmax_t) bogus_tmout->tv_sec, (intmax_t) bogus_tmout->tv_nsec, + sprintrc(rc)); + + /* Fully valid message, uncut */ + rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_SIZE - MSG_CUT, + MSG_CUT, bogus_prio, bogus_tmout); + errstr = sprintrc(rc); + printf("mq_timedsend(%d, ", (int) bogus_fd); + printstr(MSG_START + MSG_SIZE - MSG_CUT, MSG_CUT); + printf(", %llu, %u, {%jd, %jd}) = %s\n", + (unsigned long long) MSG_CUT, (unsigned) bogus_prio, + (intmax_t) bogus_tmout->tv_sec, (intmax_t) bogus_tmout->tv_nsec, + errstr); + + /* Partially invalid message, cut at maxstrlen */ + rc = syscall(__NR_mq_timedsend, bogus_fd, msg + MSG_CUT, MSG_SIZE, + bogus_prio, bogus_tmout); + errstr = sprintrc(rc); + printf("mq_timedsend(%d, ", (int) bogus_fd); + printstr(MSG_START + MSG_CUT, MSG_MAX_UNCUT); + printf("..., %llu, %u, {%jd, %jd}) = %s\n", + (unsigned long long) MSG_SIZE, (unsigned) bogus_prio, + (intmax_t) bogus_tmout->tv_sec, (intmax_t) bogus_tmout->tv_nsec, + errstr); + + + /* mq_timedreceive */ + + /* Zero values */ + rc = syscall(__NR_mq_timedreceive, bogus_zero, NULL, bogus_zero_size, + NULL, NULL); + printf("mq_timedreceive(0, NULL, 0, NULL, NULL) = %s\n", sprintrc(rc)); + + /* Invalid addresses */ + rc = syscall(__NR_mq_timedreceive, bogus_fd, msg + MSG_SIZE, bogus_size, + bogus_prio_ptr + 1, bogus_tmout + 1); + printf("mq_timedreceive(%d, %p, %llu, %p, %p) = %s\n", + (int) bogus_fd, msg + MSG_SIZE, (unsigned long long) bogus_size, + bogus_prio_ptr + 1, bogus_tmout + 1, sprintrc(rc)); + + /* Invalid fd, valid msg pointer */ + rc = syscall(__NR_mq_timedreceive, bogus_fd, msg, bogus_size, + bogus_prio_ptr, bogus_tmout); + printf("mq_timedreceive(%d, %p, %llu, %p, {%jd, %jd}) = %s\n", + (int) bogus_fd, msg, (unsigned long long) bogus_size, + bogus_prio_ptr, (intmax_t) bogus_tmout->tv_sec, + (intmax_t) bogus_tmout->tv_nsec, sprintrc(rc)); + + + /* mq_notify */ + + /* Zero values */ + rc = syscall(__NR_mq_notify, bogus_zero, NULL); + printf("mq_notify(0, NULL) = %s\n", sprintrc(rc)); + + /* Invalid pointer */ + rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev + 1); + printf("mq_notify(%d, %p) = %s\n", + (int) bogus_fd, bogus_sev + 1, sprintrc(rc)); + + /* Invalid SIGEV_* */ + rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev); + printf("mq_notify(%d, {sigev_value={int=%d, ptr=%#lx}" + ", sigev_signo=%u, sigev_notify=%#x /* SIGEV_??? */}) = %s\n", + (int) bogus_fd, bogus_sev->sigev_value.sival_int, + bogus_sev->sigev_value.sival_ptr, + bogus_sev->sigev_signo, bogus_sev->sigev_notify, + sprintrc(rc)); + + /* SIGEV_NONE */ + bogus_sev->sigev_notify = SIGEV_NONE; + rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev); + printf("mq_notify(%d, {sigev_value={int=%d, ptr=%#lx}, " + "sigev_signo=%u, sigev_notify=SIGEV_NONE}) = %s\n", + (int) bogus_fd, bogus_sev->sigev_value.sival_int, + bogus_sev->sigev_value.sival_ptr, + bogus_sev->sigev_signo, sprintrc(rc)); + + /* SIGEV_SIGNAL */ + bogus_sev->sigev_notify = SIGEV_SIGNAL; + bogus_sev->sigev_signo = SIGALRM; + rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev); + printf("mq_notify(%d, {sigev_value={int=%d, ptr=%#lx}, " + "sigev_signo=SIGALRM, sigev_notify=SIGEV_SIGNAL}) = %s\n", + (int) bogus_fd, bogus_sev->sigev_value.sival_int, + bogus_sev->sigev_value.sival_ptr, sprintrc(rc)); + + /* SIGEV_THREAD */ + bogus_sev->sigev_notify = SIGEV_THREAD; + bogus_sev->sigev_un.sigev_thread.function = + (unsigned long) 0xdeadbeefbadc0ded; + bogus_sev->sigev_un.sigev_thread.attribute = + (unsigned long) 0xcafef00dfacefeed; + rc = syscall(__NR_mq_notify, bogus_fd, bogus_sev); + printf("mq_notify(%d, {sigev_value={int=%d, ptr=%#lx}, " + "sigev_signo=SIGALRM, sigev_notify=SIGEV_THREAD, " + "sigev_notify_function=%#lx, sigev_notify_attributes=%#lx}) = " + "%s\n", + (int) bogus_fd, bogus_sev->sigev_value.sival_int, + bogus_sev->sigev_value.sival_ptr, + bogus_sev->sigev_un.sigev_thread.function, + bogus_sev->sigev_un.sigev_thread.attribute, sprintrc(rc)); + + /* mq_unlink */ + + /* Zero values */ + rc = syscall(__NR_mq_unlink, NULL); + printf("mq_unlink(NULL) = %s\n", sprintrc(rc)); + + /* Invalid ptr */ + rc = syscall(__NR_mq_unlink, msg + MSG_SIZE); + printf("mq_unlink(%p) = %s\n", msg + MSG_SIZE, sprintrc(rc)); + + /* Long unterminated string */ + rc = syscall(__NR_mq_unlink, msg); + errstr = sprintrc(rc); + printf("mq_unlink(%p) = %s\n", msg, errstr); + + + /* Sending and receiving test */ + +# if DUMPIO_READ || DUMPIO_WRITE + close(0); +# endif + bogus_attrs[1] = 2; + bogus_attrs[2] = MSG_SIZE; + fd = rc = syscall(__NR_mq_open, MQ_NAME, + O_CREAT|O_RDWR|O_NONBLOCK, S_IRWXU, bogus_attrs); + errstr = sprintrc(rc); + if (rc < 0) + perror_msg_and_skip("mq_open"); + else + atexit(cleanup); +# if DUMPIO_READ || DUMPIO_WRITE + if (fd != 0) + error_msg_and_skip("mq_open returned fd other than 0"); +# endif + fill_memory_ex((char *) bogus_attrs, sizeof(*bogus_attrs) * NUM_ATTRS, + 0xbb, 0x70); + printf("mq_open(\"" MQ_NAME "\", O_RDWR|O_CREAT|O_NONBLOCK, " + "0700, {mq_flags=%#llx, mq_maxmsg=2, mq_msgsize=%u, " + "mq_curmsgs=%lld}) = %s\n", + (unsigned long long) (kernel_ulong_t) bogus_attrs[0], MSG_SIZE, + (long long) bogus_attrs[3], errstr); + + rc = syscall(__NR_mq_getsetattr, fd, NULL, bogus_attrs); + if (rc < 0) + perror_msg_and_skip("mq_getsetattr"); + if ((bogus_attrs[1] < 2) || (bogus_attrs[2] < MSG_SIZE)) + error_msg_and_skip("mq too small"); + + do_send(fd, msg, MSG_CUT, future_tmout, false); + do_send(fd, msg, MSG_SIZE, future_tmout, true); + + memset(msg, '\0', MSG_SIZE); + do_recv(fd, msg, MSG_CUT, future_tmout, false); + + memset(msg, '\0', MSG_SIZE); + do_recv(fd, msg, MSG_SIZE, future_tmout, true); + + return 0; +} + +#else + +SKIP_MAIN_UNDEFINED("__NR_mq_open && __NR_mq_timedsend && " + "__NR_mq_timedreceive && __NR_mq_notify && __NR_mq_unlink"); + +#endif |