Struct InitialLinuxLibcStackLayout

Source
pub struct InitialLinuxLibcStackLayout<'a> { /* private fields */ }
Expand description

Wrapper around a slice of data, that represents the data structure that Linux passes to the libc on program startup. Usually this is a struct from rsp (stack pointer) to x. It is no problem, if you pass for example a slice with 10000 bytes to it, because it will automatically stop, when the end of the data structure is found. Hence, if the data structure is valid, invalid memory (above the stack) will never be accessed.

It contains argc, argv, envv, and the auxiliary vector along with additional referenced payload. The data structure is right above the stack. The initial stack pointer points to argc. See https://lwn.net/Articles/631631/ for more info.

Instances are created via InitialLinuxLibcStackLayout::from::<[u8>].

Implementations§

Source§

impl<'a> InitialLinuxLibcStackLayout<'a>

Source

pub fn argc(&self) -> usize

Returns the number of arguments.

Examples found in repository?
examples/minimal.rs (line 54)
27fn main() {
28    let builder = InitialLinuxLibcStackLayoutBuilder::new()
29        // can contain terminating zero; not mandatory in the builder
30        .add_arg_v("./first_arg\0")
31        .add_arg_v("./second_arg")
32        .add_env_v("FOO=BAR\0")
33        .add_env_v("PATH=/bin")
34        .add_aux_v(AuxVar::Clktck(100))
35        .add_aux_v(AuxVar::Random([
36            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
37        ]))
38        .add_aux_v(AuxVar::ExecFn("/usr/bin/foo"))
39        .add_aux_v(AuxVar::Platform("x86_64"));
40
41    // memory where we serialize the data structure into
42    let mut buf = vec![0; builder.total_size()];
43
44    // assume user stack is at 0x7fff0000
45    let user_base_addr = 0x7fff0000;
46    unsafe {
47        builder.serialize_into_buf(buf.as_mut_slice(), user_base_addr);
48    }
49
50    // So far, this is memory safe, as long as the slice is valid memory. No pointers are
51    // dereferenced yet.
52    let parsed = InitialLinuxLibcStackLayout::from(buf.as_slice());
53
54    println!("There are {} arguments.", parsed.argc());
55    println!(
56        "There are {} environment variables.",
57        parsed.envv_ptr_iter().count()
58    );
59    println!(
60        "There are {} auxiliary vector entries/AT variables.",
61        parsed.aux_serialized_iter().count()
62    );
63
64    println!("  argv");
65    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
66    for (i, arg) in parsed.argv_ptr_iter().enumerate() {
67        println!("    [{}] @ {:?}", i, arg);
68    }
69
70    println!("  envp");
71    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
72    for (i, env) in parsed.envv_ptr_iter().enumerate() {
73        println!("    [{}] @ {:?}", i, env);
74    }
75
76    println!("  aux");
77    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
78    for aux in parsed.aux_serialized_iter() {
79        if aux.key().value_in_data_area() {
80            println!("    {:?} => @ {:?}", aux.key(), aux.val() as *const u8);
81        } else {
82            println!("    {:?} => {:?}", aux.key(), aux.val() as *const u8);
83        }
84    }
85}
More examples
Hide additional examples
examples/build_and_parse.rs (line 72)
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}
Source

pub fn envc(&self) -> usize

Returns the number of environment variables.

Source

pub unsafe fn argv_iter(&self) -> CstrIter<'_>

Iterates over the C-string arguments. See CstrIter. This is unsafe, because it will result in segfaults/page faults or invalid memory being read, if the pointers are not valid in the address space of the caller.

§Safety

This function produces UB (page fault, seg fault, read invalid memory), if the referenced pointers are not valid inside the address space of the caller.

Examples found in repository?
examples/build_and_parse.rs (line 119)
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}
Source

pub fn argv_ptr_iter(&self) -> NullTerminatedArrIter

Iterates only over the pointers of the C-string arguments. See NullTerminatedArrIter. This is always memory-safe even if the pointers are created for another address space, because no pointers are dereference by this iterator.

Examples found in repository?
examples/build_and_parse.rs (line 97)
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}
More examples
Hide additional examples
examples/minimal.rs (line 66)
27fn main() {
28    let builder = InitialLinuxLibcStackLayoutBuilder::new()
29        // can contain terminating zero; not mandatory in the builder
30        .add_arg_v("./first_arg\0")
31        .add_arg_v("./second_arg")
32        .add_env_v("FOO=BAR\0")
33        .add_env_v("PATH=/bin")
34        .add_aux_v(AuxVar::Clktck(100))
35        .add_aux_v(AuxVar::Random([
36            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
37        ]))
38        .add_aux_v(AuxVar::ExecFn("/usr/bin/foo"))
39        .add_aux_v(AuxVar::Platform("x86_64"));
40
41    // memory where we serialize the data structure into
42    let mut buf = vec![0; builder.total_size()];
43
44    // assume user stack is at 0x7fff0000
45    let user_base_addr = 0x7fff0000;
46    unsafe {
47        builder.serialize_into_buf(buf.as_mut_slice(), user_base_addr);
48    }
49
50    // So far, this is memory safe, as long as the slice is valid memory. No pointers are
51    // dereferenced yet.
52    let parsed = InitialLinuxLibcStackLayout::from(buf.as_slice());
53
54    println!("There are {} arguments.", parsed.argc());
55    println!(
56        "There are {} environment variables.",
57        parsed.envv_ptr_iter().count()
58    );
59    println!(
60        "There are {} auxiliary vector entries/AT variables.",
61        parsed.aux_serialized_iter().count()
62    );
63
64    println!("  argv");
65    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
66    for (i, arg) in parsed.argv_ptr_iter().enumerate() {
67        println!("    [{}] @ {:?}", i, arg);
68    }
69
70    println!("  envp");
71    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
72    for (i, env) in parsed.envv_ptr_iter().enumerate() {
73        println!("    [{}] @ {:?}", i, env);
74    }
75
76    println!("  aux");
77    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
78    for aux in parsed.aux_serialized_iter() {
79        if aux.key().value_in_data_area() {
80            println!("    {:?} => @ {:?}", aux.key(), aux.val() as *const u8);
81        } else {
82            println!("    {:?} => {:?}", aux.key(), aux.val() as *const u8);
83        }
84    }
85}
Source

pub unsafe fn envv_iter(&self) -> CstrIter<'_>

Iterates over all environment variables. See CstrIter. This is unsafe, because it will result in segfaults/page faults or invalid memory being read, if the pointers are not valid in the address space of the caller.

§Safety

This function produces UB (page fault, seg fault, read invalid memory), if the referenced pointers are not valid inside the address space of the caller.

Examples found in repository?
examples/build_and_parse.rs (line 125)
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}
Source

pub fn envv_ptr_iter(&self) -> NullTerminatedArrIter

Iterates only over the pointers to the environment variables. See NullTerminatedArrIter. This is always memory-safe even if the pointers are created for another address space, because no pointers are dereference by this iterator.

Examples found in repository?
examples/minimal.rs (line 57)
27fn main() {
28    let builder = InitialLinuxLibcStackLayoutBuilder::new()
29        // can contain terminating zero; not mandatory in the builder
30        .add_arg_v("./first_arg\0")
31        .add_arg_v("./second_arg")
32        .add_env_v("FOO=BAR\0")
33        .add_env_v("PATH=/bin")
34        .add_aux_v(AuxVar::Clktck(100))
35        .add_aux_v(AuxVar::Random([
36            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
37        ]))
38        .add_aux_v(AuxVar::ExecFn("/usr/bin/foo"))
39        .add_aux_v(AuxVar::Platform("x86_64"));
40
41    // memory where we serialize the data structure into
42    let mut buf = vec![0; builder.total_size()];
43
44    // assume user stack is at 0x7fff0000
45    let user_base_addr = 0x7fff0000;
46    unsafe {
47        builder.serialize_into_buf(buf.as_mut_slice(), user_base_addr);
48    }
49
50    // So far, this is memory safe, as long as the slice is valid memory. No pointers are
51    // dereferenced yet.
52    let parsed = InitialLinuxLibcStackLayout::from(buf.as_slice());
53
54    println!("There are {} arguments.", parsed.argc());
55    println!(
56        "There are {} environment variables.",
57        parsed.envv_ptr_iter().count()
58    );
59    println!(
60        "There are {} auxiliary vector entries/AT variables.",
61        parsed.aux_serialized_iter().count()
62    );
63
64    println!("  argv");
65    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
66    for (i, arg) in parsed.argv_ptr_iter().enumerate() {
67        println!("    [{}] @ {:?}", i, arg);
68    }
69
70    println!("  envp");
71    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
72    for (i, env) in parsed.envv_ptr_iter().enumerate() {
73        println!("    [{}] @ {:?}", i, env);
74    }
75
76    println!("  aux");
77    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
78    for aux in parsed.aux_serialized_iter() {
79        if aux.key().value_in_data_area() {
80            println!("    {:?} => @ {:?}", aux.key(), aux.val() as *const u8);
81        } else {
82            println!("    {:?} => {:?}", aux.key(), aux.val() as *const u8);
83        }
84    }
85}
More examples
Hide additional examples
examples/build_and_parse.rs (line 75)
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}
Source

pub unsafe fn aux_var_iter(&self) -> AuxVarIter<'_>

Iterates over all entries in the auxiliary vector. See AuxVarIter. This is unsafe, because it will result in segfaults/page faults or invalid memory being read, if the pointers are not valid in the address space of the caller.

§Safety

This function produces UB (page fault, seg fault, read invalid memory), if the referenced pointers are not valid inside the address space of the caller.

Examples found in repository?
examples/build_and_parse.rs (line 130)
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}
Source

pub fn aux_serialized_iter(&self) -> AuxVarSerializedIter<'_>

Iterates over all entries in the auxiliary vector. See AuxVarSerializedIter. This is always memory-safe even if the pointers are created for another address space, because no pointers are dereference by this iterator.

Examples found in repository?
examples/minimal.rs (line 61)
27fn main() {
28    let builder = InitialLinuxLibcStackLayoutBuilder::new()
29        // can contain terminating zero; not mandatory in the builder
30        .add_arg_v("./first_arg\0")
31        .add_arg_v("./second_arg")
32        .add_env_v("FOO=BAR\0")
33        .add_env_v("PATH=/bin")
34        .add_aux_v(AuxVar::Clktck(100))
35        .add_aux_v(AuxVar::Random([
36            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
37        ]))
38        .add_aux_v(AuxVar::ExecFn("/usr/bin/foo"))
39        .add_aux_v(AuxVar::Platform("x86_64"));
40
41    // memory where we serialize the data structure into
42    let mut buf = vec![0; builder.total_size()];
43
44    // assume user stack is at 0x7fff0000
45    let user_base_addr = 0x7fff0000;
46    unsafe {
47        builder.serialize_into_buf(buf.as_mut_slice(), user_base_addr);
48    }
49
50    // So far, this is memory safe, as long as the slice is valid memory. No pointers are
51    // dereferenced yet.
52    let parsed = InitialLinuxLibcStackLayout::from(buf.as_slice());
53
54    println!("There are {} arguments.", parsed.argc());
55    println!(
56        "There are {} environment variables.",
57        parsed.envv_ptr_iter().count()
58    );
59    println!(
60        "There are {} auxiliary vector entries/AT variables.",
61        parsed.aux_serialized_iter().count()
62    );
63
64    println!("  argv");
65    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
66    for (i, arg) in parsed.argv_ptr_iter().enumerate() {
67        println!("    [{}] @ {:?}", i, arg);
68    }
69
70    println!("  envp");
71    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
72    for (i, env) in parsed.envv_ptr_iter().enumerate() {
73        println!("    [{}] @ {:?}", i, env);
74    }
75
76    println!("  aux");
77    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
78    for aux in parsed.aux_serialized_iter() {
79        if aux.key().value_in_data_area() {
80            println!("    {:?} => @ {:?}", aux.key(), aux.val() as *const u8);
81        } else {
82            println!("    {:?} => {:?}", aux.key(), aux.val() as *const u8);
83        }
84    }
85}
More examples
Hide additional examples
examples/build_and_parse.rs (line 79)
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}

Trait Implementations§

Source§

impl<'a> Debug for InitialLinuxLibcStackLayout<'a>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'a> From<&'a [u8]> for InitialLinuxLibcStackLayout<'a>

Source§

fn from(bytes: &'a [u8]) -> Self

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.