fix(update): sanitise env before spawning installer#899
Open
edenfunf wants to merge 1 commit intomicrosoft:mainfrom
Open
fix(update): sanitise env before spawning installer#899edenfunf wants to merge 1 commit intomicrosoft:mainfrom
edenfunf wants to merge 1 commit intomicrosoft:mainfrom
Conversation
apm update inherits the PyInstaller bootloader's LD_LIBRARY_PATH when spawning the platform installer. The shell -- and the curl / tar / sudo calls install.sh makes -- then dlopens libssl.so.3 / libcrypto.so.3 from the bundle's _internal/ directory instead of the system ones. When the bundled libs are ABI-incompatible with what the system libcurl needs, curl aborts with "OPENSSL_3.2.0 not found" on the very first release fetch, blocking the upgrade path for every user on an affected distro (Debian trixie arm64 dev-containers, Fedora 43, and similar). Centralise PyInstaller env sanitisation in a new helper, apm_cli.utils.subprocess_env.external_process_env, which restores LD_LIBRARY_PATH / DYLD_LIBRARY_PATH / DYLD_FRAMEWORK_PATH from the <NAME>_ORIG snapshots that PyInstaller's bootloader saves at launch, or drops them entirely when no snapshot exists. The _ORIG keys are stripped from the returned env so PyInstaller internals do not leak to the child. Outside a frozen build and on Windows the helper is a no-op. apm update now calls subprocess.run with env=external_process_env() so the installer runs against the user's pre-launch environment. Restoring from _ORIG rather than blindly popping preserves legitimate user exports (CUDA, Nix, custom toolchains). Complements microsoft#466's build-side exclude: that fix stopped new binaries from shipping the offending libs; this fix stops them from being inherited by spawned children even when they are present in older binaries or in any future bundle that re-introduces a similar dependency. Closes microsoft#894
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
apm updateinherits the PyInstaller bootloader'sLD_LIBRARY_PATHwhen spawning the platform installer. The shell -- and thecurl/tar/sudocallsinstall.shmakes -- then dlopenslibssl.so.3/libcrypto.so.3from the bundle's_internal/directory instead of the system ones. When the bundled libs are ABI-incompatible with what the systemlibcurlneeds,curlaborts withOPENSSL_3.2.0 not foundon the very first release fetch, blocking the upgrade path for every user on an affected distro (Debian trixie arm64 dev-containers, Fedora 43, and similar).Fixes #894
Fix
New helper
apm_cli.utils.subprocess_env.external_process_envcentralises PyInstaller env sanitisation:LD_LIBRARY_PATH/DYLD_LIBRARY_PATH/DYLD_FRAMEWORK_PATHfrom the<NAME>_ORIGsnapshots that PyInstaller's bootloader saves at launch._ORIGsnapshot exists (no pre-launch value to restore)._ORIGkeys from the returned env so PyInstaller internals do not leak to the child.apm updatenow callssubprocess.runwithenv=external_process_env()so the installer runs against the user's pre-launch environment. Restoring from_ORIGrather than blindly popping preserves legitimate user exports (CUDA, Nix, custom toolchains).Complements #466's build-side exclude: that fix stopped new binaries from shipping the offending libs; this fix stops them from being inherited by spawned children even when they are present in older binaries or in any future bundle that re-introduces a similar dependency.
Type of change
Testing
Unit coverage
tests/unit/test_subprocess_env.py-- 11 tests locking in the helper contract: no-op when not frozen,_ORIGrestoration, drop when no_ORIG, DYLD variants, immutability of input mapping andos.environ, base-mapping precedence.tests/unit/test_update_command.py-- two regression guards asserting the installer is always spawned with an explicitenv=kwarg (Unix and Windows paths).Full unit suite: 5308 passed.
End-to-end reproduction on WSL Ubuntu 22.04
libssl.so.3/libcrypto.so.3in a fake_internal/dir.LD_LIBRARY_PATHpointed at that dir,curl https://api.github.com/...failed witherror while loading shared libraries: libssl.so.3: file too short-- the same dlopen-failure class as [BUG] apm update fails #894.sys.frozen=Trueplus the realexternal_process_env()applied to the subprocess env, the samecurlcall returnedhttp_code=200, while the main process still saw the pollutedLD_LIBRARY_PATH-- proving the helper does not mutate the live environment.curlstill fails -- confirming dev-environment behaviour is untouched.Note on upgrade path from pre-0.9.3 binaries
This fix takes effect from the next release onwards. Users already on an affected binary (0.8.5 or earlier in an environment whose system
libcurlneedsOPENSSL_3.2.0+) cannotapm updatetheir way out, because their running binary lacks the fix.install.shalready points such users at the pip fallback (pip install --user apm-cli), which is a one-time escape. From 0.9.3+ onwards,apm updateis immune to this bug class.