You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
cross-libc-dlopen.so causes all chromium browsers to crash only in aarch64 #37
[0913/020816.280558:ERROR:third_party/crashpad/crashpad/snapshot/elf/elf_image_reader.cc:678] no dynamic segment
[0913/020817.310426:ERROR:third_party/crashpad/crashpad/snapshot/elf/elf_image_reader.cc:678] no dynamic segment
[0913/020817.404312:ERROR:third_party/crashpad/crashpad/snapshot/elf/elf_image_reader.cc:678] no dynamic segment
[0913/020817.465165:ERROR:third_party/crashpad/crashpad/snapshot/elf/elf_image_reader.cc:678] no dynamic segment
[0913/020817.495398:ERROR:third_party/crashpad/crashpad/snapshot/elf/elf_image_reader.cc:678] no dynamic segment
[1910:1910:0913/020817.639103:ERROR:content/browser/gpu/gpu_process_host.cc:1035] GPU process exited unexpectedly: exit_code=139
[0913/020817.648193:ERROR:third_party/crashpad/crashpad/snapshot/elf/elf_image_reader.cc:678] no dynamic segment
[0913/020817.984770:ERROR:third_party/crashpad/crashpad/snapshot/elf/elf_image_reader.cc:678] no dynamic segment
[1910:1910:0913/020818.158415:ERROR:content/browser/gpu/gpu_process_host.cc:1035] GPU process exited unexpectedly: exit_code=139
[0913/020818.178972:ERROR:third_party/crashpad/crashpad/snapshot/elf/elf_image_reader.cc:678] no dynamic segment
[0913/020826.840667:ERROR:third_party/crashpad/crashpad/util/linux/scoped_ptrace_attach.cc:27] ptrace: No such process (3)
[0913/020826.841307:ERROR:third_party/crashpad/crashpad/util/file/directory_reader_posix.cc:43] opendir /proc/2067/task: No such file or directory (2)
[0913/020826.844244:ERROR:third_party/crashpad/crashpad/util/linux/scoped_ptrace_attach.cc:27] ptrace: No such process (3)
[0913/020826.844367:ERROR:third_party/crashpad/crashpad/util/file/directory_reader_posix.cc:43] opendir /proc/2068/task: No such file or directory (2)
[0913/020826.852271:ERROR:third_party/crashpad/crashpad/snapshot/elf/elf_image_reader.cc:678] no dynamic segment
[1910:1910:0913/020827.113185:ERROR:content/browser/gpu/gpu_process_host.cc:1035] GPU process exited unexpectedly: exit_code=139
[0913/020828.033634:ERROR:third_party/crashpad/crashpad/snapshot/elf/elf_image_reader.cc:678] no dynamic segment
[0913/020829.004293:ERROR:third_party/crashpad/crashpad/snapshot/elf/elf_image_reader.cc:678] no dynamic segment
[1910:1910:0913/020829.465819:ERROR:content/browser/gpu/gpu_process_host.cc:1035] GPU process exited unexpectedly: exit_code=139
[0913/020829.494239:ERROR:third_party/crashpad/crashpad/snapshot/elf/elf_image_reader.cc:678] no dynamic segment
[0913/020829.981306:ERROR:third_party/crashpad/crashpad/snapshot/elf/elf_image_reader.cc:678] no dynamic segment
[1910:1910:0913/020830.408698:ERROR:content/browser/gpu/gpu_process_host.cc:1035] GPU process exited unexpectedly: exit_code=139
[0913/020830.902519:ERROR:third_party/crashpad/crashpad/snapshot/elf/elf_image_reader.cc:678] no dynamic segment
[1910:1910:0913/020831.387566:ERROR:content/browser/gpu/gpu_process_host.cc:1035] GPU process exited unexpectedly: exit_code=139
[1910:1910:0913/020831.387711:FATAL:content/browser/gpu/gpu_data_manager_impl_private.cc:417] GPU process isn't usable. Goodbye.
[0913/020831.400345:ERROR:third_party/crashpad/crashpad/snapshot/elf/elf_image_reader.cc:678] no dynamic segment
[0913/020831.449152:ERROR:third_party/crashpad/crashpad/snapshot/elf/elf_image_reader.cc:678] no dynamic segment
xiaomi-beryllium:/run/media/link/00a99c68-cbb9-4703-9a16-a745323da3dc$
Root cause found and measured: the generated forward shim exports a strong __stack_chk_guard, and on aarch64 that name is the process-wide stack canary owned by ld-linux. Preloading cross-libc-dlopen.so therefore interposes the canary itself, which kills chromium's GPU process (SIGSEGV, exit_code=139) independently of the dlopen hook.
The defect
The shipped aarch64 artefact exports the name as a strong function stub:
Section 11 is .text: this is shim_stub___stack_chk_guard from src/forward-shim.c, emitted because src/forward-shim-manifest.json classifies the name as stub-only: no audited implementation.
On aarch64 the name is not shim-only. glibc keeps the stack canary in thread-pointer storage only where THREAD_SET_STACK_GUARD exists (x86, x86-64, and friends, where the symbol is never exported). On aarch64 the canary is a global object exported by the loader and written by security_init():
ld-linux-aarch64.so.1: 8 OBJECT GLOBAL DEFAULT __stack_chk_guard@@GLIBC_2.17
libc.so.6 (aarch64): UND __stack_chk_guard@GLIBC_2.17, R_AARCH64_GLOB_DAT
glibc's lookup accepts an unversioned definition for a versioned reference (the interposition case in check_match), so once the preload is in scope every __stack_chk_guard GOT slot in the process, libc's own included, binds to the stub in the preload's read-only .text instead of the object the loader initializes. Canary values then disagree across the process, and the GPU process dies before any cross-libc logic runs. On x86-64 nothing references the name, which is why the x86_64 artefact is unaffected and why only aarch64 regressed.
Measurements
Real aarch64 silicon (ubuntu-24.04-arm), Helium 0.17.0.1 anylinux build, run twice against the packaged AppImage under xvfb:
preload present, CROSS_LIBC_DLOPEN=0: 6 x GPU process exited unexpectedly: exit_code=139
preload present, default mode: the same 6 crashes
The mode switch only disables the dlopen hook; the canary interposition happens at relocation time, so it changes nothing. Removing the preload stops the crash (the debug branch in Helium PR Record the merge, and why the release tag was not pushed #10).
The same build on x86_64: 0 GPU crashes in both arms.
The symbol has been exported by every aarch64 artefact since at least v0.2.0 (readelf above shows the same entry in the v0.2.0 download). This matches the CI record: every chromium --test on aarch64 with the preload present has failed (Helium, Brave-Origin, Chrome, 2026-09-12), and the only passing chromium runs use --simple-test, which never initializes GL.
Generator root cause: tools/gen_forward_shim.py decides FUNC versus OBJECT from target.get("kinds"), the x86-derived glibc inventory where the symbol is absent, instead of the merged kinds it builds from inventories/musl-1.2.5.json, where __stack_chk_guard is an 8-byte OBJECT. A function stub is emitted for what must be data.
Why the in-repo aarch64 gates stayed green: the evidence probes are small and self-consistent canary reads do not fault, and the wide appimage suite has failed at its extraction step since late August, so no real aarch64 application run covered this.
Not yet captured: the exact faulting instruction inside the crashed child (the run produced no crashpad dumps; a gdb run with --in-process-gpu is the next measurement). The causal chain above is established by the A/B, not by the backtrace.
Proposed fix
Primary: never emit __stack_chk_guard from the shim, and exclude loader-owned data generally. On global-guard architectures ld-linux supplies the real object. Weak or zero-data definitions would still interpose and would silently zero the process canary, so exclusion is the clean fix, not retyping.
Defence in depth: emit stubs from the merged kinds so musl OBJECT symbols become data, not functions.
Add a per-architecture collision gate: after each build, assert the artefact's exported dynamic symbols do not collide with the target libc.so.6/ld-linux exports. The current stale-shim guard compares only against the x86 floor inventory, where the symbol does not exist.
Measure riscv64 and loongarch64 artefacts the same way before their next consumer: they are global-guard architectures too and ship from the same manifest.
Activity
Link4Electronics commentedon Sep 13, 2026
https://github.com/pkgforge-dev/Ungoogled-Chromium-AppImage aarch64 build
talaria0101 commentedon Sep 13, 2026
Root cause found and measured: the generated forward shim exports a strong
__stack_chk_guard, and on aarch64 that name is the process-wide stack canary owned byld-linux. Preloadingcross-libc-dlopen.sotherefore interposes the canary itself, which kills chromium's GPU process (SIGSEGV,exit_code=139) independently of thedlopenhook.The defect
The shipped aarch64 artefact exports the name as a strong function stub:
Section 11 is
.text: this isshim_stub___stack_chk_guardfromsrc/forward-shim.c, emitted becausesrc/forward-shim-manifest.jsonclassifies the name asstub-only: no audited implementation.On aarch64 the name is not shim-only. glibc keeps the stack canary in thread-pointer storage only where
THREAD_SET_STACK_GUARDexists (x86, x86-64, and friends, where the symbol is never exported). On aarch64 the canary is a global object exported by the loader and written bysecurity_init():glibc's lookup accepts an unversioned definition for a versioned reference (the interposition case in
check_match), so once the preload is in scope every__stack_chk_guardGOT slot in the process, libc's own included, binds to the stub in the preload's read-only.textinstead of the object the loader initializes. Canary values then disagree across the process, and the GPU process dies before any cross-libc logic runs. On x86-64 nothing references the name, which is why the x86_64 artefact is unaffected and why only aarch64 regressed.Measurements
Real aarch64 silicon (ubuntu-24.04-arm), Helium 0.17.0.1 anylinux build, run twice against the packaged AppImage under xvfb:
CROSS_LIBC_DLOPEN=0: 6 xGPU process exited unexpectedly: exit_code=139The mode switch only disables the dlopen hook; the canary interposition happens at relocation time, so it changes nothing. Removing the preload stops the crash (the debug branch in Helium PR Record the merge, and why the release tag was not pushed #10).
The same build on x86_64: 0 GPU crashes in both arms.
The symbol has been exported by every aarch64 artefact since at least v0.2.0 (
readelfabove shows the same entry in the v0.2.0 download). This matches the CI record: every chromium--teston aarch64 with the preload present has failed (Helium, Brave-Origin, Chrome, 2026-09-12), and the only passing chromium runs use--simple-test, which never initializes GL.Generator root cause:
tools/gen_forward_shim.pydecides FUNC versus OBJECT fromtarget.get("kinds"), the x86-derived glibc inventory where the symbol is absent, instead of the merged kinds it builds frominventories/musl-1.2.5.json, where__stack_chk_guardis an 8-byte OBJECT. A function stub is emitted for what must be data.Why the in-repo aarch64 gates stayed green: the evidence probes are small and self-consistent canary reads do not fault, and the wide appimage suite has failed at its extraction step since late August, so no real aarch64 application run covered this.
Not yet captured: the exact faulting instruction inside the crashed child (the run produced no crashpad dumps; a gdb run with
--in-process-gpuis the next measurement). The causal chain above is established by the A/B, not by the backtrace.Proposed fix
__stack_chk_guardfrom the shim, and exclude loader-owned data generally. On global-guard architecturesld-linuxsupplies the real object. Weak or zero-data definitions would still interpose and would silently zero the process canary, so exclusion is the clean fix, not retyping.libc.so.6/ld-linuxexports. The current stale-shim guard compares only against the x86 floor inventory, where the symbol does not exist.Evidence logs: https://github.com/talaria0101/Helium-Browser-AppImage-Enhanced/actions/runs/34740952842 (fork, workflow patched only to keep failing artefacts and add the instrumented run).