From: Dmitry V. Levin Date: Sun, 22 Nov 2015 21:29:32 +0000 (+0000) Subject: Implement name_to_handle_at and open_by_handle_at syscalls decoding X-Git-Tag: v4.11~121 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4b3a1703bde75259457a9c4f0e888439ca849ab9;p=strace Implement name_to_handle_at and open_by_handle_at syscalls decoding * 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. --- diff --git a/Makefile.am b/Makefile.am index 56f49421..1a1a6470 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 index 00000000..66801010 --- /dev/null +++ b/file_handle.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2015 Dmitry V. Levin + * 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; +} diff --git a/linux/dummy.h b/linux/dummy.h index 3914948a..eeb576b2 100644 --- a/linux/dummy.h +++ b/linux/dummy.h @@ -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 diff --git a/pathtrace.c b/pathtrace.c index 663f3b4b..d530ec25 100644 --- a/pathtrace.c +++ b/pathtrace.c @@ -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: diff --git a/tests/.gitignore b/tests/.gitignore index 097d1c1e..1856939f 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -9,6 +9,7 @@ eventfd execve execveat fanotify_mark +file_handle filter-unavailable getdents getdents64 diff --git a/tests/Makefile.am b/tests/Makefile.am index 2db10c4e..3f3c513a 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -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 index 00000000..9351599a --- /dev/null +++ b/tests/file_handle.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2015 Dmitry V. Levin + * 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 +#include +#include +#include +#include + +#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 index 00000000..619acd5f --- /dev/null +++ b/tests/file_handle.test @@ -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