fix: fall back to userfaultfd(2) when /dev/userfaultfd is unreadable#84
Open
ShivanshVij wants to merge 1 commit intobytecodealliance:mainfrom
Open
fix: fall back to userfaultfd(2) when /dev/userfaultfd is unreadable#84ShivanshVij wants to merge 1 commit intobytecodealliance:mainfrom
ShivanshVij wants to merge 1 commit intobytecodealliance:mainfrom
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Current Implementation
In the current implementation of
UffdBuilder::create(), we only fall back to theuserfaultfd(2)syscall when/dev/userfaultfddoesn't exist. If the device node is present but the calling process lacks permission to open it (EACCES/EPERM), the builder returnsError::OpenDevUserfaultfdand never tries the syscall. This is documented in the current implementation, however the linux kernel accepts either entry point and the process is allowed to hold the capabilities (e.g.CAP_SYS_PTRACE) needed for the syscall path without having access to the/dev/userfaultfdpath.One way to enable this is by running
sysctl vm.unprivileged_userfaultfd=1- this does not grant the process or user acess to/dev/userfaultfdbut it does allow theuserfaultd(2)approach to work.Right now downstream consumers are forced to bypass the builder entirely to support this use case.
Fix
The fix is simple. We've just extended the fallback arm in
open_file_descriptorto also matchErrorKind::PermissionDenied(which covers both EACCES and EPERM), and fall through to tryinguserfaultd(2). Any real errors (ENOMEM, ENOTDIR, etc.) still surface asError::OpenDevUserfaultfd, so existing users should not be affected unless they rely on this specific scenario (which is very unlikely).Test
We've also added a unit test that creates a
chmod 0o000stand-in file, points the builder at it, and asserts the syscall fallback succeeds. The test self-skips under root (where mode 000 is bypassed). To make the helper drivable from a test,open_file_descriptornow takes the device path as a parameter; its sole caller increate()passesPath::new(UFFD_DEVICE_PATH). This does not result in a public API change.I've validated the test fails without the fix, and does not fail with the fix.