build_and_parse/
build_and_parse.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 linux_libc_auxv::{
25    AuxVar, AuxVarFlags, InitialLinuxLibcStackLayout, InitialLinuxLibcStackLayoutBuilder,
26};
27
28/// Example that builds the initial linux libc stack layout and parses it again.
29fn main() {
30    let builder = InitialLinuxLibcStackLayoutBuilder::new()
31        // can contain terminating zero; not mandatory in the builder
32        .add_arg_v("./first_arg\0")
33        .add_arg_v("./second_arg")
34        .add_env_v("FOO=BAR\0")
35        .add_env_v("PATH=/bin")
36        .add_aux_v(AuxVar::Sysinfo(0x7ffd000 as *const _))
37        .add_aux_v(AuxVar::HwCap(0x1000))
38        .add_aux_v(AuxVar::Clktck(100))
39        .add_aux_v(AuxVar::Phdr(0x5627e17 as *const _))
40        .add_aux_v(AuxVar::Phent(56))
41        .add_aux_v(AuxVar::Phnum(13))
42        .add_aux_v(AuxVar::Base(0x7f51000 as *const _))
43        .add_aux_v(AuxVar::Flags(AuxVarFlags::empty()))
44        .add_aux_v(AuxVar::Entry(0x5627e17 as *const _))
45        .add_aux_v(AuxVar::Uid(1001))
46        .add_aux_v(AuxVar::EUid(1001))
47        .add_aux_v(AuxVar::Gid(1001))
48        .add_aux_v(AuxVar::EGid(1001))
49        .add_aux_v(AuxVar::Secure(false))
50        .add_aux_v(AuxVar::Random([
51            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
52        ]))
53        .add_aux_v(AuxVar::HwCap2(0x2))
54        .add_aux_v(AuxVar::ExecFn("/usr/bin/foo"))
55        .add_aux_v(AuxVar::Platform("x86_64"));
56
57    // memory where we serialize the data structure into
58    let mut buf = vec![0; builder.total_size()];
59
60    // User base addr is the initial stack pointer in the user address space.
61    // In this example: same as write address => enables us to parse the data structure
62    // let user_base_addr = buf.as_ptr() as u64;
63    let user_base_addr = 0x1000;
64    unsafe {
65        builder.serialize_into_buf(buf.as_mut_slice(), user_base_addr);
66    }
67
68    // So far, this is memory safe, as long as the slice is valid memory. No pointers are
69    // dereferenced yet.
70    let parsed = InitialLinuxLibcStackLayout::from(buf.as_slice());
71
72    println!("There are {} arguments.", parsed.argc());
73    println!(
74        "There are {} environment variables.",
75        parsed.envv_ptr_iter().count()
76    );
77    println!(
78        "There are {} auxiliary vector entries/AT variables.",
79        parsed.aux_serialized_iter().count()
80    );
81
82    println!("===== 1/2: only pointers");
83    parse_memory_safe(&parsed);
84
85    if user_base_addr == buf.as_ptr() as u64 {
86        println!("===== 2/2: dereferenced data");
87        // this will not work, if you change the "user_base_addr" above to another address
88        unsafe {
89            parse_memory_unsafe(&parsed);
90        }
91    }
92}
93
94fn parse_memory_safe(parsed: &InitialLinuxLibcStackLayout) {
95    println!("  argv");
96    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
97    for (i, arg) in parsed.argv_ptr_iter().enumerate() {
98        println!("    [{}] @ {:?}", i, arg);
99    }
100
101    println!("  envp");
102    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
103    for (i, env) in parsed.envv_ptr_iter().enumerate() {
104        println!("    [{}] @ {:?}", i, env);
105    }
106
107    println!("  aux");
108    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
109    for aux in parsed.aux_serialized_iter() {
110        println!("    {:?} => {:?}", aux.key(), aux.val() as *const u8);
111    }
112}
113
114// will segfault/page fault or read invalid memory, if user_ptr != write_ptr
115// (i.e. other address space)
116unsafe fn parse_memory_unsafe(parsed: &InitialLinuxLibcStackLayout) {
117    println!("  argv");
118    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
119    for (i, arg) in parsed.argv_iter().enumerate() {
120        println!("    [{}] {}", i, arg);
121    }
122
123    println!("  envp");
124    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
125    for (i, env) in parsed.envv_iter().enumerate() {
126        println!("    [{}] {}", i, env);
127    }
128
129    println!("  aux");
130    for aux in parsed.aux_var_iter() {
131        // currently: Only AT_RANDOM
132        if let Some(bytes) = aux.value_payload_bytes() {
133            println!(
134                "    {:>12?} => @ {:?}: {:?}",
135                aux.key(),
136                aux.value_raw() as *const u8,
137                bytes,
138            );
139        } else if let Some(cstr) = aux.value_payload_cstr() {
140            println!(
141                "    {:>12?} => @ {:?}: {:?}",
142                aux.key(),
143                aux.value_raw() as *const u8,
144                cstr,
145            );
146        } else if let Some(flags) = aux.value_flags() {
147            println!("    {:>12?} => {:?}", aux.key(), flags,);
148        } else if let Some(boolean) = aux.value_boolean() {
149            println!("    {:>12?} => {:?}", aux.key(), boolean,);
150        } else if let Some(ptr) = aux.value_ptr() {
151            println!("    {:>12?} => {:?}", aux.key(), ptr,);
152        } else {
153            println!("    {:>12?} => {}", aux.key(), aux.value_raw());
154        }
155    }
156}