linux_libc_auxv/aux_var/
mod.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*/
24
25mod serialized;
26mod typ;
27
28use crate::cstr_util::{c_str_len_ptr, c_str_null_terminated};
29use core::cmp::Ordering;
30use core::fmt::Debug;
31pub(crate) use serialized::*;
32pub use typ::*;
33
34bitflags::bitflags! {
35    /// Flags for the auxiliary vector. See <https://elixir.bootlin.com/linux/v5.15.5/source/include/uapi/linux/binfmts.h#L23>.
36    pub struct AuxVarFlags: usize {
37        /// Opposite of [`Self::PRESERVE_ARGV0`].
38        const NOT_PRESERVE_ARGV0 = 0;
39        /// Preserve argv0 for the interpreter.
40        const PRESERVE_ARGV0 = 1;
41    }
42}
43
44/// High-level version of the serialized form of an auxiliary vector entry. It is used to construct
45/// the auxiliary vector in [`crate::InitialLinuxLibcStackLayoutBuilder`] and returned when
46/// a data structure is parsed with [`crate::InitialLinuxLibcStackLayout`].
47#[derive(Debug)]
48pub enum AuxVar<'a> {
49    /// Entry with payload for type [`AuxVarType::Null`].
50    Null,
51    /// Entry with payload for type [`AuxVarType::Ignore`].
52    Ignore(usize),
53    /// Entry with payload for type [`AuxVarType::ExecFd`].
54    ExecFd(usize),
55    /// Entry with payload for type [`AuxVarType::Phdr`].
56    Phdr(*const u8),
57    /// Entry with payload for type [`AuxVarType::Phent`].
58    Phent(usize),
59    /// Entry with payload for type [`AuxVarType::Phnum`].
60    Phnum(usize),
61    /// Entry with payload for type [`AuxVarType::Pagesz`].
62    Pagesz(usize),
63    /// Entry with payload for type [`AuxVarType::Base`].
64    Base(*const u8),
65    /// Entry with payload for type [`AuxVarType::Flags`].
66    Flags(AuxVarFlags),
67    /// Entry with payload for type [`AuxVarType::Entry`].
68    Entry(*const u8),
69    /// Entry with payload for type [`AuxVarType::NotElf`].
70    NotElf(bool),
71    /// Entry with payload for type [`AuxVarType::Uid`].
72    Uid(usize),
73    /// Entry with payload for type [`AuxVarType::EUid`].
74    EUid(usize),
75    /// Entry with payload for type [`AuxVarType::Gid`].
76    Gid(usize),
77    /// Entry with payload for type [`AuxVarType::EGid`].
78    EGid(usize),
79    /// Entry with payload for type [`AuxVarType::Platform`].
80    Platform(&'a str),
81    /// Entry with payload for type [`AuxVarType::HwCap`].
82    HwCap(usize),
83    /// Entry with payload for type [`AuxVarType::Clktck`].
84    Clktck(usize),
85    /// Entry with payload for type [`AuxVarType::Secure`].
86    Secure(bool),
87    /// Entry with payload for type [`AuxVarType::BasePlatform`].
88    BasePlatform(&'a str),
89    /// Entry with payload for type [`AuxVarType::Random`].
90    /// This data owns the bytes rather than referencing to it,
91    /// because the operation is cheap anyway but it also simplified
92    /// parsing. Otherwise, I had to create a `&'a [u8; 16]` from a
93    /// `&'a [u8]`, which is hard without hacky tricks.
94    Random([u8; 16]),
95    /// Entry with payload for type [`AuxVarType::HwCap2`].
96    HwCap2(usize),
97    /// Entry with payload for type [`AuxVarType::ExecFn`].
98    ExecFn(&'a str),
99    /// Entry with payload for type [`AuxVarType::Sysinfo`].
100    Sysinfo(*const u8),
101    /// Entry with payload for type [`AuxVarType::SysinfoEhdr`].
102    SysinfoEhdr(*const u8),
103    /// Entry with payload for type [`AuxVarType::L1iCacheSize`].
104    L1iCacheSize(usize),
105    /// Entry with payload for type [`AuxVarType::L1iCacheGeometry`].
106    L1iCacheGeometry(usize),
107    /// Entry with payload for type [`AuxVarType::L1dCacheSize`].
108    L1dCacheSize(usize),
109    /// Entry with payload for type [`AuxVarType::L1dCacheGeometry`].
110    L1dCacheGeometry(usize),
111    /// Entry with payload for type [`AuxVarType::L2CacheSize`].
112    L2CacheSize(usize),
113    /// Entry with payload for type [`AuxVarType::L2CacheGeometry`].
114    L2CacheGeometry(usize),
115    /// Entry with payload for type [`AuxVarType::L3CacheSize`].
116    L3CacheSize(usize),
117    /// Entry with payload for type [`AuxVarType::L3CacheGeometry`].
118    L3CacheGeometry(usize),
119    /// Entry with payload for type [`AuxVarType::MinSigStkSz`].
120    MinSigStkSz(usize),
121}
122
123impl<'a> AuxVar<'a> {
124    /// Creates the high-level type [`AuxVar`] from the serialized version of an
125    /// AT variable/aux vec entry.
126    ///
127    /// # Safety
128    /// This function creates undefined behaviour or might even crash, if the AT value
129    /// reference data in the aux vec data area, where the pointer is either invalid or
130    /// if the C-strings is not null-terminated.
131    pub(crate) unsafe fn from_serialized(serialized: &AuxVarSerialized) -> Self {
132        if serialized.key().value_in_data_area() {
133            let data_ptr = serialized.val() as *const u8;
134            let len = serialized
135                .key()
136                .data_area_val_size_hint()
137                .unwrap_or_else(|| c_str_len_ptr(data_ptr));
138            let slice = core::slice::from_raw_parts(data_ptr, len);
139            if serialized.key().value_is_cstr() {
140                let cstr = core::str::from_utf8(slice).expect(
141                    "must be valid c string. Either invalid memory or not null-terminated!",
142                );
143                match serialized.key() {
144                    AuxVarType::Platform => Self::Platform(cstr),
145                    AuxVarType::BasePlatform => Self::BasePlatform(cstr),
146                    AuxVarType::ExecFn => Self::ExecFn(cstr),
147                    _ => panic!("invalid variant"),
148                }
149            } else {
150                match serialized.key() {
151                    AuxVarType::Random => {
152                        let mut random_bytes = [0; 16];
153                        // memcpy into new, fixed length slice
154                        random_bytes.copy_from_slice(slice);
155                        Self::Random(random_bytes)
156                    }
157                    _ => panic!("invalid variant"),
158                }
159            }
160        } else {
161            match serialized.key() {
162                AuxVarType::Null => Self::Null,
163                AuxVarType::Ignore => Self::Ignore(serialized.val()),
164                AuxVarType::ExecFd => Self::ExecFd(serialized.val()),
165                AuxVarType::Phdr => Self::Phdr(serialized.val() as _),
166                AuxVarType::Phent => Self::Phent(serialized.val()),
167                AuxVarType::Phnum => Self::Phnum(serialized.val()),
168                AuxVarType::Pagesz => Self::Pagesz(serialized.val()),
169                AuxVarType::Base => Self::Base(serialized.val() as _),
170                AuxVarType::Flags => Self::Flags(AuxVarFlags::from_bits(serialized.val()).unwrap()),
171                AuxVarType::Entry => Self::Entry(serialized.val() as _),
172                AuxVarType::NotElf => Self::NotElf(serialized.val() != 0),
173                AuxVarType::Uid => Self::Uid(serialized.val()),
174                AuxVarType::EUid => Self::EUid(serialized.val()),
175                AuxVarType::Gid => Self::Gid(serialized.val()),
176                AuxVarType::EGid => Self::EGid(serialized.val()),
177                AuxVarType::HwCap => Self::HwCap(serialized.val()),
178                AuxVarType::Clktck => Self::Clktck(serialized.val()),
179                AuxVarType::Secure => Self::Secure(serialized.val() != 0),
180                AuxVarType::HwCap2 => Self::HwCap2(serialized.val()),
181                AuxVarType::Sysinfo => Self::Sysinfo(serialized.val() as _),
182                AuxVarType::SysinfoEhdr => Self::SysinfoEhdr(serialized.val() as _),
183                AuxVarType::L1iCacheSize => Self::L1iCacheSize(serialized.val()),
184                AuxVarType::L1iCacheGeometry => Self::L1iCacheGeometry(serialized.val()),
185                AuxVarType::L1dCacheSize => Self::L1dCacheSize(serialized.val()),
186                AuxVarType::L1dCacheGeometry => Self::L1dCacheGeometry(serialized.val()),
187                AuxVarType::L2CacheSize => Self::L2CacheSize(serialized.val()),
188                AuxVarType::L2CacheGeometry => Self::L2CacheGeometry(serialized.val()),
189                AuxVarType::L3CacheSize => Self::L3CacheSize(serialized.val()),
190                AuxVarType::L3CacheGeometry => Self::L3CacheGeometry(serialized.val()),
191                AuxVarType::MinSigStkSz => Self::MinSigStkSz(serialized.val()),
192                _ => panic!("invalid variant"),
193            }
194        }
195    }
196
197    /// Returns the [`AuxVarType`] this aux var corresponds to.
198    pub const fn key(&self) -> AuxVarType {
199        match self {
200            AuxVar::Null => AuxVarType::Null,
201            AuxVar::Ignore(_) => AuxVarType::Ignore,
202            AuxVar::ExecFd(_) => AuxVarType::ExecFd,
203            AuxVar::Phdr(_) => AuxVarType::Phdr,
204            AuxVar::Phent(_) => AuxVarType::Phent,
205            AuxVar::Phnum(_) => AuxVarType::Phnum,
206            AuxVar::Pagesz(_) => AuxVarType::Pagesz,
207            AuxVar::Base(_) => AuxVarType::Base,
208            AuxVar::Flags(_) => AuxVarType::Flags,
209            AuxVar::Entry(_) => AuxVarType::Entry,
210            AuxVar::NotElf(_) => AuxVarType::NotElf,
211            AuxVar::Uid(_) => AuxVarType::Uid,
212            AuxVar::EUid(_) => AuxVarType::EUid,
213            AuxVar::Gid(_) => AuxVarType::Gid,
214            AuxVar::EGid(_) => AuxVarType::EGid,
215            AuxVar::Platform(_) => AuxVarType::Platform,
216            AuxVar::HwCap(_) => AuxVarType::HwCap,
217            AuxVar::Clktck(_) => AuxVarType::Clktck,
218            AuxVar::Secure(_) => AuxVarType::Secure,
219            AuxVar::BasePlatform(_) => AuxVarType::BasePlatform,
220            AuxVar::Random(_) => AuxVarType::Random,
221            AuxVar::HwCap2(_) => AuxVarType::HwCap2,
222            AuxVar::ExecFn(_) => AuxVarType::ExecFn,
223            AuxVar::Sysinfo(_) => AuxVarType::Sysinfo,
224            AuxVar::SysinfoEhdr(_) => AuxVarType::SysinfoEhdr,
225            AuxVar::L1iCacheSize(_) => AuxVarType::L1iCacheSize,
226            AuxVar::L1iCacheGeometry(_) => AuxVarType::L1iCacheGeometry,
227            AuxVar::L1dCacheSize(_) => AuxVarType::L1dCacheSize,
228            AuxVar::L1dCacheGeometry(_) => AuxVarType::L1dCacheGeometry,
229            AuxVar::L2CacheSize(_) => AuxVarType::L2CacheSize,
230            AuxVar::L2CacheGeometry(_) => AuxVarType::L2CacheGeometry,
231            AuxVar::L3CacheSize(_) => AuxVarType::L3CacheSize,
232            AuxVar::L3CacheGeometry(_) => AuxVarType::L3CacheGeometry,
233            AuxVar::MinSigStkSz(_) => AuxVarType::MinSigStkSz,
234        }
235    }
236
237    /// Transforms any inner value into it's corresponding usize value.
238    /// This is similar to the data that is serialized in the data structure on the stack,
239    /// i.e. the value of the auxiliary vector entry.
240    pub fn value_raw(&self) -> usize {
241        match self {
242            AuxVar::Null => 0,
243            AuxVar::Ignore(val) => *val,
244            AuxVar::ExecFd(val) => *val,
245            AuxVar::Phdr(val) => *val as _,
246            AuxVar::Phent(val) => *val,
247            AuxVar::Phnum(val) => *val,
248            AuxVar::Pagesz(val) => *val,
249            AuxVar::Base(val) => *val as _,
250            AuxVar::Flags(val) => val.bits(),
251            AuxVar::Entry(val) => *val as _,
252            AuxVar::NotElf(val) => {
253                if *val {
254                    1
255                } else {
256                    0
257                }
258            }
259            AuxVar::Uid(val) => *val,
260            AuxVar::EUid(val) => *val,
261            AuxVar::Gid(val) => *val,
262            AuxVar::EGid(val) => *val,
263            AuxVar::Platform(val) => val.as_ptr() as _,
264            AuxVar::HwCap(val) => *val,
265            AuxVar::Clktck(val) => *val,
266            AuxVar::Secure(val) => {
267                if *val {
268                    1
269                } else {
270                    0
271                }
272            }
273            AuxVar::BasePlatform(val) => val.as_ptr() as _,
274            AuxVar::Random(val) => val.as_ptr() as _,
275            AuxVar::HwCap2(val) => *val,
276            AuxVar::ExecFn(val) => val.as_ptr() as _,
277            AuxVar::Sysinfo(val) => *val as _,
278            AuxVar::SysinfoEhdr(val) => *val as _,
279            AuxVar::L1iCacheSize(val) => *val,
280            AuxVar::L1iCacheGeometry(val) => *val,
281            AuxVar::L1dCacheSize(val) => *val,
282            AuxVar::L1dCacheGeometry(val) => *val,
283            AuxVar::L2CacheSize(val) => *val,
284            AuxVar::L2CacheGeometry(val) => *val,
285            AuxVar::L3CacheSize(val) => *val,
286            AuxVar::L3CacheGeometry(val) => *val,
287            AuxVar::MinSigStkSz(val) => *val,
288        }
289    }
290
291    /// Returns a value, if the corresponding auxiliary vector entry corresponds to a basic
292    /// value/integer, and not a pointer, flags, or a boolean.
293    pub const fn value_integer(&self) -> Option<usize> {
294        match self {
295            AuxVar::Ignore(val) => Some(*val),
296            AuxVar::ExecFd(val) => Some(*val),
297            AuxVar::Phent(val) => Some(*val),
298            AuxVar::Phnum(val) => Some(*val),
299            AuxVar::Pagesz(val) => Some(*val),
300            AuxVar::Uid(val) => Some(*val),
301            AuxVar::EUid(val) => Some(*val),
302            AuxVar::Gid(val) => Some(*val),
303            AuxVar::EGid(val) => Some(*val),
304            AuxVar::HwCap(val) => Some(*val),
305            AuxVar::Clktck(val) => Some(*val),
306            AuxVar::HwCap2(val) => Some(*val),
307            AuxVar::L1iCacheSize(val) => Some(*val),
308            AuxVar::L1iCacheGeometry(val) => Some(*val),
309            AuxVar::L1dCacheSize(val) => Some(*val),
310            AuxVar::L1dCacheGeometry(val) => Some(*val),
311            AuxVar::L2CacheSize(val) => Some(*val),
312            AuxVar::L2CacheGeometry(val) => Some(*val),
313            AuxVar::L3CacheSize(val) => Some(*val),
314            AuxVar::L3CacheGeometry(val) => Some(*val),
315            AuxVar::MinSigStkSz(val) => Some(*val),
316            _ => None,
317        }
318    }
319
320    /// Returns a value, if the corresponding auxiliary vector entry is of type [`AuxVarType::Flags`].
321    pub const fn value_flags(&self) -> Option<AuxVarFlags> {
322        match self {
323            AuxVar::Flags(flags) => Some(*flags),
324            _ => None,
325        }
326    }
327
328    /// Returns a value, if the corresponding auxiliary vector entry corresponds to a
329    /// boolean, and not a pointer, flags, or a basic value/integer.
330    pub const fn value_boolean(&self) -> Option<bool> {
331        match self {
332            AuxVar::NotElf(val) => Some(*val),
333            AuxVar::Secure(val) => Some(*val),
334            _ => None,
335        }
336    }
337
338    /// Returns a value, if the corresponding auxiliary vector entry corresponds to a
339    /// pointer, and not a boolean, flags, or a basic value/integer. This only affects
340    /// entries, that point to memory outside of the initial stack layout, i.e. the aux
341    /// vector data area.
342    pub const fn value_ptr(&self) -> Option<*const u8> {
343        match self {
344            AuxVar::Phdr(val) => Some(*val),
345            AuxVar::Base(val) => Some(*val),
346            AuxVar::Entry(val) => Some(*val),
347            AuxVar::Sysinfo(val) => Some(*val),
348            AuxVar::SysinfoEhdr(val) => Some(*val),
349            _ => None,
350        }
351    }
352
353    /// Returns a value, if the corresponding auxiliary vector entry references data in the
354    /// auxiliary vector data area of the data structure.
355    /// This returns only something for [`AuxVarType::Random`].
356    ///
357    /// This function is safe, because the creation during parsing already guarantee memory
358    /// safety (the addresses are accessed).
359    pub fn value_payload_bytes(&'a self) -> Option<&'a [u8]> {
360        match self {
361            AuxVar::Random(bytes) => Some(&bytes[..]),
362            _ => None,
363        }
364    }
365
366    /// Returns a value, if the corresponding auxiliary vector entry references data in the
367    /// auxiliary vector data area of the data structure.
368    /// This returns only something for [`AuxVarType::Random`].
369    ///
370    /// This function is safe, because the creation during parsing already guarantee memory
371    /// safety (the addresses are accessed).
372    pub const fn value_payload_cstr(&'a self) -> Option<&'a str> {
373        match self {
374            AuxVar::Platform(val) => Some(*val),
375            AuxVar::BasePlatform(val) => Some(*val),
376            AuxVar::ExecFn(val) => Some(*val),
377            _ => None,
378        }
379    }
380
381    // #########################
382    // helper methods to validate the object in the builder
383
384    /// Returns the total number of bytes that needs to be written into the aux vec
385    /// data area. This includes the null byte for c strings.
386    /// Function is used as helper in tests.
387    pub(crate) fn data_area_serialize_byte_count(&self) -> usize {
388        let mut bytes = 0;
389        bytes += self.value_payload_bytes().map(|x| x.len()).unwrap_or(0);
390        bytes += self.value_payload_cstr().map(|x| x.len()).unwrap_or(0);
391        if self.value_payload_cstr().is_some()
392            && !c_str_null_terminated(self.value_payload_cstr().unwrap().as_bytes())
393        {
394            bytes + 1
395        } else {
396            bytes
397        }
398    }
399}
400
401impl<'a> PartialEq for AuxVar<'a> {
402    fn eq(&self, other: &Self) -> bool {
403        self.key() == other.key()
404    }
405}
406
407impl<'a> PartialOrd for AuxVar<'a> {
408    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
409        self.key().partial_cmp(&other.key())
410    }
411}
412
413impl<'a> Eq for AuxVar<'a> {}
414
415impl<'a> Ord for AuxVar<'a> {
416    fn cmp(&self, other: &Self) -> Ordering {
417        self.partial_cmp(other).unwrap()
418    }
419}
420
421#[cfg(test)]
422mod tests {
423    use super::*;
424    use std::collections::BTreeSet;
425
426    /// Tests that the ATNull entry always comes last in an ordered collection. This enables
427    /// us to easily write all AT-VARs at once but keep the terminating null entry at the end.
428    #[test]
429    fn test_aux_var_order() {
430        let mut set = BTreeSet::new();
431        set.insert(AuxVar::ExecFn("./executable"));
432        set.insert(AuxVar::Platform("x86_64"));
433        set.insert(AuxVar::Null);
434        set.insert(AuxVar::Clktck(0x1337));
435        set.insert(AuxVar::ExecFn("./executable"));
436        assert_eq!(set.iter().last().unwrap().key(), AuxVarType::Null);
437    }
438
439    #[test]
440    fn test_data_area_serialize_byte_count() {
441        assert_eq!(
442            AuxVar::ExecFn("./executable").data_area_serialize_byte_count(),
443            13
444        );
445        assert_eq!(
446            AuxVar::ExecFn("./executable\0").data_area_serialize_byte_count(),
447            13
448        );
449        assert_eq!(
450            AuxVar::Platform("x86_64").data_area_serialize_byte_count(),
451            7
452        );
453        assert_eq!(
454            AuxVar::Platform("x86_64\0").data_area_serialize_byte_count(),
455            7
456        );
457        assert_eq!(AuxVar::Random([0; 16]).data_area_serialize_byte_count(), 16);
458    }
459}