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