SlackwareThis Forum is for the discussion of Slackware Linux.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
After reading about the risks of using ldd on untrusted files some days ago I have created a bash script called lddsafe. I'm posting it in the Slackware section of the forums because I'm not entirely sure the things I do and suppose in it apply correctly to other distributions.
One important thing to remember, though, is that it requires bash 4 (found in /testing in Slackware 13.0 and -current), because it uses associative arrays to run faster. Still, it's a bit slow but at an acceptable level.
So here it is:
Code:
#!/bin/bash
#
# lddsafe - Safely print shared library dependencies (similar to ldd).
# Author: Ricardo Garcia Gonzalez.
# License: Public domain code.
#
# Better for grep and expected output of other tools.
export LANG=C
# Check file exists and is executable.
checkexec() {
if [ ! -x "$1" ]; then
echo "ERROR: $1 missing or not executable" 1>&2
exit 1
fi
}
# Check file exists and is readable.
checkreadable() {
if [ ! -r "$1" ]; then
echo "ERROR: $1 missing or not readable" 1>&2
exit 1
fi
}
# Check needed programs.
checkexec /usr/bin/objdump
checkexec /bin/awk
checkexec /bin/cat
checkexec /bin/tr
checkexec /bin/grep
checkexec /bin/cut
# Check needed files.
checkreadable /etc/ld.so.conf
# Check arguments.
if [ $# -eq 0 ]; then
echo "Usage: $( basename $0 ) FILE..." 2>&1
exit 1
fi
for arg in "$@"; do
checkexec "$1"
done
# Library directories.
libdirs="$( echo /lib /usr/lib && \
/bin/cat /etc/ld.so.conf && \
/bin/tr : ' ' <<<$LD_LIBRARY_PATH )"
# Search for a given library name.
searchlib() {
found=0
for libdir in $libdirs; do
path="$libdir"/"$1"
if [ -x "$path" ]; then
found=1
break
fi
done
if [ $found -eq 1 ]; then
echo "$path"
fi
}
# Already visited libraries.
declare -A visitedlibs
# Print dependency results, recursively.
recursivedeps() {
for lib in $( /usr/bin/objdump -p "$1" | \
/bin/grep '^ NEEDED ' | cut -c24- ); do
if [ ! "${visitedlibs[$lib]}" ]; then
visitedlibs["$lib"]=1
file=`searchlib "$lib"`
if [ "$file" ]; then
echo " $lib => $file"
recursivedeps "$file"
else
echo " $lib => not found"
fi
fi
done
}
# Search symbol names in library directories.
for arg in "$@"; do
# Print file name when more than one file given.
if [ $# -gt 1 ]; then
echo "${arg}:"
fi
# Get a unique list of library dependencies for this argument.
unset visitedlibs
declare -A visitedlibs
recursivedeps "$arg"
done
exit 0
Improvements are welcome, of course. Here's a sample output:
Using ldconfig -p is a nice approach too. However, that version is definitely too slow, IMHO, and it depends on having an up-to-date locate database:
Code:
$ time ldd /usr/lib/firefox/firefox-bin >/dev/null
real 0m0.058s
user 0m0.037s
sys 0m0.013s
$ time lddsafe /usr/lib/firefox/firefox-bin >/dev/null
real 0m0.734s
user 0m0.315s
sys 0m0.406s
$ time _lddsafe /usr/lib/firefox/firefox-bin >/dev/null
real 0m45.924s
user 0m40.614s
sys 0m2.504s
Hmmm, I liked this idea for a bit of code I have which uses ldd several times, but I don't use bash-4 so I re-wrote it. As long as I was in there I removed all the external dependencies except grep (could have gotten around that too).
And I put in some lines which make it print out "Not found" if the library is not present on the system. Plus I added some lines which make the output more like that of the real ldd. Adding a TAB or two at the beginning of the lines would
make the output even more like ldd.
Code:
#!/bin/bash
# Gilbert Ashley <amigo@ibiblio.org>
# Re-written from an idea by Ricardo Garcia Gonzalez
# License: Public domain code.
# His version needed bash-4, awk, cat, cut, grep and tr -plus objdump
# This only needs bash >=3.0 and objdump :-)
# I added the "not found" report and formatting output like ldd
declare MY_LIBS="$(objdump -p $1 |grep NEEDED)"
# Library directories.
LIBDIRS="/lib /usr/lib"
if [[ -r /etc/ld.so.conf ]] ; then
while read LINE ; do
LIBDIRS=${LIBDIRS}" $LINE"
done</etc/ld.so.conf
fi
LIBDIRS=${LIBDIRS}${LD_LIBRARY_PATH//:/}
for LINE in $(echo $MY_LIBS) ; do
HAVE_LIB=0
if [[ $LINE != "NEEDED" ]] ; then
for LIBDIR in $LIBDIRS ; do
if [[ -x "$LIBDIR/$LINE" ]] ; then
HAVE_LIB=1
# echo "$LIBDIR/$LINE"
# for an output more like the real ldd:
echo -e '\t'"$LINE => $LIBDIR/$LINE"
break
else
continue
fi
done
if [[ $HAVE_LIB != 1 ]] ; then
# echo "$LINE"" not found"
# for an output more like the real ldd:
echo -e '\t'"$LINE => not found"
fi
fi
done
Yep, it runs very well. It's very similar to my first version too. However, later I discovered you had to check the dependencies recursively to be able to match what ldd does properly. That's when I entered bash4 territory by using an associative array to store which libraries had already been searched for.
Actually, for what I am doing, I don't want to show resursive dependencies. Another nice thing about checking using objdump instead of ldd is that it shows less 'false positives'. What I mean by that is that if a binary is linked to a library which it doesn't actually use, ldd will show it as a dependency while objdump will not.
I use the tool to find hard dependencies and match them against datadbase entries for installed packages to show package dependencies.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.