LinuxQuestions.org
Register a domain and help support LQ
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Distributions > Slackware
User Name
Password
Slackware This Forum is for the discussion of Slackware Linux.

Notices

Reply
 
LinkBack Search this Thread
Old 10-29-2009, 05:18 PM   #1
rg3
Member
 
Registered: Jul 2007
Distribution: Slackware Linux
Posts: 447

Rep: Reputation: Disabled
lddsafe shell script


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:

Code:
$ lddsafe /usr/bin/xclock 
        libX11.so.6 => /usr/lib/libX11.so.6
        libxcb.so.1 => /usr/lib/libxcb.so.1
        libXau.so.6 => /usr/lib/libXau.so.6
        libc.so.6 => /lib/libc.so.6
        ld-linux.so.2 => /lib/ld-linux.so.2
        libXdmcp.so.6 => /usr/lib/libXdmcp.so.6
        libdl.so.2 => /lib/libdl.so.2
        libXaw.so.7 => /usr/lib/libXaw.so.7
        libXmu.so.6 => /usr/lib/libXmu.so.6
        libXt.so.6 => /usr/lib/libXt.so.6
        libSM.so.6 => /usr/lib/libSM.so.6
        libICE.so.6 => /usr/lib/libICE.so.6
        libuuid.so.1 => /lib/libuuid.so.1
        libXext.so.6 => /usr/lib/libXext.so.6
        libXpm.so.4 => /usr/lib/libXpm.so.4
        libXft.so.2 => /usr/lib/libXft.so.2
        libfontconfig.so.1 => /usr/lib/libfontconfig.so.1
        libfreetype.so.6 => /usr/lib/libfreetype.so.6
        libz.so.1 => /usr/lib/libz.so.1
        libexpat.so.1 => /usr/lib/libexpat.so.1
        libXrender.so.1 => /usr/lib/libXrender.so.1
        libxkbfile.so.1 => /usr/lib/libxkbfile.so.1
        libm.so.6 => /lib/libm.so.6
 
Old 10-29-2009, 07:23 PM   #2
unSpawn
Moderator
 
Registered: May 2001
Posts: 20,982
Blog Entries: 44

Rep: Reputation: 1234Reputation: 1234Reputation: 1234Reputation: 1234Reputation: 1234Reputation: 1234Reputation: 1234Reputation: 1234Reputation: 1234
Doesn't work exactly like I would like it to but how about:
Code:
_lddsafe() { #http://reverse.lostrealm.com/protect/ldd.html
 LIBS=$(/usr/bin/objdump -p "$1" | awk '/NEEDED/{print $2}'); 
 LIBS=$(for LIB in $LIBS; do /usr/bin/objdump -p `locate ${LIB}` | awk '/NEEDED/{print $2}'; done); 
 for LIB in $LIBS; do /sbin/ldconfig -p| grep -m1 $LIB; done | sort -u
}#End _lddsafe
?
 
Old 10-30-2009, 03:30 PM   #3
rg3
Member
 
Registered: Jul 2007
Distribution: Slackware Linux
Posts: 447

Original Poster
Rep: Reputation: Disabled
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
 
Old 10-30-2009, 05:22 PM   #4
gnashley
Amigo developer
 
Registered: Dec 2003
Location: Germany
Distribution: Slackware
Posts: 4,394

Rep: Reputation: 284Reputation: 284Reputation: 284
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
This seems to run even faster on my system :-)
 
Old 10-30-2009, 05:40 PM   #5
rg3
Member
 
Registered: Jul 2007
Distribution: Slackware Linux
Posts: 447

Original Poster
Rep: Reputation: Disabled
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.

Code:
$ ldd /usr/lib/firefox/firefox-bin | wc -l
47
$ lddsafe /usr/lib/firefox/firefox-bin | wc -l
46
$ ./lddsafe-gnashley /usr/lib/firefox/firefox-bin | wc -l
25

Last edited by rg3; 10-30-2009 at 05:41 PM. Reason: Typo
 
Old 10-30-2009, 05:46 PM   #6
rg3
Member
 
Registered: Jul 2007
Distribution: Slackware Linux
Posts: 447

Original Poster
Rep: Reputation: Disabled
Well, I have uploaded it to github. I also removed the check for awk, which I was no longer using.
 
Old 10-31-2009, 04:51 AM   #7
gnashley
Amigo developer
 
Registered: Dec 2003
Location: Germany
Distribution: Slackware
Posts: 4,394

Rep: Reputation: 284Reputation: 284Reputation: 284
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.
 
Old 10-31-2009, 05:21 AM   #8
rg3
Member
 
Registered: Jul 2007
Distribution: Slackware Linux
Posts: 447

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by gnashley View Post
I use the tool to find hard dependencies and match them against datadbase entries for installed packages to show package dependencies.
Ah, I see. So it makes sense to only print direct dependencies for each object.
 
Old 10-31-2009, 05:42 AM   #9
rworkman
Slackware Contributor
 
Registered: Oct 2004
Location: Tuscaloosa, Alabama (USA)
Distribution: Slackware
Posts: 1,846

Rep: Reputation: Disabled
Actually, there's valid points for both - make one the default (probably the "show all including indirect") and add an option for the other.
 
Old 10-31-2009, 08:59 AM   #10
rg3
Member
 
Registered: Jul 2007
Distribution: Slackware Linux
Posts: 447

Original Poster
Rep: Reputation: Disabled
Added -n option for nonrecursive mode.
 
Old 11-03-2009, 04:32 PM   #11
rg3
Member
 
Registered: Jul 2007
Distribution: Slackware Linux
Posts: 447

Original Poster
Rep: Reputation: Disabled
Added support for 64-bit and multilib systems.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
pass variable from one shell script into another shell script xskycamefalling Programming 9 10-03-2009 02:45 AM
How to ssh from a shell script ? For ppl who can write shell scripts. thefountainhead100 Programming 14 10-22-2008 07:24 AM
help with execute mulitple shell script within shell script ufmale Programming 6 09-13-2008 01:21 AM
shell script problem, want to use shell script auto update IP~! singying304 Programming 4 11-29-2005 06:32 PM


All times are GMT -5. The time now is 09:00 AM.

Main Menu
 
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: @linuxquestions
Open Source Consulting | Domain Registration