NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
lib/59599: libc looses environment updates made during .so initialization
>Number: 59599
>Category: lib
>Synopsis: libc looses environment updates made during .so initialization
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: lib-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Fri Aug 15 23:20:00 +0000 2025
>Originator: Aliaksei Kandratsenka
>Release: 10.1
>Organization:
>Environment:
NetBSD netbsd10 10.1 NetBSD 10.1 (GENERIC) #0: Mon Dec 16 13:08:11 UTC 2024 mkrepro%mkrepro.NetBSD.org@localhost:/usr/src/sys/arch/amd64/compile/GENERIC amd64
>Description:
I am making a fix to gperftools for how it handles asking child processes to use distinct cpu profile files. Issue described here: https://github.com/gperftools/gperftools/issues/1603
The fix involves updating environ variable. And things work (on GNU/Linux and FreeBSD, at least). Except on NetBSD tests failed. Debugging this I found that some dynamic linker facility is actually overwriting environ variable (presumably back to what the kernel set) after shared library initializers have run.
Here is the disasm of the place that overwrites environ that I caught with some obvious gdb-ing:
Hardware watchpoint 4: *$29
Old value = (char **) 0x7cd789d09000
New value = (char **) 0x7f7fff51dca8
___start (cleanup=0x7f7f6f0067f6 <_rtld_exit>, ps_strings=0x7f7fff51efe0) at /usr/src/lib/csu/common/crt0-common.c:310
310 /usr/src/lib/csu/common/crt0-common.c: No such file or directory.
(gdb) bt
#0 ___start (cleanup=0x7f7f6f0067f6 <_rtld_exit>, ps_strings=0x7f7fff51efe0) at /usr/src/lib/csu/common/crt0-common.c:310
#1 0x00007f7f6f00baf8 in ?? () from /usr/libexec/ld.elf_so
#2 0x0000000000000003 in ?? ()
#3 0x00007f7fff51e258 in ?? ()
#4 0x00007f7fff51e28b in ?? ()
#5 0x00007f7fff51e28d in ?? ()
#6 0x0000000000000000 in ?? ()
(gdb) disas
Dump of assembler code for function ___start:
0x0000000000400ed1 <+0>: push %rbp
0x0000000000400ed2 <+1>: mov %rsp,%rbp
0x0000000000400ed5 <+4>: push %r14
0x0000000000400ed7 <+6>: push %r13
0x0000000000400ed9 <+8>: push %r12
0x0000000000400edb <+10>: push %rbx
0x0000000000400edc <+11>: mov %rdi,%r14
0x0000000000400edf <+14>: mov %rsi,%r12
0x0000000000400ee2 <+17>: mov 0x18(%rsi),%edx
0x0000000000400ee5 <+20>: mov 0x8(%rsi),%esi
0x0000000000400ee8 <+23>: mov (%r12),%rdi
0x0000000000400eec <+27>: call 0x400d82 <relocate_self>
0x0000000000400ef1 <+32>: mov $0x602648,%rax
0x0000000000400ef8 <+39>: mov %r12,(%rax)
0x0000000000400efb <+42>: mov $0x602680,%r13
0x0000000000400f02 <+49>: mov 0x10(%r12),%rax
0x0000000000400f07 <+54>: mov %rax,0x0(%r13)
=> 0x0000000000400f0b <+58>: mov (%r12),%rax
0x0000000000400f0f <+62>: mov (%rax),%rdx
0x0000000000400f12 <+65>: test %rdx,%rdx
0x0000000000400f15 <+68>: je 0x400fd4 <___start+259>
0x0000000000400f1b <+74>: mov $0x602340,%rcx
0x0000000000400f22 <+81>: mov %rdx,(%rcx)
0x0000000000400f25 <+84>: mov (%rax),%rax
0x0000000000400f28 <+87>: movzbl (%rax),%edx
0x0000000000400f2b <+90>: test %dl,%dl
0x0000000000400f2d <+92>: je 0x400f42 <___start+113>
>How-To-Repeat:
I prepared simple reproduction:
--- test-environ-so.c ---
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
extern char** environ;
#define CHECK(cond) do { if (!(cond)) { __builtin_trap(); } } while (0)
void verify_foobar();
static __attribute__((constructor))
void test_constructor() {
// first, ensure FOOBAR env. variable is missing
CHECK(getenv("FOOBAR") == NULL);
// now add it
/*
* setenv("FOOBAR", "1", 1);
*/
static char* new_env[] = {"FOOBAR=1", NULL};
environ = new_env;
verify_foobar();
printf("FOOBAR setup done\n");
}
void verify_foobar() {
char* fb = getenv("FOOBAR");
CHECK(fb != NULL);
CHECK(strcmp(fb, "1") == 0);
}
---
--- test-environ-main.c ---
#include <stdio.h>
extern void verify_foobar();
int main() {
printf("main started\n");
verify_foobar();
printf("foobar verified\n");
return 0;
}
---
Then build .so and main for example like this:
netbsd10# gcc -O2 -ggdb3 -fPIC -shared -Wl,-soname,libtest-environ.so.0 -o libtest-environ.so.0.0.1 test-environ-so.c
netbsd10# ln -s libtest-environ.so.0.0.1 libtest-environ.so.0
netbsd10# gcc -O2 -ggdb3 -o test-environ test-environ-main.c -Wl,-rpath,. libtest-environ.so.0.0.1
netbsd10# ldd ./test-environ
./test-environ:
-ltest-environ.0 => ./libtest-environ.so.0
-lc.12 => /usr/lib/libc.so.12
netbsd10# ./test-environ
FOOBAR setup done
main started
[1] Illegal instruction (core dumped) ./test-environ
>Fix:
Home |
Main Index |
Thread Index |
Old Index