std: fix FreeBSD environ() null deref under crt-static#159097
std: fix FreeBSD environ() null deref under crt-static#159097valentynkit wants to merge 1 commit into
Conversation
On FreeBSD, environ() looks up the environ symbol with dlsym(RTLD_DEFAULT, "environ"), which needs a dynamic symbol table. A statically linked executable (-C target-feature=+crt-static) has none, so dlsym returns null and every caller that walks the environment array (std::env::vars, Command::spawn) derefs it unchecked and segfaults. Fall back to a weakly linked reference to environ when dlsym fails. Reading an extern_weak static yields the symbol's address, or null when nothing defines it, so the fallback resolves in a static executable (crt1.o defines environ) while a cdylib linked with -Wl,--no-undefined still links, the same constraint the dlsym lookup was introduced to satisfy.
|
Author of #158939 here. I missed this draft when I opened #159112, sorry for the overlap. Both PRs use the same Happy to resolve this either way: if you'd like to fold the env() guard into this PR, I'll close mine, or the libs team can just pick one. |
|
☔ The latest upstream changes (presumably #159192) made this pull request unmergeable. Please resolve the merge conflicts by rebasing. |
The bug
On FreeBSD,
environ()resolves the symbol withdlsym(RTLD_DEFAULT, "environ"), which needs a dynamic symbol table. A-C target-feature=+crt-staticexecutable has none, sodlsymreturns null, and every caller that walks the environment array dereferences that return before the null check further down, which only guards the array contents rather than the pointer itself. Sostd::env::vars/vars_osandCommand::spawnsegfault on a statically linked FreeBSD binary.std::env::varis unaffected, since it goes throughgetenv.The
dlsymaccessor was added in #153718 to makeenvironresolve in cdylibs linked with-Wl,--no-undefined. That fixed the shared-library case but regressed the static-executable one, which is the only build of the two that lacks the dynamic symbol tabledlsymdepends on.The fix
When
dlsymreturns null, fall back to a weakly linked reference toenviron. rustc lowers anextern_weakstatic to an indirection global that holds the symbol's address, so reading the static yields the address ofenviron, or null if nothing defines it. This is the same mechanism theweak!macro insys/pal/unix/weakuses for function symbols.The fallback covers both cases the accessor has to satisfy: in a static executable it resolves because
crt1.odefinesenviron, and a weak undefined reference still links cleanly under-Wl,--no-undefined, the constraintdlsymwas introduced for.Testing
No test.
x86_64-unknown-freebsdis Tier 2, and its only CI job is a Linux-hosted cross-compiledistbuild, so FreeBSD binaries never execute in CI regardless of what ships. #151132 and #153718 (the PR this repairs) both landed FreeBSDsysfixes without one.Fixes #158939
r? libs