Resolving the Correct Library: A Loader-Level Defense Solution Against Shared Object Hijacking
Source: arXiv:2605.26665 · Published 2026-05-26 · By Can Ozkan, Dave Singelee
TL;DR
This paper addresses the persistent security problem of shared library hijacking in Linux systems, including embedded Linux. Unlike traditional integrity violations that target library modifications, hijacking exploits dynamic loader resolution order semantics to load attacker-controlled, but valid and unmodified, libraries. Existing defenses fail to guarantee that the shared library actually loaded is the intended trusted one, creating a fundamental gap in loader-level security. The authors propose a novel loader-centric verification framework implemented on GNU libc that enforces authenticity guarantees for the resolved shared object identity. This is achieved by combining ELF Build-IDs (for stable artifact identity independent of file location) with cryptographic SHA-256 hashing for integrity, verified at load time through the dynamic loader's auditing interface. Their approach supports both path-based and Build-ID-based identity policies with manifest allowlists signed by Ed25519 keys, preventing substitution attacks that manipulate resolution precedence.
They implement and evaluate their design on general-purpose Linux (Ubuntu) and embedded Linux (Buildroot) under emulation, demonstrating effective prevention of hijacking attacks. Their enforcement covers all loader-resolved shared objects, including those loaded dynamically via dlopen() or system-level modules (e.g., NSS). The work identifies the root cause as a resolution authenticity problem and provides practical, deployable runtime verification that complements prior loader-hardening or integrity-only schemes. This fundamentally shifts defense focus from file-based integrity to correctness of dynamic linkage itself.
Key findings
- Neither loader hardening nor file-centric integrity mechanisms (e.g., IMA, EVM) ensure correct library resolution at runtime, allowing substitution attacks with valid shared objects.
- Build-ID combined with SHA-256 hashing enables unique, location-independent identification of shared objects, avoiding path fragility and SONAME ambiguity.
- The proposed LD_AUDIT-based enforcement terminates process execution immediately upon detection of a library not present or mismatched in the signed manifest.
- Their Build-ID-based enforcement rejects shared objects missing a Build-ID note, preventing bypass by stripped or non-standard binaries.
- The approach verifies every shared object loaded by the loader, including static dependencies (DT_NEEDED), dlopen()-loaded libraries, and system modules like glibc's NSS.
- Offline provisioning computes the allowlist manifest using ldd dependency closure supplemented by a helper script to capture runtime-loaded libraries, enabling flexible updates.
- Signing the manifest with Ed25519 and checking signatures at runtime secures the allowlist from tampering by adversaries without root privileges.
- Implementation on glibc shows practical feasibility on mainstream Linux and embedded Linux under emulation; full results on performance overhead or false positives are not detailed.
Threat model
The adversary is a user-space attacker who can manipulate dynamic loader resolution by inserting malicious shared objects with identical names in earlier searched paths or controlling environment variables like LD_LIBRARY_PATH. They cannot modify trusted libraries, the loader, or cryptographic verification components and have no elevated privileges such as root or kernel access. The adversary aims to substitute shared objects at runtime without tampering the original files, exploiting resolution semantics to hijack control flow.
Methodology — deep read
Threat Model & Assumptions: The adversary is a user-space attacker capable of manipulating library search order via environment variables (e.g., LD_LIBRARY_PATH), writable search directories, unsafe RPATH/RUNPATH configuration, or dlopen() calls, to place malicious ELF shared objects that export expected symbols. They cannot modify the original trusted libraries or the loader/verifier, do not have root/kernel privileges, and cannot compromise the public verification key or signing process. The approach assumes a trustworthy provisioning environment and kernel.
Data: Provisioning happens in a trusted environment where approved shared objects are enumerated, including transitive dependencies obtained through ldd. Since some libraries may be dynamically loaded at runtime (invisible statically), a helper script is used at runtime to discover new legitimate shared objects to update the allowlist manifest. Each shared object must contain an ELF Build-ID note for identity.
Architecture / Algorithm: The solution comprises a signed allowlist manifest mapping either canonical file paths or ELF Build-IDs to SHA-256 hashes of the shared object bytes. At load time, the dynamic loader invokes an LD_AUDIT auditing module that intercepts all shared object loads, extracts the Build-ID from the ELF note section, computes the SHA-256 hash of the file on disk, and verifies both against the manifest. Verification failure (missing entry or hash mismatch) causes immediate process termination.
Training / Implementation: Not applicable (defense mechanism, not ML). Implementation is on GNU libc’s dynamic loader using the LD_AUDIT interface. The Ed25519 keys for manifest signing are generated during provisioning. Cryptography uses standard OpenSSL Ed25519 support. Hashing reads the file in streaming chunks to compute persistent SHA-256 digests.
Evaluation Protocol: Evaluations occur on simulated environments: Ubuntu and embedded Linux (Buildroot) under emulation. Tests demonstrate successful prevention of common hijacking attack patterns via manipulated environment variables or injected libraries. The verifier correctly terminates processes when unauthorized libraries are loaded. Detailed performance overhead metrics or false positive rates are not explicitly reported. The evaluation includes coverage of libraries loaded dynamically via dlopen() and system modules like NSS.
Reproducibility: The paper describes a prototype implementation and offline helper tools for manifest generation and signing. It is not explicitly stated whether code or artifacts are publicly released. The approach relies on standard ELF toolchain features (Build-ID) and glibc dynamic loader hooks, facilitating reproduction on similar Linux systems.
Concrete example end-to-end: In provisioning, each approved shared object is checked for a Build-ID ELF note; its Build-ID extracted and SHA-256 hash computed. The manifest file listing Build-ID and hash pairs is signed with an Ed25519 private key. At runtime, when the loader maps a shared object, the audit module extracts the Build-ID, hashes the file, and queries the manifest loaded and verified by signature. If the pair is absent or the hash mismatches, the process terminates immediately to prevent execution of attacker-controlled code.
Technical innovations
- Binding shared library identity to ELF Build-IDs combined with cryptographic hashes to enforce resolution authenticity independent of filesystem path or SONAME.
- Runtime verification of resolved shared objects at the dynamic loader level using the LD_AUDIT interface in glibc, enabling load-time enforcement of correctness guarantees.
- A cryptographically signed allowlist manifest that enumerates authorized Build-ID and hash pairs, preventing unauthorized substitution even when libraries are unmodified ELF binaries.
- Inclusion of dynamically loaded libraries (e.g., dlopen(), NSS modules) in verification by integrating runtime discovery with offline provisioning manifest updates.
Baselines vs proposed
- IMA (Linux Integrity Measurement Architecture): ensures file integrity but cannot detect substitution of different valid libraries with the same name (no Build-ID verification).
- Control-Flow Integrity (SCC, SecGOT): protects indirect calls assuming correct libraries loaded, but cannot prevent hijacking via resolution manipulation.
- TRuE loader hardening: restricts environment influence but does not verify the final resolved library identity.
- Proposed method: immediate process termination upon load of unauthorized shared object based on Build-ID + SHA-256 manifest verification.
Figures from the paper
Figures are reproduced from the source paper for academic discussion. Original copyright: the paper authors. See arXiv:2605.26665.

Fig 1: Proposed offline provisioning and online runtime enforcement workflow

Fig 2: Steps for case studies
Limitations
- The threat model excludes attackers with root/kernel or provisioning environment compromise; supply chain attacks that introduce malicious signed libraries are not addressed.
- Manifest generation relies on static dependency closure and helper scripts for runtime libraries; unseen or new legitimate libraries could cause false positives.
- No detailed analysis or benchmarking of runtime performance overhead caused by hashing and verification on resource-constrained embedded systems is reported.
- The approach mandates all protected shared objects embed Build-IDs; binaries lacking Build-IDs are rejected, which may limit compatibility with legacy or non-standard artifacts.
- The implementation currently targets glibc via LD_AUDIT; applicability to other loaders such as musl or non-glibc environments is suggested but not demonstrated.
- No explicit tests of robustness against complex adversarial evasion tactics such as race conditions or time-of-check to time-of-use (TOCTOU) attacks during verification.
Open questions / follow-ons
- What is the runtime performance impact and memory overhead of hashing and checking each loaded shared object, especially on embedded or low-resource devices?
- How to efficiently support updates or extensions to the manifest in dynamic or containerized environments without manual re-provisioning?
- Can similar loader-centric verification be generalized or adapted for other dynamic linkers (e.g., musl) and non-ELF platforms?
- How resilient is the approach to more sophisticated attacks exploiting TOCTOU windows or loader race conditions during verification?
Why it matters for bot defense
This work provides a fundamentally new angle on defending Linux systems against malicious code injection by focusing on the resolution phase of dynamic linking, which is often overlooked in bot-defense and CAPTCHA contexts that rely on process integrity guarantees. Bot and automation defense engineers can leverage these insights to enhance endpoint integrity by verifying that loaded libraries are not only untampered but also correctly resolved. This helps prevent subversion of automated or trusted processes by attacker-controlled libraries masquerading as legitimate ones.
Applying such loader-level verification mechanisms can significantly raise the bar for attackers attempting to execute arbitrary code through shared library hijacking as part of automated or bot attacks, complementing existing sandboxing and runtime monitoring solutions. However, deployment considerations include build-toolchain integration to ensure Build-ID presence and routine manifest updates accounting for dynamic dependencies. Overall, this approach strengthens the base trust assumptions in Linux native-code execution environments relevant to security-sensitive automation.
Cite
@article{arxiv2605_26665,
title={ Resolving the Correct Library: A Loader-Level Defense Solution Against Shared Object Hijacking },
author={ Can Ozkan and Dave Singelee },
journal={arXiv preprint arXiv:2605.26665},
year={ 2026 },
url={https://arxiv.org/abs/2605.26665}
}