Last active
September 25, 2019 20:10
-
-
Save devurandom/e5d7178e60c25248d3613871917a4f7c to your computer and use it in GitHub Desktop.
Call scanelf --needed recursively to build a tree of library dependencies
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# This script avoids following security problem with `ldd` and thus `lddtree` by using `scanelf` instead: | |
# Be aware that in some circumstances (e.g., where the program specifies an ELF interpreter other than ld-linux.so), some | |
# versions of ldd may attempt to obtain the dependency information by attempting to directly execute the program (which may | |
# lead to the execution of whatever code is defined in the program's ELF interpreter, and perhaps to execution of the program | |
# itself). Thus, you should never employ ldd on an untrusted executable, since this may result in the execution of arbitrary | |
# code. | |
# Repeated appearances of a library are not fully resolved. The library is instead marked with `(*)` to indicate that its | |
# dependencies are omitted here, but can be found further up in the output. | |
die() { | |
[[ "$@" ]] && echo "$@" | |
exit 1 | |
} | |
declare -A scanned | |
needed() { | |
local scan_lib="$1" level="${2:-0}" ws elfclass package | |
if ! [[ "${resolve_stdlib}" ]] ; then | |
case "${scan_lib}" in | |
*ld-linux*.so*|*libc.so*|*libdl.so*|*libm.so*|*libpthread.so*|*librt.so*|*libstdc++.so*|*libgcc_s.so*) return ;; | |
esac | |
fi | |
if ! [[ "${recursive}" ]] && [[ "${level}" -gt 1 ]] ; then | |
return | |
fi | |
for i in $(seq 1 "${level}") ; do | |
ws="${ws}| " | |
done | |
if [[ "${query_elfclass}" ]] && [[ "${level}" -eq 0 ]] ; then | |
elfclass="$(readelf -h "${scan_lib}" | grep 'Class:' | awk '{print $2}')" | |
fi | |
if [[ "${query_packages}" ]] ; then | |
package="$(q file -qv "${scan_lib}")" | |
fi | |
echo "${ws}${scan_lib}${elfclass:+ (${elfclass})}${package:+ (${package})}${scanned[${scan_lib}]:+ (*)}" | |
[[ "${scanned[${scan_lib}]}" ]] && return | |
scanned+=( ["${scan_lib}"]=1 ) | |
while read lib ; do | |
needed "${lib}" $(("${level}" + 1)) | |
done < <(scanelf --needed --use-ldpath "${scan_lib}" | awk '/^ET_(EXEC|DYN)/{print $2}' | tr , '\n') | |
} | |
recursive=yes | |
binary="$1" | |
[[ "${binary}" ]] || die "Usage $0 <binary>" | |
while [ $# -gt 0 ] ; do | |
arg=$1 ; shift | |
case $arg in | |
--resolve-stdlib) resolve_stdlib=yes ;; | |
--query-packages) query_packages=yes ;; | |
--query-elfclass) query_elfclass=yes ;; | |
--recursive=no) unset recursive ;; | |
esac | |
done | |
needed "${binary}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This script was written, because
ldd
has an arbitrary code execution security issue by design / specification. At the time I did not know aboutlddtree
, so I wrote my own script.Additionally it integrates with the Gentoo package database (via app-portage/portage-utils) and to show package information about the libraries found. It can also help to debug 32/64-bit issues.