Struct InitialLinuxLibcStackLayoutBuilder

Source
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>

Source

pub fn new() -> Self

Creates a new InitialLinuxLibcStackLayoutBuilder. The AUX entries AuxVarType::Null and AuxVarType::ExecFn will be always present.

Examples found in repository?
examples/minimal.rs (line 28)
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 30)
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 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 least Self::total_size bytes 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?
examples/minimal.rs (line 47)
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 65)
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 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_str Terminating null byte is not mandatory, but null-bytes in-between will result in a panic.
Examples found in repository?
examples/minimal.rs (line 30)
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 32)
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 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_str Terminating null byte is not mandatory, but null-bytes in-between will result in a panic.
Examples found in repository?
examples/minimal.rs (line 32)
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 34)
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 add_aux_v(self, var: AuxVar<'a>) -> Self

Adds an aux entry.

§Parameters
  • var: See AuxVar. Make sure that the payload is correct, i.e. C-strings are null terminated.
Examples found in repository?
examples/minimal.rs (line 34)
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 36)
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 total_size(&self) -> usize

Returns the number in bytes the data structure will have including the final null byte.

Examples found in repository?
examples/minimal.rs (line 42)
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 58)
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}

Trait Implementations§

Source§

impl<'a> Debug for InitialLinuxLibcStackLayoutBuilder<'a>

Source§

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

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

impl<'a> Default for InitialLinuxLibcStackLayoutBuilder<'a>

Source§

fn default() -> InitialLinuxLibcStackLayoutBuilder<'a>

Returns the “default value” for a type. Read more

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.