From 2a064a9d1bbb8de6ce489b685cce026eee167cd2 Mon Sep 17 00:00:00 2001 From: johannst Date: Tue, 17 Mar 2020 22:48:49 +0000 Subject: deploy: fb719f52b73920fb18c7f3080ebb1fc73300be49 --- ld.so.html | 177 ++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 94 insertions(+), 83 deletions(-) (limited to 'ld.so.html') diff --git a/ld.so.html b/ld.so.html index ed9f07a..42e7f67 100644 --- a/ld.so.html +++ b/ld.so.html @@ -81,7 +81,7 @@ @@ -149,16 +149,18 @@

ld.so(8)

-

Environment variables

+

Environment Variables

  LD_PRELOAD=<l_so>       colon separated list of libso's to be pre loaded
-  LD_DEBUG=<opts>         comman separated list of debug options
+  LD_DEBUG=<opts>         comma separated list of debug options
           =help           list available options
           =libs           show library search path
           =files          processing of input files
           =symbols        show search path for symbol lookup
           =bindings       show against which definition a symbol is bound
 
-

LD_PRELOAD load & init order

+

LD_PRELOAD: Initialization Order and Link Map

+

Libraries specified in LD_PRELOAD are loaded from left-to-right but +initialized from right-to-left.

  > ldd ./main
     >> libc.so.6 => /usr/lib/libc.so.6
 
@@ -167,87 +169,96 @@
       preloaded in this order
              <--
       initialized in this order
-
-  - preload order determines the order libs are inserted into the link map
-
-  - resulting link map:
-      +------+    +------+    +------+    +------+
-      | main | -> | liba | -> | libb | -> | libc |
-      +------+    +------+    +------+    +------+
-
-  - see preload and init order in action
-    > LD_DEBUG=files LD_PRELOAD=liba.so:libb.so ./main
-      # load order (-> determines link map)
-      >> file=liba.so [0];  generating link map
-      >> file=libb.so [0];  generating link map
-      >> file=libc.so.6 [0];  generating link map
-
-      # init order
-      >> calling init: /usr/lib/libc.so.6
-      >> calling init: <path>/libb.so
-      >> calling init: <path>/liba.so
-      >> initialize program: ./main
-
-  - see the symbol lookup in action and therefore the link map order
-    > LD_DEBUG=symbols,bindings LD_PRELOAD=liba.so:libb.so ./main
-      >> symbol=memcpy;  lookup in file=./main [0]
-      >> symbol=memcpy;  lookup in file=<path>/liba.so [0]
-      >> symbol=memcpy;  lookup in file=<path>/libb.so [0]
-      >> symbol=memcpy;  lookup in file=/usr/lib/libc.so.6 [0]
-      >> binding file ./main [0] to /usr/lib/libc.so.6 [0]: normal symbol
-         `memcpy' [GLIBC_2.14]
 
-

dynamic linking (x86_64)

-
  - dynamic linking basically works via one indirect jump. It uses a
-    combination of function trampolines (.plt) and a function pointer table
-    (.got.plt). On the first call the trampoline sets up some metadata and
-    then jumps to the ld.so runtime resolve function, which in turn patches
-    the table with the correct function pointer.
-      .plt ....... contains function trampolines, usually located in code
-                   segment (rx permission)
-      .got.plt ... hold the function pointer table
-
-  - following r2 dump shows this
-      - [0x00401030] indirect jump for 'puts' using function pointer in
-        _GLOBAL_OFFSET_TABLE_[3]
-      - initially points to instruction behind 'puts' trampoline [0x00401036]
-      - this pushes relocation index and then jumps to the first trampoline
-        [0x00401020]
-      - the first trampoline jumps to _GLOBAL_OFFSET_TABLE_[2] which will be
-        filled at program startup by the ld.so with its resolve function
-      - the resolve function fixes the relocation referenced by the
-        relocation index pushed by the 'puts' trampoline
-      - the relocation entry tells the resolve function which symbol to
-        search for and where to put the function pointer
-          > readelf -r <main>
-            >> Relocation section '.rela.plt' at offset 0x4b8 contains 1 entry:
-            >>   Offset          Info           Type           Sym. Value    Sym. Name + Addend
-            >> 000000404018  000200000007 R_X86_64_JUMP_SLO 0000000000000000 puts@GLIBC_2.2.5 + 0
-          - offset points to _GLOBAL_OFFSET_TABLE_[3]
-
-      [0x00401040]> pd 4 @ section..got.plt
-                  ;-- section..got.plt:
-                  ;-- .got.plt:    ; [22] -rw- section size 32 named .got.plt
-                  ;-- _GLOBAL_OFFSET_TABLE_:
-                  0x00404000      .qword 0x0000000000403e10 ; section..dynamic ; obj._DYNAMIC
-                  0x00404008      .qword 0x0000000000000000
-                  ; CODE XREF from section..plt @ +0x6
-                  0x00404010      .qword 0x0000000000000000
-                  ;-- reloc.puts:
-                  ; CODE XREF from sym.imp.puts @ 0x401030
-                  0x00404018      .qword 0x0000000000401036                  ; RELOC 64 puts
-
-      [0x00401040]> pd 6 @ section..plt
-                  ;-- section..plt:
-                  ;-- .plt:       ; [12] -r-x section size 32 named .plt
-              ┌─> 0x00401020      ff35e22f0000   push qword [0x00404008]
-              ╎   0x00401026      ff25e42f0000   jmp qword [0x00404010]
-              ╎   0x0040102c      0f1f4000       nop dword [rax]
-      ┌ 6: int sym.imp.puts (const char *s);
-      └       ╎   0x00401030      ff25e22f0000   jmp qword [reloc.puts]
-              ╎   0x00401036      6800000000     push 0
-              └─< 0x0040103b      e9e0ffffff     jmp sym..plt
+

The preload order determines:

+
    +
  • the order libraries are inserted into the link map
  • +
  • the initialization order for libraries
  • +
+

For the example listed above the resulting link map will look like the +following:

+
  +------+    +------+    +------+    +------+
+  | main | -> | liba | -> | libb | -> | libc |
+  +------+    +------+    +------+    +------+
+
+

This can be seen when running with LD_DEBUG=files:

+
  > LD_DEBUG=files LD_PRELOAD=liba.so:libb.so ./main
+    # load order (-> determines link map)
+    >> file=liba.so [0];  generating link map
+    >> file=libb.so [0];  generating link map
+    >> file=libc.so.6 [0];  generating link map
+
+    # init order
+    >> calling init: /usr/lib/libc.so.6
+    >> calling init: <path>/libb.so
+    >> calling init: <path>/liba.so
+    >> initialize program: ./main
+
+

To verify the link map order we let ld.so resolve the memcpy(3) libc +symbol (used in main) dynamically, while enabling LD_DEBUG=symbols,bindings +to see the resolving in action.

+
  > LD_DEBUG=symbols,bindings LD_PRELOAD=liba.so:libb.so ./main
+    >> symbol=memcpy;  lookup in file=./main [0]
+    >> symbol=memcpy;  lookup in file=<path>/liba.so [0]
+    >> symbol=memcpy;  lookup in file=<path>/libb.so [0]
+    >> symbol=memcpy;  lookup in file=/usr/lib/libc.so.6 [0]
+    >> binding file ./main [0] to /usr/lib/libc.so.6 [0]: normal symbol `memcpy' [GLIBC_2.14]
+
+

Dynamic Linking (x86_64)

+

Dynamic linking basically works via one indirect jump. It uses a combination of +function trampolines (.plt section) and a function pointer table (.got.plt +section). +On the first call the trampoline sets up some metadata and then jumps to the +ld.so runtime resolve function, which in turn patches the table with the +correct function pointer.

+
  .plt ....... procedure linkage table, contains function trampolines, usually
+               located in code segment (rx permission)
+  .got.plt ... global offset table for .plt, holds the function pointer table
+
+

Using radare2 we can analyze this in more detail:

+
  [0x00401040]> pd 4 @ section..got.plt
+              ;-- section..got.plt:
+              ;-- .got.plt:    ; [22] -rw- section size 32 named .got.plt
+              ;-- _GLOBAL_OFFSET_TABLE_:
+         [0]  0x00404000      .qword 0x0000000000403e10 ; section..dynamic
+         [1]  0x00404008      .qword 0x0000000000000000
+              ; CODE XREF from section..plt @ +0x6
+         [2]  0x00404010      .qword 0x0000000000000000
+              ;-- reloc.puts:
+              ; CODE XREF from sym.imp.puts @ 0x401030
+         [3]  0x00404018      .qword 0x0000000000401036 ; RELOC 64 puts
+
+  [0x00401040]> pd 6 @ section..plt
+              ;-- section..plt:
+              ;-- .plt:       ; [12] -r-x section size 32 named .plt
+          ┌─> 0x00401020      ff35e22f0000   push qword [0x00404008]
+          ╎   0x00401026      ff25e42f0000   jmp qword [0x00404010]
+          ╎   0x0040102c      0f1f4000       nop dword [rax]
+  ┌ 6: int sym.imp.puts (const char *s);
+  └       ╎   0x00401030      ff25e22f0000   jmp qword [reloc.puts]
+          ╎   0x00401036      6800000000     push 0
+          └─< 0x0040103b      e9e0ffffff     jmp sym..plt
+
+
    +
  • At address 0x00401030 in the .plt section we see the indirect jump for +puts using the function pointer in _GLOBAL_OFFSET_TABLE_[3] (GOT).
  • +
  • GOT[3] initially points to instruction after the puts trampoline +0x00401036.
  • +
  • This pushes the relocation index 0 and then jumps to the first trampoline +0x00401020.
  • +
  • The first trampoline jumps to GOT[2] which will be filled at program +startup by the ld.so with its resolve function.
  • +
  • The ld.so resolve function fixes the relocation referenced by the +relocation index pushed by the puts trampoline.
  • +
  • The relocation entry at index 0 tells the resolve function which symbol to +search for and where to put the function pointer: +
      > readelf -r <main>
    +    >> Relocation section '.rela.plt' at offset 0x4b8 contains 1 entry:
    +    >>   Offset          Info           Type           Sym. Value    Sym. Name + Addend
    +    >> 000000404018  000200000007 R_X86_64_JUMP_SLO 0000000000000000 puts@GLIBC_2.2.5 + 0
     
    +As we can see the offset from relocation at index 0 points to GOT[3].
  • +
-- cgit v1.2.3