Skip to content

Add Linux 6.4/6.7 write-protect features and Uffd::copy_with_mode - #94

Open
bchalios wants to merge 6 commits into
mainfrom
feat_copy_with_mode
Open

bchalios wants to merge 6 commits into
mainfrom
feat_copy_with_mode

Conversation

@bchalios

@bchalios bchalios commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

This adds the two userfaultfd write-protect features introduced in Linux 6.4 and 6.7, and a way to request UFFDIO_COPY_MODE_WP when resolving a missing fault.

  • linux6_4 feature: UFFD_FEATURE_WP_UNPOPULATED, exposed as FeatureFlags::WP_UNPOPULATED. Lets UFFDIO_WRITEPROTECT apply to pages that have never been populated.
  • linux6_7 feature: UFFD_FEATURE_WP_ASYNC, exposed as FeatureFlags::WP_ASYNC. The kernel resolves write-protect faults itself without queueing an event.
  • Uffd::copy_with_mode and CopyMode: exposes the full UFFDIO_COPY mode word. CopyMode::WRITE_PROTECT (behind linux5_7) maps the copied pages write-protected so the retried write raises a write-protect fault. Uffd::copy keeps its signature and delegates to the new method, mirroring the existing register / register_with_mode pair.

Feature levels

The userfaultfd-sys crate already chains its feature levels, but the top-level crate does not, so enabling only linux5_13 leaves cfg(feature = "linux5_7") items such as RegisterMode::WRITE_PROTECT compiled out. The new linux6_4 and linux6_7 features enable every lower level so a single feature selects everything up to that kernel.

I deliberately left existing features linux4_14, linux5_7, and linux5_13 as they are. Chaining them would add the thread_id field to Event::Pagefault and the WriteProtected variant to FaultKind for current users, which could break exhaustive patterns.
If we want to ever fix that, we should do it in a release that bumps major to declare the breaking change.

However, since enabling linux6_4/linux6_7 enables 5.7 and 5.13 together, they expose a non-exhaustive match in test_write_protect, which wasn't there before. So, I've extended it with a FaultKind::Minor arm.

Scope

linux6_7 just brings in write-protect. There are other features that we can add such as UFFDIO_POISON (6.6) or UFFDIO_MOVE (6.8), but I'd do these as separate PR.

As with the existing levels, the new feature bits come from bindgen, so building with linux6_4 or linux6_7 needs kernel headers of at least that version.

Tests

Four new tests, gated on the corresponding feature:

  • copy_with_mode with DONTWAKE: the page holds the source bytes before the faulting thread is woken.
  • copy_with_mode with WRITE_PROTECT: the retried write raises a write-protect fault with the copied data intact.
  • WP_UNPOPULATED: write-protecting a never-touched page makes the first write fault instead of silently populating.
  • WP_ASYNC: a write to a protected page succeeds from the same thread and no event is queued, for both an unpopulated and a repopulated page.

I ran those locally on a 7.1 kernel via both /dev/userfaultfd and the syscall fallback, at every feature level.

I added a new linux6_7 step in the CI using the ubuntu-latest runner.

Compatibility

Changes are backwards compatible. Uffd::copy produces the same ioctl mode bits as before. CopyMode, copy_with_mode, and the two feature levels are purely additive, so we don't need a major version bump.

This commit introduces support for the UFFD_FEATURE_WP_UNPOPULATED
feature flag, which was added in Linux 6.4. This feature allows
write-protection on unpopulated anonymous memory pages.

Changes:
- Add linux6_4 module in userfaultfd-sys
- Update UFFD_API_FEATURES to include WP_UNPOPULATED
- Add linux6_4 Cargo feature with appropriate dependencies
- Expose WP_UNPOPULATED flag in high-level FeatureFlags API

Signed-off-by: Babis Chalios <babis.chalios@e2b.dev>
This commit introduces support for the UFFD_FEATURE_WP_ASYNC feature
flag, which was added in Linux 6.7. This feature enables asynchronous
write-protection resolution - when a write happens to a write-protected
page, the kernel automatically resolves the protection without
generating pagefault events.

Changes:
- Add linux6_7 module in userfaultfd-sys
- Update UFFD_API_FEATURES to include WP_ASYNC
- Add linux6_7 Cargo feature with dependency on linux6_4
- Expose WP_ASYNC flag in high-level FeatureFlags API

Signed-off-by: Babis Chalios <babis.chalios@e2b.dev>
The userfaultfd-sys crate chains its feature levels, but the top-level
crate does not, so enabling only `linux5_13` leaves `cfg(feature =
"linux5_7")` items such as `RegisterMode::WRITE_PROTECT` compiled out.
Chain the new `linux6_4` and `linux6_7` levels so a single feature
selects everything up to that kernel version. The existing levels are
left alone: making them imply lower levels would add a field to
`Event::Pagefault` and variants to `FaultKind` for current users, which
can break exhaustive patterns.

Enabling 5.7 and 5.13 together also exposes a non-exhaustive match in
the write-protect test, which never compiled with both on before; add
the missing `FaultKind::Minor` arm.

Signed-off-by: Babis Chalios <babis.chalios@e2b.dev>
Expose the full UFFDIO_COPY mode word instead of only the wake flag, so
callers can request UFFDIO_COPY_MODE_WP and have the copied pages
mapped write-protected (Linux 5.7+). The existing `copy` keeps its
signature and delegates to the new method, mirroring the
`register`/`register_with_mode` pair.

Signed-off-by: Babis Chalios <babis.chalios@e2b.dev>
Signed-off-by: Babis Chalios <babis.chalios@e2b.dev>
Signed-off-by: Babis Chalios <babis.chalios@e2b.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant