1mod serialized;
26mod typ;
27
28use crate::cstr_util::{c_str_len_ptr, c_str_null_terminated};
29use core::cmp::Ordering;
30use core::fmt::Debug;
31pub(crate) use serialized::*;
32pub use typ::*;
33
34bitflags::bitflags! {
35 pub struct AuxVarFlags: usize {
37 const NOT_PRESERVE_ARGV0 = 0;
39 const PRESERVE_ARGV0 = 1;
41 }
42}
43
44#[derive(Debug)]
48pub enum AuxVar<'a> {
49 Null,
51 Ignore(usize),
53 ExecFd(usize),
55 Phdr(*const u8),
57 Phent(usize),
59 Phnum(usize),
61 Pagesz(usize),
63 Base(*const u8),
65 Flags(AuxVarFlags),
67 Entry(*const u8),
69 NotElf(bool),
71 Uid(usize),
73 EUid(usize),
75 Gid(usize),
77 EGid(usize),
79 Platform(&'a str),
81 HwCap(usize),
83 Clktck(usize),
85 Secure(bool),
87 BasePlatform(&'a str),
89 Random([u8; 16]),
95 HwCap2(usize),
97 ExecFn(&'a str),
99 Sysinfo(*const u8),
101 SysinfoEhdr(*const u8),
103 L1iCacheSize(usize),
105 L1iCacheGeometry(usize),
107 L1dCacheSize(usize),
109 L1dCacheGeometry(usize),
111 L2CacheSize(usize),
113 L2CacheGeometry(usize),
115 L3CacheSize(usize),
117 L3CacheGeometry(usize),
119 MinSigStkSz(usize),
121}
122
123impl<'a> AuxVar<'a> {
124 pub(crate) unsafe fn from_serialized(serialized: &AuxVarSerialized) -> Self {
132 if serialized.key().value_in_data_area() {
133 let data_ptr = serialized.val() as *const u8;
134 let len = serialized
135 .key()
136 .data_area_val_size_hint()
137 .unwrap_or_else(|| c_str_len_ptr(data_ptr));
138 let slice = core::slice::from_raw_parts(data_ptr, len);
139 if serialized.key().value_is_cstr() {
140 let cstr = core::str::from_utf8(slice).expect(
141 "must be valid c string. Either invalid memory or not null-terminated!",
142 );
143 match serialized.key() {
144 AuxVarType::Platform => Self::Platform(cstr),
145 AuxVarType::BasePlatform => Self::BasePlatform(cstr),
146 AuxVarType::ExecFn => Self::ExecFn(cstr),
147 _ => panic!("invalid variant"),
148 }
149 } else {
150 match serialized.key() {
151 AuxVarType::Random => {
152 let mut random_bytes = [0; 16];
153 random_bytes.copy_from_slice(slice);
155 Self::Random(random_bytes)
156 }
157 _ => panic!("invalid variant"),
158 }
159 }
160 } else {
161 match serialized.key() {
162 AuxVarType::Null => Self::Null,
163 AuxVarType::Ignore => Self::Ignore(serialized.val()),
164 AuxVarType::ExecFd => Self::ExecFd(serialized.val()),
165 AuxVarType::Phdr => Self::Phdr(serialized.val() as _),
166 AuxVarType::Phent => Self::Phent(serialized.val()),
167 AuxVarType::Phnum => Self::Phnum(serialized.val()),
168 AuxVarType::Pagesz => Self::Pagesz(serialized.val()),
169 AuxVarType::Base => Self::Base(serialized.val() as _),
170 AuxVarType::Flags => Self::Flags(AuxVarFlags::from_bits(serialized.val()).unwrap()),
171 AuxVarType::Entry => Self::Entry(serialized.val() as _),
172 AuxVarType::NotElf => Self::NotElf(serialized.val() != 0),
173 AuxVarType::Uid => Self::Uid(serialized.val()),
174 AuxVarType::EUid => Self::EUid(serialized.val()),
175 AuxVarType::Gid => Self::Gid(serialized.val()),
176 AuxVarType::EGid => Self::EGid(serialized.val()),
177 AuxVarType::HwCap => Self::HwCap(serialized.val()),
178 AuxVarType::Clktck => Self::Clktck(serialized.val()),
179 AuxVarType::Secure => Self::Secure(serialized.val() != 0),
180 AuxVarType::HwCap2 => Self::HwCap2(serialized.val()),
181 AuxVarType::Sysinfo => Self::Sysinfo(serialized.val() as _),
182 AuxVarType::SysinfoEhdr => Self::SysinfoEhdr(serialized.val() as _),
183 AuxVarType::L1iCacheSize => Self::L1iCacheSize(serialized.val()),
184 AuxVarType::L1iCacheGeometry => Self::L1iCacheGeometry(serialized.val()),
185 AuxVarType::L1dCacheSize => Self::L1dCacheSize(serialized.val()),
186 AuxVarType::L1dCacheGeometry => Self::L1dCacheGeometry(serialized.val()),
187 AuxVarType::L2CacheSize => Self::L2CacheSize(serialized.val()),
188 AuxVarType::L2CacheGeometry => Self::L2CacheGeometry(serialized.val()),
189 AuxVarType::L3CacheSize => Self::L3CacheSize(serialized.val()),
190 AuxVarType::L3CacheGeometry => Self::L3CacheGeometry(serialized.val()),
191 AuxVarType::MinSigStkSz => Self::MinSigStkSz(serialized.val()),
192 _ => panic!("invalid variant"),
193 }
194 }
195 }
196
197 pub const fn key(&self) -> AuxVarType {
199 match self {
200 AuxVar::Null => AuxVarType::Null,
201 AuxVar::Ignore(_) => AuxVarType::Ignore,
202 AuxVar::ExecFd(_) => AuxVarType::ExecFd,
203 AuxVar::Phdr(_) => AuxVarType::Phdr,
204 AuxVar::Phent(_) => AuxVarType::Phent,
205 AuxVar::Phnum(_) => AuxVarType::Phnum,
206 AuxVar::Pagesz(_) => AuxVarType::Pagesz,
207 AuxVar::Base(_) => AuxVarType::Base,
208 AuxVar::Flags(_) => AuxVarType::Flags,
209 AuxVar::Entry(_) => AuxVarType::Entry,
210 AuxVar::NotElf(_) => AuxVarType::NotElf,
211 AuxVar::Uid(_) => AuxVarType::Uid,
212 AuxVar::EUid(_) => AuxVarType::EUid,
213 AuxVar::Gid(_) => AuxVarType::Gid,
214 AuxVar::EGid(_) => AuxVarType::EGid,
215 AuxVar::Platform(_) => AuxVarType::Platform,
216 AuxVar::HwCap(_) => AuxVarType::HwCap,
217 AuxVar::Clktck(_) => AuxVarType::Clktck,
218 AuxVar::Secure(_) => AuxVarType::Secure,
219 AuxVar::BasePlatform(_) => AuxVarType::BasePlatform,
220 AuxVar::Random(_) => AuxVarType::Random,
221 AuxVar::HwCap2(_) => AuxVarType::HwCap2,
222 AuxVar::ExecFn(_) => AuxVarType::ExecFn,
223 AuxVar::Sysinfo(_) => AuxVarType::Sysinfo,
224 AuxVar::SysinfoEhdr(_) => AuxVarType::SysinfoEhdr,
225 AuxVar::L1iCacheSize(_) => AuxVarType::L1iCacheSize,
226 AuxVar::L1iCacheGeometry(_) => AuxVarType::L1iCacheGeometry,
227 AuxVar::L1dCacheSize(_) => AuxVarType::L1dCacheSize,
228 AuxVar::L1dCacheGeometry(_) => AuxVarType::L1dCacheGeometry,
229 AuxVar::L2CacheSize(_) => AuxVarType::L2CacheSize,
230 AuxVar::L2CacheGeometry(_) => AuxVarType::L2CacheGeometry,
231 AuxVar::L3CacheSize(_) => AuxVarType::L3CacheSize,
232 AuxVar::L3CacheGeometry(_) => AuxVarType::L3CacheGeometry,
233 AuxVar::MinSigStkSz(_) => AuxVarType::MinSigStkSz,
234 }
235 }
236
237 pub fn value_raw(&self) -> usize {
241 match self {
242 AuxVar::Null => 0,
243 AuxVar::Ignore(val) => *val,
244 AuxVar::ExecFd(val) => *val,
245 AuxVar::Phdr(val) => *val as _,
246 AuxVar::Phent(val) => *val,
247 AuxVar::Phnum(val) => *val,
248 AuxVar::Pagesz(val) => *val,
249 AuxVar::Base(val) => *val as _,
250 AuxVar::Flags(val) => val.bits(),
251 AuxVar::Entry(val) => *val as _,
252 AuxVar::NotElf(val) => {
253 if *val {
254 1
255 } else {
256 0
257 }
258 }
259 AuxVar::Uid(val) => *val,
260 AuxVar::EUid(val) => *val,
261 AuxVar::Gid(val) => *val,
262 AuxVar::EGid(val) => *val,
263 AuxVar::Platform(val) => val.as_ptr() as _,
264 AuxVar::HwCap(val) => *val,
265 AuxVar::Clktck(val) => *val,
266 AuxVar::Secure(val) => {
267 if *val {
268 1
269 } else {
270 0
271 }
272 }
273 AuxVar::BasePlatform(val) => val.as_ptr() as _,
274 AuxVar::Random(val) => val.as_ptr() as _,
275 AuxVar::HwCap2(val) => *val,
276 AuxVar::ExecFn(val) => val.as_ptr() as _,
277 AuxVar::Sysinfo(val) => *val as _,
278 AuxVar::SysinfoEhdr(val) => *val as _,
279 AuxVar::L1iCacheSize(val) => *val,
280 AuxVar::L1iCacheGeometry(val) => *val,
281 AuxVar::L1dCacheSize(val) => *val,
282 AuxVar::L1dCacheGeometry(val) => *val,
283 AuxVar::L2CacheSize(val) => *val,
284 AuxVar::L2CacheGeometry(val) => *val,
285 AuxVar::L3CacheSize(val) => *val,
286 AuxVar::L3CacheGeometry(val) => *val,
287 AuxVar::MinSigStkSz(val) => *val,
288 }
289 }
290
291 pub const fn value_integer(&self) -> Option<usize> {
294 match self {
295 AuxVar::Ignore(val) => Some(*val),
296 AuxVar::ExecFd(val) => Some(*val),
297 AuxVar::Phent(val) => Some(*val),
298 AuxVar::Phnum(val) => Some(*val),
299 AuxVar::Pagesz(val) => Some(*val),
300 AuxVar::Uid(val) => Some(*val),
301 AuxVar::EUid(val) => Some(*val),
302 AuxVar::Gid(val) => Some(*val),
303 AuxVar::EGid(val) => Some(*val),
304 AuxVar::HwCap(val) => Some(*val),
305 AuxVar::Clktck(val) => Some(*val),
306 AuxVar::HwCap2(val) => Some(*val),
307 AuxVar::L1iCacheSize(val) => Some(*val),
308 AuxVar::L1iCacheGeometry(val) => Some(*val),
309 AuxVar::L1dCacheSize(val) => Some(*val),
310 AuxVar::L1dCacheGeometry(val) => Some(*val),
311 AuxVar::L2CacheSize(val) => Some(*val),
312 AuxVar::L2CacheGeometry(val) => Some(*val),
313 AuxVar::L3CacheSize(val) => Some(*val),
314 AuxVar::L3CacheGeometry(val) => Some(*val),
315 AuxVar::MinSigStkSz(val) => Some(*val),
316 _ => None,
317 }
318 }
319
320 pub const fn value_flags(&self) -> Option<AuxVarFlags> {
322 match self {
323 AuxVar::Flags(flags) => Some(*flags),
324 _ => None,
325 }
326 }
327
328 pub const fn value_boolean(&self) -> Option<bool> {
331 match self {
332 AuxVar::NotElf(val) => Some(*val),
333 AuxVar::Secure(val) => Some(*val),
334 _ => None,
335 }
336 }
337
338 pub const fn value_ptr(&self) -> Option<*const u8> {
343 match self {
344 AuxVar::Phdr(val) => Some(*val),
345 AuxVar::Base(val) => Some(*val),
346 AuxVar::Entry(val) => Some(*val),
347 AuxVar::Sysinfo(val) => Some(*val),
348 AuxVar::SysinfoEhdr(val) => Some(*val),
349 _ => None,
350 }
351 }
352
353 pub fn value_payload_bytes(&'a self) -> Option<&'a [u8]> {
360 match self {
361 AuxVar::Random(bytes) => Some(&bytes[..]),
362 _ => None,
363 }
364 }
365
366 pub const fn value_payload_cstr(&'a self) -> Option<&'a str> {
373 match self {
374 AuxVar::Platform(val) => Some(*val),
375 AuxVar::BasePlatform(val) => Some(*val),
376 AuxVar::ExecFn(val) => Some(*val),
377 _ => None,
378 }
379 }
380
381 pub(crate) fn data_area_serialize_byte_count(&self) -> usize {
388 let mut bytes = 0;
389 bytes += self.value_payload_bytes().map(|x| x.len()).unwrap_or(0);
390 bytes += self.value_payload_cstr().map(|x| x.len()).unwrap_or(0);
391 if self.value_payload_cstr().is_some()
392 && !c_str_null_terminated(self.value_payload_cstr().unwrap().as_bytes())
393 {
394 bytes + 1
395 } else {
396 bytes
397 }
398 }
399}
400
401impl<'a> PartialEq for AuxVar<'a> {
402 fn eq(&self, other: &Self) -> bool {
403 self.key() == other.key()
404 }
405}
406
407impl<'a> PartialOrd for AuxVar<'a> {
408 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
409 self.key().partial_cmp(&other.key())
410 }
411}
412
413impl<'a> Eq for AuxVar<'a> {}
414
415impl<'a> Ord for AuxVar<'a> {
416 fn cmp(&self, other: &Self) -> Ordering {
417 self.partial_cmp(other).unwrap()
418 }
419}
420
421#[cfg(test)]
422mod tests {
423 use super::*;
424 use std::collections::BTreeSet;
425
426 #[test]
429 fn test_aux_var_order() {
430 let mut set = BTreeSet::new();
431 set.insert(AuxVar::ExecFn("./executable"));
432 set.insert(AuxVar::Platform("x86_64"));
433 set.insert(AuxVar::Null);
434 set.insert(AuxVar::Clktck(0x1337));
435 set.insert(AuxVar::ExecFn("./executable"));
436 assert_eq!(set.iter().last().unwrap().key(), AuxVarType::Null);
437 }
438
439 #[test]
440 fn test_data_area_serialize_byte_count() {
441 assert_eq!(
442 AuxVar::ExecFn("./executable").data_area_serialize_byte_count(),
443 13
444 );
445 assert_eq!(
446 AuxVar::ExecFn("./executable\0").data_area_serialize_byte_count(),
447 13
448 );
449 assert_eq!(
450 AuxVar::Platform("x86_64").data_area_serialize_byte_count(),
451 7
452 );
453 assert_eq!(
454 AuxVar::Platform("x86_64\0").data_area_serialize_byte_count(),
455 7
456 );
457 assert_eq!(AuxVar::Random([0; 16]).data_area_serialize_byte_count(), 16);
458 }
459}