Differences between revisions 1 and 2
Revision 1 as of 2008-12-10 18:47:10
Size: 4746
Comment:
Revision 2 as of 2008-12-10 18:49:08
Size: 4747
Comment:
Deletions are marked like this. Additions are marked like this.
Line 11: Line 11:
GLIBC needs to maintain internal consistency and stability, especially in the '''libc''' and '''libm''' libaries. If '''libc''' accesses it's own symbols via a PLT call then if a user overrides a symbol GLIBC will invoke that overridden symbol and potentially destabilize the library. Therefore applications are prevented from impacting GLIBC internally by making GLIBC directly call internal, hidden versions of all of its symbols. Only expressly allowed symbols may be overridden, and called from within '''libc''', e.g. malloc. GLIBC needs to maintain internal consistency and stability, especially in the '''libc''' and '''libm''' libaries. If '''libc''' accesses it's own symbols via a PLT call then if a user overrides a symbol GLIBC will invoke that overridden symbol and potentially destabilize the library. Therefore, applications are prevented from impacting GLIBC internally by making GLIBC directly call internal, hidden versions of all of its symbols. Only expressly allowed symbols may be overridden, and called from within '''libc''', e.g. malloc.

How does this test-suite failure manifest?

It manifests as a failure in the following test-case:

 elf/check-localplt.out

What is this test for?

GLIBC needs to maintain internal consistency and stability, especially in the libc and libm libaries. If libc accesses it's own symbols via a PLT call then if a user overrides a symbol GLIBC will invoke that overridden symbol and potentially destabilize the library. Therefore, applications are prevented from impacting GLIBC internally by making GLIBC directly call internal, hidden versions of all of its symbols. Only expressly allowed symbols may be overridden, and called from within libc, e.g. malloc.

These expressly allowed symbols are denoted in the following files:

 scripts/data/localplt-i386-linux-gnu.data
 scripts/data/localplt-generic.data
 scripts/data/localplt-powerpc-linux-gnu.data
 scripts/data/localplt-powerpc64-linux-gnu.data

Additionally, PLT calls are expensive (more-so on some architectures than other) compared to direct branches/calls to functions so they should be avoided if possible.

The check-localplt test case ensures that no PLT calls from within libc to other libc functions are introduced.

What's a failure look like?

 --- ../scripts/data/localplt-i386-linux-gnu.data        2006-01-11 
 21:06:19.000000000 +0000
 +++ -   2008-11-30 20:52:09.962033876 +0000
 @@ -1,4 +1,5 @@
  libc.so: _Unwind_Find_FDE
 +libc.so: __bzero
  libc.so: calloc
  libc.so: free
  libc.so: malloc

This indicates that one or more invocations of the symbol __bzero via the PLT have been introduced into GLIBC erroneously.

Potential Causes

There are a few potential causes for this particular error:

  1. The symbol may be new and not have the proper hidden symbol macros defined for it.
  2. libc should invoke a hidden version of the symbol rather than the PLT version.

  3. The symbol may not be intended for invocation internally.

Problem Determination

  • Search through the GLIBC source and look for usage of __bzero().

  • You may notice that there is no libc_hidden_proto(__bzero) or libc_hidden_def(__bzero) associated with this particular symbol. This means there is no internal hidden symbol.

    • NOTE: While the use of two leading underscores on a symbol name will often indicate that it is an internal symbol, in the case of __bzero() the header file strings.h provides this is in the external API for GLIBC.

  • The __bzero() API has been around for some time so we can assume that there probably shouldn't be an internal hidden symbol for it.

  • Invocation of __bzero() should only be used in the sunrpc code (or other non-libc shared object code), which is in a different library than libc proper, so invocation via the PLT in that library is allowed.

  • If you find other invocations of the symbol within libc proper then these are problematic.

  • If the symbol may be invoked from within GLIBC and it doesn't yet have a hidden symbol then use the libc_hidden_proto(__internal_bzero) and libc_hidden_def(__internal_bzero) macros to provide an internal version of the symbol.

  • Then use a weak_alias(__internal_bzero,__bzero) to provide the external interface. All libc proper invocations should be to the hidden symbol __internal_bzero, not the external interface.

  • But alas, in the case of __bzero() there isn't supposed to be to a hidden internal symbol because GLIBC proper should invoke memset() instead.

Still can't figure out where the invocation originates?

Macros, and symbol aliasing magic can obscure the invocation of a symbol and sometimes we need to use more arcane methods to find the problematic invocation.

In order to determine where an obscure invocation is originating follow these steps:

 > objdump -DR libc.so > libc.dis

Search libc.dis for:

 __bzero@plt

You should see a plt call stub, e.g.

00016198 <__bzero@plt>:
   16198:       ff a3 0c 00 00 00       jmp    *0xc(%ebx)
   1619e:       68 00 00 00 00          push   $0x0
   161a3:       e9 e0 ff ff ff          jmp    16188 <h_errno+0x16168>

Now search for all instances of: call   16198

call   16198 <__bzero@plt>

This should bring you to the disassembly of the function which invoked __bzero via the PLT. You can then go into the C source file and replace this with a memset(). Do this for all calls to the PLT stub address for __bzero@plt.

None: Testing/Check-localplt (last edited 2008-12-10 18:49:08 by RyanScottArnold)