Struct StackLayoutRef

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

Wraps a slice of bytes representing a Linux stack layout allowing to conveniently parse its content.

The stack layout under Linux contains argc, argv, envv/envp, and the auxiliary vector, all with the additional referenced payloads. More precisely, the structure contains data in the following order:

  • argc: Amount of arguments
  • argv: null-terminated array of pointers into argv data area
  • NULL pointer
  • envv: null-terminated array of pointers into envv data area
  • NULL pointer
  • auxv Array of auxiliary variables (AT variables), terminated by an AuxVarType::Null entry.
  • NUL[s] for padding
  • auxv data area: Possibly payload of auxiliary variables
  • argv data area: Null-terminated C strings representing the arguments
  • envv data area: Null-terminated C strings representing the environment
  • NUL[s] for padding

The parsing code will determine at runtime how long the data actually is, therefore, it is recommended to pass in a slice that is long enough to hold the stack layout. For example, passing in a 1 MiB slice is perfectly fine.

§Safety

Each function that loads data from one of the

§More Info

Implementations§

Source§

impl<'a> StackLayoutRef<'a>

Source

pub fn new(bytes: &'a [u8], argc: Option<usize>) -> Self

Creates a new view into the stack layout.

The argc determines whether bytes start with the argc argument (=> None) or if bytes already point to the start of argv.

Examples found in repository?
examples/minimal_builder.rs (line 36)
27fn main() {
28    let builder = StackLayoutBuilder::new()
29        // can contain terminating zero; not mandatory in the builder
30        .add_argv("foo")
31        .add_argv("hello")
32        .add_envv("PATH=/bin")
33        .add_auxv(AuxVar::ExecFn("/usr/bin/foo".into()));
34
35    let layout = builder.build(None /* we create the layout in our address space */);
36    let layout = StackLayoutRef::new(layout.as_ref(), None);
37
38    // SAFETY: This is safe as all pointers point into our address space.
39    for (i, arg) in unsafe { layout.argv_iter() }.enumerate() {
40        println!("  [{i}] {}", arg.to_str().unwrap());
41    }
42}
More examples
Hide additional examples
examples/linux_print_layout.rs (line 38)
31fn main(argc: isize, argv: *const *const u8) -> isize {
32    let buffer = unsafe {
33        // 100 KiB, reasonably big.
34        // On my Linux machine, the structure needs 23 KiB
35        slice::from_raw_parts(argv.cast::<u8>(), 0x19000)
36    };
37
38    let parsed = StackLayoutRef::new(buffer, Some(argc as usize));
39
40    println!("There are {} arguments.", parsed.argc());
41    println!("  argv (raw)");
42    for (i, arg) in parsed.argv_raw_iter().enumerate() {
43        println!("    [{i}] @ {arg:?}");
44    }
45    println!("  argv");
46    // SAFETY: The pointers are valid in the address space of this process.
47    for (i, arg) in unsafe { parsed.argv_iter() }.enumerate() {
48        println!("    [{i}] {arg:?}");
49    }
50
51    println!("There are {} environment variables.", parsed.envc());
52    println!("  envv (raw)");
53    for (i, env) in parsed.envv_raw_iter().enumerate() {
54        println!("    [{i}] {env:?}");
55    }
56    println!("  envv");
57    // SAFETY: The pointers are valid in the address space of this process.
58    for (i, env) in unsafe { parsed.envv_iter() }.enumerate() {
59        println!("    [{i}] {env:?}");
60    }
61
62    println!(
63        "There are {} auxiliary vector entries/AT variables.",
64        parsed.auxv_raw_iter().count()
65    );
66    println!("  aux");
67    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
68    for aux in unsafe { parsed.auxv_iter() } {
69        if aux.key().value_in_data_area() {
70            println!("    {:?} => @ {:?}", aux.key(), aux);
71        } else {
72            println!("    {:?} => {:?}", aux.key(), aux);
73        }
74    }
75
76    0
77}
Source

pub fn argc(&self) -> usize

Returns the number of arguments.

Examples found in repository?
examples/linux_print_layout.rs (line 40)
31fn main(argc: isize, argv: *const *const u8) -> isize {
32    let buffer = unsafe {
33        // 100 KiB, reasonably big.
34        // On my Linux machine, the structure needs 23 KiB
35        slice::from_raw_parts(argv.cast::<u8>(), 0x19000)
36    };
37
38    let parsed = StackLayoutRef::new(buffer, Some(argc as usize));
39
40    println!("There are {} arguments.", parsed.argc());
41    println!("  argv (raw)");
42    for (i, arg) in parsed.argv_raw_iter().enumerate() {
43        println!("    [{i}] @ {arg:?}");
44    }
45    println!("  argv");
46    // SAFETY: The pointers are valid in the address space of this process.
47    for (i, arg) in unsafe { parsed.argv_iter() }.enumerate() {
48        println!("    [{i}] {arg:?}");
49    }
50
51    println!("There are {} environment variables.", parsed.envc());
52    println!("  envv (raw)");
53    for (i, env) in parsed.envv_raw_iter().enumerate() {
54        println!("    [{i}] {env:?}");
55    }
56    println!("  envv");
57    // SAFETY: The pointers are valid in the address space of this process.
58    for (i, env) in unsafe { parsed.envv_iter() }.enumerate() {
59        println!("    [{i}] {env:?}");
60    }
61
62    println!(
63        "There are {} auxiliary vector entries/AT variables.",
64        parsed.auxv_raw_iter().count()
65    );
66    println!("  aux");
67    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
68    for aux in unsafe { parsed.auxv_iter() } {
69        if aux.key().value_in_data_area() {
70            println!("    {:?} => @ {:?}", aux.key(), aux);
71        } else {
72            println!("    {:?} => {:?}", aux.key(), aux);
73        }
74    }
75
76    0
77}
Source

pub fn envc(&self) -> usize

Returns the number of environment variables.

Examples found in repository?
examples/linux_print_layout.rs (line 51)
31fn main(argc: isize, argv: *const *const u8) -> isize {
32    let buffer = unsafe {
33        // 100 KiB, reasonably big.
34        // On my Linux machine, the structure needs 23 KiB
35        slice::from_raw_parts(argv.cast::<u8>(), 0x19000)
36    };
37
38    let parsed = StackLayoutRef::new(buffer, Some(argc as usize));
39
40    println!("There are {} arguments.", parsed.argc());
41    println!("  argv (raw)");
42    for (i, arg) in parsed.argv_raw_iter().enumerate() {
43        println!("    [{i}] @ {arg:?}");
44    }
45    println!("  argv");
46    // SAFETY: The pointers are valid in the address space of this process.
47    for (i, arg) in unsafe { parsed.argv_iter() }.enumerate() {
48        println!("    [{i}] {arg:?}");
49    }
50
51    println!("There are {} environment variables.", parsed.envc());
52    println!("  envv (raw)");
53    for (i, env) in parsed.envv_raw_iter().enumerate() {
54        println!("    [{i}] {env:?}");
55    }
56    println!("  envv");
57    // SAFETY: The pointers are valid in the address space of this process.
58    for (i, env) in unsafe { parsed.envv_iter() }.enumerate() {
59        println!("    [{i}] {env:?}");
60    }
61
62    println!(
63        "There are {} auxiliary vector entries/AT variables.",
64        parsed.auxv_raw_iter().count()
65    );
66    println!("  aux");
67    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
68    for aux in unsafe { parsed.auxv_iter() } {
69        if aux.key().value_in_data_area() {
70            println!("    {:?} => @ {:?}", aux.key(), aux);
71        } else {
72            println!("    {:?} => {:?}", aux.key(), aux);
73        }
74    }
75
76    0
77}
Source

pub fn auxvc(&self) -> usize

Returns the number of auxiliary vector entries.

Source

pub fn argv_raw_iter(&self) -> impl Iterator<Item = *const u8>

Returns an iterator over the raw argument vector’s (argv) CStr pointers.

§Safety

The pointers must point to valid memory. If dereferenced, the memory must be in the address space of the application. Otherwise, segmentation faults or UB will occur.

Examples found in repository?
examples/linux_print_layout.rs (line 42)
31fn main(argc: isize, argv: *const *const u8) -> isize {
32    let buffer = unsafe {
33        // 100 KiB, reasonably big.
34        // On my Linux machine, the structure needs 23 KiB
35        slice::from_raw_parts(argv.cast::<u8>(), 0x19000)
36    };
37
38    let parsed = StackLayoutRef::new(buffer, Some(argc as usize));
39
40    println!("There are {} arguments.", parsed.argc());
41    println!("  argv (raw)");
42    for (i, arg) in parsed.argv_raw_iter().enumerate() {
43        println!("    [{i}] @ {arg:?}");
44    }
45    println!("  argv");
46    // SAFETY: The pointers are valid in the address space of this process.
47    for (i, arg) in unsafe { parsed.argv_iter() }.enumerate() {
48        println!("    [{i}] {arg:?}");
49    }
50
51    println!("There are {} environment variables.", parsed.envc());
52    println!("  envv (raw)");
53    for (i, env) in parsed.envv_raw_iter().enumerate() {
54        println!("    [{i}] {env:?}");
55    }
56    println!("  envv");
57    // SAFETY: The pointers are valid in the address space of this process.
58    for (i, env) in unsafe { parsed.envv_iter() }.enumerate() {
59        println!("    [{i}] {env:?}");
60    }
61
62    println!(
63        "There are {} auxiliary vector entries/AT variables.",
64        parsed.auxv_raw_iter().count()
65    );
66    println!("  aux");
67    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
68    for aux in unsafe { parsed.auxv_iter() } {
69        if aux.key().value_in_data_area() {
70            println!("    {:?} => @ {:?}", aux.key(), aux);
71        } else {
72            println!("    {:?} => {:?}", aux.key(), aux);
73        }
74    }
75
76    0
77}
Source

pub fn envv_raw_iter(&self) -> impl Iterator<Item = *const u8>

Returns an iterator over the raw environment vector’s (envv) CStr pointers.

§Safety

The pointers must point to valid memory. If dereferenced, the memory must be in the address space of the application. Otherwise, segmentation faults or UB will occur.

Examples found in repository?
examples/linux_print_layout.rs (line 53)
31fn main(argc: isize, argv: *const *const u8) -> isize {
32    let buffer = unsafe {
33        // 100 KiB, reasonably big.
34        // On my Linux machine, the structure needs 23 KiB
35        slice::from_raw_parts(argv.cast::<u8>(), 0x19000)
36    };
37
38    let parsed = StackLayoutRef::new(buffer, Some(argc as usize));
39
40    println!("There are {} arguments.", parsed.argc());
41    println!("  argv (raw)");
42    for (i, arg) in parsed.argv_raw_iter().enumerate() {
43        println!("    [{i}] @ {arg:?}");
44    }
45    println!("  argv");
46    // SAFETY: The pointers are valid in the address space of this process.
47    for (i, arg) in unsafe { parsed.argv_iter() }.enumerate() {
48        println!("    [{i}] {arg:?}");
49    }
50
51    println!("There are {} environment variables.", parsed.envc());
52    println!("  envv (raw)");
53    for (i, env) in parsed.envv_raw_iter().enumerate() {
54        println!("    [{i}] {env:?}");
55    }
56    println!("  envv");
57    // SAFETY: The pointers are valid in the address space of this process.
58    for (i, env) in unsafe { parsed.envv_iter() }.enumerate() {
59        println!("    [{i}] {env:?}");
60    }
61
62    println!(
63        "There are {} auxiliary vector entries/AT variables.",
64        parsed.auxv_raw_iter().count()
65    );
66    println!("  aux");
67    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
68    for aux in unsafe { parsed.auxv_iter() } {
69        if aux.key().value_in_data_area() {
70            println!("    {:?} => @ {:?}", aux.key(), aux);
71        } else {
72            println!("    {:?} => {:?}", aux.key(), aux);
73        }
74    }
75
76    0
77}
Source

pub fn auxv_raw_iter(&self) -> impl Iterator<Item = AuxVarRaw>

Returns an iterator over the auxiliary variables vector’s (auxv) AuxVarRaw elements.

§Safety

Any pointers must point to valid memory. If dereferenced, the memory must be in the address space of the application. Otherwise, segmentation faults or UB will occur.

Examples found in repository?
examples/linux_print_layout.rs (line 64)
31fn main(argc: isize, argv: *const *const u8) -> isize {
32    let buffer = unsafe {
33        // 100 KiB, reasonably big.
34        // On my Linux machine, the structure needs 23 KiB
35        slice::from_raw_parts(argv.cast::<u8>(), 0x19000)
36    };
37
38    let parsed = StackLayoutRef::new(buffer, Some(argc as usize));
39
40    println!("There are {} arguments.", parsed.argc());
41    println!("  argv (raw)");
42    for (i, arg) in parsed.argv_raw_iter().enumerate() {
43        println!("    [{i}] @ {arg:?}");
44    }
45    println!("  argv");
46    // SAFETY: The pointers are valid in the address space of this process.
47    for (i, arg) in unsafe { parsed.argv_iter() }.enumerate() {
48        println!("    [{i}] {arg:?}");
49    }
50
51    println!("There are {} environment variables.", parsed.envc());
52    println!("  envv (raw)");
53    for (i, env) in parsed.envv_raw_iter().enumerate() {
54        println!("    [{i}] {env:?}");
55    }
56    println!("  envv");
57    // SAFETY: The pointers are valid in the address space of this process.
58    for (i, env) in unsafe { parsed.envv_iter() }.enumerate() {
59        println!("    [{i}] {env:?}");
60    }
61
62    println!(
63        "There are {} auxiliary vector entries/AT variables.",
64        parsed.auxv_raw_iter().count()
65    );
66    println!("  aux");
67    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
68    for aux in unsafe { parsed.auxv_iter() } {
69        if aux.key().value_in_data_area() {
70            println!("    {:?} => @ {:?}", aux.key(), aux);
71        } else {
72            println!("    {:?} => {:?}", aux.key(), aux);
73        }
74    }
75
76    0
77}
Source

pub unsafe fn argv_iter(&self) -> impl Iterator<Item = &'a CStr>

Unsafe version of Self::argv_raw_iter that only works if all pointers are valid. It emits high-level items of type CStr.

This is typically safe if you parse the stack layout you’ve got from Linux but not if you parse some other’s stack layout.

§Safety

The pointers must point to valid memory. If dereferenced, the memory must be in the address space of the application. Otherwise, segmentation faults or UB will occur.

Examples found in repository?
examples/minimal_builder.rs (line 39)
27fn main() {
28    let builder = StackLayoutBuilder::new()
29        // can contain terminating zero; not mandatory in the builder
30        .add_argv("foo")
31        .add_argv("hello")
32        .add_envv("PATH=/bin")
33        .add_auxv(AuxVar::ExecFn("/usr/bin/foo".into()));
34
35    let layout = builder.build(None /* we create the layout in our address space */);
36    let layout = StackLayoutRef::new(layout.as_ref(), None);
37
38    // SAFETY: This is safe as all pointers point into our address space.
39    for (i, arg) in unsafe { layout.argv_iter() }.enumerate() {
40        println!("  [{i}] {}", arg.to_str().unwrap());
41    }
42}
More examples
Hide additional examples
examples/linux_print_layout.rs (line 47)
31fn main(argc: isize, argv: *const *const u8) -> isize {
32    let buffer = unsafe {
33        // 100 KiB, reasonably big.
34        // On my Linux machine, the structure needs 23 KiB
35        slice::from_raw_parts(argv.cast::<u8>(), 0x19000)
36    };
37
38    let parsed = StackLayoutRef::new(buffer, Some(argc as usize));
39
40    println!("There are {} arguments.", parsed.argc());
41    println!("  argv (raw)");
42    for (i, arg) in parsed.argv_raw_iter().enumerate() {
43        println!("    [{i}] @ {arg:?}");
44    }
45    println!("  argv");
46    // SAFETY: The pointers are valid in the address space of this process.
47    for (i, arg) in unsafe { parsed.argv_iter() }.enumerate() {
48        println!("    [{i}] {arg:?}");
49    }
50
51    println!("There are {} environment variables.", parsed.envc());
52    println!("  envv (raw)");
53    for (i, env) in parsed.envv_raw_iter().enumerate() {
54        println!("    [{i}] {env:?}");
55    }
56    println!("  envv");
57    // SAFETY: The pointers are valid in the address space of this process.
58    for (i, env) in unsafe { parsed.envv_iter() }.enumerate() {
59        println!("    [{i}] {env:?}");
60    }
61
62    println!(
63        "There are {} auxiliary vector entries/AT variables.",
64        parsed.auxv_raw_iter().count()
65    );
66    println!("  aux");
67    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
68    for aux in unsafe { parsed.auxv_iter() } {
69        if aux.key().value_in_data_area() {
70            println!("    {:?} => @ {:?}", aux.key(), aux);
71        } else {
72            println!("    {:?} => {:?}", aux.key(), aux);
73        }
74    }
75
76    0
77}
Source

pub unsafe fn envv_iter(&self) -> impl Iterator<Item = &'a CStr>

Unsafe version of Self::envv_raw_iter that only works if all pointers are valid. It emits high-level items of type CStr.

This is typically safe if you parse the stack layout you’ve got from Linux but not if you parse some other’s stack layout.

§Safety

The pointers must point to valid memory. If dereferenced, the memory must be in the address space of the application. Otherwise, segmentation faults or UB will occur.

Examples found in repository?
examples/linux_print_layout.rs (line 58)
31fn main(argc: isize, argv: *const *const u8) -> isize {
32    let buffer = unsafe {
33        // 100 KiB, reasonably big.
34        // On my Linux machine, the structure needs 23 KiB
35        slice::from_raw_parts(argv.cast::<u8>(), 0x19000)
36    };
37
38    let parsed = StackLayoutRef::new(buffer, Some(argc as usize));
39
40    println!("There are {} arguments.", parsed.argc());
41    println!("  argv (raw)");
42    for (i, arg) in parsed.argv_raw_iter().enumerate() {
43        println!("    [{i}] @ {arg:?}");
44    }
45    println!("  argv");
46    // SAFETY: The pointers are valid in the address space of this process.
47    for (i, arg) in unsafe { parsed.argv_iter() }.enumerate() {
48        println!("    [{i}] {arg:?}");
49    }
50
51    println!("There are {} environment variables.", parsed.envc());
52    println!("  envv (raw)");
53    for (i, env) in parsed.envv_raw_iter().enumerate() {
54        println!("    [{i}] {env:?}");
55    }
56    println!("  envv");
57    // SAFETY: The pointers are valid in the address space of this process.
58    for (i, env) in unsafe { parsed.envv_iter() }.enumerate() {
59        println!("    [{i}] {env:?}");
60    }
61
62    println!(
63        "There are {} auxiliary vector entries/AT variables.",
64        parsed.auxv_raw_iter().count()
65    );
66    println!("  aux");
67    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
68    for aux in unsafe { parsed.auxv_iter() } {
69        if aux.key().value_in_data_area() {
70            println!("    {:?} => @ {:?}", aux.key(), aux);
71        } else {
72            println!("    {:?} => {:?}", aux.key(), aux);
73        }
74    }
75
76    0
77}
Source

pub unsafe fn auxv_iter(&self) -> impl Iterator<Item = AuxVar<'a>>

Unsafe version of Self::argv_raw_iter that only works if all pointers are valid. It emits high-level items of type AuxVar.

This is typically safe if you parse the stack layout you’ve got from Linux but not if you parse some other’s stack layout.

§Safety

Any pointers must point to valid memory. If dereferenced, the memory must be in the address space of the application. Otherwise, segmentation faults or UB will occur.

Examples found in repository?
examples/linux_print_layout.rs (line 68)
31fn main(argc: isize, argv: *const *const u8) -> isize {
32    let buffer = unsafe {
33        // 100 KiB, reasonably big.
34        // On my Linux machine, the structure needs 23 KiB
35        slice::from_raw_parts(argv.cast::<u8>(), 0x19000)
36    };
37
38    let parsed = StackLayoutRef::new(buffer, Some(argc as usize));
39
40    println!("There are {} arguments.", parsed.argc());
41    println!("  argv (raw)");
42    for (i, arg) in parsed.argv_raw_iter().enumerate() {
43        println!("    [{i}] @ {arg:?}");
44    }
45    println!("  argv");
46    // SAFETY: The pointers are valid in the address space of this process.
47    for (i, arg) in unsafe { parsed.argv_iter() }.enumerate() {
48        println!("    [{i}] {arg:?}");
49    }
50
51    println!("There are {} environment variables.", parsed.envc());
52    println!("  envv (raw)");
53    for (i, env) in parsed.envv_raw_iter().enumerate() {
54        println!("    [{i}] {env:?}");
55    }
56    println!("  envv");
57    // SAFETY: The pointers are valid in the address space of this process.
58    for (i, env) in unsafe { parsed.envv_iter() }.enumerate() {
59        println!("    [{i}] {env:?}");
60    }
61
62    println!(
63        "There are {} auxiliary vector entries/AT variables.",
64        parsed.auxv_raw_iter().count()
65    );
66    println!("  aux");
67    // ptr iter is safe for other address spaces; the other only because here user_addr == write_addr
68    for aux in unsafe { parsed.auxv_iter() } {
69        if aux.key().value_in_data_area() {
70            println!("    {:?} => @ {:?}", aux.key(), aux);
71        } else {
72            println!("    {:?} => {:?}", aux.key(), aux);
73        }
74    }
75
76    0
77}

Trait Implementations§

Source§

impl<'a> Debug for StackLayoutRef<'a>

Source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<'a> Freeze for StackLayoutRef<'a>

§

impl<'a> RefUnwindSafe for StackLayoutRef<'a>

§

impl<'a> Send for StackLayoutRef<'a>

§

impl<'a> Sync for StackLayoutRef<'a>

§

impl<'a> Unpin for StackLayoutRef<'a>

§

impl<'a> UnwindSafe for StackLayoutRef<'a>

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.