use std::collections::BTreeMap;
use std::io;
use byteorder::NativeEndian;
use byteorder::ReadBytesExt;
use crate::Pid;
use crate::syscalls::Addr;
pub struct Auxv {
map: BTreeMap<libc::c_ulong, libc::c_ulong>,
}
impl Auxv {
pub fn from_entries(entries: impl IntoIterator<Item = (libc::c_ulong, libc::c_ulong)>) -> Self {
Self {
map: entries.into_iter().collect(),
}
}
pub(crate) fn new(pid: Pid) -> io::Result<Self> {
let mut map = BTreeMap::new();
let buf = crate::process::launch_window::read(format!("/proc/{}/auxv", pid))?;
debug_assert_eq!(
buf.len() % 16,
0,
"got invalid size of auxv file: {} bytes",
buf.len()
);
let mut file = io::Cursor::new(buf);
loop {
let key = file.read_u64::<NativeEndian>()?;
let value = file.read_u64::<NativeEndian>()?;
if key == 0 && value == 0 {
break;
}
map.insert(key, value);
}
Ok(Self { map })
}
pub fn len(&self) -> usize {
self.map.len()
}
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
pub fn at_random(&self) -> Option<Addr<'_, [u8; 16]>> {
self.map
.get(&libc::AT_RANDOM)
.and_then(|val| Addr::from_raw(*val as usize))
}
pub fn at_uid(&self) -> Option<libc::uid_t> {
self.map.get(&libc::AT_UID).map(|val| *val as libc::uid_t)
}
pub fn at_euid(&self) -> Option<libc::uid_t> {
self.map.get(&libc::AT_EUID).map(|val| *val as libc::uid_t)
}
pub fn at_gid(&self) -> Option<libc::gid_t> {
self.map.get(&libc::AT_GID).map(|val| *val as libc::gid_t)
}
pub fn at_egid(&self) -> Option<libc::gid_t> {
self.map.get(&libc::AT_EGID).map(|val| *val as libc::gid_t)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn builds_from_backend_entries() {
let map = Auxv::from_entries([
(libc::AT_UID, 123),
(libc::AT_GID, 456),
(libc::AT_RANDOM, 0x1000),
]);
assert_eq!(map.len(), 3);
assert_eq!(map.at_uid(), Some(123));
assert_eq!(map.at_gid(), Some(456));
assert_eq!(
map.at_random().map(|address| address.as_raw()),
Some(0x1000),
);
}
#[test]
fn smoke() {
let map = Auxv::new(Pid::this()).unwrap();
assert!(!map.is_empty());
assert_eq!(map.at_uid(), Some(unsafe { libc::getuid() }));
assert_eq!(map.at_gid(), Some(unsafe { libc::getgid() }));
assert!(map.at_random().is_some());
}
}