Package: bash Version: 5.0-6 Severity: normal Dear Maintainer,
When a library is ld-preloaded into the bash process, it can not set environment variables without loosing the whole environment. Whenever "setenv" is called, all other environment variables disappear and are only set again, when bash's main function executes. Before that the environment is lost. Moreover when the corresponding variable is set by both the ld-preload library and the external environment, the variable set by the external environment overrides the one by the ld-preload library in any case. Consider the following example: $ cat libldpreloadenv2.C #include <stdlib.h> #include <stdio.h> static struct EarlyInitializer { EarlyInitializer() { char *baz1 = getenv("baz"); printf("baz1: %s\n", baz1); setenv("foo", "bar", 1); char *baz2 = getenv("baz"); printf("baz2: %s\n", baz2); } } ei; $ g++ --shared -o libldpreloadenv2.so libldpreloadenv2.C $ baz=hi LD_PRELOAD=./libldpreloadenv2.so bash -c "printf 'Bash is ready\n'" baz1: hi baz2: (null) Bash is ready $ baz=hi LD_PRELOAD=./libldpreloadenv2.so bash -c "printf 'Bash is ready: %s\n' \"\$foo\"" baz1: hi baz2: (null) Bash is ready: bar $ foo=outer baz=hi LD_PRELOAD=./libldpreloadenv2.so bash -c "printf 'Bash is ready: %s\n' \"\$foo\"" baz1: hi baz2: (null) Bash is ready: outer two behaviors are wrong here: 1) that "baz" disappears when setting another environment variable 2) that the external environment wins in the last execution. The problem is caused by a hacky mechanism, bash uses to set its environment variables for library functions https://salsa.debian.org/debian/bash/-/blob/6a0146056618a32be35ba89e1b092eda2f2fa749/lib/sh/getenv.c#L50 However the internal structure for bash-variables (shell_variables) is not initialized yet. The getenv implementation from bash has a special case for that, to ask the "real" environment in this case: https://salsa.debian.org/debian/bash/-/blob/6a0146056618a32be35ba89e1b092eda2f2fa749/lib/sh/getenv.c#L72 However when setenv (or putenv) is called, the variable tables are initialized (empty) which seems to clear the environment until the real bash process is started: #0 create_variable_tables () at .././variables.c:321 #1 0x00005555555a3f4e in bind_variable (name=0x7ffff7fc9012 "foo", value=0x7ffff7fc900e "bar", flags=0) at .././variables.c:3230 #2 0x0000555555601da6 in setenv (name=0x7ffff7fc9012 "foo", value=0x7ffff7fc900e "bar", rewrite=1) at ../../.././lib/sh/getenv.c:178 #3 0x00007ffff7fc81c2 in EarlyInitializer::EarlyInitializer() () from ./libldpreloadenv2.so My suggestion to fix this bug would be to have a special case for putenv/setenv as well, that writes to the real (libc) environment, when shell_variables is not initialized yet, just as it is implemented for getenv. -- System Information: Debian Release: bullseye/sid APT prefers unstable-debug APT policy: (500, 'unstable-debug'), (500, 'unstable'), (500, 'stable'), (1, 'experimental-debug'), (1, 'experimental') Architecture: amd64 (x86_64) Foreign Architectures: i386 Kernel: Linux 5.6.0-1-amd64 (SMP w/8 CPU cores) Kernel taint flags: TAINT_PROPRIETARY_MODULE, TAINT_OOT_MODULE, TAINT_UNSIGNED_MODULE Locale: LANG=C.UTF-8, LC_CTYPE=C.UTF-8 (charmap=UTF-8), LANGUAGE=C.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Init: systemd (via /run/systemd/system) LSM: AppArmor: enabled Versions of packages bash depends on: ii base-files 11 ii debianutils 4.9.1 ii libc6 2.30-8 ii libtinfo6 6.2-1 Versions of packages bash recommends: ii bash-completion 1:2.10-1 Versions of packages bash suggests: pn bash-doc <none> -- no debconf information