Hubbry Logo
Ldd (Unix)Ldd (Unix)Main
Open search
Ldd (Unix)
Community hub
Ldd (Unix)
logo
7 pages, 0 posts
0 subscribers
Be the first to start a discussion here.
Be the first to start a discussion here.
Ldd (Unix)
Ldd (Unix)
from Wikipedia

ldd (List Dynamic Dependencies) is a *nix utility that prints the shared libraries required by each program or shared library specified on the command line.[1] It was developed by Roland McGrath and Ulrich Drepper.[2] If some shared library is missing for any program, that program won't come up.

Security

[edit]

ldd is a shell script that executes the program given as argument, and shouldn't be used with untrusted binaries. The ldd manual page suggests to use the following command using the objdump and grep utilities as alternative:[3]

user@home ~/ $ objdump -p /path/program | grep NEEDED

Usage examples

[edit]
user@home ~/ $ ldd /usr/bin/mp3blaster
        linux-vdso.so.1 =>  (0x00007fff8fdff000)
        libsidplay.so.1 => /usr/lib/libsidplay.so.1 (0x00007f4ea98ec000)
        libvorbisfile.so.3 => /usr/lib/libvorbisfile.so.3 (0x00007f4ea96e4000)
        libvorbis.so.0 => /usr/lib/libvorbis.so.0 (0x00007f4ea94b6000)
        libncurses.so.5 => /lib/libncurses.so.5 (0x00007f4ea9273000)
        libpthread.so.0 => /lib/libpthread.so.0 (0x00007f4ea9056000)
        libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f4ea8d41000)
        libm.so.6 => /lib/libm.so.6 (0x00007f4ea8abe000)
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00007f4ea88a7000)
        libc.so.6 => /lib/libc.so.6 (0x00007f4ea8523000)
        libogg.so.0 => /usr/lib/libogg.so.0 (0x00007f4ea831c000)
        libdl.so.2 => /lib/libdl.so.2 (0x00007f4ea8118000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f4ea9b59000)
user@home ~/ $ ldd /usr/lib/i386-linux-gnu/libstdc++.so.6.0.20
        linux-gate.so.1 (0xb7733000)
        libm.so.6 => /lib/i386-linux-gnu/i686/cmov/libm.so.6 (0xb75da000)
        libc.so.6 => /lib/i386-linux-gnu/i686/cmov/libc.so.6 (0xb742f000)
        /lib/ld-linux.so.2 (0xb7734000)
        libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0xb7411000)

References

[edit]
Revisions and contributorsEdit on WikipediaRead on Wikipedia
from Grokipedia
ldd is a command-line utility available in Unix-like operating systems, including Linux, FreeBSD, and Solaris, that displays the shared library dependencies required by an executable file or shared object. It operates by invoking the system's dynamic linker—such as ld.so on Linux or rtld on FreeBSD—to trace and list the loaded shared objects, including their paths and memory addresses, without fully executing the target program. This tool is essential for debugging linkage issues, verifying library dependencies, and optimizing software deployment in environments relying on dynamic linking. The command originated in 4.0 and has been adapted across various Unix variants, with implementations that may differ in options and behavior. For instance, on , ldd sets the environment variable LD_TRACE_LOADED_OBJECTS=1 to enable tracing and supports options like --verbose for symbol versioning details or --unused to identify unneeded libraries. In , it uses format strings via -f for customized output and includes an -a flag to show all indirect dependencies. Solaris versions provide extensive flags, such as -r for checking relocations or -U for unreferenced dependencies, emphasizing analysis of lazy and deferred bindings. Despite these variations, the core purpose remains consistent: to resolve and report the full dependency tree at runtime. A key consideration with ldd is its potential to execute arbitrary if run on untrusted binaries, as it launches the on the target file; safer alternatives include using objdump to inspect needed libraries statically. It does not support older formats like a.out shared libraries and may fail unpredictably on certain legacy executables. For running processes, related tools like pldd provide dependency information without the risks associated with ldd. Overall, ldd facilitates efficient management of dynamic linking, a foundational aspect of modern Unix .

Overview

Purpose

ldd is a command-line utility in Unix-like operating systems that displays the shared libraries, or dynamic dependencies, required by a specified executable file or shared object. This tool examines the binary's dependency information to list libraries such as libc.so and libm.so, along with their resolved paths in the filesystem. The primary role of ldd is to assist in debugging linking issues by revealing potential problems like missing libraries or incorrect resolutions. It simulates the dynamic linking process performed by the runtime linker, such as ld.so, to report dependencies as they would be loaded during program execution. However, while it avoids executing the main program code, ldd invokes the dynamic linker on the target file, which can pose security risks when inspecting untrusted binaries; safer static alternatives like objdump are recommended for such cases. ldd reports only dynamic dependencies and provides no information for statically linked executables. It enables developers and system administrators to verify library usage, ensuring that all necessary components are available for runtime execution. Furthermore, ldd provides insights into an application's runtime requirements, aiding in tasks such as packaging, deployment, and cross-platform compatibility assessments. ldd debuted in SunOS 4.0 in 1988 alongside support for dynamic linking and has since been adapted for various object file formats, including ELF, which became standard in SVR4 during the early 1990s.

History and Availability

The ldd utility traces its origins to the late 1980s, coinciding with the advent of dynamic linking in Unix systems. Dynamic shared libraries were introduced in SunOS 4.0 in late 1988, and ldd debuted alongside this feature to list dependencies via the runtime linker. Similar capabilities emerged in SVR4 Unix around 1989, where the runtime linker provided diagnostics for shared library dependencies, predating Linux-specific implementations. In , ldd appeared in early distributions around 1992 as part of the GNU C Library (), enabling developers to inspect dynamic dependencies in the burgeoning ecosystem. Its implementation evolved distinctly across platforms: on , it is a in /usr/bin/ldd that sets the LD_TRACE_LOADED_OBJECTS to trace library loading without executing the target fully. In contrast, BSD variants like , , and implement ldd as a compiled binary for efficiency. Variations persist in systems such as Solaris (using ld.so.1 for diagnostics) and AIX (focused on XCOFF dependencies). ldd is widely available on Unix-like systems, including (via ), , , , Solaris, AIX, and . On macOS, equivalent functionality is offered by otool -L, which displays dynamic library dependencies. It is not native to Windows but can be emulated using Cygwin's ldd, which invokes the Windows loader for DLL analysis. The underlying dynamic linking diagnostics were standardized in POSIX.1-2008 via interfaces like dlopen and dlsym, though ldd as a specific command is not required by the standard. As of November 2025, ldd's core functionality remains consistent across major distributions, such as 24.04 and 43, with no significant changes to its dependency-listing behavior.

Operation

How It Works

The ldd utility operates by invoking the system's dynamic linker/loader, such as ld-linux.so on Linux systems, to simulate the library loading process without executing the target program. Specifically, ldd is implemented as a shell script that sets the environment variable LD_TRACE_LOADED_OBJECTS=1 and passes the target executable or shared object as an argument to the dynamic linker. This variable instructs the linker to trace and report the shared libraries it loads, printing their resolved paths to standard output while halting before transferring control to the program. On Linux, the linker (ld-linux.so) is itself a shared object typically located in /lib or /lib64, and ldd ensures it uses the appropriate architecture-specific version. The process begins with the parsing the (ELF) file of the target object to access its dynamic section. It examines the DT_NEEDED entries, which are tags listing the names of required shared libraries as strings. Next, the linker resolves these dependencies by searching for the libraries according to its standard algorithm: first checking the RPATH or RUNPATH embedded in the ELF file, then the directories specified in the LD_LIBRARY_PATH (if set), followed by paths in /etc/ld.so.conf (and its included files), and finally default system paths like /lib and /usr/lib. If a library is found, its full path is reported; otherwise, ldd indicates that the dependency is not found, potentially due to version mismatches or absent installations. This resolution handles recursive dependencies by iteratively applying the search algorithm to each newly identified , ensuring all transitive dependencies are traced and listed. The linker supports versioned libraries, such as libc.so.6, by matching the (shared object name) specified in DT_NEEDED against available versions in the search paths, prioritizing the highest compatible version. On non-Linux systems, such as , ldd similarly invokes the runtime linker (rtld) with tracing enabled via LD_TRACE_LOADED_OBJECTS=1, producing output that includes resolved library paths and, in verbose modes, load addresses in memory. This approach maintains portability across systems using ELF, though the exact linker binary and configuration files may vary (e.g., FreeBSD uses /etc/libmap.conf for additional path mapping). Unlike static analysis tools such as [objdump](/page/Objdump), which merely extract and display the raw DT_NEEDED tags from the ELF dynamic section without resolution, ldd performs a runtime-like to verify actual availability and paths based on the current environment. This dynamic resolution can reveal issues like missing libraries or path conflicts that static inspection overlooks.

Syntax and Options

The basic syntax of the ldd command is ldd [options] file..., where each file argument specifies an program or (typically a .so file) whose dynamic dependencies are to be examined. The command supports multiple files, processing them sequentially and reporting dependencies for each. If a specified file is not a dynamic —such as a static binary or non-ELF object—ldd issues an , for example, "not a dynamic executable". On systems using (), several standard options provide additional control over the output and analysis. The -v or --verbose option enables detailed output, including versioning details for each dependency. The -u or --unused option lists unused direct dependencies, helping identify superfluous libraries (available since 2.3.4). For relocation checking, -d or --data-relocs performs data relocations and reports any missing objects ( files only), while -r or --function-relocs extends this to function relocations as well. Additionally, --version prints the version of ldd itself, and --help displays usage information. The output format of ldd generally consists of lines showing each required in the form library.so => /full/path/to/library.so (0xload_address), where the load address is a memory location; unresolved libraries appear as library.so => not found. Options vary significantly across platforms due to differences in dynamic linking implementations. On , the command offers limited flags: -a to list all objects needed by each loaded object (including indirect ones), and -f format (usable up to twice) to customize the output using format strings defined by the runtime linker rtld. Solaris provides a broader set, including -d to verify immediate ( ) references, -r to check both immediate and lazy references, -U to identify unreferenced dependencies, and -u to show unused objects, along with options like -v for verbose dependency and version details. In contrast, AIX's ldd accepts no options and simply lists dependencies for valid XCOFF executables or libraries, outputting paths prefixed with "needs:". provides options such as -d for relocations, -r for function relocations, -u for unused dependencies, -v for verbose output, and -V for the version, producing a list of required shared objects with paths and load addresses.

Security Considerations

Potential Risks

The primary security risk associated with the ldd utility stems from its reliance on the to inspect dependencies, which can partially execute the target binary. When ldd invokes the (typically ld.so) with the LD_TRACE_LOADED_OBJECTS=1 set, the linker loads the binary and its libraries into memory, potentially triggering initialization routines in the .init and .fini sections of the or shared objects. These constructors execute code automatically upon loading, allowing malicious binaries to run arbitrary instructions, such as those designed to exploit or perform unauthorized actions. Historical vulnerabilities have highlighted these dangers, notably CVE-2009-5064 (disputed by the glibc project) in versions before 2.27, where the upstream ldd script could execute the target program directly without preventing code execution. This issue was addressed in 2.27 by modifying the ldd script to invoke the dynamic linker properly and avoid direct program execution. Unlike purely static analysis tools like [objdump](/page/Objdump), ldd can induce side effects during dependency resolution, including file system accesses for library paths, potential network connections if libraries initiate them, or even privilege escalation when run with elevated permissions like root. If the LD_PRELOAD environment variable is set to point to a malicious library, the dynamic linker's loading process during ldd execution may incorporate it, amplifying the risk of code injection before tracing begins. As of November 2025, while implementations from version 2.27 onward incorporate safer invocation methods to avoid full program execution, the utility remains inherently risky for untrusted files, particularly on legacy systems predating these patches, where direct binary execution or unmitigated constructor runs are possible. Recent vulnerabilities, such as CVE-2025-4802 in 2.27 to 2.38, further underscore risks from manipulated environment variables like LD_LIBRARY_PATH in scenarios. The official manual explicitly advises against using ldd on untrusted executables due to the persistent potential for .

Mitigation Strategies

To mitigate the security risks associated with using ldd, which executes the target binary to trace its dynamic library dependencies, it is recommended to run the command as a non-root user whenever possible. This practice limits the potential damage from any malicious code triggered during execution, as the process lacks elevated privileges to access sensitive system resources or escalate attacks. For enhanced isolation, employ environments or containerization tools such as Docker to confine the execution of ldd on untrusted binaries. changes the apparent root directory for the process, restricting access to only the specified filesystem subset, while Docker provides additional layers of namespace isolation, preventing the binary from interacting with the host system beyond controlled boundaries. These methods ensure that any anomalous actions during library loading are contained without broader system impact. Alternative safe modes include setting the LD_BIND_NOW=1 environment variable before invoking ldd, which forces the dynamic linker to resolve all symbols immediately rather than using lazy binding. This reduces the window for exploits that manipulate unresolved symbols during runtime, enhancing security without altering the tool's core functionality. Additionally, the dynamic linker's --verify option—invoked directly via /lib64/ld-linux-x86-64.so.2 --verify <binary>—can check if a binary is dynamically linked and compatible without full execution or listing dependencies, serving as a preliminary validation step. As a non-executing alternative, use static analyzers like readelf -d from the binutils package to inspect the ELF dynamic section and extract DT_NEEDED entries, which list required shared libraries without running the binary. For deeper auditing prior to ldd usage, tools such as Valgrind (for memory and execution tracing) or strace (for system call monitoring) can be applied in a controlled environment to profile the binary's behavior, identifying potential issues like unexpected file accesses or injections. On systems supporting mandatory access controls, enforce SELinux or policies to restrict actions initiated by ldd-executed processes, such as blocking unauthorized file reads, network connections, or privilege transitions. For instance, SELinux targeted policies can confine the dynamic linker's domain to prevent escalation, while profiles limit path access for specific binaries. Complement these with regular updates to and ld.so, which patch known vulnerabilities like CVE-2023-4911 (Looney Tunables) and CVE-2025-4802 that could be exploited via dynamic loading mechanisms used by ldd. For ongoing monitoring, integrate ldd runs with auditd, the Linux Audit Daemon, to log system calls and detect anomalous behavior such as unexpected opens or executes during dependency resolution. Auditd rules targeting execve or openat events for the dynamic linker can flag deviations, enabling forensic analysis and rapid response to potential compromises.

Practical Usage

Basic Examples

One common basic use of the ldd command is to examine the shared library dependencies of a standard executable, such as /bin/ls, which helps identify the core system libraries required for its operation. For example, running ldd /bin/ls on a typical system might produce output similar to the following:

linux-vdso.so.1 (0x00007ffcc3563000) libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f24ed8b5000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f24ed4c4000) libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f24ed252000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f24ed04e000) /lib64/ld-linux-x86-64.so.2 (0x00007f24edaf7000)

linux-vdso.so.1 (0x00007ffcc3563000) libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f24ed8b5000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f24ed4c4000) libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f24ed252000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f24ed04e000) /lib64/ld-linux-x86-64.so.2 (0x00007f24edaf7000)

This output lists the dynamic shared objects (DSOs) needed, including the virtual dynamic shared object (linux-vdso.so.1), standard libraries like C library (libc.so.6), and the (ld-linux-x86-64.so.2), along with their resolved file paths and load addresses in memory. If a required library is missing from the system, the output indicates this clearly, such as libxyz.so => not found, allowing quick detection of linking issues without executing the program. On , the output for ldd /bin/ls is simpler, typically showing:

/usr/lib/libc.so.7 /libexec/ld-elf.so.1

/usr/lib/libc.so.7 /libexec/ld-elf.so.1

This reflects FreeBSD's standard C library (libc.so.7) and the runtime linker (ld-elf.so.1). Another straightforward application is checking dependencies for a file itself, such as the C library at /lib/x86_64-linux-gnu/libc.so.6 on , which reveals its own minimal requirements and any versioned paths. For instance, ldd /lib/x86_64-linux-gnu/libc.so.6 typically yields:

linux-vdso.so.1 (0x00007fff...) /lib64/ld-linux-x86-64.so.2 (0x00007f...)

linux-vdso.so.1 (0x00007fff...) /lib64/ld-linux-x86-64.so.2 (0x00007f...)

Here, the primary dependency is the , demonstrating how ldd recursively traces the libraries loaded for the specified shared object, including version information where applicable. This is particularly useful for verifying linkages in build systems or scripts, where automated checks ensure all dependencies are resolvable before deployment. For statically linked binaries, ldd reports "not a dynamic ," confirming no dependencies exist, as all code is compiled directly into the file. Common elements in ldd output across these cases include full resolved paths to libraries (using =>), addresses for loaded modules, and indicators for unresolved dependencies.

Advanced Applications

In advanced debugging scenarios on and Solaris, the ldd -u option identifies unused shared libraries in a binary, enabling developers to strip unnecessary dependencies and reduce executable size during optimization passes. For instance, running ldd -u /bin/program lists direct dependencies that are not referenced, allowing targeted removal via tools like strip or relinking. Combining this with ldd -r performs both data and function relocations, revealing unresolved symbols or relocation errors that might cause runtime failures, particularly useful when diagnosing linking issues in complex applications. On , the -a option can be used to show all indirect dependencies for similar analysis. In workflows on , ldd aids optimization by mapping out the exact dependencies of an application, facilitating the creation of minimal images with only required components. This is especially effective in lightweight distributions like , which uses the libc implementation to minimize footprint; by analyzing ldd output, builders can copy just the necessary libraries into the image, avoiding bloated layers from full package installations. For example, ldd myapp might reveal dependencies like libc.musl-x86_64.so.1, guiding the inclusion of a slim -based runtime to keep images under 10 MB while maintaining functionality. For integration in automated environments, ldd can be scripted to validate dependencies across multiple files, such as in build or deployment pipelines. A common bash loop like for file in *.so; do ldd "$file" | [grep](/page/Grep) "not found" && echo "Missing deps for $file"; done scans shared objects for unresolved libraries, flagging issues early in . This approach ensures completeness without manual inspection, integrating seamlessly with hooks or automation tools. In cross-compilation setups, such as building binaries on an x86 host, dependencies can be inspected using static analysis tools like readelf -d or [objdump](/page/Objdump) -x on the target binary to list required libraries (NEEDED entries), relative to a sysroot directory mimicking the target architecture's library environment. Alternatively, custom scripts can invoke the cross-compiled with the sysroot to simulate resolution, helping verify that all foreign dependencies are available without executing on the host. Troubleshooting advanced configurations often involves ldd to detect deviations in library loading, such as rpath-embedded paths overriding defaults or LD_LIBRARY_PATH influencing resolution. The output displays actual loaded locations, revealing if custom paths are prioritized incorrectly. In CI/CD pipelines, this capability supports by scripting ldd checks to confirm consistent dependency resolution across environments, as implemented in tools like Actions workflows for container validation.

References

Add your contribution
Related Hubs
User Avatar
No comments yet.