]> granicus.if.org Git - strace/commitdiff
Fix multiple personalities support in parser of io_submit syscall
authorDmitry V. Levin <ldv@altlinux.org>
Wed, 26 Aug 2015 12:49:07 +0000 (12:49 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Wed, 26 Aug 2015 21:05:17 +0000 (21:05 +0000)
Introduce a new helper function to fetch tracee's long integers
and use it to fix multiple personalities support in io_submit parser.

* defs.h (umove_long_or_printaddr): New prototype.
* util.c (umove_long_or_printaddr): New function.
* aio.c (sys_io_submit): Use it to fetch tracee's pointers.
* tests/aio.c: New file.
* tests/aio.test: New test.
* tests/Makefile.am (check_PROGRAMS): Add aio.
(TESTS): Add aio.test.
* tests/.gitignore: Add aio.

aio.c
defs.h
tests/.gitignore
tests/Makefile.am
tests/aio.c [new file with mode: 0644]
tests/aio.test [new file with mode: 0755]
util.c

diff --git a/aio.c b/aio.c
index 83bb671f5482dcd33741fa2f3d655012fe1ebd01..5822a4fd94d5e7a5547e6fc1c96d311ed171bce8 100644 (file)
--- a/aio.c
+++ b/aio.c
@@ -109,26 +109,30 @@ SYS_FUNC(io_submit)
        tprintf("%lu, %ld, [", tcp->u_arg[0], tcp->u_arg[1]);
        {
                long i;
-               struct iocb **iocbs = (void *)tcp->u_arg[2];
-//FIXME: decoding of 32-bit call by 64-bit strace
+               long iocbs = tcp->u_arg[2];
 
-               for (i = 0; i < nr; i++, iocbs++) {
+               for (i = 0; i < nr; ++i, iocbs += current_wordsize) {
                        enum iocb_sub sub;
-                       struct iocb *iocbp;
+                       long iocbp;
                        struct iocb iocb;
+
                        if (i)
                                tprints(", ");
 
-                       if (umove_or_printaddr(tcp, (unsigned long)iocbs, &iocbp)) {
-                               /* No point in trying to read iocbs+1 etc */
-                               /* (nr can be ridiculously large): */
+                       if (umove_long_or_printaddr(tcp, iocbs, &iocbp)) {
+                               /*
+                                * No point in trying to read the whole array
+                                * because nr can be ridiculously large.
+                                */
                                break;
                        }
+
                        tprints("{");
-                       if (umove_or_printaddr(tcp, (unsigned long)iocbp, &iocb)) {
+                       if (umove_or_printaddr(tcp, iocbp, &iocb)) {
                                tprints("}");
                                continue;
                        }
+
                        if (iocb.data) {
                                tprints("data=");
                                printaddr((long) iocb.data);
diff --git a/defs.h b/defs.h
index 20587c71f84f9ffde723cb11e3da702ca8aac0af..7f9c3a3e0b0110bcf80226715729fa60e7896234 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -476,6 +476,7 @@ extern int umoven(struct tcb *, long, unsigned int, void *);
 extern int umoven_or_printaddr(struct tcb *, long, unsigned int, void *);
 #define umove_or_printaddr(pid, addr, objp)    \
        umoven_or_printaddr((pid), (addr), sizeof(*(objp)), (void *) (objp))
+extern int umove_long_or_printaddr(struct tcb *, long, long *);
 extern int umovestr(struct tcb *, long, unsigned int, char *);
 extern int upeek(int pid, long, long *);
 
index b272ceb7350585cb84fe99d20bd9a5baf00f1cb7..6326d40c6bcbe953f3a2d636c6317acac07ab2bf 100644 (file)
@@ -1,3 +1,4 @@
+aio
 bpf
 caps
 epoll_create1
index 0876a46f8f4eddbf31ae51a50d5004219365b977..9b1703cc9d7af672a6411f0ccb1728203523574a 100644 (file)
@@ -9,6 +9,7 @@ AM_CPPFLAGS = -I$(top_builddir)/$(OS)/$(ARCH) \
              -I$(top_srcdir)/$(OS)
 
 check_PROGRAMS = \
+       aio \
        bpf \
        caps \
        epoll_create1 \
@@ -78,6 +79,7 @@ TESTS = \
        strace-f.test \
        qual_syscall.test \
        bexecve.test \
+       aio.test \
        bpf.test \
        caps.test \
        dumpio.test \
diff --git a/tests/aio.c b/tests/aio.c
new file mode 100644 (file)
index 0000000..a59ae8e
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2015 Dmitry V. Levin <ldv@altlinux.org>
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/fcntl.h>
+#include <sys/syscall.h>
+
+#if defined __NR_io_setup \
+ && defined __NR_io_submit \
+ && defined __NR_io_getevents \
+ && defined __NR_io_destroy
+# include <linux/aio_abi.h>
+
+int
+main(void)
+{
+       static char data0[4096];
+       static char data1[8192];
+
+       struct iocb cb[2] = {
+               {
+                       .aio_data = 0x11111111,
+                       .aio_reqprio = 11,
+                       .aio_buf = (unsigned long) data0,
+                       .aio_offset = 0xdefacedfacefeed,
+                       .aio_nbytes = sizeof(data0)
+               },
+               {
+                       .aio_data = 0x22222222,
+                       .aio_reqprio = 22,
+                       .aio_buf = (unsigned long) data1,
+                       .aio_offset = 0xdefacedcafef00d,
+                       .aio_nbytes = sizeof(data1)
+               }
+       };
+
+       long cbs[4] = {
+               (long) &cb[0], (long) &cb[1],
+               0xdeadbeef, 0xbadc0ded
+       };
+
+       unsigned long ctx = 0;
+       const unsigned int nr = sizeof(cb) / sizeof(*cb);
+       const unsigned long lnr = (unsigned long) (0xdeadbeef00000000ULL | nr);
+
+       struct io_event ev[nr];
+       struct timespec ts = { .tv_nsec = 123456789 };
+
+       (void) close(0);
+       if (open("/dev/zero", O_RDONLY))
+               return 77;
+
+       if (syscall(__NR_io_setup, lnr, &ctx))
+               return 77;
+       printf("io_setup(%u, [%lu]) = 0\n", nr, ctx);
+
+       if (syscall(__NR_io_submit, ctx, nr, cbs) != (long) nr)
+               return 77;
+       printf("io_submit(%lu, %u, ["
+               "{data=%#llx, pread, reqprio=11, filedes=0, "
+                       "buf=%p, nbytes=%u, offset=%lld}, "
+               "{data=%#llx, pread, reqprio=22, filedes=0, "
+                       "buf=%p, nbytes=%u, offset=%lld}"
+               "]) = %u\n",
+              ctx, nr,
+              (unsigned long long) cb[0].aio_data, data0,
+              (unsigned int) sizeof(data0), (long long) cb[0].aio_offset,
+              (unsigned long long) cb[1].aio_data, data1,
+              (unsigned int) sizeof(data1), (long long) cb[1].aio_offset,
+              nr);
+
+       if (syscall(__NR_io_getevents, ctx, nr, nr, ev, &ts)  != (long) nr)
+               return 77;
+       printf("io_getevents(%lu, %u, %u, ["
+               "{data=%#llx, obj=%p, res=%u, res2=0}, "
+               "{data=%#llx, obj=%p, res=%u, res2=0}"
+               "], {0, 123456789}) = %u\n",
+              ctx, nr, nr,
+              (unsigned long long) cb[0].aio_data, &cb[0],
+              (unsigned int) sizeof(data0),
+              (unsigned long long) cb[1].aio_data, &cb[1],
+              (unsigned int) sizeof(data1),
+              nr);
+
+       if (syscall(__NR_io_destroy, ctx))
+               return 77;
+       printf("io_destroy(%lu) = 0\n", ctx);
+
+       puts("+++ exited with 0 +++");
+       return 0;
+}
+
+#else
+
+int
+main(void)
+{
+       return 77;
+}
+
+#endif
diff --git a/tests/aio.test b/tests/aio.test
new file mode 100755 (executable)
index 0000000..f5907e4
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# Check io_* syscalls decoding.
+
+. "${srcdir=.}/init.sh"
+
+run_prog > /dev/null
+OUT="$LOG.out"
+syscalls=io_setup,io_submit,io_getevents,io_destroy
+run_strace -a14 -e trace=$syscalls $args > "$OUT"
+match_diff "$LOG" "$OUT"
+rm -f "$OUT"
+
+exit 0
diff --git a/util.c b/util.c
index 94d9265f1b8c7abdcfd592ae538fc6b8a9da477c..d40eafc2946a7f2bde896988f5de8e0f24f743e8 100644 (file)
--- a/util.c
+++ b/util.c
@@ -1132,6 +1132,19 @@ umoven_or_printaddr(struct tcb *tcp, const long addr, const unsigned int len,
        return 0;
 }
 
+int
+umove_long_or_printaddr(struct tcb *tcp, const long addr, long *ptr)
+{
+       if (current_wordsize < sizeof(*ptr)) {
+               uint32_t val32;
+               int r = umove_or_printaddr(tcp, addr, &val32);
+               if (!r)
+                       *ptr = (unsigned long) val32;
+               return r;
+       }
+       return umove_or_printaddr(tcp, addr, ptr);
+}
+
 /*
  * Like `umove' but make the additional effort of looking
  * for a terminating zero byte.