• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Linux auxv support, for Mustang.
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 super::super::c;
9 use super::super::elf::*;
10 #[cfg(feature = "param")]
11 use crate::ffi::CStr;
12 use core::ffi::c_void;
13 use core::mem::size_of;
14 use core::ptr::{null, read};
15 #[cfg(feature = "runtime")]
16 use core::slice;
17 use linux_raw_sys::general::{
18     AT_CLKTCK, AT_EXECFN, AT_HWCAP, AT_HWCAP2, AT_NULL, AT_PAGESZ, AT_PHDR, AT_PHENT, AT_PHNUM,
19     AT_SYSINFO_EHDR,
20 };
21 
22 #[cfg(feature = "param")]
23 #[inline]
page_size() -> usize24 pub(crate) fn page_size() -> usize {
25     // Safety: This is initialized during program startup.
26     unsafe { PAGE_SIZE }
27 }
28 
29 #[cfg(feature = "param")]
30 #[inline]
clock_ticks_per_second() -> u6431 pub(crate) fn clock_ticks_per_second() -> u64 {
32     // Safety: This is initialized during program startup.
33     unsafe { CLOCK_TICKS_PER_SECOND as u64 }
34 }
35 
36 #[cfg(feature = "param")]
37 #[inline]
linux_hwcap() -> (usize, usize)38 pub(crate) fn linux_hwcap() -> (usize, usize) {
39     // Safety: This is initialized during program startup.
40     unsafe { (HWCAP, HWCAP2) }
41 }
42 
43 #[cfg(feature = "param")]
44 #[inline]
linux_execfn() -> &'static CStr45 pub(crate) fn linux_execfn() -> &'static CStr {
46     // Safety: This is initialized during program startup. And we
47     // assume it's a valid pointer to a NUL-terminated string.
48     unsafe { CStr::from_ptr(EXECFN.0.cast()) }
49 }
50 
51 #[cfg(feature = "runtime")]
52 #[inline]
exe_phdrs() -> (*const c_void, usize)53 pub(crate) fn exe_phdrs() -> (*const c_void, usize) {
54     // Safety: This is initialized during program startup.
55     unsafe { (PHDR.0.cast(), PHNUM) }
56 }
57 
58 #[cfg(feature = "runtime")]
59 #[inline]
exe_phdrs_slice() -> &'static [Elf_Phdr]60 pub(in super::super) fn exe_phdrs_slice() -> &'static [Elf_Phdr] {
61     let (phdr, phnum) = exe_phdrs();
62 
63     // Safety: We assume the `AT_PHDR` and `AT_PHNUM` values provided by the
64     // kernel form a valid slice.
65     unsafe { slice::from_raw_parts(phdr.cast(), phnum) }
66 }
67 
68 /// `AT_SYSINFO_EHDR` isn't present on all platforms in all configurations,
69 /// so if we don't see it, this function returns a null pointer.
70 #[inline]
sysinfo_ehdr() -> *const Elf_Ehdr71 pub(in super::super) fn sysinfo_ehdr() -> *const Elf_Ehdr {
72     // Safety: This is initialized during program startup.
73     unsafe { SYSINFO_EHDR.0 }
74 }
75 
76 /// A const pointer to `T` that implements [`Sync`].
77 #[repr(transparent)]
78 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
79 pub struct SyncConstPtr<T>(*const T);
80 unsafe impl<T> Sync for SyncConstPtr<T> {}
81 
82 impl<T> SyncConstPtr<T> {
83     /// Creates a `SyncConstPointer` from a raw pointer.
84     ///
85     /// Behavior is undefined if `ptr` is actually not
86     /// safe to share across threads.
new(ptr: *const T) -> Self87     pub const unsafe fn new(ptr: *const T) -> Self {
88         Self(ptr)
89     }
90 }
91 
92 static mut PAGE_SIZE: usize = 0;
93 static mut CLOCK_TICKS_PER_SECOND: usize = 0;
94 static mut HWCAP: usize = 0;
95 static mut HWCAP2: usize = 0;
96 static mut SYSINFO_EHDR: SyncConstPtr<Elf_Ehdr> = unsafe { SyncConstPtr::new(null()) };
97 static mut PHDR: SyncConstPtr<Elf_Phdr> = unsafe { SyncConstPtr::new(null()) };
98 static mut PHNUM: usize = 0;
99 static mut EXECFN: SyncConstPtr<c::c_char> = unsafe { SyncConstPtr::new(null()) };
100 
101 /// On mustang, we export a function to be called during initialization, and
102 /// passed a pointer to the original environment variable block set up by the
103 /// OS.
init(envp: *mut *mut u8)104 pub(crate) unsafe fn init(envp: *mut *mut u8) {
105     init_from_envp(envp);
106 }
107 
108 /// # Safety
109 ///
110 /// This must be passed a pointer to the environment variable buffer
111 /// provided by the kernel, which is followed in memory by the auxv array.
init_from_envp(mut envp: *mut *mut u8)112 unsafe fn init_from_envp(mut envp: *mut *mut u8) {
113     while !(*envp).is_null() {
114         envp = envp.add(1);
115     }
116     init_from_auxp(envp.add(1).cast())
117 }
118 
119 /// Process auxv entries from the auxv array pointed to by `auxp`.
120 ///
121 /// # Safety
122 ///
123 /// This must be passed a pointer to an auxv array.
124 ///
125 /// The buffer contains `Elf_aux_t` elements, though it need not be aligned;
126 /// function uses `read_unaligned` to read from it.
init_from_auxp(mut auxp: *const Elf_auxv_t)127 unsafe fn init_from_auxp(mut auxp: *const Elf_auxv_t) {
128     loop {
129         let Elf_auxv_t { a_type, a_val } = read(auxp);
130 
131         match a_type as _ {
132             AT_PAGESZ => PAGE_SIZE = a_val as usize,
133             AT_CLKTCK => CLOCK_TICKS_PER_SECOND = a_val as usize,
134             AT_HWCAP => HWCAP = a_val as usize,
135             AT_HWCAP2 => HWCAP2 = a_val as usize,
136             AT_PHDR => PHDR = SyncConstPtr::new(a_val.cast::<Elf_Phdr>()),
137             AT_PHNUM => PHNUM = a_val as usize,
138             AT_PHENT => assert_eq!(a_val as usize, size_of::<Elf_Phdr>()),
139             AT_EXECFN => EXECFN = SyncConstPtr::new(a_val.cast::<c::c_char>()),
140             AT_SYSINFO_EHDR => SYSINFO_EHDR = SyncConstPtr::new(a_val.cast::<Elf_Ehdr>()),
141             AT_NULL => break,
142             _ => (),
143         }
144         auxp = auxp.add(1);
145     }
146 }
147 
148 // ELF ABI
149 
150 #[repr(C)]
151 #[derive(Copy, Clone)]
152 struct Elf_auxv_t {
153     a_type: usize,
154 
155     // Some of the values in the auxv array are pointers, so we make `a_val` a
156     // pointer, in order to preserve their provenance. For the values which are
157     // integers, we cast this to `usize`.
158     a_val: *const c_void,
159 }
160