This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Compatibility symlink from old dynamic loader name to new dynamicloader name doesn't work.


Community,

The ARM GNU/Linux hard-float ABI linker name changed recently.
It was changed from /lib/ld-linux.so.3 to /lib/ld-linux-armhf.so.3.

It seemed pretty obvious that a simple way to provide backwards
compatibility for old applications was to create a symlink from
ld-linux.so.3 to ld-linux-armhf.so.3, but this turns out to be
harder than you would think.

On April 18th Steve McIntyre posts this patch:
http://sourceware.org/ml/libc-ports/2012-04/msg00081.html

The patch is designed to prevent the initial dynamic loader from
loading itself twice. It turns out that the symlink confuses the 
code in  elf/dl-load.c (_dl_map_object) and it does not correctly
determine that both dynamic linkers are the same (symlink really).

Without the patch there are two copies of the dynamic linker loaded.

The first is ld-linux-armhf.so.3 in the initial scope 0 of the application as is ld-linux-armhf.so.3:
~~~
       722:     Initial object scopes
       722:     object=./test [0]
       722:      scope 0: ./test /scratch/carloso/build4-lucid-cs/arm-none-linux-gnueabi-sourceryg++/install/arm-none-linux-gnueabi/libc/armv7-a-hard/lib/libdl.so.2 /scratch/carloso/build4-lucid-cs/arm-none-linux-gnueabi-sourceryg++/install/arm-none-linux-gnueabi/libc/armv7-a-hard/lib/libgcc_s.so.1 /scratch/carloso/build4-lucid-cs/arm-none-linux-gnueabi-sourceryg++/install/arm-none-linux-gnueabi/libc/armv7-a-hard/lib/libc.so.6 /scratch/carloso/build4-lucid-cs/arm-none-linux-gnueabi-sourceryg++/install/arm-none-linux-gnueabi/libc/armv7-a-hard/lib/ld-linux-armhf.so.3
~~~

The second is created by a forcible DT_NEEDED entry in a legacy
shared library. Something which shouldn't happen, but is technically
possible and not disallowed. You get this kind of thing for example
if you listed /lib/ld-linux.so.3 as an object on the link line
while building the legacy shared library with a legacy toolchain.
Some applications build like this and we need to support it or at
the very least not crash the application.

For example in ./libtest.so:
~~~
...
Dynamic section at offset 0x590 contains 27 entries:
  Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: [ld-linux.so.3]
 0x00000001 (NEEDED)                     Shared library: [libgcc_s.so.1]
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]
 0x0000000e (SONAME)                     Library soname: [libtest.so]
...
~~~

Continuing the same trace, when we process libtest.so we load ld-linux.so.3 (which is just a symlink to ld-linux-armhf.so.3):
~~~
       722:     file=ld-linux.so.3 [0];  needed by ./libtest.so [0]
       722:     find library=ld-linux.so.3 [0]; searching
       722:      search path=/scratch/carloso/build4-lucid-cs/arm-none-linux-gnueabi-sourceryg++/install/arm-none-linux-gnueabi/libc/armv7-a-hard/lib:/scratch/carloso/build4-lucid-cs/arm-none-linux-gnueabi-sourceryg++/install/arm-none-linux-gnueabi/libc/armv7-a-hard/usr/lib/tls/v7l/neon/vfp:/scratch/carloso/build4-lucid-cs/arm-none-linux-gnueabi-sourceryg++/install/arm-none-linux-gnueabi/libc/armv7-a-hard/usr/lib/tls/v7l/neon:/scratch/carloso/build4-lucid-cs/arm-none-linux-gnueabi-sourceryg++/install/arm-none-linux-gnueabi/libc/armv7-a-hard/usr/lib/tls/v7l/vfp:/scratch/carloso/build4-lucid-cs/arm-none-linux-gnueabi-sourceryg++/install/arm-none-linux-gnueabi/libc/armv7-a-hard/usr/lib/tls/v7l:/scratch/carloso/build4-lucid-cs/arm-none-linux-gnueabi-sourceryg++/install/arm-none-linux-gnueabi/libc/armv7-a-hard/usr/lib/tls/neon/vfp:/scratch/carloso/build4-lucid-cs/arm-none-linux-gnueabi-sourceryg++/install/arm-none-linux-gnueabi/libc/armv7-a-hard/usr/lib/tls/neon:/scratch/carloso/build4-l

ucid-cs/arm-none-linux-gnueabi-sourceryg++/install/arm-none-linux-gnueabi/libc/armv7-a-hard/usr/lib/tls/vfp:/scratch/carloso/build4-lucid-cs/arm-none-linux-gnueabi-sourceryg++/install/arm-none-linux-gnueabi/libc/armv7-a-hard/usr/lib/tls:/scratch/carloso/build4-lucid-cs/arm-none-linux-gnueabi-sourceryg++/install/arm-none-linux-gnueabi/libc/armv7-a-hard/usr/lib/v7l/neon/vfp:/scratch/carloso/build4-lucid-cs/arm-none-linux-gnueabi-sourceryg++/install/arm-none-linux-gnueabi/libc/armv7-a-hard/usr/lib/v7l/neon:/scratch/carloso/build4-lucid-cs/arm-none-linux-gnueabi-sourceryg++/install/arm-none-linux-gnueabi/libc/armv7-a-hard/usr/lib/v7l/vfp:/scratch/carloso/build4-lucid-cs/arm-none-linux-gnueabi-sourceryg++/install/arm-none-linux-gnueabi/libc/armv7-a-hard/usr/lib/v7l:/scratch/carloso/build4-lucid-cs/arm-none-linux-gnueabi-sourceryg++/install/arm-none-linux-gnueabi/libc/armv7-a-hard/usr/lib/neon/vfp:/scratch/carloso/build4-lucid-cs/arm-none-linux-gnueabi-sourceryg++/install/arm-none-linux-g
n
ueabi/libc/armv7-a-hard/usr/lib/neon:/scratch/carloso/build4-lucid-cs/arm-none-linux-gnueabi-sourceryg++/install/arm-none-linux-gnueabi/libc/armv7-a-hard/usr/lib/vfp:/scratch/carloso/build4-lucid-cs/arm-none-linux-gnueabi-sourceryg++/install/arm-none-linux-gnueabi/libc/armv7-a-hard/usr/lib:./tls/v7l/neon/vfp:./tls/v7l/neon:./tls/v7l/vfp:./tls/v7l:./tls/neon/vfp:./tls/neon:./tls/vfp:./tls:./v7l/neon/vfp:./v7l/neon:./v7l/vfp:./v7l:./neon/vfp:./neon:./vfp:.           (LD_LIBRARY_PATH)
       722:       trying file=/scratch/carloso/build4-lucid-cs/arm-none-linux-gnueabi-sourceryg++/install/arm-none-linux-gnueabi/libc/armv7-a-hard/lib/ld-linux.so.3
       722:
       722:     file=ld-linux.so.3 [0];  generating link map
       722:       dynamic: 0x401b7f44  base: 0x4018e000   size: 0x0002a96c
       722:         entry: 0x4018ee40  phdr: 0x4018e034  phnum:          6
~~~

Either way the question is: Does it cause any real problems to have two 
copies of the dynamic loader loaded?

Adam Conrad thankfully provided me with a trace of cc1 crashing with
a dynamic linker that isn't patched:
http://paste.ubuntu.com/1261263/

>From the above trace the following jumps out at me:
~~~
     16727:	binding file /lib/ld-linux-armhf.so.3 [0] to /lib/arm-linux-gnueabihf/ld-linux.so.3 [0]: normal symbol `__tls_get_addr' [GLIBC_2.4]
~~~
This looks wrong and problematic. Perhaps a minimal test case can
be constructed with TLS that shows the crash.

There are also vague comments in elf/dl-load.c (_dl_map_object_from_fd)
that say:
~~~
  /* When loading into a namespace other than the base one we must
     avoid loading ld.so since there can only be one copy.  Ever.  */
~~~
Which again doesn't tell us why that would be the case.

Detecting that the two objects are identical in _dl_map_object_from_fd
would be the most optimal solution, but it would require refactoring
the loading code to map in and read DT_SONAME as early as possible and
abort the load if we detected an existing SONAME already loaded.

I don't think that walking the symlink to see if the two files match is not an
acceptable solution.

In summary:
- To support compatibility symlinks from old dynamic loader names to new
dynamic loader names will require refactoring _dl_map_object_from_fd to
actually detect if two DSOs are the same.

Filed:
http://sourceware.org/bugzilla/show_bug.cgi?id=14761

Comments?

Cheers,
Carlos.
-- 
Carlos O'Donell
Mentor Graphics / CodeSourcery
carlos_odonell@mentor.com
carlos@codesourcery.com
+1 (613) 963 1026


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]