diff options
-rw-r--r-- | bundled/Makefile.am | 1 | ||||
-rw-r--r-- | bundled/linux/include/uapi/linux/userfaultfd.h | 269 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | src/ioctl.c | 2 | ||||
-rw-r--r-- | src/userfaultfd.c | 19 | ||||
-rw-r--r-- | src/xlat/uffd_api_features.in | 19 | ||||
-rw-r--r-- | src/xlat/uffd_api_flags.in | 1 | ||||
-rw-r--r-- | src/xlat/uffd_copy_flags.in | 5 | ||||
-rw-r--r-- | src/xlat/uffd_flags.in | 3 | ||||
-rw-r--r-- | src/xlat/uffd_register_ioctl_flags.in | 1 | ||||
-rw-r--r-- | src/xlat/uffd_register_mode_flags.in | 1 | ||||
-rw-r--r-- | src/xlat/uffd_zeropage_flags.in | 1 | ||||
-rw-r--r-- | tests/ioctl_uffdio.c | 31 |
13 files changed, 310 insertions, 44 deletions
diff --git a/bundled/Makefile.am b/bundled/Makefile.am index 9debffb5b..e2d305fa7 100644 --- a/bundled/Makefile.am +++ b/bundled/Makefile.am @@ -63,6 +63,7 @@ EXTRA_DIST = \ linux/include/uapi/linux/tee.h \ linux/include/uapi/linux/types.h \ linux/include/uapi/linux/unix_diag.h \ + linux/include/uapi/linux/userfaultfd.h \ linux/include/uapi/linux/v4l2-common.h \ linux/include/uapi/linux/v4l2-controls.h \ linux/include/uapi/linux/videodev2.h \ diff --git a/bundled/linux/include/uapi/linux/userfaultfd.h b/bundled/linux/include/uapi/linux/userfaultfd.h new file mode 100644 index 000000000..1ba9a9fee --- /dev/null +++ b/bundled/linux/include/uapi/linux/userfaultfd.h @@ -0,0 +1,269 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * include/linux/userfaultfd.h + * + * Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org> + * Copyright (C) 2015 Red Hat, Inc. + * + */ + +#ifndef _LINUX_USERFAULTFD_H +#define _LINUX_USERFAULTFD_H + +#include <linux/types.h> + +/* + * If the UFFDIO_API is upgraded someday, the UFFDIO_UNREGISTER and + * UFFDIO_WAKE ioctls should be defined as _IOW and not as _IOR. In + * userfaultfd.h we assumed the kernel was reading (instead _IOC_READ + * means the userland is reading). + */ +#define UFFD_API ((__u64)0xAA) +#define UFFD_API_FEATURES (UFFD_FEATURE_PAGEFAULT_FLAG_WP | \ + UFFD_FEATURE_EVENT_FORK | \ + UFFD_FEATURE_EVENT_REMAP | \ + UFFD_FEATURE_EVENT_REMOVE | \ + UFFD_FEATURE_EVENT_UNMAP | \ + UFFD_FEATURE_MISSING_HUGETLBFS | \ + UFFD_FEATURE_MISSING_SHMEM | \ + UFFD_FEATURE_SIGBUS | \ + UFFD_FEATURE_THREAD_ID) +#define UFFD_API_IOCTLS \ + ((__u64)1 << _UFFDIO_REGISTER | \ + (__u64)1 << _UFFDIO_UNREGISTER | \ + (__u64)1 << _UFFDIO_API) +#define UFFD_API_RANGE_IOCTLS \ + ((__u64)1 << _UFFDIO_WAKE | \ + (__u64)1 << _UFFDIO_COPY | \ + (__u64)1 << _UFFDIO_ZEROPAGE | \ + (__u64)1 << _UFFDIO_WRITEPROTECT) +#define UFFD_API_RANGE_IOCTLS_BASIC \ + ((__u64)1 << _UFFDIO_WAKE | \ + (__u64)1 << _UFFDIO_COPY) + +/* + * Valid ioctl command number range with this API is from 0x00 to + * 0x3F. UFFDIO_API is the fixed number, everything else can be + * changed by implementing a different UFFD_API. If sticking to the + * same UFFD_API more ioctl can be added and userland will be aware of + * which ioctl the running kernel implements through the ioctl command + * bitmask written by the UFFDIO_API. + */ +#define _UFFDIO_REGISTER (0x00) +#define _UFFDIO_UNREGISTER (0x01) +#define _UFFDIO_WAKE (0x02) +#define _UFFDIO_COPY (0x03) +#define _UFFDIO_ZEROPAGE (0x04) +#define _UFFDIO_WRITEPROTECT (0x06) +#define _UFFDIO_API (0x3F) + +/* userfaultfd ioctl ids */ +#define UFFDIO 0xAA +#define UFFDIO_API _IOWR(UFFDIO, _UFFDIO_API, \ + struct uffdio_api) +#define UFFDIO_REGISTER _IOWR(UFFDIO, _UFFDIO_REGISTER, \ + struct uffdio_register) +#define UFFDIO_UNREGISTER _IOR(UFFDIO, _UFFDIO_UNREGISTER, \ + struct uffdio_range) +#define UFFDIO_WAKE _IOR(UFFDIO, _UFFDIO_WAKE, \ + struct uffdio_range) +#define UFFDIO_COPY _IOWR(UFFDIO, _UFFDIO_COPY, \ + struct uffdio_copy) +#define UFFDIO_ZEROPAGE _IOWR(UFFDIO, _UFFDIO_ZEROPAGE, \ + struct uffdio_zeropage) +#define UFFDIO_WRITEPROTECT _IOWR(UFFDIO, _UFFDIO_WRITEPROTECT, \ + struct uffdio_writeprotect) + +/* read() structure */ +struct uffd_msg { + __u8 event; + + __u8 reserved1; + __u16 reserved2; + __u32 reserved3; + + union { + struct { + __u64 flags; + __u64 address; + union { + __u32 ptid; + } feat; + } pagefault; + + struct { + __u32 ufd; + } fork; + + struct { + __u64 from; + __u64 to; + __u64 len; + } remap; + + struct { + __u64 start; + __u64 end; + } remove; + + struct { + /* unused reserved fields */ + __u64 reserved1; + __u64 reserved2; + __u64 reserved3; + } reserved; + } arg; +} __attribute__((packed)); + +/* + * Start at 0x12 and not at 0 to be more strict against bugs. + */ +#define UFFD_EVENT_PAGEFAULT 0x12 +#define UFFD_EVENT_FORK 0x13 +#define UFFD_EVENT_REMAP 0x14 +#define UFFD_EVENT_REMOVE 0x15 +#define UFFD_EVENT_UNMAP 0x16 + +/* flags for UFFD_EVENT_PAGEFAULT */ +#define UFFD_PAGEFAULT_FLAG_WRITE (1<<0) /* If this was a write fault */ +#define UFFD_PAGEFAULT_FLAG_WP (1<<1) /* If reason is VM_UFFD_WP */ + +struct uffdio_api { + /* userland asks for an API number and the features to enable */ + __u64 api; + /* + * Kernel answers below with the all available features for + * the API, this notifies userland of which events and/or + * which flags for each event are enabled in the current + * kernel. + * + * Note: UFFD_EVENT_PAGEFAULT and UFFD_PAGEFAULT_FLAG_WRITE + * are to be considered implicitly always enabled in all kernels as + * long as the uffdio_api.api requested matches UFFD_API. + * + * UFFD_FEATURE_MISSING_HUGETLBFS means an UFFDIO_REGISTER + * with UFFDIO_REGISTER_MODE_MISSING mode will succeed on + * hugetlbfs virtual memory ranges. Adding or not adding + * UFFD_FEATURE_MISSING_HUGETLBFS to uffdio_api.features has + * no real functional effect after UFFDIO_API returns, but + * it's only useful for an initial feature set probe at + * UFFDIO_API time. There are two ways to use it: + * + * 1) by adding UFFD_FEATURE_MISSING_HUGETLBFS to the + * uffdio_api.features before calling UFFDIO_API, an error + * will be returned by UFFDIO_API on a kernel without + * hugetlbfs missing support + * + * 2) the UFFD_FEATURE_MISSING_HUGETLBFS can not be added in + * uffdio_api.features and instead it will be set by the + * kernel in the uffdio_api.features if the kernel supports + * it, so userland can later check if the feature flag is + * present in uffdio_api.features after UFFDIO_API + * succeeded. + * + * UFFD_FEATURE_MISSING_SHMEM works the same as + * UFFD_FEATURE_MISSING_HUGETLBFS, but it applies to shmem + * (i.e. tmpfs and other shmem based APIs). + * + * UFFD_FEATURE_SIGBUS feature means no page-fault + * (UFFD_EVENT_PAGEFAULT) event will be delivered, instead + * a SIGBUS signal will be sent to the faulting process. + * + * UFFD_FEATURE_THREAD_ID pid of the page faulted task_struct will + * be returned, if feature is not requested 0 will be returned. + */ +#define UFFD_FEATURE_PAGEFAULT_FLAG_WP (1<<0) +#define UFFD_FEATURE_EVENT_FORK (1<<1) +#define UFFD_FEATURE_EVENT_REMAP (1<<2) +#define UFFD_FEATURE_EVENT_REMOVE (1<<3) +#define UFFD_FEATURE_MISSING_HUGETLBFS (1<<4) +#define UFFD_FEATURE_MISSING_SHMEM (1<<5) +#define UFFD_FEATURE_EVENT_UNMAP (1<<6) +#define UFFD_FEATURE_SIGBUS (1<<7) +#define UFFD_FEATURE_THREAD_ID (1<<8) + __u64 features; + + __u64 ioctls; +}; + +struct uffdio_range { + __u64 start; + __u64 len; +}; + +struct uffdio_register { + struct uffdio_range range; +#define UFFDIO_REGISTER_MODE_MISSING ((__u64)1<<0) +#define UFFDIO_REGISTER_MODE_WP ((__u64)1<<1) + __u64 mode; + + /* + * kernel answers which ioctl commands are available for the + * range, keep at the end as the last 8 bytes aren't read. + */ + __u64 ioctls; +}; + +struct uffdio_copy { + __u64 dst; + __u64 src; + __u64 len; +#define UFFDIO_COPY_MODE_DONTWAKE ((__u64)1<<0) + /* + * UFFDIO_COPY_MODE_WP will map the page write protected on + * the fly. UFFDIO_COPY_MODE_WP is available only if the + * write protected ioctl is implemented for the range + * according to the uffdio_register.ioctls. + */ +#define UFFDIO_COPY_MODE_WP ((__u64)1<<1) + __u64 mode; + + /* + * "copy" is written by the ioctl and must be at the end: the + * copy_from_user will not read the last 8 bytes. + */ + __s64 copy; +}; + +struct uffdio_zeropage { + struct uffdio_range range; +#define UFFDIO_ZEROPAGE_MODE_DONTWAKE ((__u64)1<<0) + __u64 mode; + + /* + * "zeropage" is written by the ioctl and must be at the end: + * the copy_from_user will not read the last 8 bytes. + */ + __s64 zeropage; +}; + +struct uffdio_writeprotect { + struct uffdio_range range; +/* + * UFFDIO_WRITEPROTECT_MODE_WP: set the flag to write protect a range, + * unset the flag to undo protection of a range which was previously + * write protected. + * + * UFFDIO_WRITEPROTECT_MODE_DONTWAKE: set the flag to avoid waking up + * any wait thread after the operation succeeds. + * + * NOTE: Write protecting a region (WP=1) is unrelated to page faults, + * therefore DONTWAKE flag is meaningless with WP=1. Removing write + * protection (WP=0) in response to a page fault wakes the faulting + * task unless DONTWAKE is set. + */ +#define UFFDIO_WRITEPROTECT_MODE_WP ((__u64)1<<0) +#define UFFDIO_WRITEPROTECT_MODE_DONTWAKE ((__u64)1<<1) + __u64 mode; +}; + +/* + * Flags for the userfaultfd(2) system call itself. + */ + +/* + * Create a userfaultfd that can handle page faults only in user mode. + */ +#define UFFD_USER_MODE_ONLY 1 + +#endif /* _LINUX_USERFAULTFD_H */ diff --git a/configure.ac b/configure.ac index 84a4abc6e..95d84502d 100644 --- a/configure.ac +++ b/configure.ac @@ -460,7 +460,6 @@ AC_CHECK_HEADERS(m4_normalize([ linux/sched.h linux/seccomp.h linux/securebits.h - linux/userfaultfd.h linux/utsname.h ]),,, [AC_INCLUDES_DEFAULT #include <linux/types.h> diff --git a/src/ioctl.c b/src/ioctl.c index aac7a4b27..01cb0e7cf 100644 --- a/src/ioctl.c +++ b/src/ioctl.c @@ -349,10 +349,8 @@ ioctl_decode(struct tcb *tcp) return fs_0x94_ioctl(tcp, code, arg); case 0xa4: return tee_ioctl(tcp, code, arg); -#ifdef HAVE_LINUX_USERFAULTFD_H case 0xaa: return uffdio_ioctl(tcp, code, arg); -#endif case 0xab: return nbd_ioctl(tcp, code, arg); #ifdef HAVE_LINUX_KVM_H diff --git a/src/userfaultfd.c b/src/userfaultfd.c index d87d6e781..7996c94f2 100644 --- a/src/userfaultfd.c +++ b/src/userfaultfd.c @@ -8,6 +8,9 @@ #include "defs.h" #include "kernel_fcntl.h" +#include <linux/ioctl.h> +#include <linux/userfaultfd.h> + #include "xlat/uffd_flags.h" SYS_FUNC(userfaultfd) @@ -17,16 +20,13 @@ SYS_FUNC(userfaultfd) return RVAL_DECODED | RVAL_FD; } -#ifdef HAVE_LINUX_USERFAULTFD_H -# include <linux/ioctl.h> -# include <linux/userfaultfd.h> -# include "xlat/uffd_api_features.h" -# 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" +#include "xlat/uffd_api_features.h" +#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) @@ -191,4 +191,3 @@ uffdio_ioctl(struct tcb *const tcp, const unsigned int code, return RVAL_IOCTL_DECODED; } -#endif /* HAVE_LINUX_USERFAULTFD_H */ diff --git a/src/xlat/uffd_api_features.in b/src/xlat/uffd_api_features.in index 33d644778..603086f9c 100644 --- a/src/xlat/uffd_api_features.in +++ b/src/xlat/uffd_api_features.in @@ -1,10 +1,11 @@ +#unconditional #val_type uint64_t -UFFD_FEATURE_PAGEFAULT_FLAG_WP (1<<0) -UFFD_FEATURE_EVENT_FORK (1<<1) -UFFD_FEATURE_EVENT_REMAP (1<<2) -UFFD_FEATURE_EVENT_REMOVE (1<<3) -UFFD_FEATURE_MISSING_HUGETLBFS (1<<4) -UFFD_FEATURE_MISSING_SHMEM (1<<5) -UFFD_FEATURE_EVENT_UNMAP (1<<6) -UFFD_FEATURE_SIGBUS (1<<7) -UFFD_FEATURE_THREAD_ID (1<<8) +UFFD_FEATURE_PAGEFAULT_FLAG_WP +UFFD_FEATURE_EVENT_FORK +UFFD_FEATURE_EVENT_REMAP +UFFD_FEATURE_EVENT_REMOVE +UFFD_FEATURE_MISSING_HUGETLBFS +UFFD_FEATURE_MISSING_SHMEM +UFFD_FEATURE_EVENT_UNMAP +UFFD_FEATURE_SIGBUS +UFFD_FEATURE_THREAD_ID diff --git a/src/xlat/uffd_api_flags.in b/src/xlat/uffd_api_flags.in index fd210872b..66b968959 100644 --- a/src/xlat/uffd_api_flags.in +++ b/src/xlat/uffd_api_flags.in @@ -1,3 +1,4 @@ +#unconditional #val_type uint64_t 1<<_UFFDIO_REGISTER 1<<_UFFDIO_UNREGISTER diff --git a/src/xlat/uffd_copy_flags.in b/src/xlat/uffd_copy_flags.in index a9e3e9416..362b20761 100644 --- a/src/xlat/uffd_copy_flags.in +++ b/src/xlat/uffd_copy_flags.in @@ -1,3 +1,4 @@ +#unconditional #val_type uint64_t -UFFDIO_COPY_MODE_DONTWAKE (1ULL<<0) -UFFDIO_COPY_MODE_WP (1ULL<<1) +UFFDIO_COPY_MODE_DONTWAKE +UFFDIO_COPY_MODE_WP diff --git a/src/xlat/uffd_flags.in b/src/xlat/uffd_flags.in index e925a8fe7..7a68a695d 100644 --- a/src/xlat/uffd_flags.in +++ b/src/xlat/uffd_flags.in @@ -1,3 +1,4 @@ -UFFD_USER_MODE_ONLY 1 +#unconditional +UFFD_USER_MODE_ONLY O_NONBLOCK O_CLOEXEC diff --git a/src/xlat/uffd_register_ioctl_flags.in b/src/xlat/uffd_register_ioctl_flags.in index 077871f93..6d04ca3be 100644 --- a/src/xlat/uffd_register_ioctl_flags.in +++ b/src/xlat/uffd_register_ioctl_flags.in @@ -1,3 +1,4 @@ +#unconditional #val_type uint64_t 1<<_UFFDIO_WAKE 1<<_UFFDIO_COPY diff --git a/src/xlat/uffd_register_mode_flags.in b/src/xlat/uffd_register_mode_flags.in index 996b1f32e..adae3c64a 100644 --- a/src/xlat/uffd_register_mode_flags.in +++ b/src/xlat/uffd_register_mode_flags.in @@ -1,3 +1,4 @@ +#unconditional #val_type uint64_t UFFDIO_REGISTER_MODE_MISSING UFFDIO_REGISTER_MODE_WP diff --git a/src/xlat/uffd_zeropage_flags.in b/src/xlat/uffd_zeropage_flags.in index 6d48a040d..b2b3467ba 100644 --- a/src/xlat/uffd_zeropage_flags.in +++ b/src/xlat/uffd_zeropage_flags.in @@ -1,2 +1,3 @@ +#unconditional #val_type uint64_t UFFDIO_ZEROPAGE_MODE_DONTWAKE diff --git a/tests/ioctl_uffdio.c b/tests/ioctl_uffdio.c index 9b831bd3b..1aa60194a 100644 --- a/tests/ioctl_uffdio.c +++ b/tests/ioctl_uffdio.c @@ -10,22 +10,21 @@ #include "tests.h" #include "scno.h" -#if defined __NR_userfaultfd && defined HAVE_LINUX_USERFAULTFD_H +#include <inttypes.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> -# include <fcntl.h> -# include <inttypes.h> -# include <stdint.h> -# include <stdio.h> -# include <string.h> -# include <unistd.h> +#include <sys/ioctl.h> +#include <sys/mman.h> -# include <sys/ioctl.h> -# include <sys/mman.h> -# include <linux/ioctl.h> -# include <linux/userfaultfd.h> +#include "kernel_fcntl.h" +#include <linux/ioctl.h> +#include <linux/userfaultfd.h> -# include "xlat.h" -# include "xlat/uffd_api_features.h" +#include "xlat.h" +#include "xlat/uffd_api_features.h" int main(void) @@ -200,9 +199,3 @@ main(void) puts("+++ exited with 0 +++"); return 0; } - -#else - -SKIP_MAIN_UNDEFINED("__NR_userfaultfd && HAVE_LINUX_USERFAULTFD_H") - -#endif |