Skip to content

Keep the guest's environ and musl's in step - #9

Open
buyemune-sys wants to merge 2 commits into
pg83:mainfrom
buyemune-sys:fix/environ-copy-relocation
Open

buyemune-sys wants to merge 2 commits into
pg83:mainfrom
buyemune-sys:fix/environ-copy-relocation

Conversation

@buyemune-sys

@buyemune-sys buyemune-sys commented Oct 17, 2026 •

Copy link
Copy Markdown

The problem

A glibc executable that touches environ carries a COPY relocation for it: the executable's .bss holds its own copy of the pointer. solo copies musl's environ value into it once (SH_OBJECT("environ", …), lib/glibc_shim.cpp:4991). From then on there are two variables: the guest reads and writes its own, while musl's getenv/setenv/system/popen use musl's.

As long as the guest leaves environ alone, nothing shows. But setproctitle implementations (nginx, postgres, Tarantool and others) repoint environ to a heap copy and overwrite the original string area with the process title. musl then reads overwritten memory.

Example, in Tarantool after box.cfg{} under solo run:

os.getenv('HOME')   -- nil (natively: /home/...)

Child processes get a garbage environment as well.

The fix

This follows the existing optind/optarg synchronization around getopt (lib/glibc_shim.cpp:1557). Before getenv, setenv, unsetenv, putenv, clearenv, execvp, system, popen and tzset, the bridge pulls the guest's pointer into musl; after the calls that may reallocate the environment, it pushes musl's value back. The guest's copy is looked up as environ or __environ through ElfImage::lookupGlobal. Only a successful lookup is cached, so the library-only case (no guest executable) behaves as before: musl's variable is the ABI.

All of these names are added to overrideNames; otherwise resolution would find musl's functions first.

Test

The guest repoints environ to its own array {"SOLO_GUEST_ENV=repointed", 0} and reads it back through getenv. Needle: guest environ repointed=repointed.

  • on main: guest environ repointed=smoke-value. It already fails on the PIE guest, because this toolchain emits a COPY relocation for PIE too;
  • with the fix: ./build test passes.

buyemune-sys and others added 2 commits October 20, 2026 15:42
Security updates replaced libapparmor1 4.0.1really4.0.1-0ubuntu0.24.04.7
with .9 and libexpat1 2.6.1-2ubuntu0.4 with ubuntu0.6, and the pool kept
only the new files, so the cold-cache Fetch x86_64 job answers 404 and
every x86-64 job behind it is skipped. Both pins move to the versions
noble-updates ships now; their SHA256s match the archive's Packages index.
The other twelve pins are still served.
A glibc executable that touches environ carries a COPY relocation for
it, so the guest reads and writes its own copy while musl's getenv,
setenv, system and friends keep using musl's variable. Repointing environ
— which setproctitle implementations do, moving the environment to the
heap and overwriting the original strings with the title — then left
musl reading clobbered memory: after Tarantool's box.cfg, os.getenv
returned nothing and children started with a garbage environment.

The environment entry points now pull the guest's pointer into musl
before each call and push musl's back after the calls that may
reallocate it, the way the getopt wrappers already shuttle optind.

The guest test repoints environ and reads it back through getenv.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@buyemune-sys
buyemune-sys force-pushed the fix/environ-copy-relocation branch from 8dfa199 to bc03d22 Compare October 20, 2026 08:11
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.

1 participant