rustix/backend/linux_raw/param/
auxv.rs1#![allow(unsafe_code)]
7
8use super::super::conv::{c_int, pass_usize, ret_usize};
9use crate::backend::c;
10use crate::fd::OwnedFd;
11#[cfg(feature = "param")]
12use crate::ffi::CStr;
13use crate::fs::{Mode, OFlags};
14use crate::utils::{as_ptr, check_raw_pointer};
15#[cfg(feature = "alloc")]
16use alloc::vec::Vec;
17use core::mem::size_of;
18use core::ptr::{null_mut, read_unaligned, NonNull};
19#[cfg(feature = "runtime")]
20use core::sync::atomic::AtomicU8;
21use core::sync::atomic::Ordering::Relaxed;
22use core::sync::atomic::{AtomicPtr, AtomicUsize};
23use linux_raw_sys::elf::*;
24use linux_raw_sys::general::{
25 AT_CLKTCK, AT_EXECFN, AT_HWCAP, AT_HWCAP2, AT_MINSIGSTKSZ, AT_NULL, AT_PAGESZ, AT_SYSINFO_EHDR,
26};
27#[cfg(feature = "runtime")]
28use linux_raw_sys::general::{
29 AT_EGID, AT_ENTRY, AT_EUID, AT_GID, AT_PHDR, AT_PHENT, AT_PHNUM, AT_RANDOM, AT_SECURE, AT_UID,
30};
31#[cfg(feature = "alloc")]
32use {alloc::borrow::Cow, alloc::vec};
33
34#[cfg(feature = "param")]
35#[inline]
36pub(crate) fn page_size() -> usize {
37 let mut page_size = PAGE_SIZE.load(Relaxed);
38
39 if page_size == 0 {
40 init_auxv();
41 page_size = PAGE_SIZE.load(Relaxed);
42 }
43
44 page_size
45}
46
47#[cfg(feature = "param")]
48#[inline]
49pub(crate) fn clock_ticks_per_second() -> u64 {
50 let mut ticks = CLOCK_TICKS_PER_SECOND.load(Relaxed);
51
52 if ticks == 0 {
53 init_auxv();
54 ticks = CLOCK_TICKS_PER_SECOND.load(Relaxed);
55 }
56
57 ticks as u64
58}
59
60#[cfg(feature = "param")]
61#[inline]
62pub(crate) fn linux_hwcap() -> (usize, usize) {
63 let mut hwcap = HWCAP.load(Relaxed);
64 let mut hwcap2 = HWCAP2.load(Relaxed);
65
66 if hwcap == 0 || hwcap2 == 0 {
67 init_auxv();
68 hwcap = HWCAP.load(Relaxed);
69 hwcap2 = HWCAP2.load(Relaxed);
70 }
71
72 (hwcap, hwcap2)
73}
74
75#[cfg(feature = "param")]
76#[inline]
77pub(crate) fn linux_minsigstksz() -> usize {
78 let mut minsigstksz = MINSIGSTKSZ.load(Relaxed);
79
80 if minsigstksz == 0 {
81 init_auxv();
82 minsigstksz = MINSIGSTKSZ.load(Relaxed);
83 }
84
85 minsigstksz
86}
87
88#[cfg(feature = "param")]
89#[inline]
90pub(crate) fn linux_execfn() -> &'static CStr {
91 let mut execfn = EXECFN.load(Relaxed);
92
93 if execfn.is_null() {
94 init_auxv();
95 execfn = EXECFN.load(Relaxed);
96 }
97
98 unsafe { CStr::from_ptr(execfn.cast()) }
101}
102
103#[cfg(feature = "runtime")]
104#[inline]
105pub(crate) fn linux_secure() -> bool {
106 let mut secure = SECURE.load(Relaxed);
107
108 if secure == 0 {
110 init_auxv();
111 secure = SECURE.load(Relaxed);
112 }
113
114 secure > 1
118}
119
120#[cfg(feature = "runtime")]
121#[inline]
122pub(crate) fn exe_phdrs() -> (*const c::c_void, usize, usize) {
123 let mut phdr = PHDR.load(Relaxed);
124 let mut phent = PHENT.load(Relaxed);
125 let mut phnum = PHNUM.load(Relaxed);
126
127 if phdr.is_null() || phnum == 0 {
128 init_auxv();
129 phdr = PHDR.load(Relaxed);
130 phent = PHENT.load(Relaxed);
131 phnum = PHNUM.load(Relaxed);
132 }
133
134 (phdr.cast(), phent, phnum)
135}
136
137#[inline]
143pub(in super::super) fn sysinfo_ehdr() -> *const Elf_Ehdr {
144 let mut ehdr = SYSINFO_EHDR.load(Relaxed);
145
146 if ehdr.is_null() {
147 maybe_init_auxv();
151
152 ehdr = SYSINFO_EHDR.load(Relaxed);
153 }
154
155 ehdr
156}
157
158#[cfg(feature = "runtime")]
159#[inline]
160pub(crate) fn entry() -> usize {
161 let mut entry = ENTRY.load(Relaxed);
162
163 if entry == 0 {
164 init_auxv();
165 entry = ENTRY.load(Relaxed);
166 }
167
168 entry
169}
170
171#[cfg(feature = "runtime")]
172#[inline]
173pub(crate) fn random() -> *const [u8; 16] {
174 let mut random = RANDOM.load(Relaxed);
175
176 if random.is_null() {
177 init_auxv();
178 random = RANDOM.load(Relaxed);
179 }
180
181 random
182}
183
184static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0);
185static CLOCK_TICKS_PER_SECOND: AtomicUsize = AtomicUsize::new(0);
186static HWCAP: AtomicUsize = AtomicUsize::new(0);
187static HWCAP2: AtomicUsize = AtomicUsize::new(0);
188static MINSIGSTKSZ: AtomicUsize = AtomicUsize::new(0);
189static EXECFN: AtomicPtr<c::c_char> = AtomicPtr::new(null_mut());
190static SYSINFO_EHDR: AtomicPtr<Elf_Ehdr> = AtomicPtr::new(null_mut());
191#[cfg(feature = "runtime")]
192static SECURE: AtomicU8 = AtomicU8::new(0);
193#[cfg(feature = "runtime")]
194static PHDR: AtomicPtr<Elf_Phdr> = AtomicPtr::new(null_mut());
195#[cfg(feature = "runtime")]
196static PHENT: AtomicUsize = AtomicUsize::new(0);
197#[cfg(feature = "runtime")]
198static PHNUM: AtomicUsize = AtomicUsize::new(0);
199#[cfg(feature = "runtime")]
200static ENTRY: AtomicUsize = AtomicUsize::new(0);
201#[cfg(feature = "runtime")]
202static RANDOM: AtomicPtr<[u8; 16]> = AtomicPtr::new(null_mut());
203
204const PR_GET_AUXV: c::c_int = 0x4155_5856;
205
206#[cold]
214fn pr_get_auxv_static(buffer: &mut [u8; 512]) -> Result<&mut [u8], crate::io::Result<usize>> {
215 let len = unsafe {
216 ret_usize(syscall_always_asm!(
217 __NR_prctl,
218 c_int(PR_GET_AUXV),
219 buffer.as_mut_ptr(),
220 pass_usize(buffer.len()),
221 pass_usize(0),
222 pass_usize(0)
223 ))
224 .map_err(Err)?
225 };
226 if len <= buffer.len() {
227 return Ok(&mut buffer[..len]);
228 }
229 Err(Ok(len))
230}
231
232#[cfg(feature = "alloc")]
240#[cold]
241fn pr_get_auxv_dynamic(buffer: &mut [u8; 512]) -> crate::io::Result<Cow<'_, [u8]>> {
242 let len = match pr_get_auxv_static(buffer) {
244 Ok(buffer) => return Ok(Cow::Borrowed(buffer)),
245 Err(Ok(len)) => len,
246 Err(Err(err)) => return Err(err),
247 };
248
249 let mut buffer = vec![0_u8; len];
251 let len = unsafe {
252 ret_usize(syscall_always_asm!(
253 __NR_prctl,
254 c_int(PR_GET_AUXV),
255 buffer.as_mut_ptr(),
256 pass_usize(buffer.len()),
257 pass_usize(0),
258 pass_usize(0)
259 ))?
260 };
261 assert_eq!(len, buffer.len());
262 Ok(Cow::Owned(buffer))
263}
264
265#[cold]
268fn init_auxv() {
269 init_auxv_impl().unwrap();
270}
271
272#[cold]
275fn maybe_init_auxv() {
276 let _ = init_auxv_impl();
277}
278
279#[cold]
283fn init_auxv_impl() -> Result<(), ()> {
284 let mut buffer = [0_u8; 512];
286
287 #[cfg(not(feature = "alloc"))]
291 let result = pr_get_auxv_static(&mut buffer);
292
293 #[cfg(feature = "alloc")]
296 let result = pr_get_auxv_dynamic(&mut buffer);
297
298 if let Ok(buffer) = result {
299 unsafe {
301 init_from_aux_iter(AuxPointer(buffer.as_ptr().cast())).unwrap();
302 }
303 return Ok(());
304 }
305
306 if let Ok(file) = crate::fs::open("/proc/self/auxv", OFlags::RDONLY, Mode::empty()) {
311 #[cfg(feature = "alloc")]
312 init_from_auxv_file(file).unwrap();
313
314 #[cfg(not(feature = "alloc"))]
315 unsafe {
316 init_from_aux_iter(AuxFile(file)).unwrap();
317 }
318
319 return Ok(());
320 }
321
322 Err(())
323}
324
325#[cfg(feature = "alloc")]
327#[cold]
328#[must_use]
329fn init_from_auxv_file(auxv: OwnedFd) -> Option<()> {
330 let mut buffer = Vec::<u8>::with_capacity(512);
331 loop {
332 let cur = buffer.len();
333
334 buffer.reserve(1);
336
337 buffer.resize(buffer.capacity(), 0);
339
340 let n = match crate::io::read(&auxv, &mut buffer[cur..]) {
342 Err(crate::io::Errno::INTR) => 0,
343 Err(_err) => panic!(),
344 Ok(0) => break,
345 Ok(n) => n,
346 };
347
348 buffer.resize(cur + n, 0_u8);
350 }
351
352 unsafe { init_from_aux_iter(AuxPointer(buffer.as_ptr().cast())) }
354}
355
356#[cold]
365#[must_use]
366unsafe fn init_from_aux_iter(aux_iter: impl Iterator<Item = Elf_auxv_t>) -> Option<()> {
367 let mut pagesz = 0;
368 let mut clktck = 0;
369 let mut hwcap = 0;
370 let mut hwcap2 = 0;
371 let mut minsigstksz = 0;
372 let mut execfn = null_mut();
373 let mut sysinfo_ehdr = null_mut();
374 #[cfg(feature = "runtime")]
375 let mut secure = 0;
376 #[cfg(feature = "runtime")]
377 let mut phdr = null_mut();
378 #[cfg(feature = "runtime")]
379 let mut phnum = 0;
380 #[cfg(feature = "runtime")]
381 let mut phent = 0;
382 #[cfg(feature = "runtime")]
383 let mut entry = 0;
384 #[cfg(feature = "runtime")]
385 let mut uid = None;
386 #[cfg(feature = "runtime")]
387 let mut euid = None;
388 #[cfg(feature = "runtime")]
389 let mut gid = None;
390 #[cfg(feature = "runtime")]
391 let mut egid = None;
392 #[cfg(feature = "runtime")]
393 let mut random = null_mut();
394
395 for Elf_auxv_t { a_type, a_val } in aux_iter {
396 match a_type as _ {
397 AT_PAGESZ => pagesz = a_val as usize,
398 AT_CLKTCK => clktck = a_val as usize,
399 AT_HWCAP => hwcap = a_val as usize,
400 AT_HWCAP2 => hwcap2 = a_val as usize,
401 AT_MINSIGSTKSZ => minsigstksz = a_val as usize,
402 AT_EXECFN => execfn = check_raw_pointer::<c::c_char>(a_val as *mut _)?.as_ptr(),
403
404 AT_SYSINFO_EHDR => {
407 if let Some(value) = check_elf_base(a_val as *mut _) {
408 sysinfo_ehdr = value.as_ptr();
409 }
410 }
411
412 #[cfg(feature = "runtime")]
413 AT_SECURE => secure = (a_val as usize != 0) as u8 + 1,
414 #[cfg(feature = "runtime")]
415 AT_UID => uid = Some(a_val),
416 #[cfg(feature = "runtime")]
417 AT_EUID => euid = Some(a_val),
418 #[cfg(feature = "runtime")]
419 AT_GID => gid = Some(a_val),
420 #[cfg(feature = "runtime")]
421 AT_EGID => egid = Some(a_val),
422 #[cfg(feature = "runtime")]
423 AT_PHDR => phdr = check_raw_pointer::<Elf_Phdr>(a_val as *mut _)?.as_ptr(),
424 #[cfg(feature = "runtime")]
425 AT_PHNUM => phnum = a_val as usize,
426 #[cfg(feature = "runtime")]
427 AT_PHENT => phent = a_val as usize,
428 #[cfg(feature = "runtime")]
429 AT_ENTRY => entry = a_val as usize,
430 #[cfg(feature = "runtime")]
431 AT_RANDOM => random = check_raw_pointer::<[u8; 16]>(a_val as *mut _)?.as_ptr(),
432
433 AT_NULL => break,
434 _ => (),
435 }
436 }
437
438 #[cfg(feature = "runtime")]
439 assert_eq!(phent, size_of::<Elf_Phdr>());
440
441 #[cfg(feature = "runtime")]
445 if uid != euid || gid != egid {
446 secure = 2;
447 }
448
449 PAGE_SIZE.store(pagesz, Relaxed);
451 CLOCK_TICKS_PER_SECOND.store(clktck, Relaxed);
452 HWCAP.store(hwcap, Relaxed);
453 HWCAP2.store(hwcap2, Relaxed);
454 MINSIGSTKSZ.store(minsigstksz, Relaxed);
455 EXECFN.store(execfn, Relaxed);
456 SYSINFO_EHDR.store(sysinfo_ehdr, Relaxed);
457 #[cfg(feature = "runtime")]
458 SECURE.store(secure, Relaxed);
459 #[cfg(feature = "runtime")]
460 PHDR.store(phdr, Relaxed);
461 #[cfg(feature = "runtime")]
462 PHNUM.store(phnum, Relaxed);
463 #[cfg(feature = "runtime")]
464 ENTRY.store(entry, Relaxed);
465 #[cfg(feature = "runtime")]
466 RANDOM.store(random, Relaxed);
467
468 Some(())
469}
470
471#[cold]
477#[must_use]
478unsafe fn check_elf_base(base: *const Elf_Ehdr) -> Option<NonNull<Elf_Ehdr>> {
479 if base.is_null() {
484 return None;
485 }
486
487 let hdr = check_raw_pointer::<Elf_Ehdr>(base as *mut _)?;
488
489 let hdr = hdr.as_ref();
490 if hdr.e_ident[..SELFMAG] != ELFMAG {
491 return None; }
493 if !matches!(hdr.e_ident[EI_OSABI], ELFOSABI_SYSV | ELFOSABI_LINUX) {
494 return None; }
496 if hdr.e_ident[EI_ABIVERSION] != ELFABIVERSION {
497 return None; }
499 if hdr.e_type != ET_DYN {
500 return None; }
502
503 if hdr.e_ident[EI_VERSION] != EV_CURRENT
505 || hdr.e_ehsize as usize != size_of::<Elf_Ehdr>()
506 || hdr.e_phentsize as usize != size_of::<Elf_Phdr>()
507 {
508 return None;
509 }
510 if hdr.e_phnum == PN_XNUM {
512 return None;
513 }
514
515 if hdr.e_phoff < size_of::<Elf_Ehdr>() {
519 return None;
520 }
521
522 if hdr.e_ident[EI_CLASS] != ELFCLASS {
526 return None; }
528 if hdr.e_ident[EI_DATA] != ELFDATA {
529 return None; }
531 if hdr.e_machine != EM_CURRENT {
532 return None; }
534
535 Some(NonNull::new_unchecked(as_ptr(hdr) as *mut _))
536}
537
538struct AuxPointer(*const Elf_auxv_t);
542
543impl Iterator for AuxPointer {
544 type Item = Elf_auxv_t;
545
546 #[cold]
547 fn next(&mut self) -> Option<Self::Item> {
548 unsafe {
549 let value = read_unaligned(self.0);
550 self.0 = self.0.add(1);
551 Some(value)
552 }
553 }
554}
555
556#[cfg(not(feature = "alloc"))]
558struct AuxFile(OwnedFd);
559
560#[cfg(not(feature = "alloc"))]
561impl Iterator for AuxFile {
562 type Item = Elf_auxv_t;
563
564 #[cold]
567 fn next(&mut self) -> Option<Self::Item> {
568 let mut buf = [0_u8; size_of::<Self::Item>()];
569 let mut slice = &mut buf[..];
570 while !slice.is_empty() {
571 match crate::io::read(&self.0, &mut *slice) {
572 Ok(0) => panic!("unexpected end of auxv file"),
573 Ok(n) => slice = &mut slice[n..],
574 Err(crate::io::Errno::INTR) => continue,
575 Err(err) => panic!("{:?}", err),
576 }
577 }
578 Some(unsafe { read_unaligned(buf.as_ptr().cast()) })
579 }
580}