1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
//! # Just what is the auxiliary vector?
//!
//! The auxiliary vector (aka auxv) is some memory near the start of a running ELF program's stack.
//! Specifically, it's a sequence of pairs of either 64 bit or 32 bit unsigned ints. The two
//! components of the pair form a key and a value. This data is mostly there to help things
//! like runtime linkers, but sometimes it's useful for other reasons. It is ELF-specific; it does
//! not exist in, say, Mach-O.
//!
//! On most Unixy systems, you can have the linker print out the contents of the aux vector by
//! setting an environment variable when running a command like `LD_SHOW_AUXV=1 cat /dev/null`.
//!
//! The keys used in the aux vector are defined in various header files and typically prefixed with
//! `AT_`. Some of the data there is not available from any other source, like `AT_HWCAP` and
//! `AT_HWCAP2`. These expose bit vectors of architecture-dependent hardware capability information.
//! On ARM, for instance, the bit `1 << 12` in the value for `AT_HWCAP` will be set if the CPU
//! supports NEON, and `1 << 3` will be set in the value for `AT_HWCAP2` if the CPU supports
//! SHA-256 acceleration. Handy, if you're doing that sort of thing.
//!
//! Other keys are typically not used directly by programs, like `AT_UID`: the real user id is
//! great and all, but you'd pobably call [`getuid(2)`](https://linux.die.net/man/2/getuid) in C or
//! `libc::getuid` from Rust instead.
//!
//! For most people, probably the most interesting data in auxv is for `AT_HWCAP` or `AT_HWCAP2`
//! so those have constants defined in `auxv`, but you can of course use any other key as well;
//! you'll just have to look up the appropriate number.
//!
//! More info on the auxiliary vector:
//!
//! - http://articles.manugarg.com/aboutelfauxiliaryvectors.html
//! - http://phrack.org/issues/58/5.html
//! - See `include/uapi/linux/auxvec.h` in the Linux source (or `getauxval(3)`) for defined keys,
//!   as well as other header files for architecture-specific types.
//! - See `fs/binfmt_elf.c` in the Linux source for how the vector is generated.
//! - Searching for `AT_` in your OS of choice is likely to yield some good leads on the available
//!   constants and how it's generated.
//!
//! # Reading the auxiliary vector
//!
//! Unfortunately, there is no one best option for how to access the aux vector.
//!
//! - [`getauxval(3)`](https://linux.die.net/man/3/getauxval) is available in glibc 2.16+, Android
//!   libc (Bionic) since Android 4,3, and musl 1.1.0+. Since it is a non-standard extension, if
//!   you're not using those libc implementations (e.g. you're using uclibc, etc), this will
//!   not be available. Also, if you're on glibc older than 2.19, or Bionic before March 2015,
//!   `getauxval` is unable to express the concept of "not found" and will instead "find" the value 0.
//! - `/proc/self/auxv` exposes the contents of the aux vector, but it only exists on Linux.
//!   Furthermore, the OS may be configured to not allow access to it (see `proc(5)`).
//! - Navigating the ELF stack layout manually is also (sometimes) possible. There isn't a
//!   standardized way of jumping directly to auxv in the stack, but we can start at the `environ`
//!   pointer (which is specified in POSIX) and navigate from there. This will work on any ELF
//!   OS, but it is `unsafe` and only is possible if the environment has not been modified since
//!   the process started.
//!
//! This library lets you use all of these options, so chances are pretty good that at least one of
//! them will work in any given host. See each submodule for details on how and when to use it.
//!
//! For most users, it would be best practice to try the `getauxval` way first, and then try the
//! procfs way if `getauxval` is not available at runtime. You should only try the stack crawling
//! way if you are sure that it is safe; see its docs for details.
//!
//! See the `examples` dir for examples of each way of accessing auxv.
//!
//! ## Auxv type width
//!
//! `AuxvType` is selected at compile time to be either `u32` or `u64` depending on the pointer
//! width of the system. This type is used for the key and value.

// The key/value pairs in auxv are either Elf32_auxv_t or Elf64_auxv_t.
// If this is an LP64 system (a "long" is 64 bits) then it seems that
// these entries will be Elf64_auxv_t (2x 64 bits). Fortunately,
// Unixen in general are LP64 (when on 64 bit), and ELF only exists
// on Unixen, which means we can simply use pointer width to detect 32
// vs 64 bit. Furthermore, some of the things auxv holds are pointers
// (e.g. AT_BASe and AT_EXECFN), so value has to be able to hold a
// pointer, and the key is always the same width as the value.
/// The type used in auxv keys and values.
#[cfg(target_pointer_width="32")]
pub type AuxvType = u32;
/// The type used in auxv keys and values.
#[cfg(target_pointer_width="64")]
pub type AuxvType = u64;

// from [linux]/include/uapi/linux/auxvec.h. First 32 bits of HWCAP
// even on platforms where unsigned long is 64 bits.
pub const AT_HWCAP: AuxvType = 16;
pub const AT_HWCAP2: AuxvType = 26;

/// An auxv key-value pair.
#[derive(Debug, PartialEq)]
pub struct AuxvPair {
    pub key: AuxvType,
    pub value: AuxvType,
}

pub mod getauxval;
pub mod procfs;
pub mod stack;