Skip to content

Crash on change_resolve_func with PIE executables #3

@dequis

Description

@dequis

Hi there! Apparently PIE is enabled default in my distro and/or since gcc 6, which breaks this library. It looks for the PLT section in elf->plt which here has the value 0x6a0 but the elf is loaded at addresses like 0x555555554000 (when aslr is disabled)

$ ASYNCSAFE_LOGGING=1 gdb --args ./testlink
Reading symbols from ./testlink...done.
(gdb) run
Starting program: /home/dx/test/asd/monorail/asyncsafe/testlink
getting ELF info for [/proc/7859/exe]
asyncsafe: intercept signal 10 registration of handler 0x5555555547fa
asyncsafe: intercept signal 12 registration of handler 0x55555555481e

Program received signal SIGUSR1, User defined signal 1.
0x00007ffff7850860 in raise () from /usr/lib/libc.so.6
(gdb) c
Continuing.
asyncsafe on  vvv

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7bd593d in change_resolve_func (elf=0x7ffff7dd7800 <elf>, hijack=1)
    at plt.c:28
28          unsigned long handler = *(unsigned int *)(elf->plt + 8) + elf->plt + 8 + 4;
(gdb) bt
#0  0x00007ffff7bd593d in change_resolve_func (elf=0x7ffff7dd7800 <elf>, hijack=1)
    at plt.c:28
#1  0x00007ffff7bd5c6c in enable_intercept () at plt.c:84
#2  0x00007ffff7bd5025 in asyncsafe_intercept (signum=10, info=0x7fffffffdff0,
    context=0x7fffffffdec0) at safe.c:47
#3  <signal handler called>
#4  0x00007ffff7850860 in raise () from /usr/lib/libc.so.6
#5  0x0000555555554868 in main () at test.c:17

(gdb) p elf
$1 = (elf_t *) 0x7ffff7dd7800 <elf>
(gdb) p *elf
$2 = {map = 0x7ffff7ff1000, length = 12664, fd = 3, header = 0x7ffff7ff1000,
  sheader = 0x7ffff7ff38b8, pheader = 0x7ffff7ff1040,
  shstrtab = 0x7ffff7ff375f "", strtab = 0x7ffff7ff3520 "",
  dynstr = 0x7ffff7ff1438 "", plt = 1696, plt_size = 80,
  rela_plt = 0x7ffff7ff3b38, got_plt = 0x7ffff7ff3e38, symtab = 0x7ffff7ff40b8,
  dynsym = 0x7ffff7ff39f8}
(gdb) p elf->plt
$3 = 1696

Stupid/dirty patch that assumes no aslr:

diff --git a/elfmap.c b/elfmap.c
index 4354e8a..c97b023 100644
--- a/elfmap.c
+++ b/elfmap.c
@@ -11,6 +11,8 @@
 #define die(str) \
     puts(str), exit(1)
 
+extern unsigned long base_address;
+
 static void verify_elf(elf_t *elf);
 static void find_basic(elf_t *elf);
 static void find_strtab(elf_t *elf);
@@ -106,7 +108,7 @@ static void find_got_and_plt(elf_t *elf) {
         Elf64_Shdr *s = &elf->sheader[i];
         const char *name = elf->shstrtab + s->sh_name;
         if(!strcmp(name, ".plt")) {
-            elf->plt      = (unsigned long)s->sh_addr;
+            elf->plt      = (unsigned long)s->sh_addr + base_address;
             elf->plt_size = (unsigned long)s->sh_size;
         }
         else if(!strcmp(name, ".got.plt")) {
diff --git a/safe.c b/safe.c
index fdae01d..3ab05bb 100644
--- a/safe.c
+++ b/safe.c
@@ -11,7 +11,7 @@
 /* --- Initialization & ELF processing--- */
 
 elf_t elf;
-unsigned long base_address = 0;  // base of elf, for shared libraries
+unsigned long base_address = 0x555555554000;  // base of elf, for shared libraries
 
 void asyncsafe_init(void) {
     static int initialized = 0;

Not sure what's the right way to get the base address, first line of /proc/pid/maps?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions