Skip to content

Commit d98d532

Browse files
authored
Use PR_GET_AUXV if available; fall back to /proc/self/auxv (#636)
This avoids relying on /proc being mounted, and on file operations; it also reduces the total number of syscalls.
1 parent 1dc277d commit d98d532

File tree

2 files changed

+132
-9
lines changed

2 files changed

+132
-9
lines changed

src/backend/linux_raw/arch/mod.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,85 @@ macro_rules! syscall {
133133
};
134134
}
135135

136+
// Macro to invoke a syscall that always uses direct assembly, rather than the vdso. Useful when
137+
// still finding the vdso.
138+
#[allow(unused_macros)]
139+
macro_rules! syscall_always_asm {
140+
($nr:ident) => {
141+
$crate::backend::arch::asm::syscall0($crate::backend::reg::nr(linux_raw_sys::general::$nr))
142+
};
143+
144+
($nr:ident, $a0:expr) => {
145+
$crate::backend::arch::asm::syscall1(
146+
$crate::backend::reg::nr(linux_raw_sys::general::$nr),
147+
$a0.into(),
148+
)
149+
};
150+
151+
($nr:ident, $a0:expr, $a1:expr) => {
152+
$crate::backend::arch::asm::syscall2(
153+
$crate::backend::reg::nr(linux_raw_sys::general::$nr),
154+
$a0.into(),
155+
$a1.into(),
156+
)
157+
};
158+
159+
($nr:ident, $a0:expr, $a1:expr, $a2:expr) => {
160+
$crate::backend::arch::asm::syscall3(
161+
$crate::backend::reg::nr(linux_raw_sys::general::$nr),
162+
$a0.into(),
163+
$a1.into(),
164+
$a2.into(),
165+
)
166+
};
167+
168+
($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr) => {
169+
$crate::backend::arch::asm::syscall4(
170+
$crate::backend::reg::nr(linux_raw_sys::general::$nr),
171+
$a0.into(),
172+
$a1.into(),
173+
$a2.into(),
174+
$a3.into(),
175+
)
176+
};
177+
178+
($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => {
179+
$crate::backend::arch::asm::syscall5(
180+
$crate::backend::reg::nr(linux_raw_sys::general::$nr),
181+
$a0.into(),
182+
$a1.into(),
183+
$a2.into(),
184+
$a3.into(),
185+
$a4.into(),
186+
)
187+
};
188+
189+
($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr) => {
190+
$crate::backend::arch::asm::syscall6(
191+
$crate::backend::reg::nr(linux_raw_sys::general::$nr),
192+
$a0.into(),
193+
$a1.into(),
194+
$a2.into(),
195+
$a3.into(),
196+
$a4.into(),
197+
$a5.into(),
198+
)
199+
};
200+
201+
($nr:ident, $a0:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr, $a5:expr, $a6:expr) => {
202+
$crate::backend::arch::asm::syscall7(
203+
$crate::backend::reg::nr(linux_raw_sys::general::$nr),
204+
$a0.into(),
205+
$a1.into(),
206+
$a2.into(),
207+
$a3.into(),
208+
$a4.into(),
209+
$a5.into(),
210+
$a6.into(),
211+
)
212+
};
213+
}
214+
136215
/// Like `syscall`, but adds the `readonly` attribute to the inline asm, which
137216
/// indicates that the syscall does not mutate any memory.
138217
macro_rules! syscall_readonly {

src/backend/linux_raw/param/auxv.rs

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pub(crate) fn page_size() -> usize {
3232
let mut page_size = PAGE_SIZE.load(Relaxed);
3333

3434
if page_size == 0 {
35-
init_from_proc_self_auxv();
35+
init_auxv();
3636
page_size = PAGE_SIZE.load(Relaxed);
3737
}
3838

@@ -45,7 +45,7 @@ pub(crate) fn clock_ticks_per_second() -> u64 {
4545
let mut ticks = CLOCK_TICKS_PER_SECOND.load(Relaxed);
4646

4747
if ticks == 0 {
48-
init_from_proc_self_auxv();
48+
init_auxv();
4949
ticks = CLOCK_TICKS_PER_SECOND.load(Relaxed);
5050
}
5151

@@ -59,7 +59,7 @@ pub(crate) fn linux_hwcap() -> (usize, usize) {
5959
let mut hwcap2 = HWCAP2.load(Relaxed);
6060

6161
if hwcap == 0 || hwcap2 == 0 {
62-
init_from_proc_self_auxv();
62+
init_auxv();
6363
hwcap = HWCAP.load(Relaxed);
6464
hwcap2 = HWCAP2.load(Relaxed);
6565
}
@@ -73,7 +73,7 @@ pub(crate) fn linux_execfn() -> &'static CStr {
7373
let mut execfn = EXECFN.load(Relaxed);
7474

7575
if execfn.is_null() {
76-
init_from_proc_self_auxv();
76+
init_auxv();
7777
execfn = EXECFN.load(Relaxed);
7878
}
7979

@@ -89,7 +89,7 @@ pub(crate) fn exe_phdrs() -> (*const c::c_void, usize) {
8989
let mut phnum = PHNUM.load(Relaxed);
9090

9191
if phdr.is_null() || phnum == 0 {
92-
init_from_proc_self_auxv();
92+
init_auxv();
9393
phdr = PHDR.load(Relaxed);
9494
phnum = PHNUM.load(Relaxed);
9595
}
@@ -114,7 +114,7 @@ pub(in super::super) fn sysinfo_ehdr() -> *const Elf_Ehdr {
114114
let mut ehdr = SYSINFO_EHDR.load(Relaxed);
115115

116116
if ehdr.is_null() {
117-
init_from_proc_self_auxv();
117+
init_auxv();
118118
ehdr = SYSINFO_EHDR.load(Relaxed);
119119
}
120120

@@ -130,9 +130,53 @@ static PHDR: AtomicPtr<Elf_Phdr> = AtomicPtr::new(null_mut());
130130
static PHNUM: AtomicUsize = AtomicUsize::new(0);
131131
static EXECFN: AtomicPtr<c::c_char> = AtomicPtr::new(null_mut());
132132

133-
/// On non-Mustang platforms, we read the aux vector from /proc/self/auxv.
134133
#[cfg(not(target_vendor = "mustang"))]
135-
fn init_from_proc_self_auxv() {
134+
fn pr_get_auxv() -> crate::io::Result<Vec<u8>> {
135+
use super::super::conv::{c_int, pass_usize, ret_usize};
136+
const PR_GET_AUXV: c::c_int = 0x41555856;
137+
let mut buffer = alloc::vec![0u8; 512];
138+
let len = unsafe {
139+
ret_usize(syscall_always_asm!(
140+
__NR_prctl,
141+
c_int(PR_GET_AUXV),
142+
buffer.as_ptr(),
143+
pass_usize(buffer.len())
144+
))?
145+
};
146+
if len <= buffer.len() {
147+
buffer.truncate(len);
148+
return Ok(buffer);
149+
}
150+
buffer.resize(len, 0);
151+
let len = unsafe {
152+
ret_usize(syscall_always_asm!(
153+
__NR_prctl,
154+
c_int(PR_GET_AUXV),
155+
buffer.as_ptr(),
156+
pass_usize(buffer.len())
157+
))?
158+
};
159+
assert_eq!(len, buffer.len());
160+
return Ok(buffer);
161+
}
162+
163+
/// On non-Mustang platforms, we read the aux vector via the prctl PR_GET_AUXV, with a fallback to
164+
/// /proc/self/auxv for kernels that don't support PR_GET_AUXV.
165+
#[cfg(not(target_vendor = "mustang"))]
166+
fn init_auxv() {
167+
match pr_get_auxv() {
168+
Ok(buffer) => {
169+
// SAFETY: We assume the kernel returns a valid auxv.
170+
unsafe {
171+
init_from_auxp(buffer.as_ptr().cast());
172+
}
173+
return;
174+
}
175+
Err(_) => {
176+
// Fall back to /proc/self/auxv on error.
177+
}
178+
}
179+
136180
// Open "/proc/self/auxv", either because we trust "/proc", or because
137181
// we're running inside QEMU and `proc_self_auxv`'s extra checking foils
138182
// QEMU's emulation so we need to do a plain open to get the right
@@ -143,7 +187,7 @@ fn init_from_proc_self_auxv() {
143187
}
144188

145189
#[cfg(target_vendor = "mustang")]
146-
fn init_from_proc_self_auxv() {
190+
fn init_auxv() {
147191
panic!("mustang should have initialized the auxv values");
148192
}
149193

0 commit comments

Comments
 (0)