History

userfaultfd: add UFFDIO_REGISTER_MODE_RWP and UFFDIO_RWPROTECT plumbing

Add the userspace interface for read-write protection tracking: - UFFDIO_REGISTER_MODE_RWP register a range for RWP tracking - UFFD_FEATURE_RWP capability bit - UFFDIO_RWPROTECT install / remove RWP on a range Introduce CONFIG_USERFAULTFD_RWP, auto-selected on 64-bit kernels with ARCH_HAS_PTE_PROTNONE and HAVE_ARCH_USERFAULTFD_WP. The symbol gates VM_UFFD_RWP (previously aliased to VM_NONE) and the smaps/trace-flag hooks added in the preparatory patches; without it the UAPI bits added here have nothing to drive and would be unreachable. Registration sets VM_UFFD_RWP on the VMA. Combining MODE_WP with MODE_RWP is rejected because both modes claim the uffd PTE bit. UFFDIO_RWPROTECT is the bidirectional counterpart of UFFDIO_WRITEPROTECT: - MODE_RWP change_protection() with MM_CP_UFFD_RWP installs PAGE_NONE and sets the uffd bit on present PTEs - !MODE_RWP change_protection() with MM_CP_UFFD_RWP_RESOLVE restores vma->vm_page_prot and clears the bit userfaultfd_clear_vma() runs the same resolve pass on unregister so RWP state cannot outlive the uffd. Re-registering a range must not drop a mode that installs per-PTE markers (WP or RWP); doing so returns -EBUSY. This also closes a pre-existing window where re-registering without MODE_WP would strand uffd-wp markers: before, those caused extra write-faults but were otherwise benign; with RWP preservation in place, a subsequent mprotect() on a VM_UFFD_RWP VMA would silently promote the stale markers to RWP. The feature is not yet advertised. UFFDIO_REGISTER_MODE_RWP, UFFD_FEATURE_RWP, and _UFFDIO_RWPROTECT are intentionally absent from UFFD_API_REGISTER_MODES, UFFD_API_FEATURES, and UFFD_API_RANGE_IOCTLS, so UFFDIO_API masks them out and the register-mode validator rejects the bit. The follow-up patch adds fault dispatch and exposes the UAPI.

Kiryl Shutsemau (Meta) committed 4 months ago

Commit 6eab8f21 parent 7974c235 files · +228 −3Browse files

Showing the changes to include/uapi (1 of 5 files). Show all

Unified · Split

include/uapi/linux/userfaultfd.h+19−0
@@ -79,6 +79,7 @@ · 78 unmodified lines
79#define _UFFDIO_WRITEPROTECT (0x06)79#define _UFFDIO_WRITEPROTECT (0x06)
80#define _UFFDIO_CONTINUE (0x07)80#define _UFFDIO_CONTINUE (0x07)
81#define _UFFDIO_POISON (0x08)81#define _UFFDIO_POISON (0x08)
82#define _UFFDIO_RWPROTECT (0x09)
82#define _UFFDIO_API (0x3F)83#define _UFFDIO_API (0x3F)
83 84
84/* userfaultfd ioctl ids */85/* userfaultfd ioctl ids */
@@ -103,6 +104,8 @@ · 18 unmodified lines
103 struct uffdio_continue)104 struct uffdio_continue)
104#define UFFDIO_POISON _IOWR(UFFDIO, _UFFDIO_POISON, \105#define UFFDIO_POISON _IOWR(UFFDIO, _UFFDIO_POISON, \
105 struct uffdio_poison)106 struct uffdio_poison)
107#define UFFDIO_RWPROTECT _IOWR(UFFDIO, _UFFDIO_RWPROTECT, \
108 struct uffdio_rwprotect)
106 109
107/* read() structure */110/* read() structure */
108struct uffd_msg {111struct uffd_msg {
@@ -158,6 +161,7 @@ struct uffd_msg { · 49 unmodified lines
158#define UFFD_PAGEFAULT_FLAG_WRITE (1<<0) /* If this was a write fault */161#define UFFD_PAGEFAULT_FLAG_WRITE (1<<0) /* If this was a write fault */
159#define UFFD_PAGEFAULT_FLAG_WP (1<<1) /* If reason is VM_UFFD_WP */162#define UFFD_PAGEFAULT_FLAG_WP (1<<1) /* If reason is VM_UFFD_WP */
160#define UFFD_PAGEFAULT_FLAG_MINOR (1<<2) /* If reason is VM_UFFD_MINOR */163#define UFFD_PAGEFAULT_FLAG_MINOR (1<<2) /* If reason is VM_UFFD_MINOR */
164#define UFFD_PAGEFAULT_FLAG_RWP (1<<3) /* If reason is VM_UFFD_RWP */
161 165
162struct uffdio_api {166struct uffdio_api {
163 /* userland asks for an API number and the features to enable */167 /* userland asks for an API number and the features to enable */
@@ -230,6 +234,11 @@ struct uffdio_api { · 66 unmodified lines
230 *234 *
231 * UFFD_FEATURE_MOVE indicates that the kernel supports moving an235 * UFFD_FEATURE_MOVE indicates that the kernel supports moving an
232 * existing page contents from userspace.236 * existing page contents from userspace.
237 *
238 * UFFD_FEATURE_RWP indicates that the kernel supports
239 * UFFDIO_REGISTER_MODE_RWP for read-write protection tracking.
240 * Pages are made inaccessible via UFFDIO_RWPROTECT and faults
241 * are delivered when the pages are re-accessed.
233 */242 */
234#define UFFD_FEATURE_PAGEFAULT_FLAG_WP (1<<0)243#define UFFD_FEATURE_PAGEFAULT_FLAG_WP (1<<0)
235#define UFFD_FEATURE_EVENT_FORK (1<<1)244#define UFFD_FEATURE_EVENT_FORK (1<<1)
@@ -248,6 +257,7 @@ struct uffdio_api { · 12 unmodified lines
248#define UFFD_FEATURE_POISON (1<<14)257#define UFFD_FEATURE_POISON (1<<14)
249#define UFFD_FEATURE_WP_ASYNC (1<<15)258#define UFFD_FEATURE_WP_ASYNC (1<<15)
250#define UFFD_FEATURE_MOVE (1<<16)259#define UFFD_FEATURE_MOVE (1<<16)
260#define UFFD_FEATURE_RWP (1<<17)
251 __u64 features;261 __u64 features;
252 262
253 __u64 ioctls;263 __u64 ioctls;
@@ -263,6 +273,7 @@ struct uffdio_register { · 9 unmodified lines
263#define UFFDIO_REGISTER_MODE_MISSING ((__u64)1<<0)273#define UFFDIO_REGISTER_MODE_MISSING ((__u64)1<<0)
264#define UFFDIO_REGISTER_MODE_WP ((__u64)1<<1)274#define UFFDIO_REGISTER_MODE_WP ((__u64)1<<1)
265#define UFFDIO_REGISTER_MODE_MINOR ((__u64)1<<2)275#define UFFDIO_REGISTER_MODE_MINOR ((__u64)1<<2)
276#define UFFDIO_REGISTER_MODE_RWP ((__u64)1<<3)
266 __u64 mode;277 __u64 mode;
267 278
268 /*279 /*
@@ -356,6 +367,14 @@ struct uffdio_poison { · 87 unmodified lines
356 __s64 updated;367 __s64 updated;
357};368};
358 369
370struct uffdio_rwprotect {
371 struct uffdio_range range;
372 /* !RWP means undo RWP-protection */
373#define UFFDIO_RWPROTECT_MODE_RWP ((__u64)1<<0)
374#define UFFDIO_RWPROTECT_MODE_DONTWAKE ((__u64)1<<1)
375 __u64 mode;
376};
377
359struct uffdio_move {378struct uffdio_move {
360 __u64 dst;379 __u64 dst;
361 __u64 src;380 __u64 src;