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 argumentsargv
: null-terminated array of pointers into argv data areaNULL pointer
envv
: null-terminated array of pointers into envv data areaNULL pointer
auxv
Array of auxiliary variables (AT variables), terminated by anAuxVarType::Null
entry.NUL[s] for padding
auxv data area
: Possibly payload of auxiliary variablesargv data area
: Null-terminated C strings representing the argumentsenvv data area
: Null-terminated C strings representing the environmentNUL[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>
impl<'a> StackLayoutRef<'a>
Sourcepub fn new(bytes: &'a [u8], argc: Option<usize>) -> Self
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?
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
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}
Sourcepub fn argc(&self) -> usize
pub fn argc(&self) -> usize
Returns the number of arguments.
Examples found in repository?
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}
Sourcepub fn envc(&self) -> usize
pub fn envc(&self) -> usize
Returns the number of environment variables.
Examples found in repository?
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}
Sourcepub fn argv_raw_iter(&self) -> impl Iterator<Item = *const u8>
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?
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}
Sourcepub fn envv_raw_iter(&self) -> impl Iterator<Item = *const u8>
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?
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}
Sourcepub fn auxv_raw_iter(&self) -> impl Iterator<Item = AuxVarRaw>
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?
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}
Sourcepub unsafe fn argv_iter(&self) -> impl Iterator<Item = &'a CStr>
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?
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
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}
Sourcepub unsafe fn envv_iter(&self) -> impl Iterator<Item = &'a CStr>
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?
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}
Sourcepub unsafe fn auxv_iter(&self) -> impl Iterator<Item = AuxVar<'a>>
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?
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}