From 05f52a7d536c73403c6ea82b0704f4424d2d71b8 Mon Sep 17 00:00:00 2001 From: Samueru-sama Date: Thu, 17 Sep 2026 18:46:08 -0400 Subject: [PATCH 1/2] stack: synthesize AT_RANDOM when the kernel omits it AT_RANDOM was only added to the auxv in Linux 2.6.29. On older kernels getauxval(AT_RANDOM) returns NULL, so the existing assert! panics and user-land exec (and anything built on it, e.g. sharun AppImages) cannot start at all. Fall back to 16 random bytes from /dev/urandom so the interpreter we hand control to can still initialise its stack canary / pointer guard. --- src/stack.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/stack.rs b/src/stack.rs index e6102d3..7d49e6a 100644 --- a/src/stack.rs +++ b/src/stack.rs @@ -119,12 +119,21 @@ 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; + 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() From 525d7636e8339ecd4fa455db68db57df1125a1a7 Mon Sep 17 00:00:00 2001 From: Samueru-sama Date: Thu, 17 Sep 2026 19:22:54 -0400 Subject: [PATCH 2/2] stack: document that a short /dev/urandom read leaves an all-zero canary Review nit: make the accepted worst case explicit. --- src/stack.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/stack.rs b/src/stack.rs index 7d49e6a..4fd12cd 100644 --- a/src/stack.rs +++ b/src/stack.rs @@ -129,6 +129,10 @@ impl<'a, A: AsRef, E: AsRef> StackBuilder<'a, A, E> { 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