1 use crate::error::{Error, Result};
2 use crate::raw;
3 use crate::Uffd;
4 use libc::c_void;
5 #[cfg(feature = "linux4_14")]
6 use nix::unistd::Pid;
7 use std::os::unix::io::{FromRawFd, RawFd};
8 
9 /// Whether a page fault event was for a read or write.
10 #[derive(Clone, Copy, Debug, PartialEq)]
11 pub enum ReadWrite {
12     Read,
13     Write,
14 }
15 
16 /// The kind of fault for a page fault event.
17 #[derive(Clone, Copy, Debug, PartialEq)]
18 pub enum FaultKind {
19     /// The fault was a read or write on a missing page.
20     Missing,
21     /// The fault was a write on a write-protected page.
22     #[cfg(feature = "linux5_7")]
23     WriteProtected,
24 }
25 
26 /// Events from the userfaultfd object that are read by `Uffd::read_event()`.
27 #[derive(Debug)]
28 pub enum Event {
29     /// A pagefault event.
30     Pagefault {
31         /// The kind of fault.
32         kind: FaultKind,
33         /// Whether the fault is on a read or a write.
34         rw: ReadWrite,
35         /// The address that triggered the fault.
36         addr: *mut c_void,
37         /// The thread that triggered the fault, if [`FeatureFlags::THREAD_ID`] is enabled.
38         ///
39         /// If the thread ID feature is not enabled, the value of this field is undefined. It would
40         /// not be undefined behavior to use it, strictly speaking, but the [`Pid`] will not
41         /// necessarily point to a real thread.
42         ///
43         /// This requires this crate to be compiled with the `linux4_14` feature.
44         #[cfg(feature = "linux4_14")]
45         thread_id: Pid,
46     },
47     /// Generated when the faulting process invokes `fork(2)` (or `clone(2)` without the `CLONE_VM`
48     /// flag).
49     Fork {
50         /// The `Uffd` object created for the child by `fork(2)`
51         uffd: Uffd,
52     },
53     /// Generated when the faulting process invokes `mremap(2)`.
54     Remap {
55         /// The original address of the memory range that was remapped.
56         from: *mut c_void,
57         /// The new address of the memory range that was remapped.
58         to: *mut c_void,
59         /// The original length of the memory range that was remapped.
60         len: usize,
61     },
62     /// Generated when the faulting process invokes `madvise(2)` with `MADV_DONTNEED` or
63     /// `MADV_REMOVE` advice.
64     Remove {
65         /// The start address of the memory range that was freed.
66         start: *mut c_void,
67         /// The end address of the memory range that was freed.
68         end: *mut c_void,
69     },
70     /// Generated when the faulting process unmaps a meomry range, either explicitly using
71     /// `munmap(2)` or implicitly during `mmap(2)` or `mremap(2)`.
72     Unmap {
73         /// The start address of the memory range that was unmapped.
74         start: *mut c_void,
75         /// The end address of the memory range that was unmapped.
76         end: *mut c_void,
77     },
78 }
79 
80 impl Event {
from_uffd_msg(msg: &raw::uffd_msg) -> Result<Event>81     pub(crate) fn from_uffd_msg(msg: &raw::uffd_msg) -> Result<Event> {
82         match msg.event {
83             raw::UFFD_EVENT_PAGEFAULT => {
84                 let pagefault = unsafe { msg.arg.pagefault };
85                 cfg_if::cfg_if!(
86                     if #[cfg(feature = "linux5_7")] {
87                         let kind = if pagefault.flags & raw::UFFD_PAGEFAULT_FLAG_WP != 0 {
88                             FaultKind::WriteProtected
89                         } else {
90                             FaultKind::Missing
91                         };
92                     } else {
93                         let kind = FaultKind::Missing;
94                     }
95                 );
96 
97                 let rw = if pagefault.flags & raw::UFFD_PAGEFAULT_FLAG_WRITE == 0 {
98                     ReadWrite::Read
99                 } else {
100                     ReadWrite::Write
101                 };
102                 // Converting the ptid to i32 is safe because the maximum pid in
103                 // Linux is 2^22, which is about 4 million.
104                 //
105                 // Reference:
106                 //   https://github.com/torvalds/linux/blob/2d338201d5311bcd79d42f66df4cecbcbc5f4f2c/include/linux/threads.h
107                 #[cfg(feature = "linux4_14")]
108                 let thread_id = Pid::from_raw(unsafe { pagefault.feat.ptid } as i32);
109                 Ok(Event::Pagefault {
110                     kind,
111                     rw,
112                     addr: pagefault.address as *mut c_void,
113                     #[cfg(feature = "linux4_14")]
114                     thread_id,
115                 })
116             }
117             raw::UFFD_EVENT_FORK => {
118                 let fork = unsafe { msg.arg.fork };
119                 Ok(Event::Fork {
120                     uffd: unsafe { Uffd::from_raw_fd(fork.ufd as RawFd) },
121                 })
122             }
123             raw::UFFD_EVENT_REMAP => {
124                 let remap = unsafe { msg.arg.remap };
125                 Ok(Event::Remap {
126                     from: remap.from as *mut c_void,
127                     to: remap.to as *mut c_void,
128                     len: remap.len as usize,
129                 })
130             }
131             raw::UFFD_EVENT_REMOVE => {
132                 let remove = unsafe { msg.arg.remove };
133                 Ok(Event::Remove {
134                     start: remove.start as *mut c_void,
135                     end: remove.end as *mut c_void,
136                 })
137             }
138             raw::UFFD_EVENT_UNMAP => {
139                 let remove = unsafe { msg.arg.remove };
140                 Ok(Event::Unmap {
141                     start: remove.start as *mut c_void,
142                     end: remove.end as *mut c_void,
143                 })
144             }
145             _ => Err(Error::UnrecognizedEvent(msg.event)),
146         }
147     }
148 }
149