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