Skip to content

Commit c44f204

Browse files
committed
feat: fall back to userfaultfd syscall on permission errors
1 parent aac58f5 commit c44f204

File tree

2 files changed

+22
-5
lines changed

2 files changed

+22
-5
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
### Unreleased
2+
3+
- Fallback to `userfaultfd` syscall when opening `/dev/userfaultfd` fails due to permissions
4+
15
### 0.9.0
26

37
- Add support for `UFFDIO_CONTINUE` and `UFFDIO_REGISTER_MODE_MINOR` under the new `linux5_13` feature.

src/builder.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ pub struct UffdBuilder {
5858
close_on_exec: bool,
5959
non_blocking: bool,
6060
user_mode_only: bool,
61+
syscall_on_perms_error: bool,
6162
req_features: FeatureFlags,
6263
req_ioctls: IoctlFlags,
6364
}
@@ -70,6 +71,7 @@ impl UffdBuilder {
7071
close_on_exec: false,
7172
non_blocking: false,
7273
user_mode_only: true,
74+
syscall_on_perms_error: false,
7375
req_features: FeatureFlags::empty(),
7476
req_ioctls: IoctlFlags::empty(),
7577
}
@@ -104,6 +106,13 @@ impl UffdBuilder {
104106
self
105107
}
106108

109+
/// Fall back to using the `userfaultfd` system call if opening `/dev/userfaultfd` fails with
110+
/// a permissions error.
111+
pub fn syscall_on_perms_error(&mut self, syscall_on_perms_error: bool) -> &mut Self {
112+
self.syscall_on_perms_error = syscall_on_perms_error;
113+
self
114+
}
115+
107116
/// Add a requirement that a particular feature or set of features is available.
108117
///
109118
/// If a required feature is unavailable, `UffdBuilder.create()` will return an error.
@@ -147,17 +156,21 @@ impl UffdBuilder {
147156
// fall back to calling the system call.
148157
fn open_file_descriptor(&self, flags: i32) -> Result<Uffd> {
149158
// If `/dev/userfaultfd` exists we'll try to get the file descriptor from it. If the file
150-
// doesn't exist we will fall back to calling the system call. This means, that if the
151-
// device exists but the calling process does not have access rights to it, this will fail,
152-
// i.e. we will not fall back to calling the system call.
159+
// doesn't exist or we don't have the permissions to open it, we will fall back to calling
160+
// the system call.
153161
match OpenOptions::new()
154162
.read(true)
155163
.write(true)
156164
.open(UFFD_DEVICE_PATH)
157165
{
158166
Ok(mut file) => self.uffd_from_dev(&mut file, flags),
159-
Err(err) if err.kind() == ErrorKind::NotFound => self.uffd_from_syscall(flags),
160-
Err(err) => Err(Error::OpenDevUserfaultfd(err)),
167+
Err(err) => match err.kind() {
168+
ErrorKind::NotFound => self.uffd_from_syscall(flags),
169+
ErrorKind::PermissionDenied if self.syscall_on_perms_error => {
170+
self.uffd_from_syscall(flags)
171+
}
172+
_ => Err(Error::OpenDevUserfaultfd(err)),
173+
},
161174
}
162175
}
163176

0 commit comments

Comments
 (0)