Try to obtain a userfaultfd via /dev/userfaultfd (Linux 6.1+). This bypasses the capability and sysctl checks that gate the syscall, requiring only file permissions on the device node.
()
| 68 | /// This bypasses the capability and sysctl checks that gate the syscall, |
| 69 | /// requiring only file permissions on the device node. |
| 70 | fn try_dev_userfaultfd() -> Result<OwnedFd, Error> { |
| 71 | let dev = OpenOptions::new() |
| 72 | .read(true) |
| 73 | .write(true) |
| 74 | .open("/dev/userfaultfd")?; |
| 75 | let flags = libc::O_CLOEXEC | libc::O_NONBLOCK; |
| 76 | // SAFETY: USERFAULTFD_IOC_NEW on a valid /dev/userfaultfd fd returns a new |
| 77 | // userfaultfd file descriptor. |
| 78 | let fd = unsafe { |
| 79 | libc::ioctl( |
| 80 | dev.as_raw_fd(), |
| 81 | userfaultfd::USERFAULTFD_IOC_NEW as libc::Ioctl, |
| 82 | flags, |
| 83 | ) |
| 84 | }; |
| 85 | if fd < 0 { |
| 86 | return Err(Error::last_os_error()); |
| 87 | } |
| 88 | // SAFETY: the ioctl returned a valid fd above. |
| 89 | Ok(unsafe { OwnedFd::from_raw_fd(fd) }) |
| 90 | } |
| 91 | |
| 92 | /// Create a userfaultfd file descriptor and perform the API handshake. |
| 93 | /// |