1 //! Linux auxv support.
5 //! This uses raw pointers to locate and read the kernel-provided auxv array.
9 use super::super::elf
::*;
10 use crate::fd
::OwnedFd
;
11 #[cfg(feature = "param")]
13 #[cfg(not(target_vendor = "mustang"))]
14 use crate::fs
::{Mode, OFlags}
;
15 use crate::utils
::{as_ptr, check_raw_pointer}
;
17 use core
::ffi
::c_void
;
18 use core
::mem
::size_of
;
19 use core
::ptr
::{null_mut, read_unaligned, NonNull}
;
20 #[cfg(feature = "runtime")]
22 use core
::sync
::atomic
::Ordering
::Relaxed
;
23 use core
::sync
::atomic
::{AtomicPtr, AtomicUsize}
;
24 use linux_raw_sys
::general
::{
25 AT_BASE
, AT_CLKTCK
, AT_EXECFN
, AT_HWCAP
, AT_HWCAP2
, AT_NULL
, AT_PAGESZ
, AT_PHDR
, AT_PHENT
,
26 AT_PHNUM
, AT_SYSINFO_EHDR
,
29 #[cfg(feature = "param")]
31 pub(crate) fn page_size() -> usize {
32 let mut page_size
= PAGE_SIZE
.load(Relaxed
);
35 init_from_proc_self_auxv();
36 page_size
= PAGE_SIZE
.load(Relaxed
);
42 #[cfg(feature = "param")]
44 pub(crate) fn clock_ticks_per_second() -> u64 {
45 let mut ticks
= CLOCK_TICKS_PER_SECOND
.load(Relaxed
);
48 init_from_proc_self_auxv();
49 ticks
= CLOCK_TICKS_PER_SECOND
.load(Relaxed
);
55 #[cfg(feature = "param")]
57 pub(crate) fn linux_hwcap() -> (usize, usize) {
58 let mut hwcap
= HWCAP
.load(Relaxed
);
59 let mut hwcap2
= HWCAP2
.load(Relaxed
);
61 if hwcap
== 0 || hwcap2
== 0 {
62 init_from_proc_self_auxv();
63 hwcap
= HWCAP
.load(Relaxed
);
64 hwcap2
= HWCAP2
.load(Relaxed
);
70 #[cfg(feature = "param")]
72 pub(crate) fn linux_execfn() -> &'
static CStr
{
73 let mut execfn
= EXECFN
.load(Relaxed
);
76 init_from_proc_self_auxv();
77 execfn
= EXECFN
.load(Relaxed
);
80 // Safety: We assume the `AT_EXECFN` value provided by the kernel is a
81 // valid pointer to a valid NUL-terminated array of bytes.
82 unsafe { CStr::from_ptr(execfn.cast()) }
85 #[cfg(feature = "runtime")]
87 pub(crate) fn exe_phdrs() -> (*const c
::c_void
, usize) {
88 let mut phdr
= PHDR
.load(Relaxed
);
89 let mut phnum
= PHNUM
.load(Relaxed
);
91 if phdr
.is_null() || phnum
== 0 {
92 init_from_proc_self_auxv();
93 phdr
= PHDR
.load(Relaxed
);
94 phnum
= PHNUM
.load(Relaxed
);
100 #[cfg(feature = "runtime")]
102 pub(in super::super) fn exe_phdrs_slice() -> &'
static [Elf_Phdr
] {
103 let (phdr
, phnum
) = exe_phdrs();
105 // Safety: We assume the `AT_PHDR` and `AT_PHNUM` values provided by the
106 // kernel form a valid slice.
107 unsafe { slice::from_raw_parts(phdr.cast(), phnum) }
110 /// `AT_SYSINFO_EHDR` isn't present on all platforms in all configurations,
111 /// so if we don't see it, this function returns a null pointer.
113 pub(in super::super) fn sysinfo_ehdr() -> *const Elf_Ehdr
{
114 let mut ehdr
= SYSINFO_EHDR
.load(Relaxed
);
117 init_from_proc_self_auxv();
118 ehdr
= SYSINFO_EHDR
.load(Relaxed
);
124 static PAGE_SIZE
: AtomicUsize
= AtomicUsize
::new(0);
125 static CLOCK_TICKS_PER_SECOND
: AtomicUsize
= AtomicUsize
::new(0);
126 static HWCAP
: AtomicUsize
= AtomicUsize
::new(0);
127 static HWCAP2
: AtomicUsize
= AtomicUsize
::new(0);
128 static SYSINFO_EHDR
: AtomicPtr
<Elf_Ehdr
> = AtomicPtr
::new(null_mut());
129 static PHDR
: AtomicPtr
<Elf_Phdr
> = AtomicPtr
::new(null_mut());
130 static PHNUM
: AtomicUsize
= AtomicUsize
::new(0);
131 static EXECFN
: AtomicPtr
<c
::c_char
> = AtomicPtr
::new(null_mut());
133 /// On non-Mustang platforms, we read the aux vector from /proc/self/auxv.
134 #[cfg(not(target_vendor = "mustang"))]
135 fn init_from_proc_self_auxv() {
136 // Open "/proc/self/auxv", either because we trust "/proc", or because
137 // we're running inside QEMU and `proc_self_auxv`'s extra checking foils
138 // QEMU's emulation so we need to do a plain open to get the right
140 let file
= crate::fs
::openat(
148 let _
= init_from_auxv_file(file
);
151 #[cfg(target_vendor = "mustang")]
152 fn init_from_proc_self_auxv() {
153 panic
!("mustang should have initialized the auxv values");
156 /// Process auxv entries from the open file `auxv`.
157 fn init_from_auxv_file(auxv
: OwnedFd
) -> Option
<()> {
158 let mut buffer
= Vec
::<u8>::with_capacity(512);
160 let cur
= buffer
.len();
162 // Request one extra byte; `Vec` will often allocate more.
165 // Use all the space it allocated.
166 buffer
.resize(buffer
.capacity(), 0);
168 // Read up to that many bytes.
169 let n
= match crate::io
::read(&auxv
, &mut buffer
[cur
..]) {
170 Err(crate::io
::Errno
::INTR
) => 0,
171 Err(_err
) => panic
!(),
176 // Account for the number of bytes actually read.
177 buffer
.resize(cur
+ n
, 0_u8);
180 // Safety: We loaded from an auxv file into the buffer.
181 unsafe { init_from_auxp(buffer.as_ptr().cast()) }
184 /// Process auxv entries from the auxv array pointed to by `auxp`.
188 /// This must be passed a pointer to an auxv array.
190 /// The buffer contains `Elf_aux_t` elements, though it need not be aligned;
191 /// function uses `read_unaligned` to read from it.
192 unsafe fn init_from_auxp(mut auxp
: *const Elf_auxv_t
) -> Option
<()> {
197 let mut phdr
= null_mut();
199 let mut execfn
= null_mut();
200 let mut sysinfo_ehdr
= null_mut();
204 let Elf_auxv_t { a_type, a_val }
= read_unaligned(auxp
);
207 AT_PAGESZ
=> pagesz
= a_val
as usize,
208 AT_CLKTCK
=> clktck
= a_val
as usize,
209 AT_HWCAP
=> hwcap
= a_val
as usize,
210 AT_HWCAP2
=> hwcap2
= a_val
as usize,
211 AT_PHDR
=> phdr
= check_raw_pointer
::<Elf_Phdr
>(a_val
as *mut _
)?
.as_ptr(),
212 AT_PHNUM
=> phnum
= a_val
as usize,
213 AT_PHENT
=> phent
= a_val
as usize,
214 AT_EXECFN
=> execfn
= check_raw_pointer
::<c
::c_char
>(a_val
as *mut _
)?
.as_ptr(),
215 AT_BASE
=> check_interpreter_base(a_val
.cast())?
,
216 AT_SYSINFO_EHDR
=> sysinfo_ehdr
= check_vdso_base(a_val
as *mut _
)?
.as_ptr(),
223 assert_eq
!(phent
, size_of
::<Elf_Phdr
>());
225 // The base and sysinfo_ehdr (if present) matches our platform. Accept
227 PAGE_SIZE
.store(pagesz
, Relaxed
);
228 CLOCK_TICKS_PER_SECOND
.store(clktck
, Relaxed
);
229 HWCAP
.store(hwcap
, Relaxed
);
230 HWCAP2
.store(hwcap2
, Relaxed
);
231 PHDR
.store(phdr
, Relaxed
);
232 PHNUM
.store(phnum
, Relaxed
);
233 EXECFN
.store(execfn
, Relaxed
);
234 SYSINFO_EHDR
.store(sysinfo_ehdr
, Relaxed
);
239 /// Check that `base` is a valid pointer to the program interpreter.
241 /// `base` is some value we got from a `AT_BASE` aux record somewhere,
242 /// which hopefully holds the value of the program interpreter in memory. Do a
243 /// series of checks to be as sure as we can that it's safe to use.
244 unsafe fn check_interpreter_base(base
: *const Elf_Ehdr
) -> Option
<()> {
245 check_elf_base(base
)?
;
249 /// Check that `base` is a valid pointer to the kernel-provided vDSO.
251 /// `base` is some value we got from a `AT_SYSINFO_EHDR` aux record somewhere,
252 /// which hopefully holds the value of the kernel-provided vDSO in memory. Do a
253 /// series of checks to be as sure as we can that it's safe to use.
254 unsafe fn check_vdso_base(base
: *const Elf_Ehdr
) -> Option
<NonNull
<Elf_Ehdr
>> {
255 // In theory, we could check that we're not attempting to parse our own ELF
256 // image, as an additional check. However, older Linux toolchains don't
257 // support this, and Rust's `#[linkage = "extern_weak"]` isn't stable yet,
258 // so just disable this for now.
262 static __ehdr_start: c::c_void;
265 let ehdr_start: *const c::c_void = &__ehdr_start;
266 if base == ehdr_start {
272 let hdr
= check_elf_base(base
)?
;
274 // Check that the ELF is not writable, since that would indicate that this
275 // isn't the ELF we think it is. Here we're just using `clock_getres` just
276 // as an arbitrary system call which writes to a buffer and fails with
277 // `EFAULT` if the buffer is not writable.
279 use super::super::conv
::{c_uint, ret}
;
282 c_uint(linux_raw_sys
::general
::CLOCK_MONOTONIC
),
284 )) != Err(crate::io
::Errno
::FAULT
)
286 // We can't gracefully fail here because we would seem to have just
287 // mutated some unknown memory.
288 #[cfg(feature = "std")]
290 std
::process
::abort();
292 #[cfg(all(not(feature = "std"), feature = "rustc-dep-of-std"))]
294 core
::intrinsics
::abort();
302 /// Check that `base` is a valid pointer to an ELF image.
303 unsafe fn check_elf_base(base
: *const Elf_Ehdr
) -> Option
<NonNull
<Elf_Ehdr
>> {
304 // If we're reading a 64-bit auxv on a 32-bit platform, we'll see
305 // a zero `a_val` because `AT_*` values are never greater than
306 // `u32::MAX`. Zero is used by libc's `getauxval` to indicate
307 // errors, so it should never be a valid value.
312 let hdr
= match check_raw_pointer
::<Elf_Ehdr
>(base
as *mut _
) {
317 let hdr
= hdr
.as_ref();
318 if hdr
.e_ident
[..SELFMAG
] != ELFMAG
{
319 return None
; // Wrong ELF magic
321 if !matches
!(hdr
.e_ident
[EI_OSABI
], ELFOSABI_SYSV
| ELFOSABI_LINUX
) {
322 return None
; // Unrecognized ELF OS ABI
324 if hdr
.e_ident
[EI_ABIVERSION
] != ELFABIVERSION
{
325 return None
; // Unrecognized ELF ABI version
327 if hdr
.e_type
!= ET_DYN
{
328 return None
; // Wrong ELF type
331 // If ELF is extended, we'll need to adjust.
332 if hdr
.e_ident
[EI_VERSION
] != EV_CURRENT
333 || hdr
.e_ehsize
as usize != size_of
::<Elf_Ehdr
>()
334 || hdr
.e_phentsize
as usize != size_of
::<Elf_Phdr
>()
338 // We don't currently support extra-large numbers of segments.
339 if hdr
.e_phnum
== PN_XNUM
{
343 // If `e_phoff` is zero, it's more likely that we're looking at memory that
344 // has been zeroed than that the kernel has somehow aliased the `Ehdr` and
346 if hdr
.e_phoff
< size_of
::<Elf_Ehdr
>() {
350 // Verify that the `EI_CLASS`/`EI_DATA`/`e_machine` fields match the
351 // architecture we're running as. This helps catch cases where we're
352 // running under QEMU.
353 if hdr
.e_ident
[EI_CLASS
] != ELFCLASS
{
354 return None
; // Wrong ELF class
356 if hdr
.e_ident
[EI_DATA
] != ELFDATA
{
357 return None
; // Wrong ELF data
359 if hdr
.e_machine
!= EM_CURRENT
{
360 return None
; // Wrong machine type
363 Some(NonNull
::new_unchecked(as_ptr(hdr
) as *mut _
))
369 #[derive(Copy, Clone)]
373 // Some of the values in the auxv array are pointers, so we make `a_val` a
374 // pointer, in order to preserve their provenance. For the values which are
375 // integers, we cast this to `usize`.
376 a_val
: *const c_void
,