]> granicus.if.org Git - strace/commitdiff
Implement name_to_handle_at and open_by_handle_at syscalls decoding
authorDmitry V. Levin <ldv@altlinux.org>
Sun, 22 Nov 2015 21:29:32 +0000 (21:29 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Sun, 22 Nov 2015 23:21:35 +0000 (23:21 +0000)
* file_handle.c: New file.
* Makefile.am (strace_SOURCES): Add it.
* linux/dummy.h (sys_name_to_handle_at, sys_open_by_handle_at):
Remove stub aliases.
* pathtrace.c (pathtrace_match): Add SEN_name_to_handle_at.
* tests/file_handle.c: New file.
* tests/file_handle.test: New test.
* tests/Makefile.am (check_PROGRAMS): Add file_handle.
(TESTS): Add file_handle.test.
* tests/.gitignore: Add file_handle.

Makefile.am
file_handle.c [new file with mode: 0644]
linux/dummy.h
pathtrace.c
tests/.gitignore
tests/Makefile.am
tests/file_handle.c [new file with mode: 0644]
tests/file_handle.test [new file with mode: 0755]

index 56f4942176baa4f9aadc83433161840242181055..1a1a647005658359546139af1cee9521af0d2b7d 100644 (file)
@@ -63,6 +63,7 @@ strace_SOURCES =      \
        fcntl.c         \
        fetch_seccomp_fprog.c \
        file.c          \
+       file_handle.c   \
        flock.c         \
        futex.c         \
        get_robust_list.c \
diff --git a/file_handle.c b/file_handle.c
new file mode 100644 (file)
index 0000000..6680101
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+#include "defs.h"
+
+#ifndef MAX_HANDLE_SZ
+# define MAX_HANDLE_SZ 128
+#endif
+
+typedef struct {
+       unsigned int handle_bytes;
+       int handle_type;
+} file_handle_header;
+
+SYS_FUNC(name_to_handle_at)
+{
+       file_handle_header h;
+       const long addr = tcp->u_arg[2];
+
+       if (entering(tcp)) {
+               /* dirfd */
+               print_dirfd(tcp, tcp->u_arg[0]);
+
+               /* pathname */
+               printpath(tcp, tcp->u_arg[1]);
+               tprints(", ");
+
+               /* handle */
+               if (umove_or_printaddr(tcp, addr, &h)) {
+                       tprints(", ");
+
+                       /* mount_id */
+                       printaddr(tcp->u_arg[3]);
+                       tprints(", ");
+
+                       /* flags */
+                       printflags(at_flags, tcp->u_arg[4], "AT_???");
+
+                       return RVAL_DECODED;
+               }
+               tprintf("{handle_bytes=%u", h.handle_bytes);
+
+               /*
+                * Abusing tcp->auxstr as a temporary storage.
+                * Will be used and cleared on syscall exit.
+                */
+               tcp->auxstr = (void *) (unsigned long) h.handle_bytes;
+
+               return 0;
+       } else {
+               unsigned int i = (unsigned long) tcp->auxstr;
+
+               if ((!syserror(tcp) || EOVERFLOW == tcp->u_error)
+                   && !umove(tcp, addr, &h)) {
+                       unsigned char f_handle[MAX_HANDLE_SZ];
+
+                       if (i != h.handle_bytes)
+                               tprintf(" => %u", h.handle_bytes);
+                       if (!syserror(tcp)) {
+                               tprintf(", handle_type=%d", h.handle_type);
+                               if (h.handle_bytes > MAX_HANDLE_SZ)
+                                       h.handle_bytes = MAX_HANDLE_SZ;
+                               if (!umoven(tcp, addr + sizeof(h), h.handle_bytes,
+                                           f_handle)) {
+                                       tprints(", f_handle=0x");
+                                       for (i = 0; i < h.handle_bytes; ++i)
+                                               tprintf("%02x", f_handle[i]);
+                               }
+                       }
+               }
+               tprints("}, ");
+               tcp->auxstr = NULL;
+
+               /* mount_id */
+               printnum_int(tcp, tcp->u_arg[3], "%d");
+               tprints(", ");
+
+               /* flags */
+               printflags(at_flags, tcp->u_arg[4], "AT_???");
+       }
+       return 0;
+}
+
+SYS_FUNC(open_by_handle_at)
+{
+       file_handle_header h;
+       const long addr = tcp->u_arg[1];
+
+       /* mount_fd */
+       printfd(tcp, tcp->u_arg[0]);
+       tprints(", ");
+
+       /* handle */
+       if (!umove_or_printaddr(tcp, addr, &h)) {
+               unsigned char f_handle[MAX_HANDLE_SZ];
+
+               tprintf("{handle_bytes=%u, handle_type=%d",
+                       h.handle_bytes, h.handle_type);
+               if (h.handle_bytes > MAX_HANDLE_SZ)
+                       h.handle_bytes = MAX_HANDLE_SZ;
+               if (!umoven(tcp, addr + sizeof(h), h.handle_bytes, &f_handle)) {
+                       unsigned int i;
+
+                       tprints(", f_handle=0x");
+                       for (i = 0; i < h.handle_bytes; ++i)
+                               tprintf("%02x", f_handle[i]);
+               }
+               tprints("}");
+       }
+       tprints(", ");
+
+       /* flags */
+       tprint_open_modes(tcp->u_arg[2]);
+
+       return RVAL_DECODED;
+}
index 3914948a75fd8956c8184df5685a2249ac507153..eeb576b22c13f26f331398b3a0d6696a424f1c28 100644 (file)
@@ -32,8 +32,6 @@
 #endif
 
 /* still unfinished */
-#define        sys_name_to_handle_at   printargs
-#define        sys_open_by_handle_at   printargs
 #define        sys_sysfs               printargs
 #define        sys_vm86                printargs
 #define        sys_vm86old             printargs
index 663f3b4b7220c349def577eec6bdb4bcf039a03b..d530ec25619aad07b2e4682576900855ea8818a1 100644 (file)
@@ -178,6 +178,7 @@ pathtrace_match(struct tcb *tcp)
        case SEN_inotify_add_watch:
        case SEN_mkdirat:
        case SEN_mknodat:
+       case SEN_name_to_handle_at:
        case SEN_newfstatat:
        case SEN_openat:
        case SEN_pipe2:
index 097d1c1e01a4a0941fe022d49c72a5629dceb6f1..1856939f952519a231ab67f19239c19320b6b81b 100644 (file)
@@ -9,6 +9,7 @@ eventfd
 execve
 execveat
 fanotify_mark
+file_handle
 filter-unavailable
 getdents
 getdents64
index 2db10c4e95cd26c6426b8caefa746f4117bf9cb1..3f3c513a875a90b924e7ae88cf3e7cd41ccc30a7 100644 (file)
@@ -22,6 +22,7 @@ check_PROGRAMS = \
        execve \
        execveat \
        fanotify_mark \
+       file_handle \
        filter-unavailable \
        getdents \
        getdents64 \
@@ -122,6 +123,7 @@ TESTS = \
        execve.test \
        execveat.test \
        fanotify_mark.test \
+       file_handle.test \
        filter-unavailable.test \
        getdents.test \
        getdents64.test \
diff --git a/tests/file_handle.c b/tests/file_handle.c
new file mode 100644 (file)
index 0000000..9351599
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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 <alloca.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#ifdef MAX_HANDLE_SZ
+
+int
+main(void)
+{
+       struct file_handle *handle =
+               alloca(sizeof(struct file_handle) + MAX_HANDLE_SZ);
+       const int dirfd = AT_FDCWD;
+       const int flags = AT_SYMLINK_FOLLOW;
+       int mount_id;
+       unsigned int i;
+
+       handle->handle_bytes = 0;
+
+       if (name_to_handle_at(dirfd, ".", handle, &mount_id, flags | 1) != -1
+           || EINVAL != errno) {
+               perror("name_to_handle_at");
+               return 77;
+       }
+       printf("name_to_handle_at(AT_FDCWD, \".\", {handle_bytes=0}, %p"
+              ", AT_SYMLINK_FOLLOW|0x1) = -1 EINVAL (Invalid argument)\n",
+              &mount_id);
+
+       if (name_to_handle_at(dirfd, ".", handle, &mount_id, flags) != -1
+           || EOVERFLOW != errno) {
+               perror("name_to_handle_at");
+               return 77;
+       }
+       printf("name_to_handle_at(AT_FDCWD, \".\", {handle_bytes=0 => %u}"
+              ", %p, AT_SYMLINK_FOLLOW) = -1 EOVERFLOW"
+              " (Value too large for defined data type)\n",
+              handle->handle_bytes, &mount_id);
+
+       assert(!name_to_handle_at(dirfd, ".", handle, &mount_id, flags));
+       printf("name_to_handle_at(AT_FDCWD, \".\", {handle_bytes=%u"
+              ", handle_type=%d, f_handle=0x",
+              handle->handle_bytes, handle->handle_type);
+       for (i = 0; i < handle->handle_bytes; ++i)
+               printf("%02x", handle->f_handle[i]);
+       printf("}, [%d], AT_SYMLINK_FOLLOW) = 0\n", mount_id);
+
+       assert(open_by_handle_at(-1, handle, O_RDONLY | O_DIRECTORY));
+       printf("open_by_handle_at(-1, {handle_bytes=%u, handle_type=1, f_handle=0x",
+              handle->handle_bytes);
+       for (i = 0; i < handle->handle_bytes; ++i)
+               printf("%02x", handle->f_handle[i]);
+       printf("}, O_RDONLY|O_DIRECTORY) = -1 %s\n",
+              EPERM == errno ? "EPERM (Operation not permitted)" :
+              EINVAL == errno ? "EINVAL (Invalid argument)" :
+                                "EBADF (Bad file descriptor)");
+
+       puts("+++ exited with 0 +++");
+       return 0;
+}
+
+#else
+
+int
+main(void)
+{
+       return 77;
+}
+
+#endif
diff --git a/tests/file_handle.test b/tests/file_handle.test
new file mode 100755 (executable)
index 0000000..619acd5
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+# Check name_to_handle_at and open_by_handle_at syscalls decoding.
+
+. "${srcdir=.}/init.sh"
+
+run_prog > /dev/null
+
+OUT="$LOG.out"
+run_strace -ename_to_handle_at,open_by_handle_at $args > "$OUT"
+
+match_diff "$OUT" "$LOG"
+rm -f "$OUT"
+
+exit 0