Filed under misc

Runtime Linker Voodoo

Kjartan pointed out a report of a gnome-session security vulnerability
to me earlier today. Now, it turns out to actually only be a
vulnerability in a script supplied with certain distributors' packages,
but that's not the interesting part.

The script contained something like this:

  export LD_LIBRARY_PATH=/opt/gnome/lib:$LD_LIBRARY_PATH

and the "vulnerability" was apparently that if \$LD_LIBRARY_PATH
was originally unset, then you get
LD_LIBRARY_PATH="/opt/gnome/lib:".

I couldn't for the life of me understand why it was actually a
vulnerability in the first place. It gnawed at me all day. After a bit
of poking at the runtime linker code in glibc though I realized that
setting \$LD_LIBRARY_PATH like that is effectively the same as
setting it to LD_LIBRARY_PATH="/opt/gnome/lib:./". The problem is
clear then - an attacker can use it to force a rogue, untrusted
library to be loaded that could do nasty things.

So, this whole LD_LIBRARY_PATH=":" causing "./" to be added to
the runtime linker's search path thing came as a big suprise to me and
to some others. I'd never heard of before, but it seems known to at
least some people and is "expected behavior". What worries me here is
that its likely most attackers know to look out for this and most
developers don't.

My long search for a normative reference for this behaviour failed. If
anyone knows where it comes from, I'm dead curious. I expect Ulrich
knows, though :-)

Another interesting thing to play with:

$> LD_DEBUG=help /lib/ld-linux.so.2
Valid options for the LD_DEBUG environment variable are:

  libs        display library search paths
  reloc       display relocation processing
  files       display progress for input file
  symbols     display symbol table processing
  bindings    display information about symbol binding
  versions    display version dependencies
  all         all previous options combined
  statistics  display relocation statistics
  help        display this help message and exit

I read a paper
from Ulrich
some time ago that gave lots of details on how to write
shared libraries such that the runtime linker can more efficiently
resolve symbols etc. LD_DEBUG=statistics, among other things,
is useful there. I'd love to see someone with the time and interest
looking into this and analyzing GNOME libraries to see where we can
make improvements.

Tagged , ,

List moderator magic

I spent some time floundering about a while ago trying to figure out a
Javascript hack to allow you to mark all mails in a mailman moderation
queue to be discarded. I certainly wasn't going to manually click
"Discard" for each of the 400 mails in the gconf-list queue.

DV saved me with some
jamesh magic.

Mailing list admins, bookmark this link -
Discard all mails%7Bel.checked=true;%7D%7D%7D)())

(No, don't click on the link. Right-click, "Bookmark link...")

Tagged

St. Patrick's Day

Recipe for a nice relaxing Paddy's day:

  • Long walk by the sea to clear the hangover.
  • Cook gorgeous Thai Red Curry. Eat.
  • Snooze.
  • Bake a lemon cake. Eat.
  • Add wireless support to gnome-netstatus:

    Calum is the one responsible for the UI. I just did the fun hack :-)

Tagged

There be divils here

I reckon a lot of hackers don't realise how wary they need to
be when using enums. Problems occur frequently because people
(usually unwittingly) make assumptions about either the size,
alignment or signedness of the integer representation for the
enum which the compiler uses.

C99 says Each enumerated type shall be compatible with
an integer type. The choice of type is implementation-defined.
An implementation may delay the choice of which integer type
until all enumeration constants have been seen
. What
this means is that once the compiler has seen all the constants
you have defined for that enum, it will then decide what integer
representation to use and that could be a signed or unsigned
integer of any size.

So, GNOME hackers beware. gconf_enum_to_string() is
nasty. Have a look at the prototype:

gboolean  gconf_string_to_enum (GConfEnumStringPair  lookup_table[],
                                const gchar         *str,
                                gint                *enum_value_retloc);

Bugs I've seen include:

{
  enum { A, B } test_enum;

  gconf_enum_to_string (enum_to_str_table, str, (int *) &test_enum);
}

This is guaranteed to cause crashes on some architectures since
alignment of the enum is different from the expected
alignment of an int. So it should be:

{
  enum { A, B } test_enum;
  int test_int;

  if (gconf_enum_to_string (enum_to_str_table, str, &test_int))
    {
      test_enum = test_int;
    }
}

Also, this breaks:

{

  enum { A, B } test_enum;

  int test_int;
test_enum = -1;

  gconf_enum_to_string (enum_to_str_table, str, &test_int);

  test_enum = test_int;
if (test_enum

The problem here is that you're assuming the enum has a signed

representation when in fact the compiler may choose an unsigned

representation. If the conversion fails, if (test_enum

will not detect it.

Alex also points out that when adding values to an enum in an API

you need to be careful that you're not unwittingly changing the

ABI because the compiler chooses to use a large integer representation

for the enum than was previously used.
Tagged

Voodoo

I hate now knowing how things work. Especially things that I
rely on heavily as a hacker. But I love it when I get a chance
to finally figure out how the damn thing works and it turns out
to be beautifully simple.

This week I found that I had to debug a small part of libtool's
behaviour. It had always worked for me before and I had assumed
it worked a certain way, but in this case it just wasn't
working properly. I could feel myself breaking out in a cold
sweat. Don't make me debug libtool! Please God, noooo...

But the clouds parted. And it was simple.

When you build an executable, and it links against a library
in the same module, you need some way to be able to run that
uninstalled executable with the uninstalled library. So,
libtool puts a script where you think your uninstalled
executable should be and here's what it does

  • When you run the script for the first time, it re-links
    your executable with --rpath $path-to-lib/.libs and
    places that executable in .libs/lt-myexec.
  • That causes the linker to to put a DT_RPATH ELF
    attribute in the executable which tells the dynamic loader
    where to looks for libraries. (See the ld.so manpage)
  • And finally, the script just runs the modified executable.

For example:

  $> ls -l .libs/*gdk-pixbuf-csource
  -rwxrwxr-x    1 markmc   markmc      51262 Feb 26 11:28 .libs/gdk-pixbuf-csource
  $> ./gdk-pixbuf-csource
  Usage: gdk-pixbuf-csource [options] [image]
  $> ls -l .libs/*gdk-pixbuf-csource
  -rwxrwxr-x    1 markmc   markmc      51262 Feb 26 11:28 .libs/gdk-pixbuf-csource
  -rwxrwxr-x    1 markmc   markmc      51294 Feb 28 15:48 .libs/lt-gdk-pixbuf-csource
  $> objdump -p .libs/gdk-pixbuf-csource | grep RPATH
  $> objdump -p .libs/lt-gdk-pixbuf-csource | grep RPATH
    RPATH       /gnome/head/cvs/gtk+/gdk-pixbuf/.libs:/gnome/head/INSTALL/lib
  $> ldd .libs/gdk-pixbuf-csource | grep gdk_pixbuf
          libgdk_pixbuf-2.0.so.0 => /gnome/head/INSTALL/lib/libgdk_pixbuf-2.0.so.0 (0x0087d000)
  $> ldd .libs/lt-gdk-pixbuf-csource | grep gdk_pixbuf
          libgdk_pixbuf-2.0.so.0 => /gnome/head/cvs/gtk+/gdk-pixbuf/.libs/libgdk_pixbuf-2.0.so.0 (0x004a0000)

Not exactly, earth shattering. But nice to know.

Tagged ,