linux_libc_auxv/aux_var/
typ.rs

1/*
2MIT License
3
4Copyright (c) 2021 Philipp Schuster
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22SOFTWARE.
23*/
24use core::cmp::Ordering;
25use enum_iterator::IntoEnumIterator;
26
27/// All types of auxiliary variables that Linux supports for the initial stack.
28/// Also called "AT"-variables in Linux source code.
29///
30/// According to some Linux code comments, `0-17` are architecture independent
31/// The ones above and including `32` are for `x86_64`. Values above 40 are for power PC.
32///
33/// More info:
34/// * <https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/auxvec.h>
35/// * <https://elixir.bootlin.com/linux/latest/source/fs/binfmt_elf.c#L259>
36/// * <https://man7.org/linux/man-pages/man3/getauxval.3.html>
37#[derive(Copy, Clone, Debug, PartialEq, Eq, IntoEnumIterator)]
38#[repr(usize)]
39pub enum AuxVarType {
40    // ### architecture neutral
41    /// end of vector
42    Null = 0,
43    /// entry should be ignored
44    Ignore = 1,
45    /// file descriptor of program
46    ExecFd = 2,
47    /// program headers for program
48    Phdr = 3,
49    /// size of program header entry
50    Phent = 4,
51    /// number of program headers
52    Phnum = 5,
53    /// system page size
54    Pagesz = 6,
55    /// The base address of the program interpreter (usually, the
56    /// dynamic linker).
57    Base = 7,
58    /// Flags that apply on the whole auxiliary vector. See [`crate::AuxVarFlags`].
59    Flags = 8,
60    /// entry point of program
61    Entry = 9,
62    /// program is not ELF
63    NotElf = 10,
64    /// real uid
65    Uid = 11,
66    /// effective uid
67    EUid = 12,
68    /// real gid
69    Gid = 13,
70    /// effective gid
71    EGid = 14,
72    /// string identifying CPU for optimizations
73    Platform = 15,
74    /// Arch dependent hints at CPU capabilities.
75    /// On x86_64 these are the CPUID features.
76    HwCap = 16,
77    /// frequency at which times() increments
78    Clktck = 17,
79    /// secure mode boolean
80    Secure = 23,
81    /// string identifying real platform, may differ from AtPlatform.
82    BasePlatform = 24,
83    /// address of 16 random bytes
84    Random = 25,
85    /// extension of AtHwcap
86    HwCap2 = 26,
87    /// filename of program, for example "./my_executable\0"
88    ExecFn = 31,
89
90    // ### according to Linux code: from here: x86_64
91    /// The entry point to the system call function in the vDSO.
92    /// Not present/needed on all architectures (e.g., absent on
93    /// x86-64).
94    Sysinfo = 32,
95    /// The address of a page containing the virtual Dynamic
96    /// Shared Object (vDSO) that the kernel creates in order to
97    /// provide fast implementations of certain system calls.
98    SysinfoEhdr = 33,
99
100    // ### according to Linux code: from here: PowerPC
101    L1iCacheSize = 40,
102    L1iCacheGeometry = 41,
103    L1dCacheSize = 42,
104    L1dCacheGeometry = 43,
105    L2CacheSize = 44,
106    L2CacheGeometry = 45,
107    L3CacheSize = 46,
108    L3CacheGeometry = 47,
109
110    /// Minimal stack size for signal delivery.
111    MinSigStkSz = 51,
112}
113
114impl AuxVarType {
115    pub const fn val(self) -> usize {
116        self as _
117    }
118
119    /// If this is true, the value of the key should be interpreted as pointer into
120    /// the aux vector data area. Otherwise, the value of the key is an immediate value/integer.
121    // TODO move to AuxVar?!
122    pub const fn value_in_data_area(self) -> bool {
123        // this info can be found here:
124        // https://elixir.bootlin.com/linux/latest/source/fs/binfmt_elf.c#L259
125        match self {
126            AuxVarType::Null => false,
127            AuxVarType::Ignore => false,
128            AuxVarType::ExecFd => false,
129            AuxVarType::Phdr => false,
130            AuxVarType::Phent => false,
131            AuxVarType::Phnum => false,
132            AuxVarType::Pagesz => false,
133            AuxVarType::Base => false,
134            AuxVarType::Flags => false,
135            AuxVarType::Entry => false,
136            AuxVarType::NotElf => false,
137            AuxVarType::Uid => false,
138            AuxVarType::EUid => false,
139            AuxVarType::Gid => false,
140            AuxVarType::EGid => false,
141            // references C-str
142            AuxVarType::Platform => true,
143            AuxVarType::HwCap => false,
144            AuxVarType::Clktck => false,
145            AuxVarType::Secure => false,
146            // references C-str
147            AuxVarType::BasePlatform => true,
148            // references random bytes
149            AuxVarType::Random => true,
150            AuxVarType::HwCap2 => false,
151            // references C-str
152            AuxVarType::ExecFn => true,
153            AuxVarType::SysinfoEhdr => false,
154            AuxVarType::Sysinfo => false,
155            AuxVarType::L1iCacheSize => false,
156            AuxVarType::L1iCacheGeometry => false,
157            AuxVarType::L1dCacheSize => false,
158            AuxVarType::L1dCacheGeometry => false,
159            AuxVarType::L2CacheSize => false,
160            AuxVarType::L2CacheGeometry => false,
161            AuxVarType::L3CacheSize => false,
162            AuxVarType::L3CacheGeometry => false,
163            AuxVarType::MinSigStkSz => false,
164        }
165    }
166
167    /// Most of the auxiliary vector entries where [`Self::value_is_cstr`] is true,
168    /// represent a null-terminated C-string.
169    pub fn value_is_cstr(self) -> bool {
170        self.value_in_data_area()
171            && [Self::Platform, Self::BasePlatform, Self::ExecFn].contains(&self)
172    }
173
174    /// The payload of some [`AuxVarType`] is stored in the aux var data area. Some of these
175    /// data is null-terminated. Some has a fixed size. This helps to find out if there
176    /// is a fixed size.
177    pub const fn data_area_val_size_hint(self) -> Option<usize> {
178        match self {
179            AuxVarType::Random => Some(16),
180            _ => None,
181        }
182    }
183}
184
185impl From<usize> for AuxVarType {
186    fn from(val: usize) -> Self {
187        for variant in Self::into_enum_iter() {
188            if variant.val() == val {
189                return variant;
190            }
191        }
192        panic!("invalid variant {}", val);
193    }
194}
195
196impl PartialOrd for AuxVarType {
197    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
198        if matches!(self, Self::Null) && !matches!(other, Self::Null) {
199            Some(Ordering::Greater)
200        } else {
201            self.val().partial_cmp(&other.val())
202        }
203    }
204}
205
206impl Ord for AuxVarType {
207    fn cmp(&self, other: &Self) -> Ordering {
208        self.partial_cmp(other).unwrap()
209    }
210}
211
212#[cfg(test)]
213mod tests {
214    use super::*;
215    use std::collections::BTreeSet;
216
217    /// Tests that the ATNull entry always comes last in an ordered collection. This enables
218    /// us to easily write all AT-VARs at once but keep the terminating null entry at the end.
219    #[test]
220    fn test_aux_var_key_order() {
221        let mut set = BTreeSet::new();
222        set.insert(AuxVarType::ExecFn);
223        set.insert(AuxVarType::Platform);
224        set.insert(AuxVarType::Null);
225        set.insert(AuxVarType::Clktck);
226        set.insert(AuxVarType::ExecFn);
227        assert_eq!(set.into_iter().last().unwrap(), AuxVarType::Null);
228    }
229}