Implement target bins removing 05/154605/4
authorAlexander Aksenov <a.aksenov@samsung.com>
Wed, 4 Oct 2017 18:56:59 +0000 (21:56 +0300)
committerAlexander Aksenov <a.aksenov@samsung.com>
Fri, 13 Oct 2017 11:38:02 +0000 (14:38 +0300)
Now removing of target bins is handled, they are cleaned on
uninit, messages SWAP_INST_ADD and SWAP_INST_REMOVE handled
in different ways

This commit is related with the same name commit for swap-manager

Change-Id: Iaf3d61ebe98379c9fb7a63ed3c0ae0cda3e365cc
Signed-off-by: Alexander Aksenov <a.aksenov@samsung.com>
helper/dahelper.c
helper/got_patching.c
helper/got_patching.h
helper/libdaprobe.c
include/app_protocol.h
include/dahelper.h

index b191761..25202da 100755 (executable)
@@ -156,6 +156,8 @@ void swap_usleep(useconds_t usec)
  *                                  BINARIES LIST                            *
  *****************************************************************************/
 
+typedef int(*parse_cb_t)(const char *path);
+
 static struct bin_info_t *_find_binary_no_lock(const char *path)
 {
        struct bin_info_t *bin_info;
@@ -168,9 +170,19 @@ static struct bin_info_t *_find_binary_no_lock(const char *path)
        return NULL;
 }
 
+static int _decrease_size(size_t *size, size_t need)
+{
+       if (*size < need) {
+               PRINTERR("wrong buffer size");
+               return -EINVAL;
+       }
+
+       *size -= need;
+       return 0;
+}
 
 /* Returns 0 on success, -errcode on fail */
-int add_binary(char *path)
+static int _add_binary(const char *path)
 {
        struct bin_info_t *bin_info;
        int ret = 0;
@@ -214,11 +226,11 @@ add_bin_unlock:
 }
 
 /* Return 0 if binary added or already exists, -errcode otherwise */
-int add_binary_on_demand(char *path)
+static int _add_binary_on_demand(const char *path)
 {
        int ret;
 
-       ret = add_binary(path);
+       ret = _add_binary(path);
        if (!ret || ret == -EALREADY)
                return 0;
 
@@ -226,7 +238,7 @@ int add_binary_on_demand(char *path)
 }
 
 /* Returns 0 on success, -errcode on fail */
-int remove_binary(char *path)
+static int _remove_binary(const char *path)
 {
        struct bin_info_t *bin_info;
        int ret = 0;
@@ -262,6 +274,119 @@ remove_bin_unlock:
        return ret;
 }
 
+static void _parse_bundle(char *bundle, size_t size,
+                         struct ext_bininfo_t **resp, parse_cb_t cb)
+{
+       uint32_t cnt;
+       uint32_t len;
+       char *ptr = bundle;
+       char *path;
+       unsigned int i;
+       int ret;
+       struct ext_bininfo_t *res, *last, *tmp;
+
+       if (!cb) {
+               PRINTERR("Error! No callback for parsing bundle!");
+               return;
+       }
+
+       if (resp) {
+               res = *resp;
+               last = *resp;
+       }
+
+       if (_decrease_size(&size, sizeof(cnt)))
+               return;
+
+       cnt = *(uint32_t *)ptr;
+       ptr += sizeof(cnt);
+
+       for (i = 0; i < cnt; i++) {
+               if (_decrease_size(&size, sizeof(len)))
+                       return;
+
+               len = *(uint32_t *)ptr;
+               ptr += sizeof(len);
+
+               if (_decrease_size(&size, len))
+                       return;
+
+               path = malloc(len);
+               if (path == NULL) {
+                       PRINTERR("No memory to alloc for path!");
+                       return;
+               }
+
+               memcpy(path, ptr, len);
+               ptr += len;
+
+               ret = cb(path);
+               if (!ret && resp) {
+                       tmp = malloc(sizeof(*tmp));
+                       if (!tmp) {
+                               PRINTERR("No memory to alloc for ext_bininfo");
+                               return;
+                       }
+                       tmp->next = NULL;
+                       tmp->path = path;
+                       if (res) {
+                               last->next = tmp;
+                               last = tmp;
+                       } else {
+                               res = last = tmp;
+                       }
+               } else {
+                       PRINTERR("Adding failed, error code %d", ret);
+               }
+       }
+}
+
+
+void add_binaries(char *bundle, size_t size)
+{
+       _parse_bundle(bundle, size, NULL, _add_binary_on_demand);
+}
+
+struct ext_bininfo_t *add_binaries_get_new(char *bundle, size_t size)
+{
+       struct ext_bininfo_t *res = NULL;
+
+       _parse_bundle(bundle, size, &res, _add_binary_on_demand);
+
+       return res;
+}
+
+void remove_binaries(char *bundle, size_t size)
+{
+       _parse_bundle(bundle, size, NULL, _remove_binary);
+}
+
+struct ext_bininfo_t *remove_binaries_get_diff(char *bundle, size_t size)
+{
+       struct ext_bininfo_t *res = NULL;
+
+       _parse_bundle(bundle, size, &res, _remove_binary);
+
+       return res;
+}
+
+void free_bins_info(struct ext_bininfo_t *ebi)
+{
+       struct ext_bininfo_t *iter, *tmp = NULL;
+
+       if (!ebi)
+               return;
+
+       for (iter = ebi; iter; iter = iter->next) {
+               free(tmp);
+               free(iter->path);
+               tmp = iter;
+       }
+
+       /* Free last element */
+       free(tmp);
+}
+
 /* Checks if binary is a target one */
 bool check_binary(const char *path)
 {
index c21e963..8db50a4 100644 (file)
@@ -74,68 +74,37 @@ static void _init_feature_ptrs(void)
 /* Used to call symbol search in different sections by one func */
 typedef unsigned long (*find_name_cb_t)(const struct link_map *, const char *);
 
-/* Used to get main executable name */
-extern char *program_invocation_name;
-static bool inited = false;
-
-static int decrease_size(size_t *size, size_t need)
-{
-       if (*size < need) {
-               PRINTERR("wrong buffer size");
-               return -EINVAL;
-       }
-
-       *size -= need;
-       return 0;
-}
-
-static void _process_target_bins(char *bins_data, size_t avail_size)
-{
-       uint32_t cnt;
-       uint32_t len;
-       char *ptr = bins_data;
-       char *path;
-       unsigned int i;
-       int ret;
-
-       if (decrease_size(&avail_size, sizeof(cnt)))
-               return;
-
-       cnt = *(uint32_t *)ptr;
-       ptr += sizeof(cnt);
-
-       for (i = 0; i < cnt; i++) {
-               if (decrease_size(&avail_size, sizeof(len)))
-                       return;
+/* Indicate patching or unpatching */
+enum gp_indicate {
+       GP_PATCHING,
+       GP_UNPATCHING
+};
 
-               len = *(uint32_t *)ptr;
-               ptr += sizeof(len);
+/* Data struct to pass to patch_bin */
+struct gp_bin_patch {
+       struct feature_desc_t *f;
+       struct ext_bininfo_t *bins;
+       enum gp_indicate gpi;
+};
 
-               if (decrease_size(&avail_size, len))
-                       return;
+/* Patch info data */
+struct gp_sym_patch {
+       struct link_map *map;
+       struct phdr_info *info;
+       struct probe_desc_t *probe;
+       enum gp_indicate gpi;
+};
 
-               path = malloc(len);
-               if (path == NULL) {
-                       // TODO Error! error! error!
-                       return;
-               }
 
-               memcpy(path, ptr, len);
-               ptr += len;
+/* Used to get main executable name */
+extern char *program_invocation_name;
+static bool inited = false;
 
-               /* TODO Think about removing binaries */
-               ret = add_binary_on_demand(path);
-               if (!ret)
-                       PRINTERR("Adding failed, error code %d", ret);
-               /* add_binary_on_demand() allocates new buffer with realpath(),
-                * so this path should be freed */
-               free(path);
-       }
-}
 
-static void *_get_orig_on_demand(unsigned long addr)
+static void *_get_pointed_demand(unsigned long addr, struct gp_sym_patch *gsp)
 {
        Dl_info sym_info;
+       bool is_probe_pointed = false;
        int ret;
 
        ret = dladdr(*(void **)addr, &sym_info);
@@ -152,11 +121,18 @@ static void *_get_orig_on_demand(unsigned long addr)
            !strcmp(probelib_screenshot, sym_info.dli_fname) ||
            !strcmp(probelib_uihv, sym_info.dli_fname) ||
            !strcmp(probelib_lsan, sym_info.dli_fname))
-               return NULL;
-
-       return sym_info.dli_saddr;
+               is_probe_pointed = true;
+
+       /* If we are patching binaries - return NULL if already patched,
+        * if we are unpatching binaries - return NULL if haven't been patched.
+        */
+       if (gsp->gpi == GP_PATCHING)
+               return is_probe_pointed ? NULL : sym_info.dli_saddr;
+       else
+               return is_probe_pointed ? sym_info.dli_saddr : NULL;
 }
 
+
 static inline bool _is_for_all_feature(struct feature_desc_t *feature)
 {
        unsigned int i;
@@ -190,23 +166,37 @@ static inline bool _is_ignored(const char *path)
        return false;
 }
 
-static inline bool _check_if_patch(const char *path)
+
+
+static inline bool _check_if_patch_by_stored(const char *path)
+{
+       return check_binary(path);
+}
+
+static inline bool _check_if_patch_by_list(const char *path,
+                                          struct ext_bininfo_t *bins)
+{
+       struct ext_bininfo_t *cur;
+
+       for (cur = bins; cur; cur = cur->next)
+               if (!strncmp(cur->path, path, PATH_MAX))
+                       return true;
+
+       return false;
+}
+
+/* If there is no bins - check from stored */
+static inline bool _check_if_patch(const char *path,
+                                  struct ext_bininfo_t *bins)
 {
-       bool res;
-       pid_t pid;
-       char dest[PATH_MAX];
        char real[PATH_MAX];
        const char *check = NULL;
 
        if (path[0] == '\0' && program_invocation_name[0] == '\0') {
                /* If we are checking main executable and
                 * program_invocation_name was not inited yet */
-               pid = getpid();
-               snprintf(dest, sizeof(dest), "/proc/%d/exe", pid);
-
-               if (readlink(dest, real, PATH_MAX) == -1) {
-                       PRINTERR("Readlink for <%s> has failed!");
-                       res = false;
+               if (readlink("/proc/self/exe", real, PATH_MAX) == -1) {
+                       PRINTERR("Readlink has failed!");
                        goto check_if_patch_fail;
                }
 
@@ -220,11 +210,38 @@ static inline bool _check_if_patch(const char *path)
                check = path;
        }
 
-       res = check_binary(check);
+       if (!bins)
+               return _check_if_patch_by_stored(check);
+       else
+               return _check_if_patch_by_list(check, bins);
 
 check_if_patch_fail:
 
-       return res;
+       return false;
+}
+
+static inline bool _if_patch_sym(struct probe_desc_t *probe, bool target,
+                                enum gp_indicate gpi)
+{
+       if (gpi == GP_PATCHING) {
+               /* If feature is not always and flags doesn't satisfy binary's
+                * status - do not patch */
+               if ((probe->flags != GT_ALWAYS_PROBE) &&
+                   ((probe->flags != GT_TARGET_PROBE) && target))
+                       return false;
+               else
+                       return true;
+       } else {
+               /* Unpatch only if it is not always probe, if it is target
+                * binary and if it is target probe */
+               if (probe->flags == GT_ALWAYS_PROBE)
+                       return false;
+               if (probe->flags != GT_TARGET_PROBE)
+                       return false;
+               if (!target)
+                       return false;
+               return true;
+       }
 }
 
 
@@ -245,8 +262,8 @@ static const ElfW(Phdr) *_get_segment(struct phdr_info *info,
        return ret;
 }
 
-/* Resolves memory protection on ro GOT sections and writes handler address */
-static void _unprotected_write(unsigned long dest, ElfW(Addr) handler,
+/* Resolves memory protection on ro GOT sections and writes src address */
+static void _unprotected_write(unsigned long dest, ElfW(Addr) src,
                               struct phdr_info *info)
 {
        int pagesize_mask = ~(getpagesize() - 1);
@@ -271,7 +288,7 @@ static void _unprotected_write(unsigned long dest, ElfW(Addr) handler,
                }
        }
 
-       *(ElfW(Addr) *)dest = handler;
+       *(ElfW(Addr) *)dest = src;
 
        if (phdr->p_type == PT_GNU_RELRO) {
                err = mprotect((void *)((base + phdr->p_vaddr) & pagesize_mask),
@@ -282,29 +299,32 @@ static void _unprotected_write(unsigned long dest, ElfW(Addr) handler,
 }
 
 /* Find symbols for probe, stores original and patch them on demnad */
-static void _do_patch_sym(struct link_map *map, struct phdr_info *info,
-                         struct probe_desc_t *probe, find_name_cb_t cb)
+static void _do_patch_sym(struct gp_sym_patch *gsp, find_name_cb_t cb)
 {
        unsigned long addr;
+       struct probe_desc_t *probe = gsp->probe;
        void *orig;
 
        /* Patch symbol in .got.plt section */
-       addr = cb(map, probe->orig_name);
+       addr = cb(gsp->map, probe->orig_name);
        if (addr == 0)
                return;
 
-       orig = _get_orig_on_demand(addr);
+       orig = _get_pointed_demand(addr, gsp);
        if (orig != NULL) {
-               probe->orig_ptr = (ElfW(Addr))orig;
-               _unprotected_write(addr, probe->handler_ptr, info);
+               if (gsp->gpi == GP_PATCHING) {
+                       probe->orig_ptr = (ElfW(Addr))orig;
+                       _unprotected_write(addr, probe->handler_ptr, gsp->info);
+               } else {
+                       _unprotected_write(addr, probe->orig_ptr, gsp->info);
+               }
        }
 }
 
-static void _patch_sym(struct link_map *map, struct phdr_info *info,
-                      struct probe_desc_t *probe)
+static void _patch_sym(struct gp_sym_patch *gsp)
 {
-       _do_patch_sym(map, info, probe, lmap_reladdr_by_name);
-       _do_patch_sym(map, info, probe, lmap_gotaddr_by_name);
+       _do_patch_sym(gsp, lmap_reladdr_by_name);
+       _do_patch_sym(gsp, lmap_gotaddr_by_name);
 }
 
 static struct link_map *_find_map(const char *path)
@@ -328,7 +348,9 @@ 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;
-       struct feature_desc_t *feature = (struct feature_desc_t *)data;
+       struct gp_bin_patch *gpd = (struct gp_bin_patch *)data;
+       struct feature_desc_t *feature = gpd->f;
+       struct gp_sym_patch gsp;
 
        /* Get binary path */
        path = info->dlpi_name;
@@ -339,7 +361,7 @@ static int _patch_bin(struct dl_phdr_info *info, size_t __unused size, void *dat
 
        /* Check if this binary a target one */
        is_for_all = _is_for_all_feature(feature);
-       target_bin = _check_if_patch(path);
+       target_bin = _check_if_patch(path, gpd->bins);
        is_ign = _is_ignored(path);
        if (is_ign || (!target_bin && !is_for_all))
                return 0;
@@ -364,32 +386,39 @@ static int _patch_bin(struct dl_phdr_info *info, size_t __unused size, void *dat
        pi.phnum = info->dlpi_phnum;
 
        for (i = 0; i < feature->cnt; i++) {
-               /* If feature is not always and flags doesn't satisfy binary's status -
-                * continue */
-               if ((feature->probes[i].flags != GT_ALWAYS_PROBE) &&
-                   ((feature->probes[i].flags != GT_TARGET_PROBE) && target_bin))
+               if (!_if_patch_sym(&feature->probes[i], target_bin, gpd->gpi))
                        continue;
 
-               _patch_sym(map, &pi, &feature->probes[i]);
+               gsp.map = map;
+               gsp.info = &pi;
+               gsp.probe = &feature->probes[i];
+               gsp.gpi = gpd->gpi;
+
+               _patch_sym(&gsp);
        }
 
        return ret;
 }
 
-static void _patch_target_bins(struct feature_desc_t *feature)
+static void _patch_target_bins(struct gp_bin_patch *gpd)
 {
-       dl_iterate_phdr(_patch_bin, feature);
+       dl_iterate_phdr(_patch_bin, gpd);
 }
 
-void process_features(void)
+static void _process_features(enum gp_indicate gpi, struct ext_bininfo_t *bins)
 {
+       struct gp_bin_patch gpd;
        unsigned int i;
 
        for (i = 0; i < FEATURES_CNT; i++) {
                if (features[i] == NULL ||
                    !isOptionEnabled(features[i]->feature, 0))
                        continue;
-               _patch_target_bins(features[i]);
+
+               gpd.f = features[i];
+               gpd.bins = bins;
+               gpd.gpi = gpi;
+               _patch_target_bins(&gpd);
        }
 }
 
@@ -448,7 +477,7 @@ __dl_fixup_wrapper (
 //     got_addr = lmap_reladdr_by_offset(l, reloc_arg);
        got_addr = lmap_reladdr_by_name(l, func_name);
 
-       target_bin = _check_if_patch(l->l_name);
+       target_bin = _check_if_patch(l->l_name, NULL);
 
        exec_addr = dl_fixup_p(l, reloc_arg);
 
@@ -510,9 +539,10 @@ void __dl_reloc_wrapper(struct link_map *l, struct r_scope_elem *scope[],
        struct phdr_info pi;
        bool target_bin;
        bool is_for_all;
+       struct gp_sym_patch gsp;
        int err;
 
-       target_bin = _check_if_patch(path);
+       target_bin = _check_if_patch(path, NULL);
 
        dl_reloc_p(l, scope, reloc_mode, consider_profiling);
 
@@ -542,7 +572,12 @@ void __dl_reloc_wrapper(struct link_map *l, struct r_scope_elem *scope[],
                             target_bin))
                                continue;
 
-                       _patch_sym(l, &pi, &features[i]->probes[j]);
+                       gsp.map = l;
+                       gsp.info = &pi;
+                       gsp.probe = &features[i]->probes[j];
+                       gsp.gpi = GP_PATCHING;
+
+                       _patch_sym(&gsp);
                }
        }
 }
@@ -550,7 +585,7 @@ void __dl_reloc_wrapper(struct link_map *l, struct r_scope_elem *scope[],
 
 
 
-static int _init_linker_addr(void)
+int init_linker_addr(void)
 {
        struct link_map *lmap;
 
@@ -564,6 +599,8 @@ static int _init_linker_addr(void)
        dl_fixup_p = (dl_fixup_t)(dl_fixup_off + lmap->l_addr);
        dl_reloc_p = (dl_reloc_t)(dl_reloc_off + lmap->l_addr);
 
+       inited = true;
+
        return 0;
 }
 
@@ -575,18 +612,31 @@ void init_features(void)
 
 void process_got_patching(char *data, size_t size)
 {
-       if (!inited) {
-               _init_linker_addr();
-               inited = true;
-       }
-       _process_target_bins(data, size);
-       process_features();
+       struct ext_bininfo_t *bins;
+
+       if (!inited)
+               init_linker_addr();
+
+       bins = add_binaries_get_new(data, size);
+       _process_features(GP_PATCHING, bins);
+       free_bins_info(bins);
 }
 
 
-void restore_got_patching(void)
+void restore_got_patching(char *data, size_t size)
 {
-       /* TODO patch all binaries back */
+       struct ext_bininfo_t *bins;
+
+       bins = remove_binaries_get_diff(data, size);
+       _process_features(GP_UNPATCHING, bins);
+       free_bins_info(bins);
 
-       cleanup_binaries();
+       /* Repatch to apply non-target features */
+       _process_features(GP_PATCHING, NULL);
+}
+
+/* Used for initial total patching */
+void process_features(void)
+{
+       _process_features(GP_PATCHING, NULL);
 }
index 21b1410..82f4391 100644 (file)
@@ -1,9 +1,13 @@
 #ifndef __GOT_PATCHING_H__
 #define __GOT_PATCHING_H__
 
+int init_linker_addr(void);
+
 void process_got_patching(char *data, size_t size);
-void restore_got_patching(void);
+void restore_got_patching(char *data, size_t size);
 void init_features(void);
+
+/* Used for kernel call */
 void process_features(void);
 
 #endif /* __GOT_PATCHING_H__ */
index a7abfaa..86f74a7 100755 (executable)
@@ -120,15 +120,21 @@ static void _configure(char* configstr)
 
 static void _receive_target_bins(char *data_buf, size_t size)
 {
-       process_got_patching(data_buf, size);
+       init_linker_addr();
+       add_binaries(data_buf, size);
 }
 
-static void _process_target_bins(char *data_buf, size_t size)
+static void _process_target_bins_add(char *data_buf, size_t size)
 {
        process_got_patching(data_buf, size);
-       process_features();
 }
 
+static void _process_target_bins_remove(char *data_buf, size_t size)
+{
+       restore_got_patching(data_buf, size);
+}
+
+
 void application_exit()
 {
        pid_t gpid;
@@ -276,8 +282,8 @@ static int create_socket(void)
                        PRINTMSG("APP_MSG_CONFIG");
                        _configure((char *)data_buf);
                        recved |= MSG_CONFIG_RECV;
-               } else if (log.type == APP_MSG_TARGET_BINS) {
-                       PRINTMSG("APP_MSG_TARGET_BINS");
+               } else if (log.type == APP_MSG_TARGET_BINS_ADD) {
+                       PRINTMSG("APP_MSG_TARGET_BINS_ADD");
                        _receive_target_bins((char *)data_buf, data_size);
                        recved |= MSG_TARGET_BINS_RECV;
                } else {
@@ -325,8 +331,10 @@ static int msg_handler(log_t *log)
                capture_screen_call();
        } else if (log->type == APP_MSG_CONFIG) {
                _configure((char *)log->data);
-       } else if (log->type == APP_MSG_TARGET_BINS) {
-               _process_target_bins((char *)log->data, log->length);
+       } else if (log->type == APP_MSG_TARGET_BINS_ADD) {
+               _process_target_bins_add((char *)log->data, log->length);
+       } else if (log->type == APP_MSG_TARGET_BINS_REMOVE) {
+               _process_target_bins_remove((char *)log->data, log->length);
        } else if (log->type == APP_MSG_STOP) {
                /* Do leaks check if LSan is enabled. */
                lsan_do_leak_check();
@@ -554,6 +562,7 @@ void _uninit_(void)
        int i;
 
        lsan_close_liblsan();
+       cleanup_binaries();
 
        gTraceInfo.init_complete = -1;
        PRINTMSG("dynamic analyzer probe helper so unloading... pid[%d]\n",
index 4e6db60..02dec96 100644 (file)
@@ -33,6 +33,10 @@ enum AppMessageType
 {
        APP_MSG_LSAN_REPORT,
 
+       APP_MSG_TARGET_BINS_ADD,
+       APP_MSG_TARGET_BINS_REMOVE,
+
+
        APP_MSG_IMAGE = 6,
        APP_MSG_TERMINATE = 7,
        APP_MSG_PID = 8,
@@ -45,7 +49,6 @@ enum AppMessageType
        APP_MSG_STOP = 101,
        APP_MSG_CONFIG = 103,
        APP_MSG_CAPTURE_SCREEN= 108,
-       APP_MSG_TARGET_BINS = 109,
 
        APP_MSG_GET_UI_HIERARCHY = 110,
        APP_MSG_GET_UI_SCREENSHOT = 111,
index ecf9ead..aae53ce 100755 (executable)
@@ -112,6 +112,11 @@ typedef struct {
 
 extern __traceInfo gTraceInfo;
 
+struct ext_bininfo_t {
+       struct ext_bininfo_t *next;
+       char *path;
+};
+
 /* pid/tid values */
 pid_t _getpid();
 pid_t _gettid();
@@ -132,10 +137,12 @@ void on_orientation_changed(int angle, bool capi);
         ((gTraceInfo.features.feature_1 & OPT1) != 0))
 
 /* Binaries list functions */
-int add_binary(char *path);
-int add_binary_on_demand(char *path);
+void add_binaries(char *bundle, size_t size);
+struct ext_bininfo_t *add_binaries_get_new(char *bundle, size_t size);
 bool check_binary(const char *path);
-int remove_binary(char *path);
+void remove_binaries(char *bundle, size_t size);
+struct ext_bininfo_t *remove_binaries_get_diff(char *bundle, size_t size);
+void free_bins_info(struct ext_bininfo_t *ebi);
 void cleanup_binaries(void);
 
 #ifdef __cplusplus