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.
Showing the changes to include/uapi (1 of 5 files). Show all
Unified · Split
| @@ -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 */ |
| 108 | struct uffd_msg { | 111 | struct 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 | ||
| 162 | struct uffdio_api { | 166 | struct 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 an | 235 | * 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 | ||
| 370 | struct 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 | |||
| 359 | struct uffdio_move { | 378 | struct uffdio_move { |
| 360 | __u64 dst; | 379 | __u64 dst; |
| 361 | __u64 src; | 380 | __u64 src; |