Re: Another ld-linux.so problem

joost witteveen (joost@RULCMC.LEIDENUNIV.NL)
Sat, 07 Feb 1998 13:12:49 +0100

In an attempt to save the world from disaster, Solar Designer wrote:
> Hello,
>
> There's another problem in ld-linux.so (and the a.out linker ld.so, too):
> it is possible to trick the linker into loading old version of a library
> if several versions are installed. This means that if you have upgraded
> your libc (or libdb, etc) after a security hole was discovered, updated
> /etc/ld.so.cache with ldconfig, and made sure the new version is used,
> it still might be possible for an attacker to force a setuid binary into
> using your old vulnerable version of the library, if you haven't removed
> it from the directories scanned by ldconfig.

>
> The problem is that ldconfig adds all versions of a library into the cache,
> and the linker itself doesn't give up if an error occurs. Normally the
> latest version is listed first, and it's the only one used. However, we
> can consume up the resources, so that the linker fails to load the latest
> version, and then free some resources before it tries to load an older one.

It's much simpler than that:

$ LD_PRELOAD=libdoesntexist /bin/su
/bin/su: error in loading shared libraries
libdoesntexist: cannot open shared object file: No such file or directory

In other words, just use LD_PRELOAD. It is _not_ ignored on setuid binaries.

(Something I wrote about the dangers of this some time ago):

I linux (and the Solaris) dynamic linkers don't ignore
LD_PRELOAD for setuid binaries. The documentation of the
old (libc5, aka ld.so 1.8.1, 1.9 etc) said (incorrectly) that LD_PRELOAD
was ignored when executing setuid binaries, and this is the behaviour
I've always expected.

But apparently the wisdom is that
libraries that are installed on the system should be well written,
and it should be safe for them to be specified in LD_PRELOAD.

I am quite surprised by this attitude, and I think I've thought of 3
situations where this behaviour of the dynamic linkers may _possibly_
create security problems.
I very much welcome responces from peope on this list. (Like:
"Don't worry, you silly newbie, we know what we are doing"
or
"My god, this is a big concern"
or anything in between).

(If you don't believe the dynamic linkers ignore LD_PRELOAD on setuid bins,
type "LD_PRELOAD=libdoesntexist /bin/su".)

**********************
- Buffer overruns in global initialisers (C++).

Suppose you've got a 10000+ line C++ library that does linguistic analysis
of various languages. Now _somewhere_ in that library, someone on the
project added the following code:

class foo{
public:
foo(){
char buf[10], *s=getenv("FOO");
if(s)
strcpy(buf,s); // Buffer overrun, etc.
// [more code here]
}
};
foo bar; // initialise this variable. (before main() is called)

Having this library installed in any location in /usr/lib, or /lib
(more general: any directory listed in /etc/ld.so.conf) will make your
whole system vurnerable for attac.

Again one may argue that libraries like this don't belong in /usr/lib.
But you argue that way, then basically no big library belongs in /usr/lib.
Again, not current practice.

**********************
- Wrapper libraries that override important system functions.

Because many of these wrapper libraries will be written based on the
assumption that their code will not be part of any setuid binary, the
wrapping functions are not "defensively programmed", and as such may
well be vurnerable to buffer overruns etc. It may be argued that these
libraries don't belong in /usr/lib etc, but the fact is that (maybe
due to the misleading documentation) they currently often are.

**********************
- Surprising results of name-overlaps.

As an example, take another artificial-intelligence library that makes
attempts at answering simple english questions. One friday afternoon
the linguists added the function "crypt(const *char q)" that attempts to
not give a straight answer to the question, but a cryptic one. Naturally,
this question q is copied to a 80 byte-long array on the stack.
Well, you get the idea: type
LD_PRELOAD=libAI.so.2.3 /bin/su
and su will eventually call crypt(key,salt), with key being the user-typed
(max 128 chars, see getpass(3)) password. Should be root in there somewhere.

In general: setuid binaries rely on many functions in system libraries.
Some of these functions have names that also have meanings in other fields,
and as such may be implemented in completely unrelated libraries. Because
it is possible to trick the setuid binaries into using any library installed
on the system, all these functions can potentially be called by setuid biaries,
with 'interesting' effects. I don't want to imply that applies to your system
at this moment -- all I want to say is that there _is_ a potential security
problem.

Thanks,

--
joost witteveen, joostje@debian.org

The upstream maintainer is allowed to do things different than Debian, but only if he has good reasons to do so.