/rust/registry/src/index.crates.io-1949cf8c6b5b557f/nix-0.28.0/src/sys/prctl.rs
Line | Count | Source |
1 | | //! prctl is a Linux-only API for performing operations on a process or thread. |
2 | | //! |
3 | | //! Note that careless use of some prctl() operations can confuse the user-space run-time |
4 | | //! environment, so these operations should be used with care. |
5 | | //! |
6 | | //! For more documentation, please read [prctl(2)](https://man7.org/linux/man-pages/man2/prctl.2.html). |
7 | | |
8 | | use crate::errno::Errno; |
9 | | use crate::sys::signal::Signal; |
10 | | use crate::Result; |
11 | | |
12 | | use libc::{c_int, c_ulong}; |
13 | | use std::convert::TryFrom; |
14 | | use std::ffi::{CStr, CString}; |
15 | | |
16 | | libc_enum! { |
17 | | /// The type of hardware memory corruption kill policy for the thread. |
18 | | |
19 | | #[repr(i32)] |
20 | | #[non_exhaustive] |
21 | | #[allow(non_camel_case_types)] |
22 | | pub enum PrctlMCEKillPolicy { |
23 | | /// The thread will receive SIGBUS as soon as a memory corruption is detected. |
24 | | PR_MCE_KILL_EARLY, |
25 | | /// The process is killed only when it accesses a corrupted page. |
26 | | PR_MCE_KILL_LATE, |
27 | | /// Uses the system-wide default. |
28 | | PR_MCE_KILL_DEFAULT, |
29 | | } |
30 | | impl TryFrom<i32> |
31 | | } |
32 | | |
33 | 0 | fn prctl_set_bool(option: c_int, status: bool) -> Result<()> { |
34 | 0 | let res = unsafe { libc::prctl(option, status as c_ulong, 0, 0, 0) }; |
35 | 0 | Errno::result(res).map(drop) |
36 | 0 | } |
37 | | |
38 | 0 | fn prctl_get_bool(option: c_int) -> Result<bool> { |
39 | 0 | let res = unsafe { libc::prctl(option, 0, 0, 0, 0) }; |
40 | 0 | Errno::result(res).map(|res| res != 0) |
41 | 0 | } |
42 | | |
43 | | /// Set the "child subreaper" attribute for this process |
44 | 0 | pub fn set_child_subreaper(attribute: bool) -> Result<()> { |
45 | 0 | prctl_set_bool(libc::PR_SET_CHILD_SUBREAPER, attribute) |
46 | 0 | } |
47 | | |
48 | | /// Get the "child subreaper" attribute for this process |
49 | 0 | pub fn get_child_subreaper() -> Result<bool> { |
50 | | // prctl writes into this var |
51 | 0 | let mut subreaper: c_int = 0; |
52 | | |
53 | 0 | let res = unsafe { |
54 | 0 | libc::prctl(libc::PR_GET_CHILD_SUBREAPER, &mut subreaper, 0, 0, 0) |
55 | | }; |
56 | | |
57 | 0 | Errno::result(res).map(|_| subreaper != 0) |
58 | 0 | } |
59 | | |
60 | | /// Set the dumpable attribute which determines if core dumps are created for this process. |
61 | 0 | pub fn set_dumpable(attribute: bool) -> Result<()> { |
62 | 0 | prctl_set_bool(libc::PR_SET_DUMPABLE, attribute) |
63 | 0 | } |
64 | | |
65 | | /// Get the dumpable attribute for this process. |
66 | 0 | pub fn get_dumpable() -> Result<bool> { |
67 | 0 | prctl_get_bool(libc::PR_GET_DUMPABLE) |
68 | 0 | } |
69 | | |
70 | | /// Set the "keep capabilities" attribute for this process. This causes the thread to retain |
71 | | /// capabilities even if it switches its UID to a nonzero value. |
72 | 0 | pub fn set_keepcaps(attribute: bool) -> Result<()> { |
73 | 0 | prctl_set_bool(libc::PR_SET_KEEPCAPS, attribute) |
74 | 0 | } |
75 | | |
76 | | /// Get the "keep capabilities" attribute for this process |
77 | 0 | pub fn get_keepcaps() -> Result<bool> { |
78 | 0 | prctl_get_bool(libc::PR_GET_KEEPCAPS) |
79 | 0 | } |
80 | | |
81 | | /// Clear the thread memory corruption kill policy and use the system-wide default |
82 | 0 | pub fn clear_mce_kill() -> Result<()> { |
83 | 0 | let res = unsafe { |
84 | 0 | libc::prctl(libc::PR_MCE_KILL, libc::PR_MCE_KILL_CLEAR, 0, 0, 0) |
85 | | }; |
86 | | |
87 | 0 | Errno::result(res).map(drop) |
88 | 0 | } |
89 | | |
90 | | /// Set the thread memory corruption kill policy |
91 | 0 | pub fn set_mce_kill(policy: PrctlMCEKillPolicy) -> Result<()> { |
92 | 0 | let res = unsafe { |
93 | 0 | libc::prctl( |
94 | | libc::PR_MCE_KILL, |
95 | | libc::PR_MCE_KILL_SET, |
96 | 0 | policy as c_ulong, |
97 | | 0, |
98 | | 0, |
99 | | ) |
100 | | }; |
101 | | |
102 | 0 | Errno::result(res).map(drop) |
103 | 0 | } |
104 | | |
105 | | /// Get the thread memory corruption kill policy |
106 | 0 | pub fn get_mce_kill() -> Result<PrctlMCEKillPolicy> { |
107 | 0 | let res = unsafe { libc::prctl(libc::PR_MCE_KILL_GET, 0, 0, 0, 0) }; |
108 | | |
109 | 0 | match Errno::result(res) { |
110 | 0 | Ok(val) => Ok(PrctlMCEKillPolicy::try_from(val)?), |
111 | 0 | Err(e) => Err(e), |
112 | | } |
113 | 0 | } |
114 | | |
115 | | /// Set the parent-death signal of the calling process. This is the signal that the calling process |
116 | | /// will get when its parent dies. |
117 | 0 | pub fn set_pdeathsig<T: Into<Option<Signal>>>(signal: T) -> Result<()> { |
118 | 0 | let sig = match signal.into() { |
119 | 0 | Some(s) => s as c_int, |
120 | 0 | None => 0, |
121 | | }; |
122 | | |
123 | 0 | let res = unsafe { libc::prctl(libc::PR_SET_PDEATHSIG, sig, 0, 0, 0) }; |
124 | | |
125 | 0 | Errno::result(res).map(drop) |
126 | 0 | } |
127 | | |
128 | | /// Returns the current parent-death signal |
129 | 0 | pub fn get_pdeathsig() -> Result<Option<Signal>> { |
130 | | // prctl writes into this var |
131 | 0 | let mut sig: c_int = 0; |
132 | | |
133 | 0 | let res = unsafe { libc::prctl(libc::PR_GET_PDEATHSIG, &mut sig, 0, 0, 0) }; |
134 | | |
135 | 0 | match Errno::result(res) { |
136 | 0 | Ok(_) => Ok(match sig { |
137 | 0 | 0 => None, |
138 | 0 | _ => Some(Signal::try_from(sig)?), |
139 | | }), |
140 | 0 | Err(e) => Err(e), |
141 | | } |
142 | 0 | } |
143 | | |
144 | | /// Set the name of the calling thread. Strings longer than 15 bytes will be truncated. |
145 | 0 | pub fn set_name(name: &CStr) -> Result<()> { |
146 | 0 | let res = unsafe { libc::prctl(libc::PR_SET_NAME, name.as_ptr(), 0, 0, 0) }; |
147 | | |
148 | 0 | Errno::result(res).map(drop) |
149 | 0 | } |
150 | | |
151 | | /// Return the name of the calling thread |
152 | 0 | pub fn get_name() -> Result<CString> { |
153 | | // Size of buffer determined by linux/sched.h TASK_COMM_LEN |
154 | 0 | let buf = [0u8; 16]; |
155 | | |
156 | 0 | let res = unsafe { libc::prctl(libc::PR_GET_NAME, &buf, 0, 0, 0) }; |
157 | | |
158 | 0 | Errno::result(res).and_then(|_| { |
159 | 0 | CStr::from_bytes_until_nul(&buf) |
160 | 0 | .map(CStr::to_owned) |
161 | 0 | .map_err(|_| Errno::EINVAL) |
162 | 0 | }) |
163 | 0 | } |
164 | | |
165 | | /// Sets the timer slack value for the calling thread. Timer slack is used by the kernel to group |
166 | | /// timer expirations and make them the supplied amount of nanoseconds late. |
167 | 0 | pub fn set_timerslack(ns: u64) -> Result<()> { |
168 | 0 | let res = unsafe { libc::prctl(libc::PR_SET_TIMERSLACK, ns, 0, 0, 0) }; |
169 | | |
170 | 0 | Errno::result(res).map(drop) |
171 | 0 | } |
172 | | |
173 | | /// Get the timerslack for the calling thread. |
174 | 0 | pub fn get_timerslack() -> Result<i32> { |
175 | 0 | let res = unsafe { libc::prctl(libc::PR_GET_TIMERSLACK, 0, 0, 0, 0) }; |
176 | | |
177 | 0 | Errno::result(res) |
178 | 0 | } |
179 | | |
180 | | /// Disable all performance counters attached to the calling process. |
181 | 0 | pub fn task_perf_events_disable() -> Result<()> { |
182 | 0 | let res = |
183 | 0 | unsafe { libc::prctl(libc::PR_TASK_PERF_EVENTS_DISABLE, 0, 0, 0, 0) }; |
184 | | |
185 | 0 | Errno::result(res).map(drop) |
186 | 0 | } |
187 | | |
188 | | /// Enable all performance counters attached to the calling process. |
189 | 0 | pub fn task_perf_events_enable() -> Result<()> { |
190 | 0 | let res = |
191 | 0 | unsafe { libc::prctl(libc::PR_TASK_PERF_EVENTS_ENABLE, 0, 0, 0, 0) }; |
192 | | |
193 | 0 | Errno::result(res).map(drop) |
194 | 0 | } |
195 | | |
196 | | /// Set the calling threads "no new privs" attribute. Once set this option can not be unset. |
197 | 0 | pub fn set_no_new_privs() -> Result<()> { |
198 | 0 | prctl_set_bool(libc::PR_SET_NO_NEW_PRIVS, true) // Cannot be unset |
199 | 0 | } |
200 | | |
201 | | /// Get the "no new privs" attribute for the calling thread. |
202 | 0 | pub fn get_no_new_privs() -> Result<bool> { |
203 | 0 | prctl_get_bool(libc::PR_GET_NO_NEW_PRIVS) |
204 | 0 | } |
205 | | |
206 | | /// Set the state of the "THP disable" flag for the calling thread. Setting this disables |
207 | | /// transparent huge pages. |
208 | 0 | pub fn set_thp_disable(flag: bool) -> Result<()> { |
209 | 0 | prctl_set_bool(libc::PR_SET_THP_DISABLE, flag) |
210 | 0 | } |
211 | | |
212 | | /// Get the "THP disable" flag for the calling thread. |
213 | 0 | pub fn get_thp_disable() -> Result<bool> { |
214 | 0 | prctl_get_bool(libc::PR_GET_THP_DISABLE) |
215 | 0 | } |