1 | //! Bindings for the Linux `prctl` system call. |
2 | //! |
3 | //! There are similarities (but also differences) with FreeBSD's `procctl` |
4 | //! system call, whose interface is located in the `procctl.rs` file. |
5 | |
6 | #![allow (unsafe_code)] |
7 | |
8 | use core::convert::{TryFrom, TryInto}; |
9 | use core::mem::{size_of, MaybeUninit}; |
10 | use core::ptr::{null, null_mut, NonNull}; |
11 | |
12 | use bitflags::bitflags; |
13 | |
14 | use crate::backend::c::{c_int, c_uint, c_void}; |
15 | use crate::backend::process::syscalls; |
16 | use crate::backend::process::types::Signal; |
17 | use crate::fd::{AsRawFd, BorrowedFd}; |
18 | use crate::ffi::CStr; |
19 | use crate::io; |
20 | use crate::process::{Pid, RawPid}; |
21 | use crate::utils::{as_mut_ptr, as_ptr}; |
22 | |
23 | // |
24 | // Helper functions. |
25 | // |
26 | |
27 | #[inline ] |
28 | pub(crate) unsafe fn prctl_1arg(option: c_int) -> io::Result<c_int> { |
29 | const NULL: *mut c_void = null_mut(); |
30 | syscalls::prctl(option, NULL, NULL, NULL, NULL) |
31 | } |
32 | |
33 | #[inline ] |
34 | pub(crate) unsafe fn prctl_2args(option: c_int, arg2: *mut c_void) -> io::Result<c_int> { |
35 | const NULL: *mut c_void = null_mut(); |
36 | syscalls::prctl(option, arg2, NULL, NULL, NULL) |
37 | } |
38 | |
39 | #[inline ] |
40 | pub(crate) unsafe fn prctl_3args( |
41 | option: c_int, |
42 | arg2: *mut c_void, |
43 | arg3: *mut c_void, |
44 | ) -> io::Result<c_int> { |
45 | syscalls::prctl(option, arg2, arg3, arg4:null_mut(), arg5:null_mut()) |
46 | } |
47 | |
48 | #[inline ] |
49 | pub(crate) unsafe fn prctl_get_at_arg2_optional<P>(option: i32) -> io::Result<P> { |
50 | let mut value: MaybeUninit<P> = MaybeUninit::uninit(); |
51 | prctl_2args(option, arg2:value.as_mut_ptr().cast())?; |
52 | Ok(value.assume_init()) |
53 | } |
54 | |
55 | #[inline ] |
56 | pub(crate) unsafe fn prctl_get_at_arg2<P, T>(option: i32) -> io::Result<T> |
57 | where |
58 | P: Default, |
59 | T: TryFrom<P, Error = io::Errno>, |
60 | { |
61 | let mut value: P = Default::default(); |
62 | prctl_2args(option, arg2:as_mut_ptr(&mut value).cast())?; |
63 | TryFrom::try_from(value) |
64 | } |
65 | |
66 | // |
67 | // PR_GET_PDEATHSIG/PR_SET_PDEATHSIG |
68 | // |
69 | |
70 | const PR_GET_PDEATHSIG: c_int = 2; |
71 | |
72 | /// Get the current value of the parent process death signal. |
73 | /// |
74 | /// # References |
75 | /// - [Linux: `prctl(PR_GET_PDEATHSIG,...)`] |
76 | /// - [FreeBSD: `procctl(PROC_PDEATHSIG_STATUS,...)`] |
77 | /// |
78 | /// [Linux: `prctl(PR_GET_PDEATHSIG,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
79 | /// [FreeBSD: `procctl(PROC_PDEATHSIG_STATUS,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 |
80 | #[inline ] |
81 | #[doc (alias = "PR_GET_PDEATHSIG" )] |
82 | pub fn parent_process_death_signal() -> io::Result<Option<Signal>> { |
83 | unsafe { prctl_get_at_arg2_optional::<c_int>(PR_GET_PDEATHSIG) }.map(op:Signal::from_raw) |
84 | } |
85 | |
86 | const PR_SET_PDEATHSIG: c_int = 1; |
87 | |
88 | /// Set the parent-death signal of the calling process. |
89 | /// |
90 | /// # References |
91 | /// - [Linux: `prctl(PR_SET_PDEATHSIG,...)`] |
92 | /// - [FreeBSD: `procctl(PROC_PDEATHSIG_CTL,...)`] |
93 | /// |
94 | /// [Linux: `prctl(PR_SET_PDEATHSIG,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
95 | /// [FreeBSD: `procctl(PROC_PDEATHSIG_CTL,...)`]: https://man.freebsd.org/cgi/man.cgi?query=procctl&sektion=2 |
96 | #[inline ] |
97 | #[doc (alias = "PR_SET_PDEATHSIG" )] |
98 | pub fn set_parent_process_death_signal(signal: Option<Signal>) -> io::Result<()> { |
99 | let signal: usize = signal.map_or(default:0_usize, |signal: Signal| signal as usize); |
100 | unsafe { prctl_2args(PR_SET_PDEATHSIG, signal as *mut _) }.map(|_r: i32| ()) |
101 | } |
102 | |
103 | // |
104 | // PR_GET_DUMPABLE/PR_SET_DUMPABLE |
105 | // |
106 | |
107 | const PR_GET_DUMPABLE: c_int = 3; |
108 | |
109 | const SUID_DUMP_DISABLE: i32 = 0; |
110 | const SUID_DUMP_USER: i32 = 1; |
111 | const SUID_DUMP_ROOT: i32 = 2; |
112 | |
113 | /// `SUID_DUMP_*` values for use with [`dumpable_behavior`] and |
114 | /// [`set_dumpable_behavior`]. |
115 | #[derive (Copy, Clone, Debug, Eq, PartialEq)] |
116 | #[repr (i32)] |
117 | pub enum DumpableBehavior { |
118 | /// Not dumpable. |
119 | #[doc (alias = "SUID_DUMP_DISABLE" )] |
120 | NotDumpable = SUID_DUMP_DISABLE, |
121 | /// Dumpable. |
122 | #[doc (alias = "SUID_DUMP_USER" )] |
123 | Dumpable = SUID_DUMP_USER, |
124 | /// Dumpable but only readable by root. |
125 | #[doc (alias = "SUID_DUMP_ROOT" )] |
126 | DumpableReadableOnlyByRoot = SUID_DUMP_ROOT, |
127 | } |
128 | |
129 | impl TryFrom<i32> for DumpableBehavior { |
130 | type Error = io::Errno; |
131 | |
132 | fn try_from(value: i32) -> Result<Self, Self::Error> { |
133 | match value { |
134 | SUID_DUMP_DISABLE => Ok(Self::NotDumpable), |
135 | SUID_DUMP_USER => Ok(Self::Dumpable), |
136 | SUID_DUMP_ROOT => Ok(Self::DumpableReadableOnlyByRoot), |
137 | _ => Err(io::Errno::RANGE), |
138 | } |
139 | } |
140 | } |
141 | |
142 | /// Get the current state of the calling process's `dumpable` attribute. |
143 | /// |
144 | /// # References |
145 | /// - [`prctl(PR_GET_DUMPABLE,...)`] |
146 | /// |
147 | /// [`prctl(PR_GET_DUMPABLE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
148 | #[inline ] |
149 | #[doc (alias = "PR_GET_DUMPABLE" )] |
150 | pub fn dumpable_behavior() -> io::Result<DumpableBehavior> { |
151 | unsafe { prctl_1arg(PR_GET_DUMPABLE) }.and_then(op:TryInto::try_into) |
152 | } |
153 | |
154 | const PR_SET_DUMPABLE: c_int = 4; |
155 | |
156 | /// Set the state of the `dumpable` attribute, which determines whether the |
157 | /// process can be traced and whether core dumps are produced for the calling |
158 | /// process upon delivery of a signal whose default behavior is to produce a |
159 | /// core dump. |
160 | /// |
161 | /// A similar function with the same name is available on FreeBSD (as part of |
162 | /// the `procctl` interface), but it has an extra argument which allows to |
163 | /// select a process other then the current process. |
164 | /// |
165 | /// # References |
166 | /// - [`prctl(PR_SET_DUMPABLE,...)`] |
167 | /// |
168 | /// [`prctl(PR_SET_DUMPABLE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
169 | #[inline ] |
170 | #[doc (alias = "PR_SET_DUMPABLE" )] |
171 | pub fn set_dumpable_behavior(config: DumpableBehavior) -> io::Result<()> { |
172 | unsafe { prctl_2args(PR_SET_DUMPABLE, config as usize as *mut _) }.map(|_r: i32| ()) |
173 | } |
174 | |
175 | // |
176 | // PR_GET_UNALIGN/PR_SET_UNALIGN |
177 | // |
178 | |
179 | const PR_GET_UNALIGN: c_int = 5; |
180 | |
181 | bitflags! { |
182 | /// `PR_UNALIGN_*` flags for use with [`unaligned_access_control`] and |
183 | pub struct UnalignedAccessControl: u32 { |
184 | /// Silently fix up unaligned user accesses. |
185 | #[doc(alias = "NOPRINT" )] |
186 | #[doc(alias = "PR_UNALIGN_NOPRINT" )] |
187 | const NO_PRINT = 1; |
188 | /// Generate a [`Signal::Bus`] signal on unaligned user access. |
189 | #[doc(alias = "PR_UNALIGN_SIGBUS" )] |
190 | const SIGBUS = 2; |
191 | } |
192 | } |
193 | |
194 | /// Get unaligned access control bits. |
195 | /// |
196 | /// # References |
197 | /// - [`prctl(PR_GET_UNALIGN,...)`] |
198 | /// |
199 | /// [`prctl(PR_GET_UNALIGN,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
200 | #[inline ] |
201 | #[doc (alias = "PR_GET_UNALIGN" )] |
202 | pub fn unaligned_access_control() -> io::Result<UnalignedAccessControl> { |
203 | let r: u32 = unsafe { prctl_get_at_arg2_optional::<c_uint>(PR_GET_UNALIGN)? }; |
204 | UnalignedAccessControl::from_bits(r).ok_or(err:io::Errno::RANGE) |
205 | } |
206 | |
207 | const PR_SET_UNALIGN: c_int = 6; |
208 | |
209 | /// Set unaligned access control bits. |
210 | /// |
211 | /// # References |
212 | /// - [`prctl(PR_SET_UNALIGN,...)`] |
213 | /// |
214 | /// [`prctl(PR_SET_UNALIGN,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
215 | #[inline ] |
216 | #[doc (alias = "PR_SET_UNALIGN" )] |
217 | pub fn set_unaligned_access_control(config: UnalignedAccessControl) -> io::Result<()> { |
218 | unsafe { prctl_2args(PR_SET_UNALIGN, config.bits() as usize as *mut _) }.map(|_r: i32| ()) |
219 | } |
220 | |
221 | // |
222 | // PR_GET_FPEMU/PR_SET_FPEMU |
223 | // |
224 | |
225 | const PR_GET_FPEMU: c_int = 9; |
226 | |
227 | bitflags! { |
228 | /// `PR_FPEMU_*` flags for use with [`floating_point_emulation_control`] |
229 | /// and [`set_floating_point_emulation_control`]. |
230 | pub struct FloatingPointEmulationControl: u32 { |
231 | /// Silently emulate floating point operations accesses. |
232 | #[doc(alias = "PR_UNALIGN_NOPRINT" )] |
233 | const NO_PRINT = 1; |
234 | /// Don't emulate floating point operations, send a [`Signal::Fpe`] |
235 | /// signal instead. |
236 | #[doc(alias = "PR_UNALIGN_SIGFPE" )] |
237 | const SIGFPE = 2; |
238 | } |
239 | } |
240 | |
241 | /// Get floating point emulation control bits. |
242 | /// |
243 | /// # References |
244 | /// - [`prctl(PR_GET_FPEMU,...)`] |
245 | /// |
246 | /// [`prctl(PR_GET_FPEMU,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
247 | #[inline ] |
248 | #[doc (alias = "PR_GET_FPEMU" )] |
249 | pub fn floating_point_emulation_control() -> io::Result<FloatingPointEmulationControl> { |
250 | let r: u32 = unsafe { prctl_get_at_arg2_optional::<c_uint>(PR_GET_FPEMU)? }; |
251 | FloatingPointEmulationControl::from_bits(r).ok_or(err:io::Errno::RANGE) |
252 | } |
253 | |
254 | const PR_SET_FPEMU: c_int = 10; |
255 | |
256 | /// Set floating point emulation control bits. |
257 | /// |
258 | /// # References |
259 | /// - [`prctl(PR_SET_FPEMU,...)`] |
260 | /// |
261 | /// [`prctl(PR_SET_FPEMU,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
262 | #[inline ] |
263 | #[doc (alias = "PR_SET_FPEMU" )] |
264 | pub fn set_floating_point_emulation_control( |
265 | config: FloatingPointEmulationControl, |
266 | ) -> io::Result<()> { |
267 | unsafe { prctl_2args(PR_SET_FPEMU, config.bits() as usize as *mut _) }.map(|_r: i32| ()) |
268 | } |
269 | |
270 | // |
271 | // PR_GET_FPEXC/PR_SET_FPEXC |
272 | // |
273 | |
274 | const PR_GET_FPEXC: c_int = 11; |
275 | |
276 | bitflags! { |
277 | /// Zero means floating point exceptions are disabled. |
278 | pub struct FloatingPointExceptionMode: u32 { |
279 | /// Async non-recoverable exception mode. |
280 | const NONRECOV = 1; |
281 | /// Async recoverable exception mode. |
282 | const ASYNC = 2; |
283 | /// Precise exception mode. |
284 | const PRECISE = 3; |
285 | |
286 | /// Use FPEXC for floating point exception enables. |
287 | const SW_ENABLE = 0x80; |
288 | /// Floating point divide by zero. |
289 | const DIV = 0x01_0000; |
290 | /// Floating point overflow. |
291 | const OVF = 0x02_0000; |
292 | /// Floating point underflow. |
293 | const UND = 0x04_0000; |
294 | /// Floating point inexact result. |
295 | const RES = 0x08_0000; |
296 | /// Floating point invalid operation. |
297 | const INV = 0x10_0000; |
298 | } |
299 | } |
300 | |
301 | /// Get floating point exception mode. |
302 | /// |
303 | /// # References |
304 | /// - [`prctl(PR_GET_FPEXC,...)`] |
305 | /// |
306 | /// [`prctl(PR_GET_FPEXC,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
307 | #[inline ] |
308 | #[doc (alias = "PR_GET_FPEXEC" )] |
309 | pub fn floating_point_exception_mode() -> io::Result<Option<FloatingPointExceptionMode>> { |
310 | unsafe { prctl_get_at_arg2_optional::<c_uint>(PR_GET_FPEXC) } |
311 | .map(op:FloatingPointExceptionMode::from_bits) |
312 | } |
313 | |
314 | const PR_SET_FPEXC: c_int = 12; |
315 | |
316 | /// Set floating point exception mode. |
317 | /// |
318 | /// # References |
319 | /// - [`prctl(PR_SET_FPEXC,...)`] |
320 | /// |
321 | /// [`prctl(PR_SET_FPEXC,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
322 | #[inline ] |
323 | #[doc (alias = "PR_SET_FPEXEC" )] |
324 | pub fn set_floating_point_exception_mode( |
325 | config: Option<FloatingPointExceptionMode>, |
326 | ) -> io::Result<()> { |
327 | let config: u32 = config.as_ref().map_or(default:0, f:FloatingPointExceptionMode::bits); |
328 | unsafe { prctl_2args(PR_SET_FPEXC, config as usize as *mut _) }.map(|_r: i32| ()) |
329 | } |
330 | |
331 | // |
332 | // PR_GET_TIMING/PR_SET_TIMING |
333 | // |
334 | |
335 | const PR_GET_TIMING: c_int = 13; |
336 | |
337 | const PR_TIMING_STATISTICAL: i32 = 0; |
338 | const PR_TIMING_TIMESTAMP: i32 = 1; |
339 | |
340 | /// `PR_TIMING_*` values for use with [`timing_method`] and |
341 | /// [`set_timing_method`]. |
342 | #[derive (Copy, Clone, Debug, Eq, PartialEq)] |
343 | #[repr (i32)] |
344 | pub enum TimingMethod { |
345 | /// Normal, traditional, statistical process timing. |
346 | Statistical = PR_TIMING_STATISTICAL, |
347 | /// Accurate timestamp based process timing. |
348 | TimeStamp = PR_TIMING_TIMESTAMP, |
349 | } |
350 | |
351 | impl TryFrom<i32> for TimingMethod { |
352 | type Error = io::Errno; |
353 | |
354 | fn try_from(value: i32) -> Result<Self, Self::Error> { |
355 | match value { |
356 | PR_TIMING_STATISTICAL => Ok(Self::Statistical), |
357 | PR_TIMING_TIMESTAMP => Ok(Self::TimeStamp), |
358 | _ => Err(io::Errno::RANGE), |
359 | } |
360 | } |
361 | } |
362 | |
363 | /// Get which process timing method is currently in use. |
364 | /// |
365 | /// # References |
366 | /// - [`prctl(PR_GET_TIMING,...)`] |
367 | /// |
368 | /// [`prctl(PR_GET_TIMING,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
369 | #[inline ] |
370 | #[doc (alias = "PR_GET_TIMING" )] |
371 | pub fn timing_method() -> io::Result<TimingMethod> { |
372 | unsafe { prctl_1arg(PR_GET_TIMING) }.and_then(op:TryInto::try_into) |
373 | } |
374 | |
375 | const PR_SET_TIMING: c_int = 14; |
376 | |
377 | /// Set whether to use (normal, traditional) statistical process timing or |
378 | /// accurate timestamp-based process timing. |
379 | /// |
380 | /// # References |
381 | /// - [`prctl(PR_SET_TIMING,...)`] |
382 | /// |
383 | /// [`prctl(PR_SET_TIMING,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
384 | #[inline ] |
385 | #[doc (alias = "PR_SET_TIMING" )] |
386 | pub fn set_timing_method(method: TimingMethod) -> io::Result<()> { |
387 | unsafe { prctl_2args(PR_SET_TIMING, method as usize as *mut _) }.map(|_r: i32| ()) |
388 | } |
389 | |
390 | // |
391 | // PR_GET_ENDIAN/PR_SET_ENDIAN |
392 | // |
393 | |
394 | const PR_GET_ENDIAN: c_int = 19; |
395 | |
396 | const PR_ENDIAN_BIG: u32 = 0; |
397 | const PR_ENDIAN_LITTLE: u32 = 1; |
398 | const PR_ENDIAN_PPC_LITTLE: u32 = 2; |
399 | |
400 | /// `PR_ENDIAN_*` values for use with [`endian_mode`]. |
401 | #[derive (Copy, Clone, Debug, Eq, PartialEq)] |
402 | #[repr (u32)] |
403 | pub enum EndianMode { |
404 | /// Big endian mode. |
405 | Big = PR_ENDIAN_BIG, |
406 | /// True little endian mode. |
407 | Little = PR_ENDIAN_LITTLE, |
408 | /// `PowerPC` pseudo little endian. |
409 | PowerPCLittle = PR_ENDIAN_PPC_LITTLE, |
410 | } |
411 | |
412 | impl TryFrom<u32> for EndianMode { |
413 | type Error = io::Errno; |
414 | |
415 | fn try_from(value: u32) -> Result<Self, Self::Error> { |
416 | match value { |
417 | PR_ENDIAN_BIG => Ok(Self::Big), |
418 | PR_ENDIAN_LITTLE => Ok(Self::Little), |
419 | PR_ENDIAN_PPC_LITTLE => Ok(Self::PowerPCLittle), |
420 | _ => Err(io::Errno::RANGE), |
421 | } |
422 | } |
423 | } |
424 | |
425 | /// Get the endianness of the calling process. |
426 | /// |
427 | /// # References |
428 | /// - [`prctl(PR_GET_ENDIAN,...)`] |
429 | /// |
430 | /// [`prctl(PR_GET_ENDIAN,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
431 | #[inline ] |
432 | #[doc (alias = "PR_GET_ENDIAN" )] |
433 | pub fn endian_mode() -> io::Result<EndianMode> { |
434 | unsafe { prctl_get_at_arg2::<c_uint, _>(PR_GET_ENDIAN) } |
435 | } |
436 | |
437 | const PR_SET_ENDIAN: c_int = 20; |
438 | |
439 | /// Set the endianness of the calling process. |
440 | /// |
441 | /// # References |
442 | /// - [`prctl(PR_SET_ENDIAN,...)`] |
443 | /// |
444 | /// # Safety |
445 | /// |
446 | /// Please ensure the conditions necessary to safely call this function, |
447 | /// as detailed in the references above. |
448 | /// |
449 | /// [`prctl(PR_SET_ENDIAN,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
450 | #[inline ] |
451 | #[doc (alias = "PR_SET_ENDIAN" )] |
452 | pub unsafe fn set_endian_mode(mode: EndianMode) -> io::Result<()> { |
453 | prctl_2args(PR_SET_ENDIAN, mode as usize as *mut _).map(|_r: i32| ()) |
454 | } |
455 | |
456 | // |
457 | // PR_GET_TSC/PR_SET_TSC |
458 | // |
459 | |
460 | const PR_GET_TSC: c_int = 25; |
461 | |
462 | const PR_TSC_ENABLE: u32 = 1; |
463 | const PR_TSC_SIGSEGV: u32 = 2; |
464 | |
465 | /// `PR_TSC_*` values for use with [`time_stamp_counter_readability`] and |
466 | /// [`set_time_stamp_counter_readability`]. |
467 | #[derive (Copy, Clone, Debug, Eq, PartialEq)] |
468 | #[repr (u32)] |
469 | pub enum TimeStampCounterReadability { |
470 | /// Allow the use of the timestamp counter. |
471 | Readable = PR_TSC_ENABLE, |
472 | /// Throw a [`Signal::Segv`] signal instead of reading the TSC. |
473 | RaiseSIGSEGV = PR_TSC_SIGSEGV, |
474 | } |
475 | |
476 | impl TryFrom<u32> for TimeStampCounterReadability { |
477 | type Error = io::Errno; |
478 | |
479 | fn try_from(value: u32) -> Result<Self, Self::Error> { |
480 | match value { |
481 | PR_TSC_ENABLE => Ok(Self::Readable), |
482 | PR_TSC_SIGSEGV => Ok(Self::RaiseSIGSEGV), |
483 | _ => Err(io::Errno::RANGE), |
484 | } |
485 | } |
486 | } |
487 | |
488 | /// Get the state of the flag determining if the timestamp counter can be read. |
489 | /// |
490 | /// # References |
491 | /// - [`prctl(PR_GET_TSC,...)`] |
492 | /// |
493 | /// [`prctl(PR_GET_TSC,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
494 | #[inline ] |
495 | #[doc (alias = "PR_GET_TSC" )] |
496 | pub fn time_stamp_counter_readability() -> io::Result<TimeStampCounterReadability> { |
497 | unsafe { prctl_get_at_arg2::<c_uint, _>(PR_GET_TSC) } |
498 | } |
499 | |
500 | const PR_SET_TSC: c_int = 26; |
501 | |
502 | /// Set the state of the flag determining if the timestamp counter can be read |
503 | /// by the process. |
504 | /// |
505 | /// # References |
506 | /// - [`prctl(PR_SET_TSC,...)`] |
507 | /// |
508 | /// [`prctl(PR_SET_TSC,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
509 | #[inline ] |
510 | #[doc (alias = "PR_SET_TSC" )] |
511 | pub fn set_time_stamp_counter_readability( |
512 | readability: TimeStampCounterReadability, |
513 | ) -> io::Result<()> { |
514 | unsafe { prctl_2args(PR_SET_TSC, readability as usize as *mut _) }.map(|_r: i32| ()) |
515 | } |
516 | |
517 | // |
518 | // PR_TASK_PERF_EVENTS_DISABLE/PR_TASK_PERF_EVENTS_ENABLE |
519 | // |
520 | |
521 | const PR_TASK_PERF_EVENTS_DISABLE: c_int = 31; |
522 | const PR_TASK_PERF_EVENTS_ENABLE: c_int = 32; |
523 | |
524 | /// Enable or disable all performance counters attached to the calling process. |
525 | /// |
526 | /// # References |
527 | /// - [`prctl(PR_TASK_PERF_EVENTS_ENABLE,...)`] |
528 | /// - [`prctl(PR_TASK_PERF_EVENTS_DISABLE,...)`] |
529 | /// |
530 | /// [`prctl(PR_TASK_PERF_EVENTS_ENABLE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
531 | /// [`prctl(PR_TASK_PERF_EVENTS_DISABLE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
532 | #[inline ] |
533 | #[doc (alias = "PR_TASK_PERF_EVENTS_ENABLE" )] |
534 | #[doc (alias = "PR_TASK_PERF_EVENTS_DISABLE" )] |
535 | pub fn configure_performance_counters(enable: bool) -> io::Result<()> { |
536 | let option: i32 = if enable { |
537 | PR_TASK_PERF_EVENTS_ENABLE |
538 | } else { |
539 | PR_TASK_PERF_EVENTS_DISABLE |
540 | }; |
541 | |
542 | unsafe { prctl_1arg(option) }.map(|_r: i32| ()) |
543 | } |
544 | |
545 | // |
546 | // PR_MCE_KILL_GET/PR_MCE_KILL |
547 | // |
548 | |
549 | const PR_MCE_KILL_GET: c_int = 34; |
550 | |
551 | const PR_MCE_KILL_LATE: u32 = 0; |
552 | const PR_MCE_KILL_EARLY: u32 = 1; |
553 | const PR_MCE_KILL_DEFAULT: u32 = 2; |
554 | |
555 | /// `PR_MCE_KILL_*` values for use with |
556 | /// [`machine_check_memory_corruption_kill_policy`] and |
557 | /// [`set_machine_check_memory_corruption_kill_policy`]. |
558 | #[derive (Copy, Clone, Debug, Eq, PartialEq)] |
559 | #[repr (u32)] |
560 | pub enum MachineCheckMemoryCorruptionKillPolicy { |
561 | /// Late kill policy. |
562 | #[doc (alias = "PR_MCE_KILL_LATE" )] |
563 | Late = PR_MCE_KILL_LATE, |
564 | /// Early kill policy. |
565 | #[doc (alias = "PR_MCE_KILL_EARLY" )] |
566 | Early = PR_MCE_KILL_EARLY, |
567 | /// System-wide default policy. |
568 | #[doc (alias = "PR_MCE_KILL_DEFAULT" )] |
569 | Default = PR_MCE_KILL_DEFAULT, |
570 | } |
571 | |
572 | impl TryFrom<u32> for MachineCheckMemoryCorruptionKillPolicy { |
573 | type Error = io::Errno; |
574 | |
575 | fn try_from(value: u32) -> Result<Self, Self::Error> { |
576 | match value { |
577 | PR_MCE_KILL_LATE => Ok(Self::Late), |
578 | PR_MCE_KILL_EARLY => Ok(Self::Early), |
579 | PR_MCE_KILL_DEFAULT => Ok(Self::Default), |
580 | _ => Err(io::Errno::RANGE), |
581 | } |
582 | } |
583 | } |
584 | |
585 | /// Get the current per-process machine check kill policy. |
586 | /// |
587 | /// # References |
588 | /// - [`prctl(PR_MCE_KILL_GET,...)`] |
589 | /// |
590 | /// [`prctl(PR_MCE_KILL_GET,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
591 | #[inline ] |
592 | #[doc (alias = "PR_MCE_KILL_GET" )] |
593 | pub fn machine_check_memory_corruption_kill_policy( |
594 | ) -> io::Result<MachineCheckMemoryCorruptionKillPolicy> { |
595 | let r: u32 = unsafe { prctl_1arg(PR_MCE_KILL_GET)? } as c_uint; |
596 | MachineCheckMemoryCorruptionKillPolicy::try_from(r) |
597 | } |
598 | |
599 | const PR_MCE_KILL: c_int = 33; |
600 | |
601 | const PR_MCE_KILL_CLEAR: usize = 0; |
602 | const PR_MCE_KILL_SET: usize = 1; |
603 | |
604 | /// Set the machine check memory corruption kill policy for the calling thread. |
605 | /// |
606 | /// # References |
607 | /// - [`prctl(PR_MCE_KILL,...)`] |
608 | /// |
609 | /// [`prctl(PR_MCE_KILL,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
610 | #[inline ] |
611 | #[doc (alias = "PR_MCE_KILL" )] |
612 | pub fn set_machine_check_memory_corruption_kill_policy( |
613 | policy: Option<MachineCheckMemoryCorruptionKillPolicy>, |
614 | ) -> io::Result<()> { |
615 | let (sub_operation: usize, policy: *mut c_void) = if let Some(policy: MachineCheckMemoryCorruptionKillPolicy) = policy { |
616 | (PR_MCE_KILL_SET, policy as usize as *mut _) |
617 | } else { |
618 | (PR_MCE_KILL_CLEAR, null_mut()) |
619 | }; |
620 | |
621 | unsafe { prctl_3args(PR_MCE_KILL, sub_operation as *mut _, policy) }.map(|_r: i32| ()) |
622 | } |
623 | |
624 | // |
625 | // PR_SET_MM |
626 | // |
627 | |
628 | const PR_SET_MM: c_int = 35; |
629 | |
630 | const PR_SET_MM_START_CODE: u32 = 1; |
631 | const PR_SET_MM_END_CODE: u32 = 2; |
632 | const PR_SET_MM_START_DATA: u32 = 3; |
633 | const PR_SET_MM_END_DATA: u32 = 4; |
634 | const PR_SET_MM_START_STACK: u32 = 5; |
635 | const PR_SET_MM_START_BRK: u32 = 6; |
636 | const PR_SET_MM_BRK: u32 = 7; |
637 | const PR_SET_MM_ARG_START: u32 = 8; |
638 | const PR_SET_MM_ARG_END: u32 = 9; |
639 | const PR_SET_MM_ENV_START: u32 = 10; |
640 | const PR_SET_MM_ENV_END: u32 = 11; |
641 | const PR_SET_MM_AUXV: usize = 12; |
642 | const PR_SET_MM_EXE_FILE: usize = 13; |
643 | const PR_SET_MM_MAP: usize = 14; |
644 | const PR_SET_MM_MAP_SIZE: usize = 15; |
645 | |
646 | /// `PR_SET_MM_*` values for use with [`set_virtual_memory_map_address`]. |
647 | #[derive (Copy, Clone, Debug, Eq, PartialEq)] |
648 | #[repr (u32)] |
649 | pub enum VirtualMemoryMapAddress { |
650 | /// Set the address above which the program text can run. |
651 | CodeStart = PR_SET_MM_START_CODE, |
652 | /// Set the address below which the program text can run. |
653 | CodeEnd = PR_SET_MM_END_CODE, |
654 | /// Set the address above which initialized and uninitialized (bss) data |
655 | /// are placed. |
656 | DataStart = PR_SET_MM_START_DATA, |
657 | /// Set the address below which initialized and uninitialized (bss) data |
658 | /// are placed. |
659 | DataEnd = PR_SET_MM_END_DATA, |
660 | /// Set the start address of the stack. |
661 | StackStart = PR_SET_MM_START_STACK, |
662 | /// Set the address above which the program heap can be expanded with `brk` |
663 | /// call. |
664 | BrkStart = PR_SET_MM_START_BRK, |
665 | /// Set the current `brk` value. |
666 | BrkCurrent = PR_SET_MM_BRK, |
667 | /// Set the address above which the program command line is placed. |
668 | ArgStart = PR_SET_MM_ARG_START, |
669 | /// Set the address below which the program command line is placed. |
670 | ArgEnd = PR_SET_MM_ARG_END, |
671 | /// Set the address above which the program environment is placed. |
672 | EnvironmentStart = PR_SET_MM_ENV_START, |
673 | /// Set the address below which the program environment is placed. |
674 | EnvironmentEnd = PR_SET_MM_ENV_END, |
675 | } |
676 | |
677 | /// Modify certain kernel memory map descriptor addresses of the calling |
678 | /// process. |
679 | /// |
680 | /// # References |
681 | /// - [`prctl(PR_SET_MM,...)`] |
682 | /// |
683 | /// # Safety |
684 | /// |
685 | /// Please ensure the conditions necessary to safely call this function, |
686 | /// as detailed in the references above. |
687 | /// |
688 | /// [`prctl(PR_SET_MM,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
689 | #[inline ] |
690 | #[doc (alias = "PR_SET_MM" )] |
691 | pub unsafe fn set_virtual_memory_map_address( |
692 | option: VirtualMemoryMapAddress, |
693 | address: Option<NonNull<c_void>>, |
694 | ) -> io::Result<()> { |
695 | let address: *mut c_void = address.map_or_else(default:null_mut, f:NonNull::as_ptr); |
696 | prctl_3args(PR_SET_MM, option as usize as *mut _, address).map(|_r: i32| ()) |
697 | } |
698 | |
699 | /// Supersede the `/proc/pid/exe` symbolic link with a new one pointing to a |
700 | /// new executable file. |
701 | /// |
702 | /// # References |
703 | /// - [`prctl(PR_SET_MM,PR_SET_MM_EXE_FILE,...)`] |
704 | /// |
705 | /// [`prctl(PR_SET_MM,PR_SET_MM_EXE_FILE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
706 | #[inline ] |
707 | #[doc (alias = "PR_SET_MM" )] |
708 | #[doc (alias = "PR_SET_MM_EXE_FILE" )] |
709 | pub fn set_executable_file(fd: BorrowedFd) -> io::Result<()> { |
710 | let fd: usize = usize::try_from(fd.as_raw_fd()).map_err(|_r: TryFromIntError| io::Errno::RANGE)?; |
711 | unsafe { prctl_3args(PR_SET_MM, PR_SET_MM_EXE_FILE as *mut _, fd as *mut _) }.map(|_r: i32| ()) |
712 | } |
713 | |
714 | /// Set a new auxiliary vector. |
715 | /// |
716 | /// # References |
717 | /// - [`prctl(PR_SET_MM,PR_SET_MM_AUXV,...)`] |
718 | /// |
719 | /// # Safety |
720 | /// |
721 | /// Please ensure the conditions necessary to safely call this function, |
722 | /// as detailed in the references above. |
723 | /// |
724 | /// [`prctl(PR_SET_MM,PR_SET_MM_AUXV,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
725 | #[inline ] |
726 | #[doc (alias = "PR_SET_MM" )] |
727 | #[doc (alias = "PR_SET_MM_AUXV" )] |
728 | pub unsafe fn set_auxiliary_vector(auxv: &[*const c_void]) -> io::Result<()> { |
729 | syscalls::prctl( |
730 | PR_SET_MM, |
731 | PR_SET_MM_AUXV as *mut _, |
732 | auxv.as_ptr() as *mut _, |
733 | auxv.len() as *mut _, |
734 | null_mut(), |
735 | ) |
736 | .map(|_r: i32| ()) |
737 | } |
738 | |
739 | /// Get the size of the [`PrctlMmMap`] the kernel expects. |
740 | /// |
741 | /// # References |
742 | /// - [`prctl(PR_SET_MM,PR_SET_MM_MAP_SIZE,...)`] |
743 | /// |
744 | /// [`prctl(PR_SET_MM,PR_SET_MM_MAP_SIZE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
745 | #[inline ] |
746 | #[doc (alias = "PR_SET_MM" )] |
747 | #[doc (alias = "PR_SET_MM_MAP_SIZE" )] |
748 | pub fn virtual_memory_map_config_struct_size() -> io::Result<usize> { |
749 | let mut value: c_uint = 0; |
750 | let value_ptr: *mut u32 = as_mut_ptr(&mut value); |
751 | unsafe { prctl_3args(PR_SET_MM, PR_SET_MM_MAP_SIZE as *mut _, arg3:value_ptr.cast())? }; |
752 | Ok(value as usize) |
753 | } |
754 | |
755 | /// This structure provides new memory descriptor map which mostly modifies |
756 | /// `/proc/pid/stat[m]` output for a task. |
757 | /// This mostly done in a sake of checkpoint/restore functionality. |
758 | #[repr (C)] |
759 | #[derive (Debug, Clone)] |
760 | pub struct PrctlMmMap { |
761 | /// Code section start address. |
762 | pub start_code: u64, |
763 | /// Code section end address. |
764 | pub end_code: u64, |
765 | /// Data section start address. |
766 | pub start_data: u64, |
767 | /// Data section end address. |
768 | pub end_data: u64, |
769 | /// `brk` start address. |
770 | pub start_brk: u64, |
771 | /// `brk` current address. |
772 | pub brk: u64, |
773 | /// Stack start address. |
774 | pub start_stack: u64, |
775 | /// Program command line start address. |
776 | pub arg_start: u64, |
777 | /// Program command line end address. |
778 | pub arg_end: u64, |
779 | /// Program environment start address. |
780 | pub env_start: u64, |
781 | /// Program environment end address. |
782 | pub env_end: u64, |
783 | /// Auxiliary vector start address. |
784 | pub auxv: *mut u64, |
785 | /// Auxiliary vector size. |
786 | pub auxv_size: u32, |
787 | /// File descriptor of executable file that was used to create this |
788 | /// process. |
789 | pub exe_fd: u32, |
790 | } |
791 | |
792 | /// Provides one-shot access to all the addresses by passing in a |
793 | /// [`PrctlMmMap`]. |
794 | /// |
795 | /// # References |
796 | /// - [`prctl(PR_SET_MM,PR_SET_MM_MAP,...)`] |
797 | /// |
798 | /// # Safety |
799 | /// |
800 | /// Please ensure the conditions necessary to safely call this function, |
801 | /// as detailed in the references above. |
802 | /// |
803 | /// [`prctl(PR_SET_MM,PR_SET_MM_MAP,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
804 | #[inline ] |
805 | #[doc (alias = "PR_SET_MM" )] |
806 | #[doc (alias = "PR_SET_MM_MAP" )] |
807 | pub unsafe fn configure_virtual_memory_map(config: &PrctlMmMap) -> io::Result<()> { |
808 | syscalls::prctl( |
809 | PR_SET_MM, |
810 | PR_SET_MM_MAP as *mut _, |
811 | as_ptr(config) as *mut _, |
812 | size_of::<PrctlMmMap>() as *mut _, |
813 | null_mut(), |
814 | ) |
815 | .map(|_r: i32| ()) |
816 | } |
817 | |
818 | // |
819 | // PR_SET_PTRACER |
820 | // |
821 | |
822 | const PR_SET_PTRACER: c_int = 0x59_61_6d_61; |
823 | |
824 | const PR_SET_PTRACER_ANY: usize = usize::MAX; |
825 | |
826 | /// Process ptracer. |
827 | #[derive (Copy, Clone, Debug, Eq, PartialEq)] |
828 | pub enum PTracer { |
829 | /// None. |
830 | None, |
831 | /// Disable `ptrace` restrictions for the calling process. |
832 | Any, |
833 | /// Specific process. |
834 | ProcessID(Pid), |
835 | } |
836 | |
837 | /// Declare that the ptracer process can `ptrace` the calling process as if it |
838 | /// were a direct process ancestor. |
839 | /// |
840 | /// # References |
841 | /// - [`prctl(PR_SET_PTRACER,...)`] |
842 | /// |
843 | /// [`prctl(PR_SET_PTRACER,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
844 | #[inline ] |
845 | #[doc (alias = "PR_SET_PTRACER" )] |
846 | pub fn set_ptracer(tracer: PTracer) -> io::Result<()> { |
847 | let pid: *mut c_void = match tracer { |
848 | PTracer::None => null_mut(), |
849 | PTracer::Any => PR_SET_PTRACER_ANY as *mut _, |
850 | PTracer::ProcessID(pid: Pid) => pid.as_raw_nonzero().get() as usize as *mut _, |
851 | }; |
852 | |
853 | unsafe { prctl_2args(PR_SET_PTRACER, pid) }.map(|_r: i32| ()) |
854 | } |
855 | |
856 | // |
857 | // PR_GET_CHILD_SUBREAPER/PR_SET_CHILD_SUBREAPER |
858 | // |
859 | |
860 | const PR_GET_CHILD_SUBREAPER: c_int = 37; |
861 | |
862 | /// Get the `child subreaper` setting of the calling process. |
863 | /// |
864 | /// # References |
865 | /// - [`prctl(PR_GET_CHILD_SUBREAPER,...)`] |
866 | /// |
867 | /// [`prctl(PR_GET_CHILD_SUBREAPER,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
868 | #[inline ] |
869 | #[doc (alias = "PR_GET_CHILD_SUBREAPER" )] |
870 | pub fn child_subreaper() -> io::Result<Option<Pid>> { |
871 | unsafe { |
872 | let r: u32 = prctl_get_at_arg2_optional::<c_uint>(PR_GET_CHILD_SUBREAPER)?; |
873 | Ok(Pid::from_raw(r as RawPid)) |
874 | } |
875 | } |
876 | |
877 | const PR_SET_CHILD_SUBREAPER: c_int = 36; |
878 | |
879 | /// Set the `child subreaper` attribute of the calling process. |
880 | /// |
881 | /// # References |
882 | /// - [`prctl(PR_SET_CHILD_SUBREAPER,...)`] |
883 | /// |
884 | /// [`prctl(PR_SET_CHILD_SUBREAPER,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
885 | #[inline ] |
886 | #[doc (alias = "PR_SET_CHILD_SUBREAPER" )] |
887 | pub fn set_child_subreaper(pid: Option<Pid>) -> io::Result<()> { |
888 | let pid: usize = pid.map_or(default:0_usize, |pid: Pid| pid.as_raw_nonzero().get() as usize); |
889 | unsafe { prctl_2args(PR_SET_CHILD_SUBREAPER, pid as *mut _) }.map(|_r: i32| ()) |
890 | } |
891 | |
892 | // |
893 | // PR_GET_FP_MODE/PR_SET_FP_MODE |
894 | // |
895 | |
896 | const PR_GET_FP_MODE: c_int = 46; |
897 | |
898 | const PR_FP_MODE_FR: u32 = 1_u32 << 0; |
899 | const PR_FP_MODE_FRE: u32 = 1_u32 << 1; |
900 | |
901 | /// `PR_FP_MODE_*` values for use with [`floating_point_mode`] and |
902 | /// [`set_floating_point_mode`]. |
903 | #[derive (Copy, Clone, Debug, Eq, PartialEq)] |
904 | #[repr (u32)] |
905 | pub enum FloatingPointMode { |
906 | /// 64-bit floating point registers. |
907 | FloatingPointRegisters = PR_FP_MODE_FR, |
908 | /// Enable emulation of 32-bit floating-point mode. |
909 | FloatingPointEmulation = PR_FP_MODE_FRE, |
910 | } |
911 | |
912 | impl TryFrom<u32> for FloatingPointMode { |
913 | type Error = io::Errno; |
914 | |
915 | fn try_from(value: u32) -> Result<Self, Self::Error> { |
916 | match value { |
917 | PR_FP_MODE_FR => Ok(Self::FloatingPointRegisters), |
918 | PR_FP_MODE_FRE => Ok(Self::FloatingPointEmulation), |
919 | _ => Err(io::Errno::RANGE), |
920 | } |
921 | } |
922 | } |
923 | |
924 | /// Get the current floating point mode. |
925 | /// |
926 | /// # References |
927 | /// - [`prctl(PR_GET_FP_MODE,...)`] |
928 | /// |
929 | /// [`prctl(PR_GET_FP_MODE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
930 | #[inline ] |
931 | #[doc (alias = "PR_GET_FP_MODE" )] |
932 | pub fn floating_point_mode() -> io::Result<FloatingPointMode> { |
933 | let r: u32 = unsafe { prctl_1arg(PR_GET_FP_MODE)? } as c_uint; |
934 | FloatingPointMode::try_from(r) |
935 | } |
936 | |
937 | const PR_SET_FP_MODE: c_int = 45; |
938 | |
939 | /// Allow control of the floating point mode from user space. |
940 | /// |
941 | /// # References |
942 | /// - [`prctl(PR_SET_FP_MODE,...)`] |
943 | /// |
944 | /// [`prctl(PR_SET_FP_MODE,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
945 | #[inline ] |
946 | #[doc (alias = "PR_SET_FP_MODE" )] |
947 | pub fn set_floating_point_mode(mode: FloatingPointMode) -> io::Result<()> { |
948 | unsafe { prctl_2args(PR_SET_FP_MODE, mode as usize as *mut _) }.map(|_r: i32| ()) |
949 | } |
950 | |
951 | // |
952 | // PR_GET_SPECULATION_CTRL/PR_SET_SPECULATION_CTRL |
953 | // |
954 | |
955 | const PR_GET_SPECULATION_CTRL: c_int = 52; |
956 | |
957 | const PR_SPEC_STORE_BYPASS: u32 = 0; |
958 | const PR_SPEC_INDIRECT_BRANCH: u32 = 1; |
959 | const PR_SPEC_L1D_FLUSH: u32 = 2; |
960 | |
961 | /// `PR_SPEC_*` values for use with [`speculative_feature_state`] and |
962 | /// [`control_speculative_feature`]. |
963 | #[derive (Copy, Clone, Debug, Eq, PartialEq)] |
964 | #[repr (u32)] |
965 | pub enum SpeculationFeature { |
966 | /// Set the state of the speculative store bypass misfeature. |
967 | SpeculativeStoreBypass = PR_SPEC_STORE_BYPASS, |
968 | /// Set the state of the indirect branch speculation misfeature. |
969 | IndirectBranchSpeculation = PR_SPEC_INDIRECT_BRANCH, |
970 | /// Flush L1D Cache on context switch out of the task. |
971 | FlushL1DCacheOnContextSwitchOutOfTask = PR_SPEC_L1D_FLUSH, |
972 | } |
973 | |
974 | impl TryFrom<u32> for SpeculationFeature { |
975 | type Error = io::Errno; |
976 | |
977 | fn try_from(value: u32) -> Result<Self, Self::Error> { |
978 | match value { |
979 | PR_SPEC_STORE_BYPASS => Ok(Self::SpeculativeStoreBypass), |
980 | PR_SPEC_INDIRECT_BRANCH => Ok(Self::IndirectBranchSpeculation), |
981 | PR_SPEC_L1D_FLUSH => Ok(Self::FlushL1DCacheOnContextSwitchOutOfTask), |
982 | _ => Err(io::Errno::RANGE), |
983 | } |
984 | } |
985 | } |
986 | |
987 | bitflags! { |
988 | /// `PR_SPEC_*` flags for use with [`control_speculative_feature`]. |
989 | pub struct SpeculationFeatureControl: u32 { |
990 | /// The speculation feature is enabled, mitigation is disabled. |
991 | const ENABLE = 1_u32 << 1; |
992 | /// The speculation feature is disabled, mitigation is enabled. |
993 | const DISABLE = 1_u32 << 2; |
994 | /// The speculation feature is disabled, mitigation is enabled, and it cannot be undone. |
995 | const FORCE_DISABLE = 1_u32 << 3; |
996 | /// The speculation feature is disabled, mitigation is enabled, and the state will be cleared on `execve`. |
997 | const DISABLE_NOEXEC = 1_u32 << 4; |
998 | } |
999 | } |
1000 | |
1001 | bitflags! { |
1002 | /// Zero means the processors are not vulnerable. |
1003 | pub struct SpeculationFeatureState: u32 { |
1004 | /// Mitigation can be controlled per thread by `PR_SET_SPECULATION_CTRL`. |
1005 | const PRCTL = 1_u32 << 0; |
1006 | /// The speculation feature is enabled, mitigation is disabled. |
1007 | const ENABLE = 1_u32 << 1; |
1008 | /// The speculation feature is disabled, mitigation is enabled. |
1009 | const DISABLE = 1_u32 << 2; |
1010 | /// The speculation feature is disabled, mitigation is enabled, and it cannot be undone. |
1011 | const FORCE_DISABLE = 1_u32 << 3; |
1012 | /// The speculation feature is disabled, mitigation is enabled, and the state will be cleared on `execve`. |
1013 | const DISABLE_NOEXEC = 1_u32 << 4; |
1014 | } |
1015 | } |
1016 | |
1017 | /// Get the state of the speculation misfeature. |
1018 | /// |
1019 | /// # References |
1020 | /// - [`prctl(PR_GET_SPECULATION_CTRL,...)`] |
1021 | /// |
1022 | /// [`prctl(PR_GET_SPECULATION_CTRL,...)`]: https://www.kernel.org/doc/html/v5.18/userspace-api/spec_ctrl.html |
1023 | #[inline ] |
1024 | #[doc (alias = "PR_GET_SPECULATION_CTRL" )] |
1025 | pub fn speculative_feature_state( |
1026 | feature: SpeculationFeature, |
1027 | ) -> io::Result<Option<SpeculationFeatureState>> { |
1028 | let r: u32 = unsafe { prctl_2args(PR_GET_SPECULATION_CTRL, arg2:feature as usize as *mut _)? } as c_uint; |
1029 | Ok(SpeculationFeatureState::from_bits(r)) |
1030 | } |
1031 | |
1032 | const PR_SET_SPECULATION_CTRL: c_int = 53; |
1033 | |
1034 | /// Sets the state of the speculation misfeature. |
1035 | /// |
1036 | /// # References |
1037 | /// - [`prctl(PR_SET_SPECULATION_CTRL,...)`] |
1038 | /// |
1039 | /// [`prctl(PR_SET_SPECULATION_CTRL,...)`]: https://www.kernel.org/doc/html/v5.18/userspace-api/spec_ctrl.html |
1040 | #[inline ] |
1041 | #[doc (alias = "PR_SET_SPECULATION_CTRL" )] |
1042 | pub fn control_speculative_feature( |
1043 | feature: SpeculationFeature, |
1044 | config: SpeculationFeatureControl, |
1045 | ) -> io::Result<()> { |
1046 | let feature: *mut c_void = feature as usize as *mut _; |
1047 | let config: *mut c_void = config.bits() as usize as *mut _; |
1048 | unsafe { prctl_3args(PR_SET_SPECULATION_CTRL, feature, config) }.map(|_r: i32| ()) |
1049 | } |
1050 | |
1051 | // |
1052 | // PR_GET_IO_FLUSHER/PR_SET_IO_FLUSHER |
1053 | // |
1054 | |
1055 | const PR_GET_IO_FLUSHER: c_int = 58; |
1056 | |
1057 | /// Get the `IO_FLUSHER` state of the caller. |
1058 | /// |
1059 | /// # References |
1060 | /// - [`prctl(PR_GET_IO_FLUSHER,...)`] |
1061 | /// |
1062 | /// [`prctl(PR_GET_IO_FLUSHER,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
1063 | #[inline ] |
1064 | #[doc (alias = "PR_GET_IO_FLUSHER" )] |
1065 | pub fn is_io_flusher() -> io::Result<bool> { |
1066 | unsafe { prctl_1arg(PR_GET_IO_FLUSHER) }.map(|r: i32| r != 0) |
1067 | } |
1068 | |
1069 | const PR_SET_IO_FLUSHER: c_int = 57; |
1070 | |
1071 | /// Put the process in the `IO_FLUSHER` state, allowing it to make progress |
1072 | /// when allocating memory. |
1073 | /// |
1074 | /// # References |
1075 | /// - [`prctl(PR_SET_IO_FLUSHER,...)`] |
1076 | /// |
1077 | /// [`prctl(PR_SET_IO_FLUSHER,...)`]: https://man7.org/linux/man-pages/man2/prctl.2.html |
1078 | #[inline ] |
1079 | #[doc (alias = "PR_SET_IO_FLUSHER" )] |
1080 | pub fn configure_io_flusher_behavior(enable: bool) -> io::Result<()> { |
1081 | unsafe { prctl_2args(PR_SET_IO_FLUSHER, usize::from(enable) as *mut _) }.map(|_r: i32| ()) |
1082 | } |
1083 | |
1084 | // |
1085 | // PR_PAC_GET_ENABLED_KEYS/PR_PAC_SET_ENABLED_KEYS |
1086 | // |
1087 | |
1088 | const PR_PAC_GET_ENABLED_KEYS: c_int = 61; |
1089 | |
1090 | bitflags! { |
1091 | /// `PR_PAC_AP*`. |
1092 | pub struct PointerAuthenticationKeys: u32 { |
1093 | /// Instruction authentication key `A`. |
1094 | const INSTRUCTION_AUTHENTICATION_KEY_A = 1_u32 << 0; |
1095 | /// Instruction authentication key `B`. |
1096 | const INSTRUCTION_AUTHENTICATION_KEY_B = 1_u32 << 1; |
1097 | /// Data authentication key `A`. |
1098 | const DATA_AUTHENTICATION_KEY_A = 1_u32 << 2; |
1099 | /// Data authentication key `B`. |
1100 | const DATA_AUTHENTICATION_KEY_B = 1_u32 << 3; |
1101 | /// Generic authentication `A` key. |
1102 | const GENERIC_AUTHENTICATION_KEY_A = 1_u32 << 4; |
1103 | } |
1104 | } |
1105 | |
1106 | /// Get enabled pointer authentication keys. |
1107 | /// |
1108 | /// # References |
1109 | /// - [`prctl(PR_PAC_GET_ENABLED_KEYS,...)`] |
1110 | /// |
1111 | /// [`prctl(PR_PAC_GET_ENABLED_KEYS,...)`]: https://www.kernel.org/doc/html/v5.18/arm64/pointer-authentication.html |
1112 | #[inline ] |
1113 | #[doc (alias = "PR_PAC_GET_ENABLED_KEYS" )] |
1114 | pub fn enabled_pointer_authentication_keys() -> io::Result<PointerAuthenticationKeys> { |
1115 | let r: u32 = unsafe { prctl_1arg(PR_PAC_GET_ENABLED_KEYS)? } as c_uint; |
1116 | PointerAuthenticationKeys::from_bits(r).ok_or(err:io::Errno::RANGE) |
1117 | } |
1118 | |
1119 | const PR_PAC_SET_ENABLED_KEYS: c_int = 60; |
1120 | |
1121 | /// Set enabled pointer authentication keys. |
1122 | /// |
1123 | /// # References |
1124 | /// - [`prctl(PR_PAC_SET_ENABLED_KEYS,...)`] |
1125 | /// |
1126 | /// # Safety |
1127 | /// |
1128 | /// Please ensure the conditions necessary to safely call this function, |
1129 | /// as detailed in the references above. |
1130 | /// |
1131 | /// [`prctl(PR_PAC_SET_ENABLED_KEYS,...)`]: https://www.kernel.org/doc/html/v5.18/arm64/pointer-authentication.html |
1132 | #[inline ] |
1133 | #[doc (alias = "PR_PAC_SET_ENABLED_KEYS" )] |
1134 | pub unsafe fn configure_pointer_authentication_keys( |
1135 | config: impl Iterator<Item = (PointerAuthenticationKeys, bool)>, |
1136 | ) -> io::Result<()> { |
1137 | let mut affected_keys: u32 = 0; |
1138 | let mut enabled_keys: u32 = 0; |
1139 | |
1140 | for (key, enable) in config { |
1141 | let key = key.bits(); |
1142 | affected_keys |= key; |
1143 | |
1144 | if enable { |
1145 | enabled_keys |= key; |
1146 | } else { |
1147 | enabled_keys &= !key; |
1148 | } |
1149 | } |
1150 | |
1151 | if affected_keys == 0 { |
1152 | return Ok(()); // Nothing to do. |
1153 | } |
1154 | |
1155 | prctl_3args( |
1156 | PR_PAC_SET_ENABLED_KEYS, |
1157 | affected_keys as usize as *mut _, |
1158 | enabled_keys as usize as *mut _, |
1159 | ) |
1160 | .map(|_r| ()) |
1161 | } |
1162 | |
1163 | // |
1164 | // PR_SET_VMA |
1165 | // |
1166 | |
1167 | const PR_SET_VMA: c_int = 0x53_56_4d_41; |
1168 | |
1169 | const PR_SET_VMA_ANON_NAME: usize = 0; |
1170 | |
1171 | /// Set the name for a virtual memory region. |
1172 | /// |
1173 | /// # References |
1174 | /// - [`prctl(PR_SET_VMA,PR_SET_VMA_ANON_NAME,...)`] |
1175 | /// |
1176 | /// [`prctl(PR_SET_VMA,PR_SET_VMA_ANON_NAME,...)`]: https://lwn.net/Articles/867818/ |
1177 | #[inline ] |
1178 | #[doc (alias = "PR_SET_VMA" )] |
1179 | #[doc (alias = "PR_SET_VMA_ANON_NAME" )] |
1180 | pub fn set_virtual_memory_region_name(region: &[u8], name: Option<&CStr>) -> io::Result<()> { |
1181 | unsafe { |
1182 | syscalls::prctl( |
1183 | PR_SET_VMA, |
1184 | PR_SET_VMA_ANON_NAME as *mut _, |
1185 | region.as_ptr() as *mut _, |
1186 | region.len() as *mut _, |
1187 | name.map_or_else(null, CStr::as_ptr) as *mut _, |
1188 | ) |
1189 | .map(|_r: i32| ()) |
1190 | } |
1191 | } |
1192 | |