Skip to content

stack: synthesize AT_RANDOM when the kernel omits it - #3

Merged
Samueru-sama merged 2 commits into
mainfrom
fix-at-random-old-kernels
Sep 17, 2026
Merged

Samueru-sama merged 2 commits into
mainfrom
fix-at-random-old-kernels

Conversation

@Samueru-sama

Copy link
Copy Markdown
Member

What

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!(!ptr.is_null()) in stack.rs panics:

thread 'main' panicked at .../src/stack.rs:123:13:
assertion failed: !ptr.is_null()

With panic = "abort" (as used by sharun's release profile) that's a hard ud2/SIGILL before the interpreter is ever entered, so user-land exec and everything built on it cannot start on those kernels.

Fix

Fall back to 16 bytes from /dev/urandom when the kernel doesn't supply AT_RANDOM, so the interpreter we hand control to can still initialise its stack canary / pointer guard.

Only triggers when AT_RANDOM is actually absent (kernel < 2.6.29), so there's no behaviour change on newer kernels.

Needed together with pkgforge-dev/Anylinux-sharun#15 to run current AppImages on very old kernels. Verified on Ubuntu 7.04 (kernel 2.6.20), where the gtk2-ng-demo, gtk3-demo, and Qt6 dbus-demo AppImages now launch.

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.

@talaria0101 talaria0101 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at 05f52a7, re-fetched immediately before reviewing (head unchanged since fetch). Built and A/B tested on this machine.

The change is correct. AT_RANDOM appeared in Linux 2.6.29, the comment is accurate, and the fallback chain (parent auxv -> /dev/urandom -> zeros) is fine. The all-zero worst case is no worse than what glibc itself does when _dl_random is NULL (it fills a fixed terminator canary), and the previous code panicked in that spot, so this only ever runs where the alternative was death.

Regression check, measured: built v0.3.1 (9249ef1) and this head side by side and ran both over /bin/true, /bin/false, /bin/sh -c, and /usr/bin/env: identical output and exit codes. On any kernel that supplies AT_RANDOM (>= 2.6.29) the pushed bytes are the same 16 bytes as before, so previously-working paths are byte-identical in behavior.

Two nits, non-blocking:

  1. read_exact failure is swallowed with let _; after a partial read you push a half-random half-zero canary. Harmless, but a one-line comment that zeros are the accepted worst case would document the intent.
  2. The urandom File is dropped at end of scope so no fd leaks into the loaded image. No change needed, confirming I checked.

Merge dependency: this must be tagged before Anylinux-sharun#15 can work on < 2.6.29 kernels. sharun still pins tag = "v0.3.0" (ce43131), which predates even #2 and still contains assert!(!ptr.is_null()) in stack.rs. Without a tag containing this commit, the tracer in sharun#15 cannot help; userland_execve::exec panics inside the tracee on any kernel that omits AT_RANDOM. Please cut v0.3.2 after merging so #15 can pin it.

Review nit: make the accepted worst case explicit.
@Samueru-sama

Copy link
Copy Markdown
Member Author

Thanks for the review and the A/B regression check.

  • Nit 1 (short read): addressed in 525d763 — the read_exact call now carries a comment making the all-zero worst case explicit.
  • Nit 2 (fd): confirmed no change needed.
  • Merge dependency: agreed. Once this is merged I'll cut v0.3.2 and bump Anylinux-sharun#15 to pin tag = "v0.3.2" (it currently pins v0.3.0, which predates the fix). Until then #15 won't help on < 2.6.29 kernels.

@Samueru-sama
Samueru-sama merged commit 22a8c33 into main Sep 17, 2026
Samueru-sama added a commit that referenced this pull request Sep 21, 2026
* 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.

* stack: document that a short /dev/urandom read leaves an all-zero canary

Review nit: make the accepted worst case explicit.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants