Skip to content

Commit 1691ace

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

File tree

2 files changed

+25
-5
lines changed

2 files changed

+25
-5
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
### Unreleased
2+
3+
- Add option to fall back to `userfaultfd` syscall when opening `/dev/userfaultfd` fails due to
4+
missing access rights
5+
16
### 0.9.0
27

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

src/builder.rs

Lines changed: 20 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,23 @@ 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 we will fall back to calling the system call.
160+
// If the file exists but calling process does not have access rights to it, we have the
161+
// option to fall back to calling the system call instead. This is only done when the
162+
// `syscall_on_perms_error` setting is true. Otherwise, this will just fail.
153163
match OpenOptions::new()
154164
.read(true)
155165
.write(true)
156166
.open(UFFD_DEVICE_PATH)
157167
{
158168
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)),
169+
Err(err) => match err.kind() {
170+
ErrorKind::NotFound => self.uffd_from_syscall(flags),
171+
ErrorKind::PermissionDenied if self.syscall_on_perms_error => {
172+
self.uffd_from_syscall(flags)
173+
}
174+
_ => Err(Error::OpenDevUserfaultfd(err)),
175+
},
161176
}
162177
}
163178

0 commit comments

Comments
 (0)