GOT patcher: support API-by-pointer calls 91/92191/6
authorAlexander Aksenov <a.aksenov@samsung.com>
Thu, 13 Oct 2016 14:59:06 +0000 (17:59 +0300)
committerAlexander Aksenov <a.aksenov@samsung.com>
Wed, 26 Oct 2016 18:31:34 +0000 (21:31 +0300)
Issue:
When target API function is called via pointer, not directly,
it was not handled, because symbol was stored in variables section
and not in functions.

Solution:
Patch not only function, but also variable section when variable
name is the same as a target API.

Change-Id: I3178360ddf8d1099e63ec9119d7322e70fefc5f7
Signed-off-by: Alexander Aksenov <a.aksenov@samsung.com>
helper/get_got.c
helper/get_got.h
helper/got_patching.c

index f72d492..1eee3da 100644 (file)
 
 
 #if (defined __x86_64__) || (defined __aarch64__)
+
 # define PLTREL  ElfW(Rela)
+
+enum {
+       RELPTR = DT_RELA,
+       RELSZ =  DT_RELASZ,
+};
+
 #elif (defined __i386__) || (defined __arm__) || (defined __thumb__)
+
 # define PLTREL  ElfW(Rel)
+
+enum {
+       RELPTR = DT_REL,
+       RELSZ =  DT_RELSZ,
+};
+
 #else
 #error "This arch is not supported"
 #endif
@@ -36,32 +50,25 @@ struct ext_map {
        ElfW(Dyn) *l_info[0];
 };
 
+struct sdesc_id_t {
+       int ptr_id;
+       int s_size_id;
+};
 
-const char *lmap_get_name(const struct link_map *map, unsigned long offset)
-{
-       const struct ext_map *emap = (const struct ext_map *)map;
-       const char *strtab;
-       const PLTREL *reloc;
-       const ElfW(Sym) *symtab;
-       const ElfW(Sym) *sym;
-
-       symtab = (const void *)D_PTR(emap, l_info[DT_SYMTAB]);
-       strtab = (const void *)D_PTR(emap, l_info[DT_STRTAB]);
-       reloc = (const void *)(D_PTR(emap, l_info[DT_JMPREL]) + offset);
 
-       sym = &symtab[ELFW(R_SYM)(reloc->r_info)];
-       return strtab + sym->st_name;
-}
+static struct sdesc_id_t got = {
+       .ptr_id = RELPTR,
+       .s_size_id = RELSZ,
+};
 
-unsigned long lmap_reladdr_by_offset(const struct link_map *map,
-                                    unsigned long offset)
-{
-       const struct ext_map *emap = (const struct ext_map *)map;
+static struct sdesc_id_t got_plt = {
+       .ptr_id = DT_JMPREL,
+       .s_size_id = DT_PLTRELSZ,
+};
 
-       return (unsigned long)(D_PTR(emap, l_info[DT_JMPREL]) + offset);
-}
 
-unsigned long lmap_reladdr_by_name(const struct link_map *map, const char *name)
+static unsigned long _addr_by_name(const struct link_map *map, const char *name,
+                                  struct sdesc_id_t *sdesc)
 {
        const struct ext_map *emap = (const struct ext_map *)map;
        const char *strtab;
@@ -73,19 +80,20 @@ unsigned long lmap_reladdr_by_name(const struct link_map *map, const char *name)
                return 0;
 
        /* relocation table doesn't exist */
-       if (emap->l_info[DT_PLTRELSZ] == NULL)
+       if (emap->l_info[sdesc->s_size_id] == NULL)
                return 0;
 
        symtab = (const void *)D_PTR(emap, l_info[DT_SYMTAB]);
        strtab = (const void *)D_PTR(emap, l_info[DT_STRTAB]);
-       size = emap->l_info[DT_PLTRELSZ]->d_un.d_val;
+       size = emap->l_info[sdesc->s_size_id]->d_un.d_val;
 
        for (offset = 0; offset < size; offset += sizeof(PLTREL)) {
                const PLTREL *reloc;
                const ElfW(Sym) *sym;
                const char *sym_name;
 
-               reloc = (const void *)(D_PTR(emap, l_info[DT_JMPREL]) + offset);
+               reloc = (const void *)(D_PTR(emap, l_info[sdesc->ptr_id]) +
+                                      offset);
                sym = &symtab[ELFW(R_SYM)(reloc->r_info)];
                sym_name = strtab + sym->st_name;
 
@@ -95,3 +103,38 @@ unsigned long lmap_reladdr_by_name(const struct link_map *map, const char *name)
 
        return 0;
 }
+
+
+const char *lmap_get_name(const struct link_map *map, unsigned long offset)
+{
+       const struct ext_map *emap = (const struct ext_map *)map;
+       const char *strtab;
+       const PLTREL *reloc;
+       const ElfW(Sym) *symtab;
+       const ElfW(Sym) *sym;
+
+       symtab = (const void *)D_PTR(emap, l_info[DT_SYMTAB]);
+       strtab = (const void *)D_PTR(emap, l_info[DT_STRTAB]);
+       reloc = (const void *)(D_PTR(emap, l_info[DT_JMPREL]) + offset);
+
+       sym = &symtab[ELFW(R_SYM)(reloc->r_info)];
+       return strtab + sym->st_name;
+}
+
+unsigned long lmap_reladdr_by_offset(const struct link_map *map,
+                                    unsigned long offset)
+{
+       const struct ext_map *emap = (const struct ext_map *)map;
+
+       return (unsigned long)(D_PTR(emap, l_info[DT_JMPREL]) + offset);
+}
+
+unsigned long lmap_reladdr_by_name(const struct link_map *map, const char *name)
+{
+       return _addr_by_name(map, name, &got_plt);
+}
+
+unsigned long lmap_gotaddr_by_name(const struct link_map *map, const char *name)
+{
+       return _addr_by_name(map, name, &got);
+}
index 52631a7..6813daa 100644 (file)
@@ -4,8 +4,10 @@
 /* Pass address - get function name */
 const char *lmap_get_name(const struct link_map *map, unsigned long offset);
 
-/* Pass name - get GOT entry address */
+/* Pass name - get .got.plt entry address */
 unsigned long lmap_reladdr_by_name(const struct link_map *map, const char *name);
+/* Pass name - get .got entry address */
+unsigned long lmap_gotaddr_by_name(const struct link_map *map, const char *name);
 
 /* Pass offset - get GOT entry address */
 unsigned long lmap_reladdr_by_offset(const struct link_map *map,
index 5679131..348e801 100644 (file)
@@ -139,6 +139,7 @@ static void _process_target_bins(char *bins_data)
 static void *_get_orig_on_demand(unsigned long addr)
 {
        Dl_info sym_info;
+       /* TODO Add other libraries after splitting */
        const char probe_lib[] = "/usr/lib/da_probe_tizen.so";
        int ret;
 
@@ -186,6 +187,7 @@ static inline bool _is_ignored(const char *path)
        const char udev_lib[] = "/lib/libudev.so.1";
        const char evdev_lib[] = "/lib/libevdev.so.2";
        const char evdev[] = "/usr/lib/libevdev.so.2";
+       const char libc[] = "/lib/libc.so.6";
 
        if (!strcmp(probe_lib, path) ||
            !strcmp(event_lib, path) ||
@@ -200,7 +202,8 @@ static inline bool _is_ignored(const char *path)
            !strcmp(udev_lib, path) ||
            !strcmp(udev, path) ||
            !strcmp(evdev_lib, path) ||
-           !strcmp(evdev, path))
+           !strcmp(evdev, path) ||
+           !strcmp(libc, path))
                return true;
 
        return false;
@@ -244,6 +247,37 @@ check_if_patch_fail:
 }
 
 
+
+static void _patch_sym(struct link_map *map, struct probe_desc_t *probe)
+{
+       unsigned long addr;
+       void *orig;
+
+       /* Patch symbol in .got.plt section */
+       addr = lmap_reladdr_by_name(map, probe->orig_name);
+       if (addr == 0)
+               goto patch_got;
+
+       orig = _get_orig_on_demand(addr);
+       if (orig != NULL) {
+               probe->orig_ptr = (ElfW(Addr))orig;
+               *(ElfW(Addr) *)addr = probe->handler_ptr;
+       }
+
+patch_got:
+       /* Patch symbol in .got section */
+       addr = lmap_gotaddr_by_name(map, probe->orig_name);
+       if (addr == 0)
+               return;
+
+       orig = _get_orig_on_demand(addr);
+       if (orig != NULL) {
+               probe->orig_ptr = (ElfW(Addr))orig;
+               *(ElfW(Addr) *)addr = probe->handler_ptr;
+       }
+}
+
+
 static int _patch_bin(struct dl_phdr_info *info, size_t __unused size, void *data)
 {
        struct link_map *map;
@@ -253,8 +287,7 @@ static int _patch_bin(struct dl_phdr_info *info, size_t __unused size, void *dat
        bool is_for_all;
        bool is_ign;
        unsigned int i;
-       unsigned long addr;
-       void *orig, *handle;
+       void *handle;
        struct feature_desc_t *feature = (struct feature_desc_t *)data;
 
        /* Get binary path */
@@ -297,15 +330,7 @@ static int _patch_bin(struct dl_phdr_info *info, size_t __unused size, void *dat
                    ((feature->probes[i].flags != GT_TARGET_PROBE) && target_bin))
                        continue;
 
-               addr = lmap_reladdr_by_name(map, feature->probes[i].orig_name);
-               if (addr == 0)
-                       continue;
-
-               orig = _get_orig_on_demand(addr);
-               if (orig != NULL) {
-                       feature->probes[i].orig_ptr = (ElfW(Addr))orig;
-                       *(ElfW(Addr) *)addr = feature->probes[i].handler_ptr;
-               }
+               _patch_sym(map, &feature->probes[i]);
        }
 
 fail_get_map:
@@ -448,8 +473,6 @@ void __dl_reloc_wrapper(struct link_map *l, struct r_scope_elem *scope[],
        const char *path = l->l_name;
        bool target_bin;
        bool is_for_all;
-       unsigned long addr;
-       void *orig;
 
        target_bin = _check_if_patch(path);
 
@@ -475,17 +498,7 @@ void __dl_reloc_wrapper(struct link_map *l, struct r_scope_elem *scope[],
                             target_bin))
                                continue;
 
-                       addr = lmap_reladdr_by_name(l,
-                                                 features[i]->probes[j].orig_name);
-                       if (addr == 0)
-                               continue;
-
-                       orig = _get_orig_on_demand(addr);
-                       if (orig != NULL) {
-                               features[i]->probes[j].orig_ptr = (ElfW(Addr))orig;
-                               *(ElfW(Addr) *)addr =
-                                       features[i]->probes[j].handler_ptr;
-                       }
+                       _patch_sym(l, &features[i]->probes[j]);
                }
        }
 }