1 //! Linux auxv `init` function, for "use-explicitly-provided-auxv" mode.
2 //!
3 //! # Safety
4 //!
5 //! This uses raw pointers to locate and read the kernel-provided auxv array.
6 #![allow(unsafe_code)]
7
8 use crate::backend::c;
9 #[cfg(feature = "param")]
10 use crate::ffi::CStr;
11 use core::ffi::c_void;
12 use core::ptr::{null_mut, read, NonNull};
13 #[cfg(feature = "runtime")]
14 use core::sync::atomic::AtomicBool;
15 use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
16 use linux_raw_sys::elf::*;
17 use linux_raw_sys::general::{
18 AT_CLKTCK, AT_EXECFN, AT_HWCAP, AT_HWCAP2, AT_NULL, AT_PAGESZ, AT_SYSINFO_EHDR,
19 };
20 #[cfg(feature = "runtime")]
21 use linux_raw_sys::general::{AT_ENTRY, AT_PHDR, AT_PHENT, AT_PHNUM, AT_RANDOM, AT_SECURE};
22
23 #[cfg(feature = "param")]
24 #[inline]
page_size() -> usize25 pub(crate) fn page_size() -> usize {
26 unsafe { PAGE_SIZE.load(Ordering::Relaxed) }
27 }
28
29 #[cfg(feature = "param")]
30 #[inline]
clock_ticks_per_second() -> u6431 pub(crate) fn clock_ticks_per_second() -> u64 {
32 unsafe { CLOCK_TICKS_PER_SECOND.load(Ordering::Relaxed) as u64 }
33 }
34
35 #[cfg(feature = "param")]
36 #[inline]
linux_hwcap() -> (usize, usize)37 pub(crate) fn linux_hwcap() -> (usize, usize) {
38 unsafe {
39 (
40 HWCAP.load(Ordering::Relaxed),
41 HWCAP2.load(Ordering::Relaxed),
42 )
43 }
44 }
45
46 #[cfg(feature = "param")]
47 #[inline]
linux_execfn() -> &'static CStr48 pub(crate) fn linux_execfn() -> &'static CStr {
49 let execfn = unsafe { EXECFN.load(Ordering::Relaxed) };
50
51 // SAFETY: We initialize `EXECFN` to a valid `CStr` pointer, and we assume
52 // the `AT_EXECFN` value provided by the kernel points to a valid C string.
53 unsafe { CStr::from_ptr(execfn.cast()) }
54 }
55
56 #[cfg(feature = "runtime")]
57 #[inline]
linux_secure() -> bool58 pub(crate) fn linux_secure() -> bool {
59 unsafe { SECURE.load(Ordering::Relaxed) }
60 }
61
62 #[cfg(feature = "runtime")]
63 #[inline]
exe_phdrs() -> (*const c_void, usize, usize)64 pub(crate) fn exe_phdrs() -> (*const c_void, usize, usize) {
65 unsafe {
66 (
67 PHDR.load(Ordering::Relaxed).cast(),
68 PHENT.load(Ordering::Relaxed),
69 PHNUM.load(Ordering::Relaxed),
70 )
71 }
72 }
73
74 /// `AT_SYSINFO_EHDR` isn't present on all platforms in all configurations, so
75 /// if we don't see it, this function returns a null pointer.
76 #[inline]
sysinfo_ehdr() -> *const Elf_Ehdr77 pub(in super::super) fn sysinfo_ehdr() -> *const Elf_Ehdr {
78 unsafe { SYSINFO_EHDR.load(Ordering::Relaxed) }
79 }
80
81 #[cfg(feature = "runtime")]
82 #[inline]
entry() -> usize83 pub(crate) fn entry() -> usize {
84 unsafe { ENTRY.load(Ordering::Relaxed) }
85 }
86
87 #[cfg(feature = "runtime")]
88 #[inline]
random() -> *const [u8; 16]89 pub(crate) fn random() -> *const [u8; 16] {
90 unsafe { RANDOM.load(Ordering::Relaxed) }
91 }
92
93 static mut PAGE_SIZE: AtomicUsize = AtomicUsize::new(0);
94 static mut CLOCK_TICKS_PER_SECOND: AtomicUsize = AtomicUsize::new(0);
95 static mut HWCAP: AtomicUsize = AtomicUsize::new(0);
96 static mut HWCAP2: AtomicUsize = AtomicUsize::new(0);
97 static mut SYSINFO_EHDR: AtomicPtr<Elf_Ehdr> = AtomicPtr::new(null_mut());
98 // Initialize `EXECFN` to a valid `CStr` pointer so that we don't need to check
99 // for null on every `execfn` call.
100 static mut EXECFN: AtomicPtr<c::c_char> = AtomicPtr::new(b"\0".as_ptr() as _);
101 #[cfg(feature = "runtime")]
102 static mut SECURE: AtomicBool = AtomicBool::new(false);
103 // Use `dangling` so that we can always treat it like an empty slice.
104 #[cfg(feature = "runtime")]
105 static mut PHDR: AtomicPtr<Elf_Phdr> = AtomicPtr::new(NonNull::dangling().as_ptr());
106 #[cfg(feature = "runtime")]
107 static mut PHENT: AtomicUsize = AtomicUsize::new(0);
108 #[cfg(feature = "runtime")]
109 static mut PHNUM: AtomicUsize = AtomicUsize::new(0);
110 #[cfg(feature = "runtime")]
111 static mut ENTRY: AtomicUsize = AtomicUsize::new(0);
112 #[cfg(feature = "runtime")]
113 static mut RANDOM: AtomicPtr<[u8; 16]> = AtomicPtr::new(NonNull::dangling().as_ptr());
114
115 /// When "use-explicitly-provided-auxv" is enabled, we export a function to be
116 /// called during initialization, and passed a pointer to the original
117 /// environment variable block set up by the OS.
init(envp: *mut *mut u8)118 pub(crate) unsafe fn init(envp: *mut *mut u8) {
119 init_from_envp(envp);
120 }
121
122 /// # Safety
123 ///
124 /// This must be passed a pointer to the environment variable buffer
125 /// provided by the kernel, which is followed in memory by the auxv array.
init_from_envp(mut envp: *mut *mut u8)126 unsafe fn init_from_envp(mut envp: *mut *mut u8) {
127 while !(*envp).is_null() {
128 envp = envp.add(1);
129 }
130 init_from_auxp(envp.add(1).cast())
131 }
132
133 /// Process auxv entries from the auxv array pointed to by `auxp`.
134 ///
135 /// # Safety
136 ///
137 /// This must be passed a pointer to an auxv array.
138 ///
139 /// The buffer contains `Elf_aux_t` elements, though it need not be aligned;
140 /// function uses `read_unaligned` to read from it.
init_from_auxp(mut auxp: *const Elf_auxv_t)141 unsafe fn init_from_auxp(mut auxp: *const Elf_auxv_t) {
142 loop {
143 let Elf_auxv_t { a_type, a_val } = read(auxp);
144
145 match a_type as _ {
146 AT_PAGESZ => PAGE_SIZE.store(a_val as usize, Ordering::Relaxed),
147 AT_CLKTCK => CLOCK_TICKS_PER_SECOND.store(a_val as usize, Ordering::Relaxed),
148 AT_HWCAP => HWCAP.store(a_val as usize, Ordering::Relaxed),
149 AT_HWCAP2 => HWCAP2.store(a_val as usize, Ordering::Relaxed),
150 AT_EXECFN => EXECFN.store(a_val.cast::<c::c_char>(), Ordering::Relaxed),
151 AT_SYSINFO_EHDR => SYSINFO_EHDR.store(a_val.cast::<Elf_Ehdr>(), Ordering::Relaxed),
152
153 #[cfg(feature = "runtime")]
154 AT_SECURE => SECURE.store(a_val as usize != 0, Ordering::Relaxed),
155 #[cfg(feature = "runtime")]
156 AT_PHDR => PHDR.store(a_val.cast::<Elf_Phdr>(), Ordering::Relaxed),
157 #[cfg(feature = "runtime")]
158 AT_PHNUM => PHNUM.store(a_val as usize, Ordering::Relaxed),
159 #[cfg(feature = "runtime")]
160 AT_PHENT => PHENT.store(a_val as usize, Ordering::Relaxed),
161 #[cfg(feature = "runtime")]
162 AT_ENTRY => ENTRY.store(a_val as usize, Ordering::Relaxed),
163 #[cfg(feature = "runtime")]
164 AT_RANDOM => RANDOM.store(a_val.cast::<[u8; 16]>(), Ordering::Relaxed),
165
166 AT_NULL => break,
167 _ => (),
168 }
169 auxp = auxp.add(1);
170 }
171 }
172