From: Dr. David Alan Gilbert Date: Tue, 10 May 2016 10:49:02 +0000 (+0100) Subject: Decode UFFDIO_* ioctls X-Git-Tag: v4.12~194 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5d1216a56b3218716cc8192cb08a3a3e817ea57d;p=strace Decode UFFDIO_* ioctls Decode the ioctls associated with the userfaultfd fd. Note that they tend to read from and also return result in it's data structure. * configure.ac (AC_CHECK_HEADERS): Add linux/userfaultfd.h. * userfaultfd.c [HAVE_LINUX_USERFAULTFD_H]: Add ioctl decoder. * defs.h (uffdio_ioctl): New prototype. * ioctl.c (ioctl_decode) [HAVE_LINUX_USERFAULTFD_H]: Wire in uffdio_ioctl. * xlat/uffd_*.in: Create flag xlat for all the IOCTLs. --- diff --git a/configure.ac b/configure.ac index dbe52e45..7c030f89 100644 --- a/configure.ac +++ b/configure.ac @@ -375,6 +375,7 @@ AC_CHECK_HEADERS(m4_normalize([ linux/securebits.h linux/sem.h linux/shm.h + linux/userfaultfd.h linux/utsname.h mqueue.h netinet/sctp.h diff --git a/defs.h b/defs.h index 80610479..a5aff96a 100644 --- a/defs.h +++ b/defs.h @@ -668,6 +668,7 @@ extern int scsi_ioctl(struct tcb *, const unsigned int, long); extern int sock_ioctl(struct tcb *, const unsigned int, long); extern int term_ioctl(struct tcb *, const unsigned int, long); extern int ubi_ioctl(struct tcb *, const unsigned int, long); +extern int uffdio_ioctl(struct tcb *, const unsigned int, long); extern int v4l2_ioctl(struct tcb *, const unsigned int, long); extern int tv_nz(const struct timeval *); diff --git a/ioctl.c b/ioctl.c index f70dc44e..1b69e977 100644 --- a/ioctl.c +++ b/ioctl.c @@ -262,6 +262,10 @@ ioctl_decode(struct tcb *tcp) #ifdef HAVE_LINUX_INPUT_H case 'E': return evdev_ioctl(tcp, code, arg); +#endif +#ifdef HAVE_LINUX_USERFAULTFD_H + case 0xaa: + return uffdio_ioctl(tcp, code, arg); #endif default: break; diff --git a/userfaultfd.c b/userfaultfd.c index 15f825a0..27211051 100644 --- a/userfaultfd.c +++ b/userfaultfd.c @@ -36,3 +36,123 @@ SYS_FUNC(userfaultfd) return RVAL_DECODED | RVAL_FD; } + +#ifdef HAVE_LINUX_USERFAULTFD_H +# include +# include + +# include "xlat/uffd_api_flags.h" +# include "xlat/uffd_copy_flags.h" +# include "xlat/uffd_register_ioctl_flags.h" +# include "xlat/uffd_register_mode_flags.h" +# include "xlat/uffd_zeropage_flags.h" + +static void +tprintf_uffdio_range(const struct uffdio_range *range) +{ + tprintf("{start=%#" PRI__x64 ", len=%#" PRI__x64 "}", + range->start, range->len); +} + +int +uffdio_ioctl(struct tcb *tcp, const unsigned int code, const long arg) +{ + switch (code) { + case UFFDIO_API: { + struct uffdio_api ua; + if (entering(tcp)) { + tprints(", "); + if (umove_or_printaddr(tcp, arg, &ua)) + return RVAL_DECODED | 1; + /* Features is intended to contain some flags, but + * there aren't any defined yet. + */ + tprintf("{api=%#" PRI__x64 + ", features=%#" PRI__x64, + ua.api, ua.features); + } else { + if (!syserror(tcp) && !umove(tcp, arg, &ua)) { + tprintf(", features.out=%#" PRI__x64 + ", ioctls=", ua.features); + printflags64(uffd_api_flags, ua.ioctls, + "_UFFDIO_???"); + } + tprintf("}"); + } + return 1; + } + + case UFFDIO_COPY: { + struct uffdio_copy uc; + if (entering(tcp)) { + tprints(", "); + if (umove_or_printaddr(tcp, arg, &uc)) + return RVAL_DECODED | 1; + tprintf("{dst=%#" PRI__x64 ", src=%#" PRI__x64 + ", len=%#" PRI__x64 ", mode=", + uc.dst, uc.src, uc.len); + printflags64(uffd_copy_flags, uc.mode, + "UFFDIO_COPY_???"); + } else { + if (!syserror(tcp) && !umove(tcp, arg, &uc)) + tprintf(", copy=%#" PRI__x64, uc.copy); + tprints("}"); + } + return 1; + } + + case UFFDIO_REGISTER: { + struct uffdio_register ur; + if (entering(tcp)) { + tprints(", "); + if (umove_or_printaddr(tcp, arg, &ur)) + return RVAL_DECODED | 1; + tprintf("{range="); + tprintf_uffdio_range(&ur.range); + tprintf(", mode="); + printflags64(uffd_register_mode_flags, ur.mode, + "UFFDIO_REGISTER_MODE_???"); + } else { + if (!syserror(tcp) && !umove(tcp, arg, &ur)) { + tprintf(", ioctls="); + printflags64(uffd_register_ioctl_flags, + ur.ioctls, "UFFDIO_???"); + } + tprints("}"); + } + return 1; + } + + case UFFDIO_UNREGISTER: + case UFFDIO_WAKE: { + struct uffdio_range ura; + tprints(", "); + if (!umove_or_printaddr(tcp, arg, &ura)) + tprintf_uffdio_range(&ura); + return RVAL_DECODED | 1; + } + + case UFFDIO_ZEROPAGE: { + struct uffdio_zeropage uz; + if (entering(tcp)) { + tprints(", "); + if (umove_or_printaddr(tcp, arg, &uz)) + return RVAL_DECODED | 1; + tprintf("{range="); + tprintf_uffdio_range(&uz.range); + tprintf(", mode="); + printflags64(uffd_zeropage_flags, uz.mode, + "UFFDIO_ZEROPAGE_???"); + } else { + if (!syserror(tcp) && !umove(tcp, arg, &uz)) + tprintf(", zeropage=%#" PRI__x64, uz.zeropage); + tprints("}"); + } + return 1; + } + + default: + return RVAL_DECODED; + } +} +#endif /* HAVE_LINUX_USERFAULTFD_H */ diff --git a/xlat/uffd_api_flags.in b/xlat/uffd_api_flags.in new file mode 100644 index 00000000..fd210872 --- /dev/null +++ b/xlat/uffd_api_flags.in @@ -0,0 +1,4 @@ +#val_type uint64_t +1<<_UFFDIO_REGISTER +1<<_UFFDIO_UNREGISTER +1<<_UFFDIO_API diff --git a/xlat/uffd_copy_flags.in b/xlat/uffd_copy_flags.in new file mode 100644 index 00000000..02d6b19c --- /dev/null +++ b/xlat/uffd_copy_flags.in @@ -0,0 +1,2 @@ +#val_type uint64_t +UFFDIO_COPY_MODE_DONTWAKE diff --git a/xlat/uffd_register_ioctl_flags.in b/xlat/uffd_register_ioctl_flags.in new file mode 100644 index 00000000..f4e3b943 --- /dev/null +++ b/xlat/uffd_register_ioctl_flags.in @@ -0,0 +1,4 @@ +#val_type uint64_t +1<<_UFFDIO_WAKE +1<<_UFFDIO_COPY +1<<_UFFDIO_ZEROPAGE diff --git a/xlat/uffd_register_mode_flags.in b/xlat/uffd_register_mode_flags.in new file mode 100644 index 00000000..996b1f32 --- /dev/null +++ b/xlat/uffd_register_mode_flags.in @@ -0,0 +1,3 @@ +#val_type uint64_t +UFFDIO_REGISTER_MODE_MISSING +UFFDIO_REGISTER_MODE_WP diff --git a/xlat/uffd_zeropage_flags.in b/xlat/uffd_zeropage_flags.in new file mode 100644 index 00000000..6d48a040 --- /dev/null +++ b/xlat/uffd_zeropage_flags.in @@ -0,0 +1,2 @@ +#val_type uint64_t +UFFDIO_ZEROPAGE_MODE_DONTWAKE