diff --git a/src/stack.rs b/src/stack.rs index e6102d3..4fd12cd 100644 --- a/src/stack.rs +++ b/src/stack.rs @@ -119,12 +119,25 @@ impl<'a, A: AsRef, E: AsRef> StackBuilder<'a, A, E> { let at_platform = unsafe { CStr::from_ptr(at_platform) }; Some(self.push_str(at_platform)) }; - let at_random = unsafe { + // AT_RANDOM is only provided by Linux >= 2.6.29. On older kernels it is + // absent, so synthesize 16 bytes for the interpreter we are about to + // hand control to (it uses them for the stack canary / pointer guard). + let at_random_bytes: [u8; 16] = unsafe { let ptr = getauxval(AT_RANDOM) as *const u8; - assert!(!ptr.is_null()); - std::slice::from_raw_parts(ptr, 16) + let mut buf = [0u8; 16]; + if !ptr.is_null() { + std::ptr::copy_nonoverlapping(ptr, buf.as_mut_ptr(), 16); + } else if let Ok(mut urandom) = std::fs::File::open("/dev/urandom") { + use std::io::Read; + // On a short or failed read the remaining bytes stay zero. An + // all-zero canary is the accepted worst case here: it is no + // worse than what glibc itself does when its AT_RANDOM is + // absent, and the alternative on these kernels is a panic. + let _ = urandom.read_exact(&mut buf); + } + buf }; - let at_random_addr = self.push_bytes(at_random); + let at_random_addr = self.push_bytes(&at_random_bytes); // Align argc at bottom while (self.stack_reversed.len()