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>
impl<'a> InitialLinuxLibcStackLayout<'a>
Sourcepub fn argc(&self) -> usize
pub fn argc(&self) -> usize
Returns the number of arguments.
Examples found in repository?
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
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}Sourcepub unsafe fn argv_iter(&self) -> CstrIter<'_> ⓘ
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?
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}Sourcepub fn argv_ptr_iter(&self) -> NullTerminatedArrIter ⓘ
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?
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
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}Sourcepub unsafe fn envv_iter(&self) -> CstrIter<'_> ⓘ
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?
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}Sourcepub fn envv_ptr_iter(&self) -> NullTerminatedArrIter ⓘ
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?
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
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}Sourcepub unsafe fn aux_var_iter(&self) -> AuxVarIter<'_> ⓘ
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?
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}Sourcepub fn aux_serialized_iter(&self) -> AuxVarSerializedIter<'_> ⓘ
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?
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
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>
impl<'a> Debug for InitialLinuxLibcStackLayout<'a>
Source§impl<'a> From<&'a [u8]> for InitialLinuxLibcStackLayout<'a>
impl<'a> From<&'a [u8]> for InitialLinuxLibcStackLayout<'a>
Source§fn from(bytes: &'a [u8]) -> Self
fn from(bytes: &'a [u8]) -> Self
Creates a new InitialLinuxLibcStackLayout.