pub struct InitialLinuxLibcStackLayoutBuilder<'a> { /* private fields */ }Expand description
Builder to construct the stack layout that a libc implementation under Linux initially
expects. See https://lwn.net/Articles/631631/ for more info. It helps to write the
arguments, the environment variables, and the auxiliary vector at a given address.
It will translate addresses (pointers) to user addresses. Serialization is done
with InitialLinuxLibcStackLayoutBuilder::serialize_into_buf.
Implementations§
Source§impl<'a> InitialLinuxLibcStackLayoutBuilder<'a>
impl<'a> InitialLinuxLibcStackLayoutBuilder<'a>
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new InitialLinuxLibcStackLayoutBuilder. The AUX entries AuxVarType::Null
and AuxVarType::ExecFn will be always present.
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 serialize_into_buf(&self, write_buf: &mut [u8], user_ptr: u64)
pub unsafe fn serialize_into_buf(&self, write_buf: &mut [u8], user_ptr: u64)
Serializes the data structure into the provided buffer.
§Parameters
write_buf: Destination buffer that must be at leastSelf::total_sizebytes long.user_ptr: Stack pointer in user address space. Important, so that all pointers are valid and can be dereferenced by libc (or the entity that parses the structure).
§Safety
This function is safe, as long as write_buf points to valid memory.
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 fn add_arg_v(self, c_str: &'a str) -> Self
pub fn add_arg_v(self, c_str: &'a str) -> Self
Adds an argument. An argument in the final Linux stack layout is a null-terminated C-string.
§Parameters
c_strTerminating null byte is not mandatory, but null-bytes in-between will result in a panic.
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 fn add_env_v(self, c_str: &'a str) -> Self
pub fn add_env_v(self, c_str: &'a str) -> Self
Adds an environmental variable. An envv in the final Linux stack layout is a null-terminated
C-string with a format of KEY=VALUE\0.
§Parameters
c_strTerminating null byte is not mandatory, but null-bytes in-between will result in a panic.
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 fn add_aux_v(self, var: AuxVar<'a>) -> Self
pub fn add_aux_v(self, var: AuxVar<'a>) -> Self
Adds an aux entry.
§Parameters
var: SeeAuxVar. Make sure that the payload is correct, i.e. C-strings are null terminated.
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 fn total_size(&self) -> usize
pub fn total_size(&self) -> usize
Returns the number in bytes the data structure will have including the final null byte.
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}