Skip to content

Commit f466001

Browse files
authored
Add a rustix::runtime::linux_secure function (#864)
This function tests for "secure execution" mode which isn't as comprehensive as it first sounds, but it is something that libc implementations are expected to check in a few places, so add it to the "runtime" module for c-scape to use.
1 parent 62afd55 commit f466001

5 files changed

Lines changed: 109 additions & 22 deletions

File tree

src/backend/linux_raw/param/auxv.rs

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,18 @@ use crate::utils::{as_ptr, check_raw_pointer};
1515
use alloc::vec::Vec;
1616
use core::mem::size_of;
1717
use core::ptr::{null_mut, read_unaligned, NonNull};
18+
#[cfg(feature = "runtime")]
19+
use core::sync::atomic::AtomicU8;
1820
use core::sync::atomic::Ordering::Relaxed;
1921
use core::sync::atomic::{AtomicPtr, AtomicUsize};
2022
use linux_raw_sys::elf::*;
2123
use linux_raw_sys::general::{
2224
AT_BASE, AT_CLKTCK, AT_EXECFN, AT_HWCAP, AT_HWCAP2, AT_NULL, AT_PAGESZ, AT_SYSINFO_EHDR,
2325
};
2426
#[cfg(feature = "runtime")]
25-
use linux_raw_sys::general::{AT_ENTRY, AT_PHDR, AT_PHENT, AT_PHNUM};
27+
use linux_raw_sys::general::{
28+
AT_EGID, AT_ENTRY, AT_EUID, AT_GID, AT_PHDR, AT_PHENT, AT_PHNUM, AT_SECURE, AT_UID,
29+
};
2630

2731
#[cfg(feature = "param")]
2832
#[inline]
@@ -80,6 +84,23 @@ pub(crate) fn linux_execfn() -> &'static CStr {
8084
unsafe { CStr::from_ptr(execfn.cast()) }
8185
}
8286

87+
#[cfg(feature = "runtime")]
88+
#[inline]
89+
pub(crate) fn linux_secure() -> bool {
90+
let mut secure = SECURE.load(Relaxed);
91+
92+
// 0 means not initialized yet.
93+
if secure == 0 {
94+
init_auxv();
95+
secure = SECURE.load(Relaxed);
96+
}
97+
98+
// 0 means not present. Libc `getauxval(AT_SECURE)` would return 0.
99+
// 1 means not in secure mode.
100+
// 2 means in secure mode.
101+
secure > 1
102+
}
103+
83104
#[cfg(feature = "runtime")]
84105
#[inline]
85106
pub(crate) fn exe_phdrs() -> (*const c::c_void, usize, usize) {
@@ -131,6 +152,8 @@ static HWCAP2: AtomicUsize = AtomicUsize::new(0);
131152
static EXECFN: AtomicPtr<c::c_char> = AtomicPtr::new(null_mut());
132153
static SYSINFO_EHDR: AtomicPtr<Elf_Ehdr> = AtomicPtr::new(null_mut());
133154
#[cfg(feature = "runtime")]
155+
static SECURE: AtomicU8 = AtomicU8::new(0);
156+
#[cfg(feature = "runtime")]
134157
static PHDR: AtomicPtr<Elf_Phdr> = AtomicPtr::new(null_mut());
135158
#[cfg(feature = "runtime")]
136159
static PHENT: AtomicUsize = AtomicUsize::new(0);
@@ -256,13 +279,23 @@ unsafe fn init_from_aux_iter(aux_iter: impl Iterator<Item = Elf_auxv_t>) -> Opti
256279
let mut execfn = null_mut();
257280
let mut sysinfo_ehdr = null_mut();
258281
#[cfg(feature = "runtime")]
282+
let mut secure = 0;
283+
#[cfg(feature = "runtime")]
259284
let mut phdr = null_mut();
260285
#[cfg(feature = "runtime")]
261286
let mut phnum = 0;
262287
#[cfg(feature = "runtime")]
263288
let mut phent = 0;
264289
#[cfg(feature = "runtime")]
265290
let mut entry = 0;
291+
#[cfg(feature = "runtime")]
292+
let mut uid = None;
293+
#[cfg(feature = "runtime")]
294+
let mut euid = None;
295+
#[cfg(feature = "runtime")]
296+
let mut gid = None;
297+
#[cfg(feature = "runtime")]
298+
let mut egid = None;
266299

267300
for Elf_auxv_t { a_type, a_val } in aux_iter {
268301
match a_type as _ {
@@ -277,6 +310,16 @@ unsafe fn init_from_aux_iter(aux_iter: impl Iterator<Item = Elf_auxv_t>) -> Opti
277310
let _ = check_elf_base(a_val.cast())?;
278311
}
279312

313+
#[cfg(feature = "runtime")]
314+
AT_SECURE => secure = (a_val as usize != 0) as u8 + 1,
315+
#[cfg(feature = "runtime")]
316+
AT_UID => uid = Some(a_val),
317+
#[cfg(feature = "runtime")]
318+
AT_EUID => euid = Some(a_val),
319+
#[cfg(feature = "runtime")]
320+
AT_GID => gid = Some(a_val),
321+
#[cfg(feature = "runtime")]
322+
AT_EGID => egid = Some(a_val),
280323
#[cfg(feature = "runtime")]
281324
AT_PHDR => phdr = check_raw_pointer::<Elf_Phdr>(a_val as *mut _)?.as_ptr(),
282325
#[cfg(feature = "runtime")]
@@ -294,15 +337,25 @@ unsafe fn init_from_aux_iter(aux_iter: impl Iterator<Item = Elf_auxv_t>) -> Opti
294337
#[cfg(feature = "runtime")]
295338
assert_eq!(phent, size_of::<Elf_Phdr>());
296339

297-
// The base and sysinfo_ehdr (if present) matches our platform. Accept
298-
// the aux values.
340+
// If we're running set-uid or set-gid, enable "secure execution" mode,
341+
// which doesn't do much, but users may be depending on the things that
342+
// it does do.
343+
#[cfg(feature = "runtime")]
344+
if uid != euid || gid != egid {
345+
secure = 2;
346+
}
347+
348+
// The base and sysinfo_ehdr (if present) matches our platform. Accept the
349+
// aux values.
299350
PAGE_SIZE.store(pagesz, Relaxed);
300351
CLOCK_TICKS_PER_SECOND.store(clktck, Relaxed);
301352
HWCAP.store(hwcap, Relaxed);
302353
HWCAP2.store(hwcap2, Relaxed);
303354
EXECFN.store(execfn, Relaxed);
304355
SYSINFO_EHDR.store(sysinfo_ehdr, Relaxed);
305356
#[cfg(feature = "runtime")]
357+
SECURE.store(secure, Relaxed);
358+
#[cfg(feature = "runtime")]
306359
PHDR.store(phdr, Relaxed);
307360
#[cfg(feature = "runtime")]
308361
PHNUM.store(phnum, Relaxed);

src/backend/linux_raw/param/init.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use linux_raw_sys::general::{
1616
AT_CLKTCK, AT_EXECFN, AT_HWCAP, AT_HWCAP2, AT_NULL, AT_PAGESZ, AT_SYSINFO_EHDR,
1717
};
1818
#[cfg(feature = "runtime")]
19-
use linux_raw_sys::general::{AT_ENTRY, AT_PHDR, AT_PHENT, AT_PHNUM};
19+
use linux_raw_sys::general::{AT_ENTRY, AT_PHDR, AT_PHENT, AT_PHNUM, AT_SECURE};
2020

2121
#[cfg(feature = "param")]
2222
#[inline]
@@ -51,6 +51,12 @@ pub(crate) fn linux_execfn() -> &'static CStr {
5151
unsafe { CStr::from_ptr(execfn.cast()) }
5252
}
5353

54+
#[cfg(feature = "runtime")]
55+
#[inline]
56+
pub(crate) fn linux_secure() -> bool {
57+
unsafe { SECURE.load(Ordering::Relaxed) }
58+
}
59+
5460
#[cfg(feature = "runtime")]
5561
#[inline]
5662
pub(crate) fn exe_phdrs() -> (*const c_void, usize, usize) {
@@ -84,6 +90,8 @@ static mut SYSINFO_EHDR: AtomicPtr<Elf_Ehdr> = AtomicPtr::new(null_mut());
8490
// Initialize `EXECFN` to a valid `CStr` pointer so that we don't need to check
8591
// for null on every `execfn` call.
8692
static mut EXECFN: AtomicPtr<c::c_char> = AtomicPtr::new(b"\0".as_ptr() as _);
93+
#[cfg(feature = "runtime")]
94+
static mut SECURE: AtomicBool = AtomicBool::new(false);
8795
// Use `dangling` so that we can always treat it like an empty slice.
8896
#[cfg(feature = "runtime")]
8997
static mut PHDR: AtomicPtr<Elf_Phdr> = AtomicPtr::new(NonNull::dangling().as_ptr());
@@ -132,6 +140,8 @@ unsafe fn init_from_auxp(mut auxp: *const Elf_auxv_t) {
132140
AT_EXECFN => EXECFN.store(a_val.cast::<c::c_char>(), Ordering::Relaxed),
133141
AT_SYSINFO_EHDR => SYSINFO_EHDR.store(a_val.cast::<Elf_Ehdr>(), Ordering::Relaxed),
134142

143+
#[cfg(feature = "runtime")]
144+
AT_SECURE => SECURE.store(a_val != 0, Ordering::Relaxed),
135145
#[cfg(feature = "runtime")]
136146
AT_PHDR => PHDR.store(a_val.cast::<Elf_Phdr>(), Ordering::Relaxed),
137147
#[cfg(feature = "runtime")]

src/backend/linux_raw/param/libc_auxv.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const AT_PHNUM: c::c_ulong = 5;
3434
const AT_ENTRY: c::c_ulong = 9;
3535
const AT_HWCAP: c::c_ulong = 16;
3636
const AT_HWCAP2: c::c_ulong = 26;
37+
const AT_SECURE: c::c_ulong = 23;
3738
const AT_EXECFN: c::c_ulong = 31;
3839
const AT_SYSINFO_EHDR: c::c_ulong = 33;
3940

@@ -59,6 +60,7 @@ fn test_abi() {
5960
const_assert_eq!(self::AT_HWCAP, ::libc::AT_HWCAP);
6061
const_assert_eq!(self::AT_HWCAP2, ::libc::AT_HWCAP2);
6162
const_assert_eq!(self::AT_EXECFN, ::libc::AT_EXECFN);
63+
const_assert_eq!(self::AT_SECURE, ::libc::AT_SECURE);
6264
const_assert_eq!(self::AT_SYSINFO_EHDR, ::libc::AT_SYSINFO_EHDR);
6365
#[cfg(feature = "runtime")]
6466
const_assert_eq!(self::AT_PHDR, ::libc::AT_PHDR);
@@ -120,6 +122,12 @@ pub(crate) fn linux_execfn() -> &'static CStr {
120122
}
121123
}
122124

125+
#[cfg(feature = "runtime")]
126+
#[inline]
127+
pub(crate) fn linux_secure() -> bool {
128+
unsafe { getauxval(AT_SECURE) as usize != 0 }
129+
}
130+
123131
#[cfg(feature = "runtime")]
124132
#[inline]
125133
pub(crate) fn exe_phdrs() -> (*const c::c_void, usize, usize) {

src/param/auxv.rs

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
use crate::backend;
22
#[cfg(any(
33
linux_raw,
4-
all(
5-
libc,
6-
any(
7-
all(target_os = "android", target_pointer_width = "64"),
8-
target_os = "linux",
9-
)
4+
any(
5+
all(target_os = "android", target_pointer_width = "64"),
6+
target_os = "linux",
107
)
118
))]
129
use crate::ffi::CStr;
@@ -58,12 +55,9 @@ pub fn clock_ticks_per_second() -> u64 {
5855
/// [Linux]: https://man7.org/linux/man-pages/man3/getauxval.3.html
5956
#[cfg(any(
6057
linux_raw,
61-
all(
62-
libc,
63-
any(
64-
all(target_os = "android", target_pointer_width = "64"),
65-
target_os = "linux",
66-
)
58+
any(
59+
all(target_os = "android", target_pointer_width = "64"),
60+
target_os = "linux",
6761
)
6862
))]
6963
#[inline]
@@ -82,12 +76,9 @@ pub fn linux_hwcap() -> (usize, usize) {
8276
/// [Linux]: https://man7.org/linux/man-pages/man3/getauxval.3.html
8377
#[cfg(any(
8478
linux_raw,
85-
all(
86-
libc,
87-
any(
88-
all(target_os = "android", target_pointer_width = "64"),
89-
target_os = "linux",
90-
)
79+
any(
80+
all(target_os = "android", target_pointer_width = "64"),
81+
target_os = "linux",
9182
)
9283
))]
9384
#[inline]

src/runtime.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,3 +485,28 @@ pub unsafe fn sigwaitinfo(set: &Sigset) -> io::Result<Siginfo> {
485485
pub unsafe fn sigtimedwait(set: &Sigset, timeout: Option<Timespec>) -> io::Result<Siginfo> {
486486
backend::runtime::syscalls::sigtimedwait(set, timeout)
487487
}
488+
489+
/// `getauxval(AT_SECURE)`—Returns the Linux "secure execution" mode.
490+
///
491+
/// Return a boolean value indicating whether "secure execution" mode was
492+
/// requested, due the the process having elevated privileges. This includes
493+
/// whether the `AT_SECURE` AUX value is set, and whether the initial real
494+
/// UID and GID differ from the initial effective UID and GID.
495+
///
496+
/// The meaning of "secure execution" mode is beyond the scope of this comment.
497+
///
498+
/// # References
499+
/// - [Linux]
500+
///
501+
/// [Linux]: https://man7.org/linux/man-pages/man3/getauxval.3.html
502+
#[cfg(any(
503+
linux_raw,
504+
any(
505+
all(target_os = "android", target_pointer_width = "64"),
506+
target_os = "linux",
507+
)
508+
))]
509+
#[inline]
510+
pub fn linux_secure() -> bool {
511+
backend::param::auxv::linux_secure()
512+
}

0 commit comments

Comments
 (0)