Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
### Unreleased

- Add option to fall back to `userfaultfd` syscall when opening `/dev/userfaultfd` fails due to
missing access rights

### 0.9.0

- Add support for `UFFDIO_CONTINUE` and `UFFDIO_REGISTER_MODE_MINOR` under the new `linux5_13` feature.
Expand Down
25 changes: 20 additions & 5 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pub struct UffdBuilder {
close_on_exec: bool,
non_blocking: bool,
user_mode_only: bool,
syscall_on_perms_error: bool,
req_features: FeatureFlags,
req_ioctls: IoctlFlags,
}
Expand All @@ -70,6 +71,7 @@ impl UffdBuilder {
close_on_exec: false,
non_blocking: false,
user_mode_only: true,
syscall_on_perms_error: false,
req_features: FeatureFlags::empty(),
req_ioctls: IoctlFlags::empty(),
}
Expand Down Expand Up @@ -104,6 +106,13 @@ impl UffdBuilder {
self
}

/// Fall back to using the `userfaultfd` system call if opening `/dev/userfaultfd` fails with
/// a permissions error.
pub fn syscall_on_perms_error(&mut self, syscall_on_perms_error: bool) -> &mut Self {
self.syscall_on_perms_error = syscall_on_perms_error;
self
}

/// Add a requirement that a particular feature or set of features is available.
///
/// If a required feature is unavailable, `UffdBuilder.create()` will return an error.
Expand Down Expand Up @@ -147,17 +156,23 @@ impl UffdBuilder {
// fall back to calling the system call.
fn open_file_descriptor(&self, flags: i32) -> Result<Uffd> {
// If `/dev/userfaultfd` exists we'll try to get the file descriptor from it. If the file
// doesn't exist we will fall back to calling the system call. This means, that if the
// device exists but the calling process does not have access rights to it, this will fail,
// i.e. we will not fall back to calling the system call.
// doesn't exist we will fall back to calling the system call.
// If the file exists but calling process does not have access rights to it, we have the
// option to fall back to calling the system call instead. This is only done when the
// `syscall_on_perms_error` setting is true. Otherwise, this will just fail.
match OpenOptions::new()
.read(true)
.write(true)
.open(UFFD_DEVICE_PATH)
{
Ok(mut file) => self.uffd_from_dev(&mut file, flags),
Err(err) if err.kind() == ErrorKind::NotFound => self.uffd_from_syscall(flags),
Err(err) => Err(Error::OpenDevUserfaultfd(err)),
Err(err) => match err.kind() {
ErrorKind::NotFound => self.uffd_from_syscall(flags),
ErrorKind::PermissionDenied if self.syscall_on_perms_error => {
self.uffd_from_syscall(flags)
}
_ => Err(Error::OpenDevUserfaultfd(err)),
},
}
}

Expand Down
Loading