summaryrefslogtreecommitdiff
path: root/tests/mq_sendrecv.c
diff options
context:
space:
mode:
authorEugene Syromyatnikov <evgsyr@gmail.com>2016-10-27 10:18:44 +0300
committerEugene Syromyatnikov <evgsyr@gmail.com>2016-11-09 04:27:53 +0300
commit62218efa6cfd382d9519ae7d93c427948aa89dfa (patch)
treeb21a87bb5aac05278bf79af2e0847da313ab55c3 /tests/mq_sendrecv.c
parent64ac9ee78535ec3921445a213fdb2c5f4efc1083 (diff)
downloadstrace-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.c479
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