Bugtraq mailing list archives

Re: LD_PRELOAD potential problems


From: vandry () MLINK NET (Phillip Vandry)
Date: Fri, 14 May 1999 11:58:34 -0400


You should note of course that LD_PRELOAD will not work for any setuid
or setgid binary. Users thus cannot do anything they wouldn't have been
able to do otherwise by modifying code or compiling their own using this
trick.

I agree that LD_PRELOAD is very easy to use, but vendors shipping
statically linked binaries is a big inconvenience, and I don't believe
they should do it on account of the LD_PRELOAD hack. It's just not
worth it.

Here are some of the disadvantages of a statically linked binary:

- It's big on disk. Not only that but if there are multiple binaries that
share code (and what two binaries don't share at least code from libc?),
the size of this code is multiplied by the number of binaries.
- It's big in memory. Same argument, but this time regarding code that it
duplicated in memory (shared libraries are mapped only once)
- It's compatible with only one version of the operating system. (libc's
kernel interfaces are always free to change)
- The binary won't benefit from bugfixes in the vendor's system libraries.
- In many cases, it may not even be possible. For example, in Solaris,
using the name service switch REQUIRES a dynamically linked binary, and
keep in mind that you need the name service switch for all getXXXbyYYY()
functions.

In fact, it's not hard using gdb and breakpoints to override any desired
function in statically linked binaries too. (Harder if it's stripped,
admitedly).

If you must, extract those functions which you consider critical from
libc.a, and link those into the main binary (or even use syscall()
directly, but please link your stuff dynamically!

I assume that in your original message you are referring to an example of
using time() for a task such as forcing a demo copy of software to
expire (and overriding time() to fool the scheme). Similar situations
occur with binaries that check a machine's hostid or IP address to
verify license to use it.

In all these cases, if you are writing software that does this, and you
want to protect yourself from people bypassing your tests, you definately
need to contort your code a bit. If there's a function called
check_license() and a user can overwrite the beginning of this function
with code for "return 0" and that totally bypasses all your checks, then
you got fooled pretty easily. I suggest the following:

- Check this inside main() or some other big long function to discourage
disassembly/decompilation.
- Arrange that it is not possible to bypass your checks by nopping out a
single function/function call
- Don't print a message immediately after you do the checks. The user will
be able to set a breakpoint at the place where you print your message
(since you ultimately have to make a system call to print text) and know
pretty much what section of your code is making the checks.

Tangeant: On Solaris, you can override the system call of your choice
by making a kernel module that goes in the kernel/sys subdirectory. I
do not have documentation as to how that's done, but this method of
overriding a system call is virtually undetectable by user level
software. On OSes where you have source, of course, you're free to
modify system calls with even more ease!

-Phil

Many UNIX systems allow you to "pre-load" shared libraries by setting
an environment variable LD_PRELOAD.  This allows you to do interesting
things like replace standard C library functions or even the C
interfaces to system calls with your own functions.

I recently ran across a piece of software which depended upon knowing
the time reasonably accurately.  By replacing the time(2) UNIX system
call with my own function, I was able to fool the program and get it
to misbehave, without the inconvenience of actually changing the system
time or even requiring root privileges.

If you are writing programs which depend on C library functions or
UNIX system calls for secure operation, please distribute only
statically-linked versions, as the effort to fool statically-linked
binaries is a lot higher than a simple LD_PRELOAD spoof.



Current thread: