From 80b20d42554250bdb7112ce1ecf49ab905bfccde Mon Sep 17 00:00:00 2001 From: muyi Date: Tue, 19 Aug 2025 14:08:06 +0800 Subject: [PATCH] So Merge Signed-off-by: muyi --- ldso/linux/cfi.c | 113 +- ldso/linux/dynlink.c | 1209 ++++++++----- ldso/linux/dynlink_adlt.inc | 1575 +++++++++++++++++ ldso/linux/dynlink_rand.c | 21 + ldso/linux/dynlink_rand.h | 16 +- libc-test/src/api/BUILD.gn | 4 + libc-test/src/common/BUILD.gn | 4 + .../src/functionalext/supplement/BUILD.gn | 4 + .../hook/hook_gtest/hook_realloc_test.cpp | 7 +- .../functionalext/test_src_functionalext.gni | 7 +- libc-test/src/nativehook/BUILD.gn | 4 + libc-test/test_template.gni | 5 + scripts/run_libcgtest_linux.sh | 24 +- scripts/runtest.sh | 36 +- scripts/runtest_Windows.bat | 2 +- scripts/runtest_linux.sh | 12 +- src/internal/ADLTSection.h | 150 ++ src/internal/dynlink.h | 99 ++ 18 files changed, 2833 insertions(+), 459 deletions(-) create mode 100644 ldso/linux/dynlink_adlt.inc create mode 100644 src/internal/ADLTSection.h diff --git a/ldso/linux/cfi.c b/ldso/linux/cfi.c index 5f3360883..e3c632a41 100644 --- a/ldso/linux/cfi.c +++ b/ldso/linux/cfi.c @@ -14,6 +14,7 @@ */ #define _GNU_SOURCE +#define CFI_CHECK_NAME_BUFFER_SIZE 32 #include #include #include "cfi.h" @@ -120,6 +121,9 @@ static int create_cfi_shadow(void); /* Map dsos to CFI shadow */ static int add_dso_to_cfi_shadow(struct dso *dso); + +/* dsos / cfi shadow for ADLT */ +static int fill_dso_to_cfi_shadow(struct dso *p, uintptr_t cfi_check, uint16_t type); static int fill_shadow_value_to_shadow(uintptr_t begin, uintptr_t end, uintptr_t cfi_check, uint16_t type); /* Find the __cfi_check() of target dso and call it */ @@ -133,13 +137,28 @@ static inline uintptr_t addr_to_offset(uintptr_t addr, int bits) return (addr >> bits) << 1; } +/* CFI check for ADLT */ static struct symdef find_cfi_check_sym(struct dso *p) { LD_LOGD("[CFI] [%{public}s] start!\n", __FUNCTION__); - - struct verinfo verinfo = { .s = "__cfi_check", .v = "", .use_vna_hash = false }; + char buf[CFI_CHECK_NAME_BUFFER_SIZE] = {0}; + const char *fun_name = "__cfi_check"; + + if (p->adlt_ndso_index != -1) { + snprintf(buf, sizeof buf, "__cfi_check__%zX", p->adlt_ndso_index); + LD_LOGD("[CFI] [%{public}s] this is adlt, search for suffix: %{public}s!\n", __FUNCTION__, buf); + fun_name = buf; + } + + struct verinfo verinfo = { .s = fun_name, .v = "", .use_vna_hash = false }; struct sym_info_pair s_info_p = gnu_hash(verinfo.s); - return find_sym_impl(p, &verinfo, s_info_p, 0, p->namespace); + struct symdef res = find_sym_impl(p, &verinfo, s_info_p, 0, p->namespace); + if (res.sym) { + LD_LOGD("[CFI] [%{public}s] found symbol: %{public}p!\n", __FUNCTION__, res.sym); + } else { + LD_LOGD("[CFI] [%{public}s] did not find.\n", __FUNCTION__); + } + return res; } @@ -173,6 +192,11 @@ static int addr_in_kernel_mapped_dso(size_t addr) return 0; } +static const char *addr2dso_name(void *addr) { + struct dso *p = (struct dso *)addr2dso((size_t)addr); + return p ? p->name : ""; +} + static uintptr_t get_cfi_check_addr(uint16_t value, void* func_ptr) { LD_LOGD("[CFI] [%{public}s] start!\n", __FUNCTION__); @@ -185,12 +209,13 @@ static uintptr_t get_cfi_check_addr(uint16_t value, void* func_ptr) cfi_check_func_addr++; #endif LD_LOGD("[CFI] [%{public}s] cfi_check_func_addr[%{public}p] in dso[%{public}s]\n", - __FUNCTION__, cfi_check_func_addr, ((struct dso *)addr2dso((size_t)cfi_check_func_addr))->name); + __FUNCTION__, cfi_check_func_addr, addr2dso_name((void *)cfi_check_func_addr)); return cfi_check_func_addr; } -static inline void cfi_slowpath_common(uint64_t call_site_type_id, void *func_ptr, void *diag_data) +static inline __attribute__((always_inline)) void cfi_slowpath_common( + uint64_t call_site_type_id, void *func_ptr, void *diag_data) { uint16_t value = sv_invalid; @@ -224,8 +249,8 @@ static inline void cfi_slowpath_common(uint64_t call_site_type_id, void *func_pt } LD_LOGD("[CFI] [%{public}s] called from %{public}s to %{public}s func_ptr:0x%{public}p shadow value:%{public}d diag_data:0x%{public}p call_site_type_id[%{public}p.\n", __FUNCTION__, - ((struct dso *)addr2dso((size_t)__builtin_return_address(0)))->name, - ((struct dso *)addr2dso((size_t)func_ptr))->name, + addr2dso_name(__builtin_return_address(0)), + addr2dso_name(func_ptr), func_ptr, value, diag_data, call_site_type_id); struct dso *dso = NULL; @@ -361,7 +386,7 @@ void unmap_dso_from_cfi_shadow(struct dso *dso) } /* Set the dso's shadow value as invalid. */ - fill_shadow_value_to_shadow(dso->map, dso->map + dso->map_len, 0, sv_invalid); + fill_dso_to_cfi_shadow(dso, 0, sv_invalid); dso->is_mapped_to_shadow = false; prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, cfi_shadow_start, shadow_size, "cfi_shadow:musl"); @@ -418,8 +443,7 @@ static int add_dso_to_cfi_shadow(struct dso *dso) } } - if (fill_shadow_value_to_shadow(p->map, p->map + p->map_len, 0, sv_uncheck) == CFI_FAILED) { - LD_LOGE("[CFI] [%{public}s] add dso to cfi shadow failed!\n", __FUNCTION__); + if (fill_dso_to_cfi_shadow(p, 0, sv_uncheck) == CFI_FAILED) { return CFI_FAILED; } /* If the dso has __cfi_check(), set it's shadow value valid. */ @@ -454,7 +478,7 @@ static int add_dso_to_cfi_shadow(struct dso *dso) } } - if (fill_shadow_value_to_shadow(p->map, end, cfi_check, sv_valid_min) == CFI_FAILED) { + if (fill_dso_to_cfi_shadow(p, cfi_check, sv_valid_min) == CFI_FAILED) { LD_LOGE("[CFI] [%{public}s] add %{public}s to cfi shadow failed!\n", __FUNCTION__, p->name); return CFI_FAILED; } @@ -467,6 +491,65 @@ static int add_dso_to_cfi_shadow(struct dso *dso) return CFI_SUCCESS; } +static int fill_dso_to_cfi_shadow(struct dso *p, uintptr_t cfi_check, uint16_t type) { + if (!p->adlt) { + if (fill_shadow_value_to_shadow(p->map, p->map + p->map_len, cfi_check, type) == CFI_FAILED) { + LD_LOGE("[CFI] [%{public}s] fill %{public}s to cfi shadow failed!\n", __FUNCTION__, p->name); + return CFI_FAILED; + } + return CFI_SUCCESS; + } + adlt_phindex_t *ph_indexes; + LD_LOGD("[CFI] [%{public}s] fill ADLT %{public}s to cfi shadow: ndso index %{public}d!\n", + __FUNCTION__, p->name, p->adlt_ndso_index); + ssize_t ph_count = get_adlt_library_ph(p->adlt, p->adlt_ndso_index, &ph_indexes); + if (ph_count < 0 || !ph_indexes) { + LD_LOGE("[CFI] [%{public}s] fill ADLT %{public}s to cfi shadow failed!\n", __FUNCTION__, p->name); + return CFI_FAILED; + } + for (size_t i = 0; i < ph_count; i++) { + const Phdr *phdr = &p->phdr[ph_indexes[i]]; + if (phdr->p_type == PT_LOAD) { + uintptr_t base = p->adlt->map - p->adlt->addr_min; + uintptr_t cur_beg = base + phdr->p_vaddr; + uintptr_t cur_end = cur_beg + phdr->p_memsz; + LD_LOGD("[CFI] [%{public}s] fill ADLT %{public}s header " + "%{public}d [%{public}p; %{public}p) to cfi shadow!\n", + __FUNCTION__, p->name, ph_indexes[i], cur_beg, cur_end); + if (cfi_check >= cur_end && type == sv_valid_min) { + LD_LOGD("[CFI] [%{public}s] ADLT %{public}s header " + "%{public}d is before __cfi_check, ignore\n", + __FUNCTION__, p->name, ph_indexes[i]); + continue; + } + if (fill_shadow_value_to_shadow(cur_beg, cur_end, cfi_check, type) == CFI_FAILED) { + LD_LOGE("[CFI] [%{public}s] fill %{public}s to cfi shadow failed!\n", __FUNCTION__, p->name); + return CFI_FAILED; + } + } + } + + adlt_phindex_t *pc_indexes = NULL; + ssize_t pc_count = get_adlt_common_ph(p->adlt, &pc_indexes); + if (pc_count <= 0 || !pc_indexes) { + return CFI_FAILED; + } + for (int i = 0; i < pc_count; ++i) { + const Phdr *phdr = &p->phdr[pc_indexes[i]]; + if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X)) { + uintptr_t base = p->adlt->map - p->adlt->addr_min; + uintptr_t cur_beg = base + phdr->p_vaddr; + uintptr_t cur_end = cur_beg + phdr->p_memsz; + if (fill_shadow_value_to_shadow(cur_beg, cur_end, 0, sv_uncheck) == CFI_FAILED) { + LD_LOGE("[CFI] [%{public}s] fill %{public}s to cfi shadow failed!\n", __FUNCTION__, p->name); + return CFI_FAILED; + } + } + } + + return CFI_SUCCESS; +} + static int fill_shadow_value_to_shadow(uintptr_t begin, uintptr_t end, uintptr_t cfi_check, uint16_t type) { LD_LOGD("[CFI] [%{public}s] begin[%{public}x] end[%{public}x] cfi_check[%{public}x] type[%{public}x]!\n", @@ -556,8 +639,8 @@ void __cfi_slowpath(uint64_t call_site_type_id, void *func_ptr) { LD_LOGD("[CFI] [%{public}s] called from dso[%{public}s] to dso[%{public}s] func_ptr[%{public}p]\n", __FUNCTION__, - ((struct dso *)addr2dso((size_t)__builtin_return_address(0)))->name, - ((struct dso *)addr2dso((size_t)func_ptr))->name, + addr2dso_name(__builtin_return_address(0)), + addr2dso_name(func_ptr), func_ptr); cfi_slowpath_common(call_site_type_id, func_ptr, NULL); @@ -568,8 +651,8 @@ void __cfi_slowpath_diag(uint64_t call_site_type_id, void *func_ptr, void *diag_ { LD_LOGD("[CFI] [%{public}s] called from dso[%{public}s] to dso[%{public}s] func_ptr[%{public}p]\n", __FUNCTION__, - ((struct dso *)addr2dso((size_t)__builtin_return_address(0)))->name, - ((struct dso *)addr2dso((size_t)func_ptr))->name, + addr2dso_name(__builtin_return_address(0)), + addr2dso_name(func_ptr), func_ptr); cfi_slowpath_common(call_site_type_id, func_ptr, diag_data); diff --git a/ldso/linux/dynlink.c b/ldso/linux/dynlink.c index 15914ac8d..9116efe1c 100644 --- a/ldso/linux/dynlink.c +++ b/ldso/linux/dynlink.c @@ -88,6 +88,8 @@ static void (*error)(const char *, ...) = error_noop; #define container_of(p,t,m) ((t*)((char *)(p)-offsetof(t,m))) #define countof(a) ((sizeof (a))/(sizeof (a)[0])) #define DSO_FLAGS_NODELETE 0x1 +#define __predict_true(exp) __builtin_expect((exp) != 0, 1) +#define __predict_false(exp) __builtin_expect((exp) != 0, 0) #ifdef HANDLE_RANDOMIZATION #define NEXT_DYNAMIC_INDEX 2 @@ -220,9 +222,10 @@ int do_dlclose(struct dso *p, bool check_deps_all); #ifdef LOAD_ORDER_RANDOMIZATION static bool task_check_xpm(struct loadtask *task); -static bool map_library_header(struct loadtask *task); +static bool map_library_header(struct loadtask *task, const ns_t *ns, bool check_inherited); static bool task_map_library(struct loadtask *task, struct reserved_address_params *reserved_params); static bool resolve_fd_to_realpath(struct loadtask *task); +static ssize_t fd_to_realpath(int fd, char *buf, size_t buf_size); static bool load_library_header(struct loadtask *task); static void task_load_library(struct loadtask *task, struct reserved_address_params *reserved_params); static void preload_direct_deps(struct dso *p, ns_t *namespace, struct loadtasks *tasks); @@ -253,10 +256,19 @@ static void notify_addition_to_debugger(struct dso *p); static void notify_remove_to_debugger(struct dso *p); static void add_dso_info_to_debug_map(struct dso *p); static void remove_dso_info_from_debug_map(struct dso *p); +/* symbol lookup function */ +static inline int sym_is_matched(const Sym* sym, size_t addr_offset_so); /* add namespace function */ static void get_sys_path(ns_configor *conf); static void dlclose_ns(struct dso *p); +static struct symdef find_sym(struct dso *dso, const char *s, int need_def); +static size_t decode_android_relocs( + struct dso *p, size_t dt_name, size_t dt_size, size_t **reloc_cache, size_t *map_len); +static void do_one_reloc(struct dso *dso, size_t *rel, size_t stride, size_t addend); +static void do_relr_relocs(struct dso *dso, size_t *relr, size_t relr_size, size_t rel_cnt, adlt_relindex_t *rel_index); +static void free_reloc_can_search_dso(struct dso *p); +static void reclaim(struct dso *dso, size_t start, size_t end); #if defined(BTI_SUPPORT) && (!defined(__LITEOS__)) struct gnu_property { @@ -670,6 +682,8 @@ static int search_vec(size_t *v, size_t *r, size_t key) return 1; } +#include "dynlink_adlt.inc" + UT_STATIC int check_vna_hash(Verdef *def, int16_t vsym, uint32_t vna_hash) { int matched = 0; @@ -794,7 +808,9 @@ static Sym *sysv_lookup(struct verinfo *verinfo, struct sym_info_pair s_info_p, if (!check_verinfo(dso->verdef, dso->versym, i, verinfo, dso->strings)) { continue; } - + if (!is_adlt_dso_sym(dso, i)) { + continue; + } return syms+i; } @@ -826,8 +842,10 @@ static Sym *gnu_lookup(struct sym_info_pair s_info_p, uint32_t *hashtab, struct if (!check_verinfo(dso->verdef, dso->versym, i, verinfo, dso->strings)) { continue; } - - return dso->syms+i; + if (!is_adlt_dso_sym(dso, i)) { + continue; + } + return dso->syms+i; } if (h2 & 1) break; @@ -1287,7 +1305,10 @@ static void do_pauth_reloc(size_t *reloc_addr, size_t val) #endif } -static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stride) +/* OHOS_LOCAL ADLT + * rel_index - list of relocs indexes to be considered (if not specified, + * we consider all relocks) */ +static void do_one_reloc(struct dso *dso, size_t *rel, size_t stride, size_t addend) { unsigned char *base = dso->base; Sym *syms = dso->syms; @@ -1301,6 +1322,181 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri size_t *reloc_addr; size_t sym_val; size_t tls_val; + + type = R_TYPE(rel[1]); + reloc_addr = laddr(dso, rel[0]); + + sym_index = R_SYM(rel[1]); + if (sym_index) { + sym = syms + sym_index; + name = strings + sym->st_name; + ctx = type==REL_COPY ? head->syms_next : head; + struct verinfo vinfo = { .s = name, .v = ""}; + + vinfo.use_vna_hash = get_vna_hash(dso, sym_index, &vinfo.vna_hash); + if (!vinfo.use_vna_hash && dso->versym && (dso->versym[sym_index] & 0x7fff) >= 0) { + get_verinfo(dso, sym_index, &vinfo); + } + if (dso->cache_sym_index == sym_index) { + def = (struct symdef){ .dso = dso->cache_dso, .sym = dso->cache_sym }; + } else { + def = (sym->st_info>>4) == STB_LOCAL + ? (struct symdef){ .dso = dso, .sym = sym } + : dso != &ldso ? find_sym_by_saved_so_list(type, ctx, &vinfo, type==REL_PLT, dso) + : find_sym2(ctx, &vinfo, type==REL_PLT, 0, dso->namespace); + dso->cache_sym_index = sym_index; + dso->cache_dso = def.dso; + dso->cache_sym = def.sym; + } + + if (!def.sym && (sym->st_shndx != SHN_UNDEF + || sym->st_info>>4 != STB_WEAK)) { +#ifdef ENABLE_HWASAN + /* libc hwasan symbols will be preloaded during the + * dls3 stage, so we will skip this step. */ + if (dso == &ldso) { + return; + } +#endif + if (dso->lazy && (type==REL_PLT || type==REL_GOT)) { + dso->lazy[3*dso->lazy_cnt+0] = rel[0]; + dso->lazy[3*dso->lazy_cnt+1] = rel[1]; + dso->lazy[3*dso->lazy_cnt+2] = addend; + dso->lazy_cnt++; + return; + } + if (dso != &ldso) { + LD_LOGW("relocating failed: symbol not found. " + "dso=%{public}s s=%{public}s use_vna_hash=%{public}d van_hash=%{public}x", + dso->name, name, vinfo.use_vna_hash, vinfo.vna_hash); + error("Error relocating %s: %s: symbol not found", + dso->name, name); + } + if (runtime) longjmp(*rtld_fail, 1); + return; + } + } else { + sym = 0; + def.sym = 0; + def.dso = dso; + } + + sym_val = def.sym ? (size_t)laddr(def.dso, def.sym->st_value) : 0; + tls_val = def.sym ? def.sym->st_value : 0; + + if ((type == REL_TPOFF || type == REL_TPOFF_NEG) + && def.dso->tls_id > static_tls_cnt) { + error("Error relocating %s: %s: initial-exec TLS " + "resolves to dynamic definition in %s", + dso->name, name, def.dso->name); + longjmp(*rtld_fail, 1); + } + + switch(type) { + case REL_OFFSET: + addend -= (size_t)reloc_addr; + case REL_SYMBOLIC: + case REL_GOT: + case REL_PLT: + *reloc_addr = sym_val + addend; + break; + case REL_USYMBOLIC: + memcpy(reloc_addr, &(size_t){sym_val + addend}, sizeof(size_t)); + break; + case REL_RELATIVE: + *reloc_addr = (size_t)base + addend; + break; + case REL_SYM_OR_REL: + if (sym) *reloc_addr = sym_val + addend; + else *reloc_addr = (size_t)base + addend; + break; + case REL_COPY: + memcpy(reloc_addr, (void *)sym_val, sym->st_size); + break; + case REL_OFFSET32: + *(uint32_t *)reloc_addr = sym_val + addend + - (size_t)reloc_addr; + break; + case REL_FUNCDESC: + *reloc_addr = def.sym ? (size_t)(def.dso->funcdescs + + (def.sym - def.dso->syms)) : 0; + break; + case REL_FUNCDESC_VAL: + if ((sym->st_info&0xf) == STT_SECTION) *reloc_addr += sym_val; + else *reloc_addr = sym_val; + reloc_addr[1] = def.sym ? (size_t)def.dso->got : 0; + break; + case REL_DTPMOD: + *reloc_addr = def.dso->tls_id; + break; + case REL_DTPOFF: + *reloc_addr = tls_val + addend - DTP_OFFSET; + break; +#ifdef TLS_ABOVE_TP + case REL_TPOFF: + *reloc_addr = tls_val + def.dso->tls.offset + TPOFF_K + addend; + break; +#else + case REL_TPOFF: + *reloc_addr = tls_val - def.dso->tls.offset + addend; + break; + case REL_TPOFF_NEG: + *reloc_addr = def.dso->tls.offset - tls_val + addend; + break; +#endif + case REL_AUTH_SYMBOLIC: + case REL_AUTH_GLOB_DAT: + do_pauth_reloc(reloc_addr, sym_val + addend); + break; + case REL_AUTH_RELATIVE: + do_pauth_reloc(reloc_addr, base + addend); + break; + case REL_TLSDESC: + if (stride<3) addend = reloc_addr[!TLSDESC_BACKWARDS]; + if (def.dso->tls_id > static_tls_cnt) { + struct td_index *new = malloc(sizeof *new); + if (!new) { + error( + "Error relocating %s: cannot allocate TLSDESC for %s", + dso->name, sym ? name : "(local)" ); + longjmp(*rtld_fail, 1); + } + new->next = dso->td_index; + dso->td_index = new; + new->args[0] = def.dso->tls_id; + new->args[1] = tls_val + addend - DTP_OFFSET; + reloc_addr[0] = (size_t)__tlsdesc_dynamic; + reloc_addr[1] = (size_t)new; + } else { + reloc_addr[0] = (size_t)__tlsdesc_static; +#ifdef TLS_ABOVE_TP + reloc_addr[1] = tls_val + def.dso->tls.offset + + TPOFF_K + addend; +#else + reloc_addr[1] = tls_val - def.dso->tls.offset + + addend; +#endif + } + /* Some archs (32-bit ARM at least) invert the order of + * the descriptor members. Fix them up here. */ + if (TLSDESC_BACKWARDS) { + size_t tmp = reloc_addr[0]; + reloc_addr[0] = reloc_addr[1]; + reloc_addr[1] = tmp; + } + break; + default: + error("Error relocating %s: unsupported relocation type %d", + dso->name, type); + if (runtime) longjmp(*rtld_fail, 1); + return; + } +} + +static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stride) +{ + int type; + size_t *reloc_addr; size_t addend; int skip_relative = 0, reuse_addends = 0, save_slot = 0; @@ -1311,7 +1507,7 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri skip_relative = 1; } - for (; rel_size; rel+=stride, rel_size-=stride*sizeof(size_t)) { + for (; rel_size; rel = rel + stride , rel_size -= stride * sizeof(size_t)) { if (skip_relative && IS_RELATIVE(rel[1], dso->syms)) continue; type = R_TYPE(rel[1]); if (type == REL_NONE) continue; @@ -1325,176 +1521,14 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri /* Save original addend in stage 2 where the dso * chain consists of just ldso; otherwise read back * saved addend since the inline one was clobbered. */ - if (head==&ldso) + if (head==&ldso) { saved_addends[save_slot] = *reloc_addr; + } addend = saved_addends[save_slot++]; } else { addend = *reloc_addr; } - - sym_index = R_SYM(rel[1]); - if (sym_index) { - sym = syms + sym_index; - name = strings + sym->st_name; - ctx = type==REL_COPY ? head->syms_next : head; - struct verinfo vinfo = { .s = name, .v = ""}; - - vinfo.use_vna_hash = get_vna_hash(dso, sym_index, &vinfo.vna_hash); - if (!vinfo.use_vna_hash && dso->versym && (dso->versym[sym_index] & 0x7fff) >= 0) { - get_verinfo(dso, sym_index, &vinfo); - } - if (dso->cache_sym_index == sym_index) { - def = (struct symdef){ .dso = dso->cache_dso, .sym = dso->cache_sym }; - } else { - def = (sym->st_info>>4) == STB_LOCAL - ? (struct symdef){ .dso = dso, .sym = sym } - : dso != &ldso ? find_sym_by_saved_so_list(type, ctx, &vinfo, type==REL_PLT, dso) - : find_sym2(ctx, &vinfo, type==REL_PLT, 0, dso->namespace); - dso->cache_sym_index = sym_index; - dso->cache_dso = def.dso; - dso->cache_sym = def.sym; - } - - if (!def.sym && (sym->st_shndx != SHN_UNDEF - || sym->st_info>>4 != STB_WEAK)) { -#ifdef ENABLE_HWASAN - /* libc hwasan symbols will be preloaded during the - * dls3 stage, so we will skip this step. */ - if (dso == &ldso) { - continue; - } -#endif - if (dso->lazy && (type==REL_PLT || type==REL_GOT)) { - dso->lazy[3*dso->lazy_cnt+0] = rel[0]; - dso->lazy[3*dso->lazy_cnt+1] = rel[1]; - dso->lazy[3*dso->lazy_cnt+2] = addend; - dso->lazy_cnt++; - continue; - } - LD_LOGW("relocating failed: symbol not found. " - "dso=%{public}s s=%{public}s use_vna_hash=%{public}d van_hash=%{public}x", - dso->name, name, vinfo.use_vna_hash, vinfo.vna_hash); - error("Error relocating %s: %s: symbol not found", - dso->name, name); - if (runtime) longjmp(*rtld_fail, 1); - continue; - } - } else { - sym = 0; - def.sym = 0; - def.dso = dso; - } - - sym_val = def.sym ? (size_t)laddr(def.dso, def.sym->st_value) : 0; - tls_val = def.sym ? def.sym->st_value : 0; - - if ((type == REL_TPOFF || type == REL_TPOFF_NEG) - && def.dso->tls_id > static_tls_cnt) { - error("Error relocating %s: %s: initial-exec TLS " - "resolves to dynamic definition in %s", - dso->name, name, def.dso->name); - longjmp(*rtld_fail, 1); - } - - switch(type) { - case REL_OFFSET: - addend -= (size_t)reloc_addr; - case REL_SYMBOLIC: - case REL_GOT: - case REL_PLT: - *reloc_addr = sym_val + addend; - break; - case REL_USYMBOLIC: - memcpy(reloc_addr, &(size_t){sym_val + addend}, sizeof(size_t)); - break; - case REL_RELATIVE: - *reloc_addr = (size_t)base + addend; - break; - case REL_SYM_OR_REL: - if (sym) *reloc_addr = sym_val + addend; - else *reloc_addr = (size_t)base + addend; - break; - case REL_COPY: - memcpy(reloc_addr, (void *)sym_val, sym->st_size); - break; - case REL_OFFSET32: - *(uint32_t *)reloc_addr = sym_val + addend - - (size_t)reloc_addr; - break; - case REL_FUNCDESC: - *reloc_addr = def.sym ? (size_t)(def.dso->funcdescs - + (def.sym - def.dso->syms)) : 0; - break; - case REL_FUNCDESC_VAL: - if ((sym->st_info&0xf) == STT_SECTION) *reloc_addr += sym_val; - else *reloc_addr = sym_val; - reloc_addr[1] = def.sym ? (size_t)def.dso->got : 0; - break; - case REL_DTPMOD: - *reloc_addr = def.dso->tls_id; - break; - case REL_DTPOFF: - *reloc_addr = tls_val + addend - DTP_OFFSET; - break; -#ifdef TLS_ABOVE_TP - case REL_TPOFF: - *reloc_addr = tls_val + def.dso->tls.offset + TPOFF_K + addend; - break; -#else - case REL_TPOFF: - *reloc_addr = tls_val - def.dso->tls.offset + addend; - break; - case REL_TPOFF_NEG: - *reloc_addr = def.dso->tls.offset - tls_val + addend; - break; -#endif - case REL_AUTH_SYMBOLIC: - case REL_AUTH_GLOB_DAT: - do_pauth_reloc(reloc_addr, sym_val + addend); - break; - case REL_AUTH_RELATIVE: - do_pauth_reloc(reloc_addr, base + addend); - break; - case REL_TLSDESC: - if (stride<3) addend = reloc_addr[!TLSDESC_BACKWARDS]; - if (def.dso->tls_id > static_tls_cnt) { - struct td_index *new = malloc(sizeof *new); - if (!new) { - error( - "Error relocating %s: cannot allocate TLSDESC for %s", - dso->name, sym ? name : "(local)" ); - longjmp(*rtld_fail, 1); - } - new->next = dso->td_index; - dso->td_index = new; - new->args[0] = def.dso->tls_id; - new->args[1] = tls_val + addend - DTP_OFFSET; - reloc_addr[0] = (size_t)__tlsdesc_dynamic; - reloc_addr[1] = (size_t)new; - } else { - reloc_addr[0] = (size_t)__tlsdesc_static; -#ifdef TLS_ABOVE_TP - reloc_addr[1] = tls_val + def.dso->tls.offset - + TPOFF_K + addend; -#else - reloc_addr[1] = tls_val - def.dso->tls.offset - + addend; -#endif - } - /* Some archs (32-bit ARM at least) invert the order of - * the descriptor members. Fix them up here. */ - if (TLSDESC_BACKWARDS) { - size_t tmp = reloc_addr[0]; - reloc_addr[0] = reloc_addr[1]; - reloc_addr[1] = tmp; - } - break; - default: - error("Error relocating %s: unsupported relocation type %d", - dso->name, type); - if (runtime) longjmp(*rtld_fail, 1); - continue; - } + do_one_reloc(dso, rel, stride, addend); } } @@ -1525,9 +1559,23 @@ static void redo_lazy_relocs() static void reclaim(struct dso *dso, size_t start, size_t end) { - if (start >= dso->relro_start && start < dso->relro_end) start = dso->relro_end; - if (end >= dso->relro_start && end < dso->relro_end) end = dso->relro_start; - if (start >= end) return; + /* For adlt nDSO donating to heap should be done carefully considering other + * nDSOs that may also be present in the same segments. Therefore, we will + * disable it for now. + */ + if (__predict_false(dso->adlt)) { + return; + } + + if (start >= dso->relro_start && start < dso->relro_end) { + start = dso->relro_end; + } + if (end >= dso->relro_start && end < dso->relro_end) { + end = dso->relro_start; + } + if (start >= end) { + return; + } char *base = laddr_pg(dso, start); __malloc_donate(base, base+(end-start)); } @@ -1537,6 +1585,12 @@ static void reclaim_gaps(struct dso *dso) Phdr *ph = dso->phdr; size_t phcnt = dso->phnum; + + if (dso->adlt) { + adlt_reclaim_gaps(dso); + return; + } + for (; phcnt--; ph=(void *)((char *)ph+dso->phentsize)) { if (ph->p_type!=PT_LOAD) continue; if ((ph->p_flags&(PF_R|PF_W))!=(PF_R|PF_W)) continue; @@ -1592,7 +1646,9 @@ UT_STATIC void unmap_library(struct dso *dso) } free(dso->loadmap); } else if (dso->map && dso->map_len) { - if (!is_dlclose_debug_enable()) { + if (__predict_false(dso->adlt)) { + unmap_adlt_library(dso); + } else if (!is_dlclose_debug_enable()) { munmap(dso->map, dso->map_len); } else { mprotect(dso->map, dso->map_len, PROT_NONE); @@ -2785,109 +2841,197 @@ static uint8_t* sleb128_decoder(uint8_t* current, uint8_t* end, size_t* value) return current; } -static void do_android_relocs(struct dso *p, size_t dt_name, size_t dt_size) +static void save_decode_relocs( + size_t *rel_addr, size_t relocs_num, size_t dt_name, uint8_t *android_rel_curr, uint8_t *android_rel_end) { - size_t android_rel_addr = 0, android_rel_size = 0; - uint8_t *android_rel_curr, *android_rel_end; - - search_vec(p->dynv, &android_rel_addr, dt_name); - search_vec(p->dynv, &android_rel_size, dt_size); - - if (!android_rel_addr || (android_rel_size < 4)) { - return; - } - - android_rel_curr = laddr(p, android_rel_addr); - if (memcmp(android_rel_curr, "APS2", ANDROID_REL_SIGN_SIZE)) { - return; - } - - android_rel_curr += ANDROID_REL_SIGN_SIZE; - android_rel_size -= ANDROID_REL_SIGN_SIZE; - - android_rel_end = android_rel_curr + android_rel_size; - - size_t relocs_num; size_t rel[3] = {0}; - - android_rel_curr = sleb128_decoder(android_rel_curr, android_rel_end, &relocs_num); android_rel_curr = sleb128_decoder(android_rel_curr, android_rel_end, &rel[0]); - for (size_t i = 0; i < relocs_num;) { - - size_t group_size, group_flags; - + size_t group_size, group_flags, group_r_offset_delta = 0; + size_t addend, offset_detla; android_rel_curr = sleb128_decoder(android_rel_curr, android_rel_end, &group_size); android_rel_curr = sleb128_decoder(android_rel_curr, android_rel_end, &group_flags); - - size_t group_r_offset_delta = 0; - if (group_flags & RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) { android_rel_curr = sleb128_decoder(android_rel_curr, android_rel_end, &group_r_offset_delta); } - if (group_flags & RELOCATION_GROUPED_BY_INFO_FLAG) { android_rel_curr = sleb128_decoder(android_rel_curr, android_rel_end, &rel[1]); } - const size_t addend_flags = group_flags & (RELOCATION_GROUP_HAS_ADDEND_FLAG | RELOCATION_GROUPED_BY_ADDEND_FLAG); - if (addend_flags == RELOCATION_GROUP_HAS_ADDEND_FLAG) { } else if (addend_flags == (RELOCATION_GROUP_HAS_ADDEND_FLAG | RELOCATION_GROUPED_BY_ADDEND_FLAG)) { - size_t addend; android_rel_curr = sleb128_decoder(android_rel_curr, android_rel_end, &addend); rel[2] += addend; } else { rel[2] = 0; } - for (size_t j = 0; j < group_size; j++) { if (group_flags & RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) { rel[0] += group_r_offset_delta; } else { - size_t offset_detla; android_rel_curr = sleb128_decoder(android_rel_curr, android_rel_end, &offset_detla); - rel[0] += offset_detla; } - if ((group_flags & RELOCATION_GROUPED_BY_INFO_FLAG) == 0) { android_rel_curr = sleb128_decoder(android_rel_curr, android_rel_end, &rel[1]); } - if (addend_flags == RELOCATION_GROUP_HAS_ADDEND_FLAG) { - size_t addend; android_rel_curr = sleb128_decoder(android_rel_curr, android_rel_end, &addend); rel[2] += addend; } - if (dt_name == DT_ANDROID_REL) { - do_relocs(p, rel, sizeof(size_t) * 2, 2); + *rel_addr++ = rel[0]; + *rel_addr++ = rel[1]; } else { - do_relocs(p, rel, sizeof(size_t) * 3, 3); + *rel_addr++ = rel[0]; + *rel_addr++ = rel[1]; + *rel_addr++ = rel[2]; } } - i += group_size; } } -static void do_relr_relocs(struct dso *dso, size_t *relr, size_t relr_size) +static size_t decode_android_relocs( + struct dso *p, size_t dt_name, size_t dt_size, size_t **reloc_cache, size_t *map_len) +{ + size_t android_rel_addr = 0, android_rel_size = 0; + uint8_t *android_rel_curr, *android_rel_end; + + search_vec(p->dynv, &android_rel_addr, dt_name); + search_vec(p->dynv, &android_rel_size, dt_size); + + if (!android_rel_addr || (android_rel_size < ANDROID_REL_SIGN_SIZE)) { + return 0; + } + + android_rel_curr = laddr(p, android_rel_addr); + if (memcmp(android_rel_curr, "APS2", ANDROID_REL_SIGN_SIZE)) { + return 0; + } + + android_rel_curr += ANDROID_REL_SIGN_SIZE; + android_rel_size -= ANDROID_REL_SIGN_SIZE; + + android_rel_end = android_rel_curr + android_rel_size; + + size_t relocs_num; + size_t reloc_sz; + + android_rel_curr = sleb128_decoder(android_rel_curr, android_rel_end, &relocs_num); + reloc_sz = relocs_num * (dt_name == DT_ANDROID_REL ? 2 : 3) * sizeof(size_t); + *map_len = (reloc_sz + PAGE_SIZE - 1) & (-PAGE_SIZE); + *reloc_cache = (size_t *)mmap(0, *map_len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (*reloc_cache == MAP_FAILED) { + LD_LOGE("Error android reloc mapping:%{public}s", p->name); + error("Error android reloc mapping :%s", p->name); + return 0; + } + + save_decode_relocs(*reloc_cache, relocs_num, dt_name, android_rel_curr, android_rel_end); + return reloc_sz; +} + +static void do_android_relocs(struct dso *p, size_t dt_name, size_t dt_size) +{ + size_t *reloc_cache = MAP_FAILED; + size_t map_len = 0; + size_t reloc_sz = decode_android_relocs(p, dt_name, dt_size, &reloc_cache, &map_len); + if (reloc_cache != MAP_FAILED) { + if (dt_name == DT_ANDROID_REL) { + do_relocs(p, reloc_cache, reloc_sz, 2); + } else { + do_relocs(p, reloc_cache, reloc_sz, 3); + } + munmap((void*)reloc_cache, map_len); + } +} + +static void do_relr_relocs(struct dso *dso, size_t *relr, size_t relr_size, size_t rel_cnt, adlt_relindex_t *rel_index) { if (dso == &ldso) return; /* self-relocation was done in _dlstart */ - unsigned char *base = dso->base; + + if (!relr_size) { + return; + } + + size_t base = (size_t)dso->base; size_t *reloc_addr; - for (; relr_size; relr++, relr_size -= sizeof(size_t)) - if ((relr[0] & 1) == 0) { - reloc_addr = laddr(dso, relr[0]); - *reloc_addr++ += (size_t)base; - } else { - int i = 0; - for (size_t bitmap = relr[0]; (bitmap >>= 1); i++) - if (bitmap & 1) - reloc_addr[i] += (size_t)base; - reloc_addr += 8 * sizeof(size_t) - 1; + struct unpack_reloc *relocs = !rel_index || !dso->adlt ? NULL : (void *)&(dso->adlt->relr_rel); + + if (!relocs) { + for (; relr_size; relr++, relr_size -= sizeof(size_t)) { + if ((relr[0] & 1) == 0) { + reloc_addr = laddr(dso, relr[0]); + *reloc_addr++ += base; + } else { + int i = 0; + for (size_t bitmap = relr[0]; (bitmap >>= 1); i++) { + if (bitmap & 1) + reloc_addr[i] += base; + } + reloc_addr += CHAR_BIT * sizeof(size_t) - 1; + } + } + return; + } + + if (rel_cnt) { /* adlt */ + size_t *rel_addr; + if (relocs->map == MAP_FAILED) { + /* We use mapping instead of malloc, because we can optimize by + * decompressing only to the necessary relocs. */ + relocs->unpack_num = 0; + relocs->map_len = (relr_size * CHAR_BIT * sizeof(size_t) + PAGE_SIZE - 1) & -PAGE_SIZE; + relocs->map = mmap(0, relocs->map_len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (relocs->map == MAP_FAILED) { + LD_LOGE("Error relr reloc mapping for adlt %{public}s", dso->adlt->name); + error("Error relr reloc mapping for adlt %s", dso->adlt->name); + if (runtime) { + longjmp(*rtld_fail, 1); + } + return; + } } + /* Consider that the reloc indexes in the list are stored in + ascending order. */ + if ((adlt_relindex_t)relocs->unpack_num <= rel_index[rel_cnt - 1]) { + size_t *rel_addr_last = (size_t *)relocs->map + rel_index[rel_cnt - 1]; + size_t *relr_start = relr; + rel_addr = (size_t *)relocs->map + relocs->unpack_num; + if (relocs->unpack_num) { + relr_size -= (size_t)relocs->unpack_offset * sizeof(size_t); + relr += relocs->unpack_offset; + } + + for (; relr_size; relr++, relr_size -= sizeof(size_t)) { + if ((relr[0] & 1) == 0) { + if (rel_addr > rel_addr_last) { + break; + } + reloc_addr = laddr(dso, relr[0]); + *rel_addr++ = (size_t)reloc_addr++; + } else { + int i = 0; + for (size_t bitmap = relr[0]; (bitmap >>= 1); i++) { + if (bitmap & 1) + *rel_addr++ = (size_t)(reloc_addr + i); + } + reloc_addr += CHAR_BIT * sizeof(size_t) - 1; + } + } + relocs->unpack_num = rel_addr - (size_t *)relocs->map; + relocs->unpack_offset = relr - relr_start; + } + + rel_addr = (size_t *)relocs->map; + for (; rel_cnt; --rel_cnt) { + if (has_relocation(dso, (size_t)(rel_addr[*rel_index]) - base)) { + continue; + } + *(size_t *)(rel_addr[*rel_index++]) += base; + } + } } static void do_auth_relr_relocs(struct dso *p, size_t dt_name, size_t dt_size) @@ -2936,6 +3080,10 @@ static void reloc_all(struct dso *p, const dl_extinfo *extinfo) add_can_search_so_list_in_dso(p, head); } decode_vec(p->dynv, dyn, DYN_CNT); + if (__predict_false(p->adlt)) { + adlt_reloc(p, dyn, extinfo, &relro_fd_offset); + continue; + } if (NEED_MIPS_GOT_RELOCS) do_mips_relocs(p, laddr(p, dyn[DT_PLTGOT])); do_relocs(p, laddr(p, dyn[DT_JMPREL]), dyn[DT_PLTRELSZ], @@ -2943,7 +3091,7 @@ static void reloc_all(struct dso *p, const dl_extinfo *extinfo) do_relocs(p, laddr(p, dyn[DT_REL]), dyn[DT_RELSZ], 2); do_relocs(p, laddr(p, dyn[DT_RELA]), dyn[DT_RELASZ], 3); if (!DL_FDPIC) - do_relr_relocs(p, laddr(p, dyn[DT_RELR]), dyn[DT_RELRSZ]); + do_relr_relocs(p, laddr(p, dyn[DT_RELR]), dyn[DT_RELRSZ], 0, NULL); #if defined(__aarch64__) && (!defined(__LITEOS__)) do_auth_relr_relocs(p, DT_AARCH64_AUTH_RELR, DT_AARCH64_AUTH_RELRSZ); // only enable in arm64 @@ -3010,6 +3158,8 @@ void __libc_exit_fini() struct dso *p; size_t dyn[DYN_CNT]; pthread_t self = __pthread_self(); + size_t n; + size_t *fn; /* Take both locks before setting shutting_down, so that * either lock is sufficient to read its value. The lock @@ -3023,13 +3173,22 @@ void __libc_exit_fini() pthread_cond_wait(&ctor_cond, &init_fini_lock); if (!p->constructed) continue; decode_vec(p->dynv, dyn, DYN_CNT); - if (dyn[0] & (1<adlt)){ + size_t nn = get_adlt_library_fini_array(p->adlt, p->adlt_ndso_index, NULL); + if (nn > 0) { + n = nn; + fn = (size_t *)laddr(p, p->fini_array_off) + n; + } + } else if (dyn[0] & (1 << DT_FINI_ARRAY)) { + n = dyn[DT_FINI_ARRAYSZ] / sizeof(size_t); + fn = (size_t *)laddr(p, dyn[DT_FINI_ARRAY]) + n; + } + while (n--) ((void (*)(void))*--fn)(); + #ifndef NO_LEGACY_INITFINI - if ((dyn[0] & (1<ctor_visitor = self; decode_vec(p->dynv, dyn, DYN_CNT); - if (dyn[0] & ((1<adlt)) { + /* If ndso has an deinit function, it should be considered here. */ + bfini = (get_adlt_library_fini_array(p->adlt, p->adlt_ndso_index, NULL) > 0) || ((dyn[0] & (1 << DT_FINI)) != 0); + } else { + bfini = (dyn[0] & ((1 << DT_FINI) | (1 << DT_FINI_ARRAY))) != 0; + } + if (bfini) { p->fini_next = fini_head; fini_head = p; } @@ -3145,12 +3313,25 @@ static void do_init_fini(struct dso **queue) pthread_mutex_unlock(&init_fini_lock); #ifndef NO_LEGACY_INITFINI - if ((dyn[0] & (1<adlt)) { + size_t nn = get_adlt_library_init_array(p->adlt, p->adlt_ndso_index, NULL); + if (nn > 0) { + n = nn; + fn = laddr(p, p->init_array_off); + } + } else { + if (dyn[0] & (1 << DT_INIT_ARRAY)) { + n = dyn[DT_INIT_ARRAYSZ] / sizeof(size_t); + fn = laddr(p, dyn[DT_INIT_ARRAY]); + } + } + + if (n) { if (p != &ldso) { trace_marker_begin(HITRACE_TAG_MUSL, "calling constructors: ", p->name); } @@ -3381,6 +3562,7 @@ hidden void __dls2(unsigned char *base, size_t *sp) ldso.phdr = laddr(&ldso, ehdr->e_phoff); ldso.phentsize = ehdr->e_phentsize; ldso.is_global = true; + ldso.adlt_ndso_index = -1; search_vec(auxv, &ldso_page_size, AT_PAGESZ); kernel_mapped_dso(&ldso); decode_dyn(&ldso); @@ -3517,6 +3699,7 @@ void __dls3(size_t *sp, size_t *auxv, size_t *aux) app.name = (char *)aux[AT_EXECFN]; else app.name = argv[0]; + app.adlt_ndso_index = -1; kernel_mapped_dso(&app); } else { int fd; @@ -3797,12 +3980,29 @@ void __dls3(size_t *sp, size_t *auxv, size_t *aux) static void prepare_lazy(struct dso *p) { size_t dyn[DYN_CNT], n, flags1=0; + ssize_t rel_dyn_cnt, rel_plt_cnt; + decode_vec(p->dynv, dyn, DYN_CNT); search_vec(p->dynv, &flags1, DT_FLAGS_1); if (dyn[DT_BIND_NOW] || (dyn[DT_FLAGS] & DF_BIND_NOW) || (flags1 & DF_1_NOW)) return; - n = dyn[DT_RELSZ]/2 + dyn[DT_RELASZ]/3 + dyn[DT_PLTRELSZ]/2 + 1; - if (NEED_MIPS_GOT_RELOCS) { + + if (__predict_false(p->adlt)) { + /* For adlt mode, it is assumed that there are sections of type either + * SHT_REL, SHT_RELA, SHT_ANDROID_REL, or SHT_ANDROID_RELA. That is, it + * is impossible to combine them. So we can use the same reloc list for + * them (relaDynIndx). */ + rel_dyn_cnt = get_adlt_library_rela_dyn(p->adlt, p->adlt_ndso_index, NULL); + rel_plt_cnt = get_adlt_library_rela_plt(p->adlt, p->adlt_ndso_index, NULL); + n = 1 + + (!dyn[DT_RELSZ] ? (size_t)0 : rel_dyn_cnt <= 0 ? dyn[DT_RELSZ]/2 : (size_t)rel_dyn_cnt) + + (!dyn[DT_RELASZ] ? (size_t)0 : rel_dyn_cnt <= 0 ? dyn[DT_RELASZ]/3 : (size_t)rel_dyn_cnt) + + (rel_plt_cnt <= 0 ? dyn[DT_PLTRELSZ]/2 : (size_t)rel_plt_cnt); + } else { + n = dyn[DT_RELSZ] / 2 + dyn[DT_RELASZ] / 3 + dyn[DT_PLTRELSZ] / 2 + 1; + } + + if (NEED_MIPS_GOT_RELOCS) { size_t j=0; search_vec(p->dynv, &j, DT_MIPS_GOTSYM); size_t i=0; search_vec(p->dynv, &i, DT_MIPS_SYMTABNO); n += i-j; @@ -4493,22 +4693,47 @@ hidden int __dl_invalid_handle(void *h) return 1; } +static bool find_in_dso(struct dso *p, Phdr *phdr, size_t entsz, size_t addr) +{ + Phdr *ph = phdr; + size_t ph_count = p->phnum; + for (; ph_count--; ph = (void *)((char *)ph + entsz)) { + if (ph->p_type != PT_LOAD) continue; + if (addr - ph->p_vaddr < ph->p_memsz){ + return true; + } + } + return false; +} + void *addr2dso(size_t a) { struct dso *p; - for (p=head; p; p=p->next) { - if (a < (size_t)p->map || a - (size_t)p->map >= p->map_len) continue; - Phdr *ph = p->phdr; - size_t phcnt = p->phnum; + size_t remap_org_addr = bolt_remap_addr_func_adlt(a); + struct adlt *adlt = NULL; + + for (p = head; p; p = p->next) { + if (remap_org_addr < (size_t)p->map || remap_org_addr - (size_t)p->map >= p->map_len) { + continue; + } + Phdr *phdr = p->phdr; + if (!phdr) { + continue; + } size_t entsz = p->phentsize; size_t base = (size_t)p->base; - for (; phcnt--; ph=(void *)((char *)ph+entsz)) { - if (ph->p_type != PT_LOAD) continue; - if (a-base-ph->p_vaddr < ph->p_memsz) + + if (__predict_true(!p->adlt)) { + if (find_in_dso(p, phdr, entsz, remap_org_addr - base)) { return p; - } - if (a-(size_t)p->map < p->map_len) + } + return 0; + } + + if (adlt_find_in_dso(p, phdr, adlt, entsz, remap_org_addr - base)) { + return p; + } } return 0; } @@ -4704,11 +4929,49 @@ static int dlclose_impl(struct dso *p) return 0; } +static void dlclose_impl_post(struct dso *p) +{ + size_t n; + /* call destructors if needed */ + pthread_mutex_lock(&init_fini_lock); + int constructed = p->constructed; + pthread_mutex_unlock(&init_fini_lock); + + if (constructed) { + size_t dyn[DYN_CNT]; + size_t *fn; + decode_vec(p->dynv, dyn, DYN_CNT); + n = 0; + if (__predict_false(p->adlt)) { + size_t nn = get_adlt_library_fini_array(p->adlt, p->adlt_ndso_index, NULL); + if (nn > 0) { + n = nn; + fn = (size_t *)laddr(p, p->fini_array_off) + n; + } + } else if (dyn[0] & (1 << DT_FINI_ARRAY)) { + n = dyn[DT_FINI_ARRAYSZ] / sizeof(size_t); + fn = (size_t *)laddr(p, dyn[DT_FINI_ARRAY]) + n; + } + if (n) { + trace_marker_begin(HITRACE_TAG_MUSL, "calling destructors:", p->name); + + pthread_rwlock_unlock(&lock); + while (n--) + ((void (*)(void))*--fn)(); + pthread_rwlock_wrlock(&lock); + + trace_marker_end(HITRACE_TAG_MUSL); + } + pthread_mutex_lock(&init_fini_lock); + p->constructed = 0; + pthread_mutex_unlock(&init_fini_lock); + } +} + int do_dlclose(struct dso *p, bool check_deps_all) { struct dso_entry *ef = NULL; struct dso_entry *ef_tmp = NULL; - size_t n; int unload_check_result; TAILQ_HEAD(unload_queue, dso_entry) unload_queue; TAILQ_HEAD(need_unload_queue, dso_entry) need_unload_queue; @@ -4825,30 +5088,7 @@ int do_dlclose(struct dso *p, bool check_deps_all) } TAILQ_FOREACH(ef, &need_unload_queue, entries) { - /* call destructors if needed */ - pthread_mutex_lock(&init_fini_lock); - int constructed = ef->dso->constructed; - pthread_mutex_unlock(&init_fini_lock); - - if (constructed) { - size_t dyn[DYN_CNT]; - decode_vec(ef->dso->dynv, dyn, DYN_CNT); - if (dyn[0] & (1<dso, dyn[DT_FINI_ARRAY]) + n; - trace_marker_begin(HITRACE_TAG_MUSL, "calling destructors:", ef->dso->name); - - pthread_rwlock_unlock(&lock); - while (n--) - ((void (*)(void))*--fn)(); - pthread_rwlock_wrlock(&lock); - - trace_marker_end(HITRACE_TAG_MUSL); - } - pthread_mutex_lock(&init_fini_lock); - ef->dso->constructed = 0; - pthread_mutex_unlock(&init_fini_lock); - } + dlclose_impl_post(ef->dso); } // Unload all sos at the end because weak symbol may cause later unloaded so to access the previous so's function. TAILQ_FOREACH(ef, &need_unload_queue, entries) { @@ -4961,7 +5201,6 @@ int dladdr(const void *addr_arg, Dl_info *info) size_t addr = (size_t)addr_arg; struct dso *p; Sym *match_sym = NULL; - char *strings; pthread_rwlock_rdlock(&lock); p = addr2dso(addr); @@ -4969,10 +5208,13 @@ int dladdr(const void *addr_arg, Dl_info *info) if (!p) return 0; - strings = p->strings; size_t addr_offset_so = addr - (size_t)p->base; - info->dli_fname = p->name; + if (__predict_false(p->adlt)) { + info->dli_fname = p->adlt_ndso_name; + } else { + info->dli_fname = p->name; + } info->dli_fbase = p->map; if (p->ghashtab) { @@ -4982,13 +5224,14 @@ int dladdr(const void *addr_arg, Dl_info *info) match_sym = find_addr_by_elf(addr_offset_so, p); } - if (!match_sym) { - info->dli_sname = 0; - info->dli_saddr = 0; + if (match_sym) { + info->dli_sname = p->strings + match_sym->st_name; + info->dli_saddr = (void *)laddr(p, match_sym->st_value); + return 1; } - info->dli_sname = strings + match_sym->st_name; - info->dli_saddr = (void *)laddr(p, match_sym->st_value); + info->dli_sname = 0; + info->dli_saddr = 0; return 1; } @@ -5070,7 +5313,15 @@ int dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void struct dso *current; struct dl_phdr_info info; int ret = 0; - for(current = head; current;) { + struct adlt_phdr_info phdr_map_info = { + .map = MAP_FAILED, + .map_len = 0, + .map_ph_addr = NULL, + .map_adlt = NULL, + .ph_ndso_index = 0, + .map_prot = PROT_READ + }; + for (current = head; current;) { info.dlpi_addr = (uintptr_t)current->base; info.dlpi_name = current->name; info.dlpi_phdr = current->phdr; @@ -5081,6 +5332,17 @@ int dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void info.dlpi_tls_data = !current->tls_id ? 0 : __tls_get_addr((tls_mod_off_t[]){current->tls_id,0}); + if (__predict_true(!current->adlt)) { + info.dlpi_phdr = current->phdr; + info.dlpi_phnum = current->phnum; + } else { + int adlt_phdr_ret = + handle_adlt_phdr(current, &info, &phdr_map_info); + if (adlt_phdr_ret != 0) { + break; + } + } + // FIXME: add dl_phdr_lock for unwind callback pthread_mutex_lock(&dl_phdr_lock); ret = (callback)(&info, sizeof (info), data); @@ -5094,7 +5356,10 @@ int dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void setDlcloseLockLastExitTid(gettid()); setDlcloseLockStatus(0); pthread_mutex_unlock(&dlclose_lock); - return ret; + if (phdr_map_info.map != MAP_FAILED) { + munmap(phdr_map_info.map, phdr_map_info.map_len); + } + return ret; } static void error_impl(const char *fmt, ...) @@ -5293,7 +5558,10 @@ static void open_library_by_path(const char *name, const char *s, struct loadtas memset(z_info->path_buf, 0, sizeof(z_info->path_buf)); } } else { - if ((task->fd = open(buf, O_RDONLY|O_CLOEXEC))>=0) break; + if ((task->fd = open(buf, O_RDONLY|O_CLOEXEC))>=0) { + task->fullname = ld_strdup(buf); + break; + } } } s += l; @@ -5472,7 +5740,7 @@ static bool task_check_xpm(struct loadtask *task) return true; } -static bool map_library_header(struct loadtask *task) +static bool map_library_header(struct loadtask *task, const ns_t *ns, bool check_inherited) { off_t off_start; Phdr *ph; @@ -5482,6 +5750,9 @@ static bool map_library_header(struct loadtask *task) if (!task_check_xpm(task)) { return false; } + // size_t tls_image; + + bool tls_appeared = false; ssize_t l = pread(task->fd, task->ehdr_buf, sizeof task->ehdr_buf, task->file_offset); task->eh = task->ehdr_buf; @@ -5530,10 +5801,14 @@ static bool map_library_header(struct loadtask *task) if (ph->p_type == PT_DYNAMIC) { task->dyn = ph->p_vaddr; } else if (ph->p_type == PT_TLS) { + tls_appeared = true; task->tls_image = ph->p_vaddr; task->tls.align = ph->p_align; task->tls.len = ph->p_filesz; task->tls.size = ph->p_memsz; + } else if (ph->p_type == PT_ADLT) { + if (__predict_false(task->adlt)) continue; + if (!parse_adlt_library_header(task, ph)) goto error; } if (ph->p_type != PT_DYNAMIC) { @@ -5578,6 +5853,8 @@ static bool map_library_header(struct loadtask *task) goto error; } Shdr *sh = (Shdr *)((char *)task->shdr_allocated_buf + task->eh->e_shoff - off_start); + Shdr *sh2 = sh; + // Looking for string section (typically .dynstr) for (i = task->eh->e_shnum; i; i--, sh = (void *)((char *)sh + task->eh->e_shentsize)) { if (sh->sh_type != SHT_STRTAB || sh->sh_addr != str_table || sh->sh_size != str_size) { continue; @@ -5598,19 +5875,16 @@ static bool map_library_header(struct loadtask *task) LD_LOGW("Error mapping header %{public}s: dynamic section not found", task->name); goto noexec; } - if (task->shdr_allocated_buf != MAP_FAILED) { - munmap(task->shdr_allocated_buf, task->shsize); - task->shdr_allocated_buf = MAP_FAILED; - } + if (!lookup_adlt_library(task, sh2, tls_appeared)) goto noexec; return true; noexec: errno = ENOEXEC; error: free(task->allocated_buf); task->allocated_buf = NULL; - if (task->shdr_allocated_buf != MAP_FAILED) { - munmap(task->shdr_allocated_buf, task->shsize); - task->shdr_allocated_buf = MAP_FAILED; + if (__predict_false(task->adlt)) { + free_adlt(task->adlt); + task->adlt = NULL; } return false; } @@ -5632,6 +5906,22 @@ static bool task_map_library(struct loadtask *task, struct reserved_address_para size_t start_addr; size_t start_alignment = PAGE_SIZE; bool hugepage_enabled = false; + bool need_map = !(task->adlt && (task->adlt->map != MAP_FAILED)); + + if (!need_map) { + base = task->adlt->base; + task->p->map = task->adlt->map; + task->p->map_len = task->adlt->map_len; + task->p->relro_start = task->adlt->relro_start; + task->p->relro_end = task->adlt->relro_end; + task->p->phdr = task->adlt->phdr; + task->p->phnum = task->eh->e_phnum; + task->p->phentsize = task->eh->e_phentsize; + if (runtime && !adlt_init_rw_seg(task)) { + goto error; + } + goto done_mapping; + } for (i = task->eh->e_phnum; i; i--, ph = (void *)((char *)ph + task->eh->e_phentsize)) { if (ph->p_type == PT_GNU_RELRO) { @@ -5736,9 +6026,9 @@ static bool task_map_library(struct loadtask *task, struct reserved_address_para start_addr = addr_min; hugepage_enabled = get_transparent_hugepages_supported(); + size_t maxinum_alignment = 0; if (hugepage_enabled) { - size_t maxinum_alignment = phdr_table_get_maxinum_alignment(task->ph0, task->eh->e_phnum); - + maxinum_alignment = phdr_table_get_maxinum_alignment(task->ph0, task->eh->e_phnum); start_alignment = maxinum_alignment == KPMD_SIZE ? KPMD_SIZE : PAGE_SIZE; } @@ -5904,9 +6194,27 @@ static bool task_map_library(struct loadtask *task, struct reserved_address_para break; } } + + if (__predict_false(task->adlt)) { + task->adlt->map = task->p->map; + task->adlt->map_len = task->p->map_len; + task->adlt->addr_min = addr_min; + task->adlt->base = base; + task->adlt->hugepage_enabled = hugepage_enabled; + task->adlt->relro_start = task->p->relro_start; + task->adlt->relro_end = task->p->relro_end; + task->adlt->phdr = task->p->phdr; + task->adlt->phnum = task->eh->e_phnum; + task->adlt->phentsize = task->eh->e_phentsize; + pgbo_region.text_start = (uint8_t*)(task->adlt->pgbo_addr_start + base); + pgbo_region.text_end = (uint8_t*)(task->adlt->pgbo_addr_end + base); + pgbo_region.adlt = task->adlt; + } done_mapping: task->p->base = base; task->p->dynv = laddr(task->p, task->dyn); + task->p->init_array_off = task->init_array_off; + task->p->fini_array_off = task->fini_array_off; if (task->p->tls.size) { task->p->tls.image = laddr(task->p, task->tls_image); } @@ -5927,22 +6235,31 @@ error: return false; } -static bool resolve_fd_to_realpath(struct loadtask *task) -{ +static ssize_t fd_to_realpath(int fd, char *buf, size_t buf_size) { + if (fd < 0 || !buf || !buf_size) { + return -1; + } char proc_self_fd[32]; - static char resolved_path[PATH_MAX]; - - int ret = snprintf(proc_self_fd, sizeof(proc_self_fd), "/proc/self/fd/%d", task->fd); + int ret = snprintf(proc_self_fd, sizeof(proc_self_fd), "/proc/self/fd/%d", fd); + + if (ret < 0 || ret >= sizeof(proc_self_fd)) { - return false; + return -1; + } + ssize_t len = readlink(proc_self_fd, buf, buf_size); + if (len < 0 || len >= buf_size) { + return -1; } - ssize_t len = readlink(proc_self_fd, resolved_path, sizeof(resolved_path) - 1); + buf[len] = '\0'; + return len; +} + +static bool resolve_fd_to_realpath(struct loadtask *task) { + ssize_t len = fd_to_realpath(task->fd, task->buf, sizeof(task->buf)); if (len < 0) { + *(task->buf) = '\0'; return false; } - resolved_path[len] = '\0'; - strncpy(task->buf, resolved_path, PATH_MAX); - return true; } @@ -5959,6 +6276,8 @@ static bool load_library_header(struct loadtask *task) size_t alloc_size; int n_th = 0; int is_self = 0; + struct adlt *adlt = NULL; + bool is_adlt_known = false; if (!*name) { errno = EINVAL; @@ -6007,78 +6326,85 @@ static bool load_library_header(struct loadtask *task) task->p = &ldso; return true; } - if (strchr(name, '/')) { - char *separator = strstr(name, ZIP_FILE_PATH_SEPARATOR); - if (separator != NULL) { - int res = open_uncompressed_library_in_zipfile(name, &z_info, separator); - if (!res) { + if (task->fd < 0) { + if (strchr(name, '/')) { + char *separator = strstr(name, ZIP_FILE_PATH_SEPARATOR); + if (separator != NULL) { + int res = open_uncompressed_library_in_zipfile(name, &z_info, separator); + if (!res) { + task->pathname = name; + if (!is_accessible(namespace, task->pathname, g_is_asan, check_inherited)) { + LD_LOGW("Open uncompressed library: check ns accessible failed, pathname %{public}s namespace %{public}s.", + task->pathname, namespace ? namespace->ns_name : "NULL"); + task->fd = -1; + } else { + task->fd = z_info.fd; + task->file_offset = z_info.file_offset; + } + } else { + LD_LOGW("Open uncompressed library in zip file failed, name:%{public}s res:%{public}d", name, res); + return false; + } + } else { task->pathname = name; if (!is_accessible(namespace, task->pathname, g_is_asan, check_inherited)) { - LD_LOGW("Open uncompressed library: check ns accessible failed, pathname %{public}s namespace %{public}s.", + LD_LOGW("load absolute_path %{public}s: check ns accessible failed namespace=%{public}s.", task->pathname, namespace ? namespace->ns_name : "NULL"); task->fd = -1; } else { - task->fd = z_info.fd; - task->file_offset = z_info.file_offset; + task->fd = open(name, O_RDONLY | O_CLOEXEC); + task->fullname = ld_strdup(task->name); } - } else { - LD_LOGW("Open uncompressed library in zip file failed, name:%{public}s res:%{public}d", name, res); - return false; } } else { - task->pathname = name; - if (!is_accessible(namespace, task->pathname, g_is_asan, check_inherited)) { - LD_LOGW("load absolute_path %{public}s: check ns accessible failed namespace=%{public}s.", - task->pathname, namespace ? namespace->ns_name : "NULL"); - task->fd = -1; - } else { - task->fd = open(name, O_RDONLY | O_CLOEXEC); + /* Search for the name to see if it's already loaded */ + /* Search in namespace */ + task->p = find_library_by_name(name, namespace, check_inherited); + if (task->p) { + task->isloaded = true; + LD_LOGD("find_library_by_name(name=%{public}s ns=%{public}s) already loaded by %{public}s in " + "%{public}s namespace ", + name, + namespace->ns_name, + task->p->name, + task->p->namespace->ns_name); + return true; } - } - } else { - /* Search for the name to see if it's already loaded */ - /* Search in namespace */ - task->p = find_library_by_name(name, namespace, check_inherited); - if (task->p) { - task->isloaded = true; - LD_LOGD("find_library_by_name(name=%{public}s ns=%{public}s) already loaded by %{public}s in %{public}s namespace ", - name, namespace->ns_name, task->p->name, task->p->namespace->ns_name); - return true; - } - if (strlen(name) > NAME_MAX) { - LD_LOGW("load_library name length is larger than NAME_MAX:%{public}s.", name); - return false; - } - task->fd = -1; - if (namespace->env_paths) { - open_library_by_path(name, namespace->env_paths, task, &z_info); - } - for (task->p = needed_by; task->fd == -1 && task->p; task->p = task->p->needed_by) { - if (fixup_rpath(task->p, task->buf, sizeof task->buf) < 0) { - task->fd = INVALID_FD_INHIBIT_FURTHER_SEARCH; /* Inhibit further search. */ + if (strlen(name) > NAME_MAX) { + LD_LOGW("load_library name length is larger than NAME_MAX:%{public}s.", name); + return false; + } + task->fd = -1; + if (namespace->env_paths) { + open_library_by_path(name, namespace->env_paths, task, &z_info); } - if (task->p->rpath) { - open_library_by_path(name, task->p->rpath, task, &z_info); - if (task->fd != -1 && resolve_fd_to_realpath(task)) { - if (!is_accessible(namespace, task->buf, g_is_asan, check_inherited)) { - LD_LOGW("Open library: check ns accessible failed, name %{public}s namespace %{public}s.", + for (task->p = needed_by; task->fd == -1 && task->p; task->p = task->p->needed_by) { + if (fixup_rpath(task->p, task->buf, sizeof task->buf) < 0) { + task->fd = INVALID_FD_INHIBIT_FURTHER_SEARCH; /* Inhibit further search. */ + } + if (task->p->rpath) { + open_library_by_path(name, task->p->rpath, task, &z_info); + if (task->fd != -1 && resolve_fd_to_realpath(task)) { + if (!is_accessible(namespace, task->buf, g_is_asan, check_inherited)) { + LD_LOGW("Open library: check ns accessible failed, name %{public}s namespace %{public}s.", name, namespace ? namespace->ns_name : "NULL"); - close(task->fd); - task->fd = -1; + close(task->fd); + task->fd = -1; + } } } } - } - if (g_is_asan) { - handle_asan_path_open_by_task(task->fd, name, namespace, task, &z_info); - LD_LOGD("load_library handle_asan_path_open_by_task fd:%{public}d.", task->fd); - } else { - if (task->fd == -1 && namespace->lib_paths) { - open_library_by_path(name, namespace->lib_paths, task, &z_info); - LD_LOGD("load_library no asan lib_paths path_open fd:%{public}d.", task->fd); + if (g_is_asan) { + handle_asan_path_open_by_task(task->fd, name, namespace, task, &z_info); + LD_LOGD("load_library handle_asan_path_open_by_task fd:%{public}d.", task->fd); + } else { + if (task->fd == -1 && namespace->lib_paths) { + open_library_by_path(name, namespace->lib_paths, task, &z_info); + LD_LOGD("load_library no asan lib_paths path_open fd:%{public}d.", task->fd); + } } + task->pathname = task->buf; } - task->pathname = task->buf; } if (task->fd < 0) { if (!check_inherited || !namespace->ns_inherits) { @@ -6103,7 +6429,7 @@ static bool load_library_header(struct loadtask *task) task->name, namespace->ns_name, topLayerErrno); return false; } - + /* This is where the library file should be opened */ if (fstat(task->fd, &st) < 0) { LD_LOGW("Error loading header %{public}s: failed to get file state errno=%{public}d", task->name, errno); close(task->fd); @@ -6111,13 +6437,24 @@ static bool load_library_header(struct loadtask *task) return false; } /* Search in namespace */ - task->p = find_library_by_fstat(&st, namespace, check_inherited, task->file_offset); + task->adlt = find_adlt_by_fstat(&st); + if (__predict_false(task->adlt)) { + /* There are cases where task->pathname points to the actual + * path+name of the adlt library file. So we use task->name + * to calculate the index of nDSO.*/ + task->file_offset = task->adlt->file_offset; + task->adlt_ndso_index = get_adlt_library_index2(task->adlt, task->fullname); + task->p = find_library_by_adlt_index(task->adlt, namespace, check_inherited, task->adlt_ndso_index); + } else { + task->p = find_library_by_fstat(&st, namespace, check_inherited, task->file_offset); + } if (task->p) { /* If this library was previously loaded with a * pathname but a search found the same inode, * setup its shortname so it can be found by name. */ if (!task->p->shortname && task->pathname != name) { - task->p->shortname = strrchr(task->p->name, '/') + 1; + char *delimiter = strrchr(task->p->name, '/'); + task->p->shortname = delimiter ? delimiter + 1 : task->p->name; } close(task->fd); task->fd = -1; @@ -6127,20 +6464,24 @@ static bool load_library_header(struct loadtask *task) return true; } - map = noload ? 0 : map_library_header(task); + adlt = task->adlt; + map = noload ? 0 : map_library_header(task, namespace, check_inherited); if (!map) { LD_LOGW("Error loading header %{public}s: failed to map header", task->name); close(task->fd); task->fd = -1; return false; } + if (__predict_false(task->adlt)) + is_adlt_known = true; /* Allocate storage for the new DSO. When there is TLS, this * storage must include a reservation for all pre-existing * threads to obtain copies of both the new TLS, and an * extended DTV capable of storing an additional slot for * the newly-loaded DSO. */ - alloc_size = sizeof(struct dso) + strlen(task->pathname) + 1; + alloc_size = sizeof(struct dso) + + (!is_adlt_known ? strlen(task->pathname) : strlen(name)) + 1; if (runtime && task->tls.size) { size_t per_th = task->tls.size + task->tls.align + sizeof(void *) * (tls_cnt + TLS_CNT_INCREASE); n_th = libc.threads_minus_1 + 1; @@ -6155,14 +6496,20 @@ static bool load_library_header(struct loadtask *task) LD_LOGW("Error loading header %{public}s: failed to allocate dso", task->name); close(task->fd); task->fd = -1; + if (!adlt) { + free_adlt(task->adlt); + task->adlt = NULL; + } return false; } + task->p->adlt = task->adlt; + task->p->adlt_ndso_index = task->adlt_ndso_index; task->p->dev = st.st_dev; task->p->ino = st.st_ino; task->p->file_offset = task->file_offset; task->p->needed_by = needed_by; task->p->name = task->p->buf; - strcpy(task->p->name, task->pathname); + strcpy(task->p->name, !is_adlt_known ? task->pathname : name); task->p->tls = task->tls; task->p->dynv = task->dyn_addr; task->p->strings = task->str_addr; @@ -6175,7 +6522,8 @@ static bool load_library_header(struct loadtask *task) /* Add a shortname only if name arg was not an explicit pathname. */ if (task->pathname != name) { - task->p->shortname = strrchr(task->p->name, '/') + 1; + char *delimiter = strrchr(task->p->name, '/'); + task->p->shortname = delimiter ? delimiter + 1 : task->p->name; } if (task->p->tls.size) { @@ -6184,10 +6532,21 @@ static bool load_library_header(struct loadtask *task) (uintptr_t)(task->p->name + strlen(task->p->name) + sizeof(size_t))); task->p->new_tls = (void *)(task->p->new_dtv + n_th * (tls_cnt + 1)); } + if (__predict_false(task->adlt)) + get_adlt_library_final_sym_indexes(task->adlt, task->adlt_ndso_index, &task->p->sym_idx); tail->next = task->p; task->p->prev = tail; tail = task->p; + if (task->p->adlt) { + task->p->adlt_ndso_name = calloc(strlen(task->p->name) + strlen(task->p->adlt->name) + 2, sizeof(char)); + if (task->p->adlt_ndso_name) { + strcpy(task->p->adlt_ndso_name, task->p->adlt->name); + strcat(task->p->adlt_ndso_name, ":"); + strcat(task->p->adlt_ndso_name, task->p->name); + } + task->p->adlt->npsod_load++; + } /* Add dso to namespace */ task->p->namespace = namespace; @@ -6232,6 +6591,7 @@ static void task_load_library(struct loadtask *task, struct reserved_address_par } return; } + set_adlt_symindex_map_to_library(task->p); /* Past this point, if we haven't reached runtime yet, ldso has * committed either to use the mapped library or to abort execution. * Unmapping is not possible, so we can safely reclaim gaps. */ @@ -6259,9 +6619,42 @@ static void task_load_library(struct loadtask *task, struct reserved_address_par #endif } +static void runtime_jumper() +{ + if (runtime) { + longjmp(*rtld_fail, 1); + } +} + +static size_t get_step_size(struct dso *p, size_t *cnt, ssize_t adlt_dtneeded_cnt, + adlt_dt_needed_index_t *adlt_dtneeded) +{ + size_t i; + size_t step; + if (adlt_dtneeded) { + // For ndso + if (!p->adlt || !p->adlt->strtab_addr) { + LD_LOGE("Error loading dependencies for ndso %{public}s", p->name); + error("Error loading dependencies for ndso %s", p->name); + runtime_jumper(); + } + *cnt += (size_t)adlt_dtneeded_cnt; + step = 1; + } else { + for (i = 0; p->dynv[i]; i += NEXT_DYNAMIC_INDEX) { + if (p->dynv[i] == DT_NEEDED) { + *cnt += 1; + } + } + step = NEXT_DYNAMIC_INDEX; + } + return step; +} + static void preload_direct_deps(struct dso *p, ns_t *namespace, struct loadtasks *tasks) { size_t i, cnt = 0; + size_t step; if (p->deps) { return; } @@ -6272,11 +6665,9 @@ static void preload_direct_deps(struct dso *p, ns_t *namespace, struct loadtasks cnt++; } } - for (i = 0; p->dynv[i]; i += NEXT_DYNAMIC_INDEX) { - if (p->dynv[i] == DT_NEEDED) { - cnt++; - } - } + adlt_dt_needed_index_t *adlt_dtneeded = NULL; + ssize_t adlt_dtneeded_cnt = get_adlt_library_dt_needed(p->adlt, p->adlt_ndso_index, &adlt_dtneeded); + step = get_step_size(p, &cnt, adlt_dtneeded_cnt, adlt_dtneeded); /* Use builtin buffer for apps with no external deps, to * preserve property of no runtime failure paths. */ p->deps = (p == head && cnt < MIN_DEPS_COUNT) ? builtin_deps : @@ -6284,9 +6675,7 @@ static void preload_direct_deps(struct dso *p, ns_t *namespace, struct loadtasks if (!p->deps) { LD_LOGW("Error loading dependencies for %{public}s", p->name); error("Error loading dependencies for %s", p->name); - if (runtime) { - longjmp(*rtld_fail, 1); - } + runtime_jumper(); } cnt = 0; if (p == head) { @@ -6294,33 +6683,42 @@ static void preload_direct_deps(struct dso *p, ns_t *namespace, struct loadtasks p->deps[cnt++] = q; } } - for (i = 0; p->dynv[i]; i += NEXT_DYNAMIC_INDEX) { - if (p->dynv[i] != DT_NEEDED) { - continue; + i = 0; + do { + char *dtneed_name; + struct loadtask *task; + if (adlt_dtneeded) { + // For ndso + if (i >= (size_t)adlt_dtneeded_cnt) + break; + dtneed_name = (void *)((char *)p->adlt->strtab_addr + adlt_dtneeded[i].sonameOffset); + task = create_loadtask(dtneed_name, p, namespace, true); + } else { + if (!p->dynv[i]) + break; + if (p->dynv[i] != DT_NEEDED) + continue; + dtneed_name = (void *)((char *)p->strings + p->dynv[i + 1]); + task = create_loadtask(dtneed_name, p, namespace, true); } - const char* dtneed_name = p->strings + p->dynv[i + 1]; - LD_LOGD("load_library %{public}s adding DT_NEEDED task %{public}s namespace(%{public}s)", p->name, dtneed_name, namespace->ns_name); - struct loadtask *task = create_loadtask(dtneed_name, p, namespace, true); + LD_LOGD("load_library %{public}s adding DT_NEEDED task %{public}s namespace(%{public}s)", + p->name, dtneed_name, namespace->ns_name); + if (!task) { LD_LOGW("Error loading dependencies %{public}s : create load task failed", p->name); error("Error loading dependencies for %s : create load task failed", p->name); - if (runtime) { - longjmp(*rtld_fail, 1); - } + runtime_jumper(); continue; } - LD_LOGD("loading shared library %{public}s: (needed by %{public}s)", p->strings + p->dynv[i+1], p->name); + LD_LOGD("loading shared library %{public}s: (needed by %{public}s)", dtneed_name, p->name); if (!load_library_header(task)) { free_task(task); task = NULL; - LD_LOGW("failed to load %{public}s: (needed by %{public}s)", - p->strings + p->dynv[i + 1], - p->name); - error("Error loading shared library %s: %m (needed by %s)", - p->strings + p->dynv[i + 1], p->name); - if (runtime) { - longjmp(*rtld_fail, 1); - } + LD_LOGW("Error loading shared library %{public}s: (needed by %{public}s)", + dtneed_name, p->name); + error("Error loading shared library %s: (needed by %s)", + dtneed_name, p->name); + runtime_jumper(); continue; } p->deps[cnt++] = task->p; @@ -6330,7 +6728,7 @@ static void preload_direct_deps(struct dso *p, ns_t *namespace, struct loadtasks } else { append_loadtasks(tasks, task); } - } + } while (i += step); p->deps[cnt] = 0; p->ndeps_direct = cnt; for (i = 0; i < p->ndeps_direct; i++) { @@ -6585,8 +6983,15 @@ static void set_bss_vma_name(char *path_name, void *addr, size_t zeromap_size) static void find_and_set_bss_name(struct dso *p) { - size_t cnt; Phdr *ph = p->phdr; + if (!ph) { + return; + } + size_t cnt; + if (__predict_false(p->adlt)) { + adlt_find_and_set_bss_name(p, ph); + return; + } for (cnt = p->phnum; cnt--; ph = (void *)((char *)ph + p->phentsize)) { if (ph->p_type != PT_LOAD) continue; size_t seg_start = p->base + ph->p_vaddr; diff --git a/ldso/linux/dynlink_adlt.inc b/ldso/linux/dynlink_adlt.inc new file mode 100644 index 000000000..244747471 --- /dev/null +++ b/ldso/linux/dynlink_adlt.inc @@ -0,0 +1,1575 @@ +// feature ADLT segment type +#define PT_ADLT 0x6788FC61 + +#if UINTPTR_MAX == 0xffffffff +typedef Elf32_Off adlt_index_t; +#else +// feature ADLT index in section type +typedef Elf64_Off adlt_index_t; +#endif + +// // feature ADLT section .rela.dyn/plt index type +// typedef uint32_t adlt_relindex_t; +// // feature ADLT section index type +// typedef uint32_t adlt_secindex_t; +#define ADLT_MAX_NSO (32) +#define BITS_IN_BYTE 8 +#define ADLT_UPALIGN(x, div) (((x) + (div) - 1) / (div)) + +typedef enum { + FIRST_RELOCATED, + SECOND_RELOCATED, + NOT_GOT +} Relocated_Flag; + +// ADLT begin +struct pgbo_text_region { + uint8_t *text_start; + uint8_t *text_end; + struct adlt *adlt; +}; +// ADLT end + +static struct adlt *g_adlt_ptr = NULL; +static struct pgbo_text_region pgbo_region = {0}; + +#if defined(__aarch64__) + +/* feature ADLT function */ +static struct dso *find_library_by_adlt_lstat( + const struct stat *st, const ns_t *ns, bool check_inherited, uint64_t file_offset); +static struct dso *find_library_by_adlt_index( + const struct adlt *adlt, const ns_t *ns, bool check_inherited, ssize_t library_index); +static void free_adlt(struct adlt *adlt); +static void init_adlt(struct adlt *adlt); +static void unmap_adlt_library(struct dso *dso); +ssize_t get_adlt_common_ph(struct adlt *adlt, adlt_phindex_t **ph_indexes); +static ssize_t get_adlt_library_index(unsigned char *strtab_addr, unsigned char *sa_addr, const char *pathname); +static ssize_t get_adlt_library_index2(struct adlt *adlt, const char *pathname); +static adlt_psod_t *get_adlt_library_entry(struct adlt *adlt, ssize_t library_index, char **blob); +ssize_t get_adlt_library_ph(struct adlt *adlt, ssize_t library_index, adlt_phindex_t **ph_indexes); +static ssize_t get_adlt_library_dt_needed(struct adlt *adlt, ssize_t library_index, adlt_dt_needed_index_t **dt_needed); +static ssize_t get_adlt_library_rela_dyn(struct adlt *adlt, ssize_t library_index, adlt_relindex_t **rela_dyn); +static ssize_t get_adlt_library_rela_plt(struct adlt *adlt, ssize_t library_index, adlt_relindex_t **rela_plt); +static ssize_t get_adlt_library_relr_dyn(struct adlt *adlt, ssize_t library_index, adlt_relindex_t **relr_dyn); +static size_t get_adlt_library_init_array( + struct adlt *adlt, ssize_t library_index, adlt_cross_section_array_t **init_cross); +static inline bool adlt_ndso_index_check(ssize_t ndso_index) { + if (ndso_index < 0 || ndso_index >= ADLT_MAX_NSO) { + return false; + } + return true; +} +static void adlt_clean_gotentry(struct dso *p, struct adlt *adlt); +static size_t get_adlt_library_fini_array( + struct adlt *adlt, ssize_t library_index, adlt_cross_section_array_t **fini_cross); +static ssize_t get_adlt_library_final_sym_indexes( + struct adlt *adlt, ssize_t library_index, struct adlt_dso_sym_index *idx); +static adlt_secindex_t get_adlt_symbol_sec_index(struct adlt *adlt); +static ssize_t get_adlt_objects_num(struct adlt *adlt); +static ssize_t merge_sort_arrays(adlt_phindex_t **ph_indexes, ssize_t ph_count, + adlt_phindex_t **phl_indexes, ssize_t phl_count, + adlt_phindex_t **phc_indexes, ssize_t phc_count); +static bool replace_to_adlt_duplicate(struct dso *dso, Sym **sym, const char **name); +static bool replace_to_adlt_duplicate2(struct dso *dso, Sym **sym, const char **name); +static bool is_adlt_partly_load(); +static bool is_adlt_dso_sym(struct dso *dso, uint32_t idx); +static void add_adlt(struct adlt* adlt); +static void del_adlt_from_gadlt(struct adlt* adlt); +static bool is_same_adlt(struct adlt* adlt, struct stat* st); +static struct adlt* find_adlt_by_fstat(struct stat* st); +static char *create_realpath_from_fd(int fd); + + +static struct dso *search_dso_by_adlt_lstat(const struct stat *st, const ns_t *ns, uint64_t file_offset) +{ + LD_LOGD("search_dso_by_adlt_lstat ns_name:%{public}s", ns ? ns->ns_name : "NULL"); + for (size_t i = 0; i < ns->ns_dsos->num; i++){ + struct dso *p = ns->ns_dsos->dsos[i]; + if (p->adlt && p->ldev == st->st_dev && p->lino == st->st_ino) { + LD_LOGD("search_dso_by_adlt_lstat found dev:%{public}lu, ino:%{public}lu, ns_name:%{public}s", + st->st_dev, st->st_ino, ns ? ns->ns_name : "NULL"); + return p; + } + } + return NULL; +} + + +static struct dso *find_library_by_adlt_lstat(const struct stat *st, const ns_t *ns, bool check_inherited, uint64_t file_offset) +{ + LD_LOGD("find_library_by_adlt_lstat ns_name:%{public}s, check_inherited:%{public}d", + ns ? ns->ns_name : "NULL", + !!check_inherited); + struct dso *p = search_dso_by_adlt_lstat(st, ns, file_offset); + if (p) return p; + if (check_inherited && ns->ns_inherits) { + for (size_t i = 0; i < ns->ns_inherits->num; i++) { + ns_inherit *inherit = ns->ns_inherits->inherits[i]; + p = search_dso_by_adlt_lstat(st, inherit->inherited_ns, file_offset); + if (p && is_sharable(inherit, p->shortname)) return p; + } + } + return NULL; +} + +static struct dso *search_dso_by_adlt_index(const struct adlt *adlt, const ns_t *ns, ssize_t library_index) +{ + LD_LOGD("search_dso_by_adlt_index ns_name:%{public}s", ns ? ns->ns_name : "NULL"); + if (adlt && ns && library_index >= 0) { + for (size_t i = 0; i < ns->ns_dsos->num; i++){ + struct dso *p = ns->ns_dsos->dsos[i]; + if (p->adlt == adlt && p->adlt_ndso_index == library_index) { + LD_LOGD("search_dso_by_adlt_index found index:%{public}ld, ns_name:%{public}s", + library_index, ns->ns_name); + return p; + } + } + } + return NULL; +} + +static struct dso *find_library_by_adlt_index( + const struct adlt *adlt, const ns_t *ns, bool check_inherited, ssize_t library_index) +{ + LD_LOGD("find_library_by_adlt_index ns_name:%{public}s, check_inherited:%{public}d, library_index:%{public}ld", + ns ? ns->ns_name : "NULL", !!check_inherited, library_index); + if (adlt && ns && library_index >= 0) { + struct dso *p = search_dso_by_adlt_index(adlt, ns, library_index); + if (p) return p; + if (!check_inherited || !ns->ns_inherits) { + return NULL; + } + for (size_t i = 0; i < ns->ns_inherits->num; i++) { + ns_inherit *inherit = ns->ns_inherits->inherits[i]; + p = search_dso_by_adlt_index(adlt, inherit->inherited_ns, library_index); + if (p && is_sharable(inherit, p->shortname)) return p; + } + } + return NULL; +} + +static void init_adlt(struct adlt *adlt) +{ + if (adlt) { + adlt->map = MAP_FAILED; + adlt->sa_map = MAP_FAILED; + adlt->strtab_map = MAP_FAILED; + adlt->android_rel.map = MAP_FAILED; + adlt->android_rela.map = MAP_FAILED; + adlt->relr_rel.map = MAP_FAILED; + adlt->bsl_syms_map = MAP_FAILED; + adlt->bsl_strings_map = MAP_FAILED; + adlt->name = NULL; + adlt->npsod_load = 0; + } +} + +static void free_record_entry(struct adlt_got_entry *entry) +{ + if (entry->record_entry != NULL) { + free(entry->record_entry); + entry->record_entry = NULL; + } + if (entry->got_map != MAP_FAILED) { + munmap(entry->got_map, entry->got_map_len); + entry->got_map = NULL; + } +} + +static void free_adlt(struct adlt *adlt) +{ + if (!adlt) { + return; + } + if (adlt->sa_map != MAP_FAILED) { + munmap(adlt->sa_map, adlt->sa_map_len); + } + if (adlt->strtab_map != MAP_FAILED) { + munmap(adlt->strtab_map, adlt->strtab_map_len); + } + if (adlt->map != MAP_FAILED) { + munmap(adlt->map, adlt->map_len); + } + if (adlt->android_rel.map != MAP_FAILED) { + munmap(adlt->android_rel.map, adlt->android_rel.map_len); + } + if (adlt->android_rela.map != MAP_FAILED) { + munmap(adlt->android_rela.map, adlt->android_rela.map_len); + } + if (adlt->relr_rel.map != MAP_FAILED) { + munmap(adlt->relr_rel.map, adlt->relr_rel.map_len); + } + if (adlt->bsl_syms_map != MAP_FAILED) { + munmap(adlt->bsl_syms_map, adlt->bsl_syms_map_len); + } + if (adlt->bsl_strings_map != MAP_FAILED) { + munmap(adlt->bsl_strings_map, adlt->bsl_strings_map_len); + } + if (adlt->bolt_remap != MAP_FAILED) { + munmap(adlt->bolt_remap, adlt->bolt_remap_len); + } + if (!adlt->sym_idx_map) { + free(adlt->sym_idx_map); + } + free_record_entry(&adlt->gotEntry); + free_record_entry(&adlt->gotPltEntry); + del_adlt_from_gadlt(adlt); + free(adlt->name); + free(adlt); +} + +static void unmap_adlt_library(struct dso *dso) +{ + if (!dso) { + return; + } + struct adlt *adlt = dso->adlt; + adlt_clean_gotentry(dso, adlt); + adlt->npsod_load--; + dso->adlt = NULL; + if (adlt->npsod_load > 0) { + return; + } + + if (!is_dlclose_debug_enable()) { + free_adlt(adlt); + dso->adlt = NULL; + } else { + if (adlt->sa_map != MAP_FAILED) { + mprotect(adlt->sa_map, adlt->sa_map_len, PROT_NONE); + } + if (adlt->strtab_map != MAP_FAILED) { + mprotect(adlt->strtab_map, adlt->strtab_map_len, PROT_NONE); + } + if (adlt->map != MAP_FAILED) { + mprotect(adlt->map, adlt->map_len, PROT_NONE); + } + if (adlt->android_rel.map != MAP_FAILED) { + mprotect(adlt->android_rel.map, adlt->android_rel.map_len, PROT_NONE); + } + if (adlt->android_rela.map != MAP_FAILED) { + mprotect(adlt->android_rela.map, adlt->android_rela.map_len, PROT_NONE); + } + if (adlt->relr_rel.map != MAP_FAILED) { + mprotect(adlt->relr_rel.map, adlt->relr_rel.map_len, PROT_NONE); + } + if (adlt->bsl_syms_map != MAP_FAILED) { + mprotect(adlt->bsl_syms_map, adlt->bsl_syms_map_len, PROT_NONE); + } + if (adlt->bsl_strings_map != MAP_FAILED) { + mprotect(adlt->bsl_strings_map, adlt->bsl_strings_map_len, PROT_NONE); + } + if (adlt->bolt_remap != MAP_FAILED) { + mprotect(adlt->bolt_remap, adlt->bolt_remap_len, PROT_NONE); + } + if (adlt->gotEntry.got_map != MAP_FAILED) { + mprotect(adlt->gotEntry.got_map, adlt->gotEntry.got_map_len, PROT_NONE); + } + if (adlt->gotPltEntry.got_map != MAP_FAILED) { + mprotect(adlt->gotPltEntry.got_map, adlt->gotPltEntry.got_map_len, PROT_NONE); + } + free(adlt); + } +} + +/* + next_link_name() - get a basename for next hop in chain of links + Input: + fullpath - fullpath to current file (or link) + buf, bufsize - caller's buffer and bufsize for readlink result + Return: + pointer to basename of resolved link (fullpath points to resolved object) + NULL - error or not a link (fullpath not changed) +*/ + +char *next_link_name(char **fullpath, char *buf, ssize_t bufsize) +{ + ssize_t ret; + char *p; + ret = readlink(*fullpath, buf, bufsize - 1); + if (ret < 0) { + return NULL; + } + + *fullpath = buf; + buf[ret] = '\0'; + p = buf + ret; + while (p != buf) { + if (*p == '/') { + return p + 1; + } + p--; + } + if (*p == '/') { + p++; + } + return p; +} + +static ssize_t get_adlt_library_index(unsigned char *strtab_addr, unsigned char *sa_addr, const char *pathname) +{ + ssize_t i; + char *soname; + char *fullpath; + char *psod_soname = NULL; + char *psod_sofilename = NULL; + adlt_psod_t *psod = NULL; + adlt_section_header_t *sah = (adlt_section_header_t*)sa_addr; + char block[PATH_MAX]; // PATH_MAX from limits.h == block size + + soname = (char*)pathname; + // get soname - lib.so + for (i = 0; i < strlen(pathname); i++) { + if (pathname[i] == '/') { + soname = (char *)&pathname[i + 1]; + } + } + // loop deals with case when libname != soname + fullpath = (char*) pathname; + do { + // index search + for (i = 0; i < sah->sharedObjectsNum; i++) { + psod = (adlt_psod_t*)(sa_addr + sah->schemaHeaderSize + (i * sah->schemaPSODSize)); + psod_soname = (char*)(strtab_addr + psod->soName); + psod_sofilename = (char*)(strtab_addr + psod->soFileName); + if (strcmp(psod_soname, soname) == 0) + return i; + if (strcmp(psod_sofilename, soname) == 0) + return i; + } + } while ((soname = next_link_name(&fullpath, block, sizeof(block))) != NULL); + + return -1; +} + +static ssize_t get_adlt_library_index2(struct adlt *adlt, const char *pathname) +{ + return adlt ? get_adlt_library_index(adlt->strtab_addr, adlt->sa_addr, pathname) : -1; +} + +static adlt_psod_t *get_adlt_library_entry(struct adlt *adlt, ssize_t library_index, char **blob) +{ + if (!adlt || (library_index < 0)) { + if (blob) { + *blob = NULL; + } + return NULL; + } + adlt_section_header_t *sah = (void *)adlt->sa_addr; + if (!sah || (library_index >= sah->sharedObjectsNum)) { + if (blob) { + *blob = NULL; + } + return NULL; + } + if (blob) { + *blob = (char *)adlt->sa_addr + sah->blobStart; + } + return (void *)((char *)adlt->sa_addr + sah->schemaHeaderSize + library_index * sah->schemaPSODSize); +} + +ssize_t get_adlt_common_ph(struct adlt *adlt, adlt_phindex_t **ph_indexes) +{ + if (!adlt) { + if (ph_indexes) *ph_indexes = NULL; + return -1; + } + adlt_section_header_t *sah = (void *)adlt->sa_addr; + if (!sah) { + if (ph_indexes) *ph_indexes = NULL; + return -1; + } + char *blob = (void *)((char *)adlt->sa_addr + sah->blobStart); + if (ph_indexes) + *ph_indexes = (void *)((char *)blob + sah->phIndexes.offset); + return sah->phIndexes.size / sizeof(adlt_phindex_t); +} + +ssize_t get_adlt_library_ph(struct adlt *adlt, ssize_t library_index, adlt_phindex_t **ph_indexes) +{ + char *blob; + adlt_psod_t *psod = get_adlt_library_entry(adlt, library_index, &blob); + if (!psod) { + if (ph_indexes) *ph_indexes = NULL; + return -1; + } + if (ph_indexes) { + *ph_indexes = (void *)((char *)blob + psod->phIndexes.offset); + } + return psod->phIndexes.size / sizeof(adlt_phindex_t); +} + +static ssize_t get_adlt_library_dt_needed(struct adlt *adlt, ssize_t library_index, adlt_dt_needed_index_t **dt_needed) +{ + char *blob; + adlt_psod_t *psod = get_adlt_library_entry(adlt, library_index, &blob); + if (!psod) { + if (dt_needed) *dt_needed = NULL; + return -1; + } + if (dt_needed) + *dt_needed = (void *)((char *)blob + psod->dtNeeded.offset); + return psod->dtNeeded.size / sizeof(adlt_dt_needed_index_t); +} + +static ssize_t get_adlt_library_rela_dyn(struct adlt *adlt, ssize_t library_index, adlt_relindex_t **rela_dyn) +{ + char *blob; + adlt_psod_t *psod = get_adlt_library_entry(adlt, library_index, &blob); + if (!psod) { + if (rela_dyn) { + *rela_dyn = NULL; + } + return 0; + } + if (rela_dyn) + *rela_dyn = (void *)((char *)blob + psod->relaDynIndx.offset); + return psod->relaDynIndx.size / sizeof(adlt_relindex_t); +} + +static ssize_t get_adlt_library_rela_plt(struct adlt *adlt, ssize_t library_index, adlt_relindex_t **rela_plt) +{ + char *blob; + adlt_psod_t *psod = get_adlt_library_entry(adlt, library_index, &blob); + if (!psod) { + if (rela_plt) { + *rela_plt = NULL; + } + return 0; + } + if (rela_plt) { + *rela_plt = (void *)((char *)blob + psod->relaPltIndx.offset); + } + return psod->relaPltIndx.size / sizeof(adlt_relindex_t); +} + +static bool replace_to_adlt_duplicate(struct dso *dso, Sym **sym, const char **name){ + char *name_idx; + Sym *sym_idx; + struct dso *p; + ssize_t idx; + + // Skip dso without dependencies + if (!(dso->deps)){ + return false; + } + + // Search dyplicate symbol in adlt lib. + name_idx = malloc((strlen(*name) + 10) * sizeof(char)); + for (int i = 0; dso->deps[i]; i++) { + p = dso->deps[i]; + if (__predict_true(!(p->adlt))) { + continue; + } + + idx = p->adlt_ndso_index; + if (idx == -1) { + continue; + } + + // Get name with postfix: name + __ + hex(order index) + (void)sprintf(name_idx, "%s__%x", *name, idx); + sym_idx = find_sym(p, name_idx, 1).sym; + if (sym_idx) { + *sym = sym_idx; + *name = name_idx; + return true; + } + } + free(name_idx); + return false; +} + +static bool replace_to_adlt_duplicate2(struct dso *dso, Sym **sym, const char **name) +{ + // Skip found or aren't global symbols. + if (!(dso->deps) || (((*sym)->st_info) >> 4) != STB_GLOBAL || find_sym(dso, *name, 1).sym) { + return false; + } + for (int i = 0; dso->deps[i]; i++) { + if (find_sym(dso->deps[i], *name, 1).sym) { + return false; + } + } + // Search duplicate symbol in adlt lib. + return replace_to_adlt_duplicate(dso, sym, name); +} + +static ssize_t get_adlt_library_relr_dyn(struct adlt *adlt, ssize_t library_index, adlt_relindex_t **relr_dyn) +{ + char *blob; + adlt_psod_t *psod = get_adlt_library_entry(adlt, library_index, &blob); + if (!psod) { + if (relr_dyn) { + *relr_dyn = NULL; + } + return 0; + } + if (relr_dyn) { + *relr_dyn = (void *)((char *)blob + psod->relrDynIndx.offset); + } + return psod->relrDynIndx.size / sizeof(adlt_relindex_t); +} + +static size_t get_adlt_library_init_array( + struct adlt *adlt, ssize_t library_index, adlt_cross_section_array_t **init_cross) +{ + adlt_psod_t *psod = get_adlt_library_entry(adlt, library_index, NULL); + if (!psod) { + if (init_cross) *init_cross = NULL; + return -1; + } + if (init_cross) + *init_cross = (void *)&psod->initArray; + return psod->initArray.size / sizeof(size_t); +} + +static size_t get_adlt_library_fini_array( + struct adlt *adlt, ssize_t library_index, adlt_cross_section_array_t **fini_cross) +{ + adlt_psod_t *psod = get_adlt_library_entry(adlt, library_index, NULL); + if (!psod) { + if (fini_cross) { + *fini_cross = NULL; + } + return -1; + } + if (fini_cross) { + *fini_cross = (void *)&psod->finiArray; + } + + return psod->finiArray.size / sizeof(size_t); +} + +static void adlt_reclaim_gaps(struct dso *dso) +{ + Phdr *phdr = dso->phdr; + if (!phdr) { + return; + } + size_t entsz = dso->phentsize; + adlt_phindex_t *ph_indexes, *phc_indexes, *phl_indexes; + ssize_t phl_count = get_adlt_library_ph(dso->adlt, dso->adlt_ndso_index, &phl_indexes); + ssize_t phc_count = get_adlt_common_ph(dso->adlt, &phc_indexes); + int loop = 2; + Phdr *ph; + ssize_t ph_num; + size_t i, q; + while(loop--) { + if (loop) { + if (phc_count <= 0 || !phc_indexes) { + continue; + } + ph_indexes = phc_indexes; + ph_num = phc_count; + i = ph_indexes[0]; + } else { + if (phl_count < 0 || !phl_indexes) { + continue; + } + ph_indexes = phl_indexes; + ph_num = phl_count; + i = ph_indexes[0]; + } + + q = 0; + for (ph = (void *)((char *)phdr + i * entsz); ph_num; + ph_num--, i = (size_t)ph_indexes[++q], ph = (void *)((char *)phdr + i * entsz)) { + if (ph->p_type != PT_LOAD) continue; + if ((ph->p_flags & (PF_R | PF_W)) != (PF_R | PF_W)) continue; + reclaim(dso, ph->p_vaddr & -PAGE_SIZE, ph->p_vaddr); + reclaim(dso, ph->p_vaddr + ph->p_memsz, + ph->p_vaddr + ph->p_memsz + PAGE_SIZE - 1 & -PAGE_SIZE); + } + } +} + +static ssize_t get_adlt_library_final_sym_indexes( + struct adlt *adlt, ssize_t library_index, struct adlt_dso_sym_index *idx) +{ + char *blob; + adlt_psod_t *psod; + + if (!idx) { + return -1; + } + + psod = get_adlt_library_entry(adlt, library_index, &blob); + if (!psod) { + idx->idx = NULL; + idx->size = 0; + return -1; + } + + idx->idx = (uint32_t *)(blob + psod->finalSymIndexes.offset); + idx->size = psod->finalSymIndexes.size / sizeof(uint32_t); + return 0; +} + +static void set_adlt_symindex_map_to_library(struct dso *p) +{ + struct adlt *adlt = p->adlt; + if (!adlt) { + return; + } + size_t nsym = 0; + if (!adlt->sym_idx_map) { + nsym = count_syms(p); + adlt->sym_idx_map = calloc(nsym, sizeof(uint8_t)); + if (!adlt->sym_idx_map) { + LD_LOGE("sym_idx_map calloc fail nsym:%{public}zu", nsym); + return; + } + memset((void*)adlt->sym_idx_map, 0xff, nsym * sizeof(uint8_t)); + adlt->nsym = nsym; + } + struct adlt_dso_sym_index *sym_idx = &p->sym_idx; + uint32_t idx; + if (!sym_idx->idx || sym_idx->size == 0) { + return; + } + for (int i = 0; i < sym_idx->size; ++i) { + idx = sym_idx->idx[i]; + if (idx >= adlt->nsym) { + LD_LOGE("sym_idx_map calloc fail nsym:%{public}zu", nsym); + continue; + } + adlt->sym_idx_map[idx] = p->adlt_ndso_index; + } + return; +} + + +/* + * ADLT + */ +static adlt_secindex_t get_adlt_symbol_sec_index(struct adlt *adlt) +{ + if (adlt && adlt->sa_addr) { + adlt_section_header_t *sah = (void *)adlt->sa_addr; + return (adlt_secindex_t)sah->sharedEndGlobalSymbolIndex.secIndex; + } + return (adlt_secindex_t)-1; +} + +static ssize_t get_adlt_objects_num(struct adlt *adlt) +{ + if (adlt) { + adlt_section_header_t *sah = (void *)adlt->sa_addr; + if (sah) { + return (ssize_t)sah->sharedObjectsNum; + } + } + return -1; +} + +static bool is_adlt_dso_sym(struct dso *dso, uint32_t idx) +{ + // struct adlt_dso_sym_index *sym_idx; + // uint64_t i; + + if (__predict_true(!dso->adlt)) { + return true; + } + if (idx >= dso->adlt->nsym) { + return false; + } + return dso->adlt->sym_idx_map[idx] == dso->adlt_ndso_index; +} + +static void add_adlt(struct adlt *adlt) +{ + if (!g_adlt_ptr) { + g_adlt_ptr = adlt; + } else { + for (struct adlt *adlt_ptr = g_adlt_ptr; adlt_ptr; adlt_ptr = adlt_ptr->next) { + if (!adlt_ptr->next) { + adlt_ptr->next = adlt; + adlt->prev = adlt_ptr; + break; + } + } + } +} + +static void del_adlt_from_gadlt(struct adlt *adlt) +{ + if (!adlt) { + return; + } + if (adlt == g_adlt_ptr) { + g_adlt_ptr = adlt->next; + if (g_adlt_ptr) { + g_adlt_ptr->prev = NULL; + } + } else { + if (adlt->prev) { + adlt->prev->next = adlt->next; + } + if (adlt->next) { + adlt->next->prev = adlt->prev; + } + } + return; +} + +static bool is_same_adlt(struct adlt* adlt, struct stat* st) +{ + return (adlt->dev == st->st_dev && adlt->ino == st->st_ino && adlt->file_size == st->st_size); +} + +static struct adlt* find_adlt_by_fstat(struct stat* st) +{ + struct adlt* adlt; + for (adlt = g_adlt_ptr; adlt; adlt = adlt->next) { + if (is_same_adlt(adlt, st)) { + return adlt; + } + } + return NULL; +} + + +static Relocated_Flag check_and_set_bit(struct adlt_got_entry *et, size_t reloc_addr , struct dso *dso) +{ + if (!et->entry_addr) { + return NOT_GOT; + } + ssize_t ndso_index = dso->adlt_ndso_index; + uintptr_t reloc_ptr = (uintptr_t)reloc_addr; + uintptr_t got_start = (uintptr_t)et->entry_addr; + uintptr_t got_end = got_start + (et->entry_len * sizeof(unsigned char)); + size_t *reloc_va = (size_t*)laddr(dso, reloc_addr); + if ((reloc_ptr >= got_start) && (reloc_ptr < got_end)) + { + size_t index; + index = (reloc_ptr - (uintptr_t)et->entry_addr) / sizeof(size_t); + if (et->record_entry[index] == 0) { + et->record_entry[index] |= (1UL << ndso_index); + *reloc_va = et->got_entry[index]; + return FIRST_RELOCATED; + } + et->record_entry[index] |= (1UL << ndso_index); + return SECOND_RELOCATED; + } + return NOT_GOT; // not in got/gotplt range +} + +static bool has_relocation(struct dso *dso, size_t *reloc_addr) +{ + if (__predict_true(!dso->adlt)) { + return false; + } + if (!adlt_ndso_index_check(dso->adlt_ndso_index)) { + LD_LOGE("adlt_ndso_index is invalid, index=%{public}zd", dso->adlt_ndso_index); + return false; + } + + if (check_and_set_bit(&dso->adlt->gotEntry, reloc_addr, dso) == SECOND_RELOCATED) { + return true; + } + + return (check_and_set_bit(&dso->adlt->gotPltEntry, reloc_addr, dso) == SECOND_RELOCATED); +} + +static void adlt_do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stride, adlt_relindex_t *rel_index) +{ + int skip_relative = 0, reuse_addends = 0, save_slot = 0; + int type; + size_t addend; + size_t *reloc_addr; + size_t *rel_start = rel; + + if (dso == &ldso) { + /* Only ldso's REL table needs addend saving/reuse. */ + if (rel == apply_addends_to) + reuse_addends = 1; + skip_relative = 1; + } + + if (!rel_index) { + return; + } + rel = rel_start + *rel_index++ * stride; + + for (; rel_size; + rel = rel_start + *rel_index++ * stride, rel_size -= stride * sizeof(size_t)) { + if (skip_relative && IS_RELATIVE(rel[1], dso->syms)) continue; + type = R_TYPE(rel[1]); + if (type == REL_NONE) continue; + if (has_relocation(dso, rel[0])) { + continue; + } + reloc_addr = laddr(dso, rel[0]); + if (stride > 2) { + addend = rel[2]; + } else if (type==REL_GOT || type==REL_PLT|| type==REL_COPY) { + addend = 0; + } else if (reuse_addends) { + /* Save original addend in stage 2 where the dso + * chain consists of just ldso; otherwise read back + * saved addend since the inline one was clobbered. */ + if (head==&ldso){ + saved_addends[save_slot] = *reloc_addr; + } + addend = saved_addends[save_slot++]; + } else { + addend = *reloc_addr; + } + do_one_reloc(dso, rel, stride, addend); + } +} + +static void adlt_do_android_relocs( + struct dso *p, size_t dt_name, size_t dt_size, size_t rel_cnt, adlt_relindex_t *rel_index) +{ + struct unpack_reloc *relocs = NULL; + size_t android_rel_addr = 0; + + relocs =(dt_name == DT_ANDROID_REL ? &(p->adlt->android_rel) : &(p->adlt->android_rela)); + search_vec(p->dynv, &android_rel_addr, dt_name); + if (!android_rel_addr) { + return; + } + if (relocs->map == MAP_FAILED) { + (void)decode_android_relocs(p, dt_name, dt_size, (size_t **)&relocs->map, &relocs->map_len); + } + if (relocs->map != MAP_FAILED) { + if (dt_name == DT_ANDROID_REL) { + adlt_do_relocs(p, (size_t *)relocs->map, rel_cnt * sizeof(size_t) * 2, 2, rel_index); + } else { + adlt_do_relocs(p, (size_t *)relocs->map, rel_cnt * sizeof(size_t) * 3, 3, rel_index); + } + } +} + + +static void adlt_reloc(struct dso *p, size_t dyn[],const dl_extinfo *extinfo, ssize_t *relro_fd_offset) +{ + size_t plt_stride; + // OHOS_LOCAL ADLT begin + adlt_relindex_t *adlt_rel_dyn, *adlt_rel_plt; + size_t rel_dyn_cnt, rel_plt_sz; + + if (head != &ldso && p->relro_start != p->relro_end) { + if (mprotect(laddr(p, p->relro_start), p->relro_end-p->relro_start, PROT_READ | PROT_WRITE) + && errno != ENOSYS) { + LD_LOGE("Error relocating %{public}s: RELRO protection failed: %{public}d", p->name, errno); + if (runtime) longjmp(*rtld_fail, 1); + } + } + + /* For adlt mode, it is assumed that there are sections of type either + * SHT_REL, SHT_RELA, SHT_ANDROID_REL, or SHT_ANDROID_RELA. That is, it + * is impossible to combine them. So we can use the same reloc list for + * them (relaDynIndx). */ + rel_dyn_cnt = (size_t)get_adlt_library_rela_dyn(p->adlt, p->adlt_ndso_index, &adlt_rel_dyn); + plt_stride = 2 + (dyn[DT_PLTREL] == DT_RELA); + rel_plt_sz = (size_t)get_adlt_library_rela_plt(p->adlt, p->adlt_ndso_index, &adlt_rel_plt) * + plt_stride * sizeof(size_t); + + adlt_do_relocs(p, laddr(p, dyn[DT_JMPREL]), rel_plt_sz, plt_stride, adlt_rel_plt); + + if (dyn[DT_RELSZ]) { + adlt_do_relocs(p, laddr(p, dyn[DT_REL]), rel_dyn_cnt * 2 * sizeof(size_t), 2, adlt_rel_dyn); + } + if (dyn[DT_RELASZ]){ + adlt_do_relocs(p, laddr(p, dyn[DT_RELA]), rel_dyn_cnt * 3 * sizeof(size_t), 3, adlt_rel_dyn); + } + + if (!DL_FDPIC) { + adlt_relindex_t *adlt_rel_relr; + size_t rel_relr_cnt = (size_t)get_adlt_library_relr_dyn(p->adlt, p->adlt_ndso_index, &adlt_rel_relr); + do_relr_relocs(p, laddr(p, dyn[DT_RELR]), dyn[DT_RELRSZ], rel_relr_cnt, adlt_rel_relr); + } + + adlt_do_android_relocs(p, DT_ANDROID_REL, DT_ANDROID_RELSZ, rel_dyn_cnt, adlt_rel_dyn); + adlt_do_android_relocs(p, DT_ANDROID_RELA, DT_ANDROID_RELASZ, rel_dyn_cnt, adlt_rel_dyn); + + if (head != &ldso && p->relro_start != p->relro_end && + mprotect(laddr(p, p->relro_start), p->relro_end-p->relro_start, PROT_READ) + && errno != ENOSYS) { + LD_LOGE("Error relocating %{public}s: RELRO protection failed: %{public}d", + p->name, errno); + if (runtime) longjmp(*rtld_fail, 1); + } + /* Handle serializing/mapping the RELRO segment */ + handle_relro_sharing(p, extinfo, relro_fd_offset); + + p->relocated = 1; + free_reloc_can_search_dso(p); +} + +static size_t bolt_remap_addr_func(size_t in_addr, struct adlt *adlt) { + if (!adlt || adlt->bolt_remap_len == 0) { + return in_addr; + } + + struct bolt_remap_data* remap_data = (struct bolt_remap_data*)adlt->bolt_remap_addr; + ssize_t min = 1; + ssize_t max = ((size_t *)adlt->bolt_remap_addr)[1]; + size_t minAddr = remap_data[min].new_addr; + size_t maxAddr = ((size_t *)adlt->bolt_remap_addr)[0]; + if (in_addr < minAddr || in_addr >= maxAddr) { + return in_addr; + } + + while (min <= max) { + ssize_t mid = min + (max - min) / 2; + size_t addr = remap_data[mid].new_addr; + + if (in_addr == addr) { + return remap_data[mid].old_addr; + } else if (in_addr < addr) { + max = mid - 1; + } else { + min = mid + 1; + } + } + return remap_data[max].old_addr; +} + +void *bolt_remap_addr_func_adlt(size_t a) +{ + if (!pgbo_region.adlt) { + return a; + } + if (a < (size_t)pgbo_region.text_start || a >= (size_t)pgbo_region.text_end) { + return a; + } + + size_t base = (size_t)pgbo_region.adlt->base; + size_t elf_addr = a - base; + size_t bolt_remap = bolt_remap_addr_func(elf_addr, pgbo_region.adlt); + if (bolt_remap != elf_addr) { + return bolt_remap + base; + } + return a; +} + + +static bool adlt_find_in_dso(struct dso *p, Phdr *phdr, struct adlt *adlt, size_t entsz, size_t addr) +{ + Phdr *ph; + adlt_phindex_t *phc_indexes, *phl_indexes; + ssize_t phl_count = get_adlt_library_ph(p->adlt, p->adlt_ndso_index, &phl_indexes); + ssize_t phc_count = get_adlt_common_ph(p->adlt, &phc_indexes); + + if (p->adlt != adlt && phc_indexes) { + while(phc_count-- > 0) { + ph = (void *)((char *)phdr + (size_t)(*phc_indexes++) * entsz); + if (ph->p_type != PT_LOAD) continue; + if (addr - ph->p_vaddr < ph->p_memsz) { + return true; + } + } + adlt = p->adlt; + } + if (phl_indexes) { + while(phl_count-- > 0) { + ph = (void *)((char *)phdr + (size_t)(*phl_indexes++) * entsz); + if (ph->p_type != PT_LOAD) continue; + if (addr - ph->p_vaddr < ph->p_memsz){ + return true; + } + } + } + return false; +} + + + +static int update_adlt_mapping(struct dso *current, struct adlt_phdr_info *phdr_info) +{ + Phdr *ph; + char *ph_addr; + ssize_t ph_count; + adlt_phindex_t *ph_indexes; + size_t entsz = current->phentsize; + Phdr *phdr = current->phdr; + + if (phdr_info->map_adlt == current->adlt) { + return 0; + } + + phdr_info->map_adlt = NULL; + if (phdr_info->map != MAP_FAILED) { + munmap(phdr_info->map, phdr_info->map_len); + } + + size_t cnt = current->phnum; + phdr_info->map_len = (cnt * entsz + PAGE_SIZE - 1) & -PAGE_SIZE; + phdr_info->map = + mmap(0, phdr_info->map_len, (phdr_info->map_prot = PROT_READ | PROT_WRITE), MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (phdr_info->map == MAP_FAILED) { + LD_LOGE("Error iterate headers %{public}s: failed to map program headers", current->name); + return -1; + } + + phdr_info->map_ph_addr = (void *)phdr_info->map; + phdr_info->map_adlt = current->adlt; + phdr_info->ph_ndso_index = 0; + ph_addr = phdr_info->map_ph_addr; + + for (ph = phdr; cnt--; ph = (void *)((char *)ph + entsz)) { + switch (ph->p_type) { + case PT_LOAD: + case PT_TLS: + case PT_GNU_EH_FRAME: + continue; + default: + break; + } + memcpy(ph_addr, ph, entsz); + ph_addr += entsz; + ++phdr_info->ph_ndso_index; + } + + ph_count = get_adlt_common_ph(current->adlt, &ph_indexes); + if (ph_count > 0 && ph_indexes) { + while (ph_count--) { + memcpy(ph_addr, (char *)phdr + (*ph_indexes) * entsz, entsz); + ph_addr += entsz; + ++phdr_info->ph_ndso_index; + ++ph_indexes; + } + } + + return 0; +} + +static int handle_adlt_phdr(struct dso *current, struct dl_phdr_info *info, struct adlt_phdr_info *phdr_info) +{ + char *ph_addr; + ssize_t ph_count; + adlt_phindex_t *ph_indexes; + size_t entsz = current->phentsize; + Phdr *phdr = current->phdr; + + if (!phdr) { + return -1; + } + + int ret = update_adlt_mapping(current, phdr_info); + if (ret != 0) { + return ret; + } + + info->dlpi_phdr = (void *)phdr_info->map_ph_addr; + ph_count = get_adlt_library_ph(current->adlt, current->adlt_ndso_index, &ph_indexes); + if (ph_count > 0 && ph_indexes) { + if (!(phdr_info->map_prot & PROT_WRITE)) { + if (mprotect(phdr_info->map, phdr_info->map_len, PROT_READ | PROT_WRITE) && errno != ENOSYS) { + error("Error iterating phdr %s: protection failed: %m", current->name); + return -1; + } + } + phdr_info->map_prot = PROT_READ | PROT_WRITE; + info->dlpi_phnum = phdr_info->ph_ndso_index + (size_t)ph_count; + ph_addr = phdr_info->map_ph_addr + phdr_info->ph_ndso_index * entsz; + while (ph_count--) { + memcpy(ph_addr, (char *)phdr + (*ph_indexes) * entsz, entsz); + ph_addr += entsz; + ++ph_indexes; + } + } else { + info->dlpi_phnum = phdr_info->ph_ndso_index; + } + + if (phdr_info->map_prot & PROT_WRITE) { + if (mprotect(phdr_info->map, phdr_info->map_len, PROT_READ) && errno != ENOSYS) { + error("Error iterating phdr %s: protection failed: %m", current->name); + return -1; + } + phdr_info->map_prot = PROT_READ; + } + + return 0; +} + + +#ifdef LOAD_ORDER_RANDOMIZATION +void init_entry(struct adlt_got_entry *entry, Shdr *sh, struct loadtask *task) +{ + entry->entry_addr = sh->sh_addr; + entry->entry_len = sh->sh_size; + entry->record_entry = (uint8_t *)calloc(ADLT_UPALIGN(sh->sh_size, sizeof(uint64_t)) * ADLT_UPALIGN(ADLT_MAX_NSO, BITS_IN_BYTE), sizeof(uint8_t)); + if (!entry->record_entry) { + LD_LOGE("Error mapping header : failed to allocate gotEntry"); + return; + } + off_t off_start; + off_start = sh->sh_offset; + off_start &= -PAGE_SIZE; + entry->got_map_len = sh->sh_size + (sh->sh_offset - off_start); + entry->got_map = mmap(0, entry->got_map_len, PROT_READ, MAP_PRIVATE, task->fd, off_start + task->file_offset); + if (entry->got_map == MAP_FAILED) { + LD_LOGE("Error mapping got entry %{public}s: failed to map got/got.plt section", task->name); + return; + } + entry->got_entry = (size_t *)(entry->got_map + sh->sh_offset - off_start); +} + +void init_gotentry(struct adlt *adlt, Shdr *sh, struct loadtask *task, unsigned char *shstr_addr) +{ + if (!adlt) { + return; + } + // init for gotEntry/got.pltEntry + Shdr *sh3 = (void *)((char *)sh + (task->eh->e_shnum - 1) * task->eh->e_shentsize); + for (size_t i = task->eh->e_shnum; i; --i, sh3 = (void *)((char *)sh3 - task->eh->e_shentsize)) + { + if (sh3->sh_type != SHT_PROGBITS) { + continue; + } + const char *section_header_name = (const char *)(shstr_addr + sh3->sh_name); + if (!strcmp(section_header_name, ".got")) { + init_entry(&adlt->gotEntry, sh3, task); + } + if (!strcmp(section_header_name, ".got.plt")) { + init_entry(&adlt->gotEntry, sh3, task); + } + } +} + +static void adlt_clean_dso_flag(struct adlt_got_entry *entry, ssize_t ndso_index) +{ + size_t got_num = ADLT_UPALIGN(entry->entry_len, sizeof(uint64_t)); + for (size_t i = 0; i < got_num; i++) { + uint64_t mask = ~(1UL << ndso_index); + entry->record_entry[i] &= mask; + } +} + +static void adlt_clean_gotentry(struct dso *p, struct adlt *adlt) +{ + if (!adlt_ndso_index_check(p->adlt_ndso_index)) { + return; + } + + adlt_clean_dso_flag(&adlt->gotEntry, p->adlt_ndso_index); + adlt_clean_dso_flag(&adlt->gotPltEntry, p->adlt_ndso_index); +} + +static bool parse_adlt_library_header(struct loadtask *task, Phdr *ph) +{ + struct adlt *adlt = calloc(1, sizeof(struct adlt)); + if (!adlt) { + LD_LOGE("Error mapping header %{public}s: failed to allocate adlt", task->name); + return false; + } + init_adlt(adlt); + task->adlt = adlt; + + struct stat st; + if (fstat(task->fd, &st) < 0) { + LD_LOGE("Error mapping header %{public}s: failed to get file state", task->name); + return false; + } + adlt->dev = st.st_dev; + adlt->ino = st.st_ino; + adlt->file_size = st.st_size; + adlt->file_offset = task->file_offset; + // Resolve adlt so real path+name + adlt->name = create_realpath_from_fd(task->fd); + if (!adlt->name) { + LD_LOGE("Error mapping header %{public}s: failed to resolve adlt name", task->name); + return false; + } + // Map .adlt section + off_t off_start = ph->p_offset; + off_start &= -PAGE_SIZE; + adlt->sa_map_len = ph->p_filesz + (ph->p_offset - off_start); + adlt->sa_map = mmap(0, adlt->sa_map_len, PROT_READ, MAP_PRIVATE, task->fd, off_start + task->file_offset); + if (adlt->sa_map == MAP_FAILED) { + LD_LOGE("Error mapping header %{public}s: failed to map adlt section", task->name); + return false; + } + adlt->sa_addr = (void *)((char *)(adlt->sa_map) + ph->p_offset - off_start); + add_adlt(adlt); + return true; +} + +static void set_start_end_addr(struct loadtask *task, Shdr *sh) +{ + uint64_t _end = sh->sh_addr + sh->sh_size; + if (task->adlt->pgbo_addr_start == 0) { + task->adlt->pgbo_addr_start = sh->sh_addr; + task->adlt->pgbo_addr_end = _end; + } else { + task->adlt->pgbo_addr_start = + (task->adlt->pgbo_addr_start < sh->sh_addr) ? task->adlt->pgbo_addr_start : sh->sh_addr; + task->adlt->pgbo_addr_end = + (task->adlt->pgbo_addr_end > _end) ? task->adlt->pgbo_addr_end : _end; + } +} + +static bool map_remap_strtab(struct loadtask *task, Shdr *sh2, size_t bsl_bolt_remap_index, size_t strtab_sec_index) +{ + Shdr *sh; + off_t off_start; + if (!strtab_sec_index) { + LD_LOGE("Error mapping header %{public}s: failed to find adlt strtab section(s)", task->name); + return false; + } + + if (bsl_bolt_remap_index) { + /* .bolt.remap mapping */ + sh = (void *)((char *)sh2 + bsl_bolt_remap_index * task->eh->e_shentsize); + off_start = sh->sh_offset; + off_start &= -PAGE_SIZE; + task->adlt->bolt_remap_len = sh->sh_size + (sh->sh_offset - off_start); + task->adlt->bolt_remap = + mmap(0, task->adlt->bolt_remap_len, PROT_READ, MAP_PRIVATE, task->fd, off_start + task->file_offset); + if (task->adlt->bolt_remap == MAP_FAILED) { + LD_LOGE("Error mapping header %{public}s: failed to map adlt .bolt.remap section", task->name); + return false; + } + task->adlt->bolt_remap_addr = (void *)(task->adlt->bolt_remap + sh->sh_offset - off_start); + } else { + task->adlt->bolt_remap_len = 0; + } + + /* .adlt.strtab mapping */ + sh = (void *)((char *)sh2 + strtab_sec_index * task->eh->e_shentsize); + off_start = sh->sh_offset; + off_start &= -PAGE_SIZE; + task->adlt->strtab_map_len = sh->sh_size + (sh->sh_offset - off_start); + task->adlt->strtab_map = + mmap(0, task->adlt->strtab_map_len, PROT_READ, MAP_PRIVATE, task->fd, off_start + task->file_offset); + if (task->adlt->strtab_map == MAP_FAILED) { + LD_LOGE("Error mapping header %{public}s: failed to map adlt strtab section", task->name); + return false; + } + task->adlt->strtab_addr = (void *)(task->adlt->strtab_map + sh->sh_offset - off_start); + + return true; +} + +static bool lookup_strtab_map(struct loadtask *task, Shdr *sh2) +{ + size_t i; + /* Looking for .adlt.strtab, .strtab, .symtab */ + if (task->adlt->strtab_map != MAP_FAILED) return true; + /* By current design, the .adlt.strtab section and the strings section + for the backtrace procedure are searched by name */ + if (task->eh->e_shstrndx >= task->eh->e_shnum) { + LD_LOGE("Error mapping header %{public}s: sections strtab section not found", task->name); + return false; + } + /* sections name section mapping */ + Shdr *shstr = (void *)((char *)sh2 + task->eh->e_shstrndx * task->eh->e_shentsize); + off_t off_start = shstr->sh_offset; + off_start &= -PAGE_SIZE; + size_t shstr_map_len = shstr->sh_size + (shstr->sh_offset - off_start); + unsigned char *shstr_map = mmap(0, shstr_map_len, PROT_READ, MAP_PRIVATE, task->fd, off_start + task->file_offset); + if (shstr_map == MAP_FAILED) { + LD_LOGE("Error mapping header %{public}s: failed to map sections strtab section", task->name); + return false; + } + + unsigned char *shstr_addr = (void *)(shstr_map + shstr->sh_offset - off_start); + size_t strtab_sec_index = 0; + size_t bsl_bolt_remap_index = 0; + size_t text_remap_index = 0; + size_t text_cold_remap_index = 0; + + Shdr *sh = (void *)((char *)sh2 + (task->eh->e_shnum - 1) * task->eh->e_shentsize); + for (i = task->eh->e_shnum; + i && (!strtab_sec_index || !bsl_bolt_remap_index || !text_remap_index || !text_cold_remap_index); + --i, sh = (void *)((char *)sh - task->eh->e_shentsize)) { + const char *name_ = (const char *)(shstr_addr + sh->sh_name); + if (sh->sh_type == SHT_STRTAB && !strcmp(name_, ".adlt.strtab")) { + strtab_sec_index = i - 1; + continue; + } else if (sh->sh_type == SHT_PROGBITS){ + if (!strcmp(name_, ".bolt.remap")) { + bsl_bolt_remap_index = i - 1; + } else if (!strcmp(name_, ".text")) { + set_start_end_addr(task, sh); + text_remap_index = i - 1; + } else if (!strcmp(name_, ".text.cold")) { + set_start_end_addr(task, sh); + text_cold_remap_index = i - 1; + } + } + } + + init_gotentry(task->adlt, sh2, task, shstr_addr); + + munmap(shstr_map, shstr_map_len); + + if (!map_remap_strtab(task, sh2, bsl_bolt_remap_index, strtab_sec_index)) return false; + + return true; +} + +static bool lookup_ndso(struct loadtask *task, Shdr *sh2) +{ + Shdr *sh; + if (task->adlt_ndso_index < 0) { + /* There are cases where task->pathname points to the actual path+name + * of the adlt library file. So we use task->name to calculate the + * index of nDSO.*/ + task->adlt_ndso_index = get_adlt_library_index2(task->adlt, task->fullname); + } + /* Looking for nDSO init_array and fini_array */ + if (task->adlt_ndso_index >= 0) { + adlt_cross_section_array_t *cross; + + get_adlt_library_init_array(task->adlt, task->adlt_ndso_index, &cross); + if (!cross || cross->secIndex >= task->eh->e_shnum) { + LD_LOGE("Error mapping header %{public}s: failed to find init array", task->name); + return false; + } + sh = (void *)((char *)sh2 + cross->secIndex * task->eh->e_shentsize); + task->init_array_off = sh->sh_addr + cross->offset; + + get_adlt_library_fini_array(task->adlt, task->adlt_ndso_index, &cross); + if (!cross || cross->secIndex >= task->eh->e_shnum) { + LD_LOGE("Error mapping header %{public}s: failed to find fini array", task->name); + return false; + } + sh = (void *)((char *)sh2 + cross->secIndex * task->eh->e_shentsize); + task->fini_array_off = sh->sh_addr + cross->offset; + } + return true; +} + +static void lookup_tls(struct loadtask *task, bool tls_appeared) +{ + Phdr *ph; + /* Looking for nDSO TLS */ + if (!tls_appeared) return; + task->tls_image = 0; + task->tls.align = 0; + task->tls.len = 0; + task->tls.size = 0; + + adlt_phindex_t *ph_indexes, *phc_indexes, *phl_indexes; + ssize_t phl_count = get_adlt_library_ph(task->adlt, task->adlt_ndso_index, &phl_indexes); + ssize_t phc_count = get_adlt_common_ph(task->adlt, &phc_indexes); + ssize_t ph_count; + + size_t z = 2; + while(z--) { + ph_count = z > 0 ? phc_count : phl_count; + ph_indexes = z > 0 ? phc_indexes : phl_indexes; + if (ph_count <= 0 || ph_indexes <= 0) { + continue; + } + for (ph = (void *)((char *)task->ph0 + (*ph_indexes) * task->eh->e_phentsize); ph_count; + ph_count--, ph_indexes++, ph = (void *)((char *)task->ph0 + (*ph_indexes) * task->eh->e_phentsize)) { + if (ph->p_type == PT_TLS) { + task->tls_image = ph->p_vaddr; + task->tls.align = ph->p_align; + task->tls.len = ph->p_filesz; + task->tls.size = ph->p_memsz; + z = 0; + break; + } + } + } +} + +static bool lookup_adlt_library(struct loadtask *task, Shdr *sh2, bool tls_appeared) +{ + if (__predict_true(!task->adlt)) return true; + if (!lookup_strtab_map(task, sh2)) return false; + if (!lookup_ndso(task, sh2)) return false; + lookup_tls(task, tls_appeared); + return true; +} + +static bool adlt_init_rw_seg(struct loadtask *task) +{ + size_t off_start; + size_t addr_max; + size_t addr_min; + size_t map_len; + unsigned char *map; + unsigned int relro_flag; + struct dso *p = task->p; + unsigned char *base = NULL; + adlt_phindex_t *ph_indexes = NULL; + ssize_t ph_count = get_adlt_library_ph(p->adlt, p->adlt_ndso_index, &ph_indexes); + if (ph_count < 0 || !ph_indexes) { + return false; + } + base = p->adlt->base; + for (size_t i = 0; i < ph_count; i++) { + const Phdr *ph = &p->phdr[ph_indexes[i]]; + if (ph->p_type == PT_LOAD && (ph->p_flags & PF_W)) { + unsigned char *cur_beg = base + ph->p_vaddr; + if (DL_NOMMU_SUPPORT) { + memset((void *)cur_beg, 0, ph->p_memsz); + continue; + } + relro_flag = ((p->relro_start) <= (ph)->p_vaddr)&&(((ph)->p_vaddr + (ph)->p_memsz) <= p->relro_end)? 1 : 0; + if (relro_flag && mprotect((base + ph->p_vaddr), ph->p_memsz, PROT_READ | PROT_WRITE) + && errno != ENOSYS) { + error("Error relocating %s: RELRO protection failed", p->name); + longjmp(*rtld_fail, 1); + } + off_start = ph->p_offset & -PAGE_SIZE; + /* align up page size */ + addr_max = (ph->p_vaddr + ph->p_filesz + PAGE_SIZE - 1) & (-PAGE_SIZE); + /* align down page size */ + addr_min = ph->p_vaddr & -PAGE_SIZE; + map_len = addr_max - addr_min; + map = mmap((void*)NULL, map_len, PROT_READ, MAP_PRIVATE, task->fd, off_start + task->file_offset); + if (map == MAP_FAILED) { + error("Mapping loadtask %s failed , err = %d\n", task->name, errno); + longjmp(*rtld_fail, 1); + } + /* load segment always page size align */ + memcpy((base + addr_min), map, map_len); + if (ph->p_memsz > ph->p_filesz) { + size_t brk = (size_t)base + ph->p_vaddr + ph->p_filesz; + size_t this_max = (ph->p_vaddr + ph->p_memsz + PAGE_SIZE - 1) & (-PAGE_SIZE); + size_t zeromap_size = (size_t)base + this_max - brk; + /* zeropadding the remaining memory with page size alignment*/ + memset((void *)brk, 0, zeromap_size); + } + munmap(map, map_len); + + } + } + return true; +} + + +static char *create_realpath_from_fd(int fd) +{ + void *buf = malloc(PATH_MAX + 1); + if (buf) { + ssize_t len = fd_to_realpath(fd, buf, PATH_MAX + 1); + if (len >= 0) { + void *buf_new = realloc(buf, len + 1); + return buf_new ? buf_new : buf; + } + free(buf); + } + return NULL; +} + +#endif + +static void adlt_find_and_set_bss_name(struct dso *p, Phdr *phdr) +{ + size_t entsz = p->phentsize; + adlt_phindex_t *ph_indexes, *phc_indexes, *phl_indexes; + ssize_t phl_count = get_adlt_library_ph(p->adlt, p->adlt_ndso_index, &phl_indexes); + ssize_t phc_count = get_adlt_common_ph(p->adlt, &phc_indexes); + int loop = 2; + ssize_t ph_num; + size_t i, q; + Phdr *ph; + while(loop--) { + if (loop) { + if (phc_count <= 0 || !phc_indexes) { + continue; + } + ph_indexes = phc_indexes; + ph_num = phc_count; + i = ph_indexes[0]; + } else { + if (phl_count < 0 || !phl_indexes) { + continue; + } + ph_indexes = phl_indexes; + ph_num = phl_count; + i = ph_indexes[0]; + } + + q = 0; + for (ph = (void *)((char *)phdr + i * entsz); ph_num; + ph_num--, i = ph_indexes ? (size_t)ph_indexes[++q] : i + 1, ph = (void *)((char *)phdr + i * entsz)) { + if (ph->p_type != PT_LOAD) continue; + size_t seg_start = p->base + ph->p_vaddr; + size_t seg_file_end = seg_start + ph->p_filesz + PAGE_SIZE - 1 & -PAGE_SIZE; + size_t seg_max_addr = seg_start + ph->p_memsz + PAGE_SIZE - 1 & -PAGE_SIZE; + size_t zeromap_size = seg_max_addr - seg_file_end; + if (zeromap_size > 0 && (ph->p_flags & PF_W)) { + set_bss_vma_name(p->name, (void *)seg_file_end, zeromap_size); + } + } + } +} +#else + +static struct dso *find_library_by_adlt_lstat( + const struct stat *st, const ns_t *ns, bool check_inherited, uint64_t file_offset) {return NULL;}; +static struct dso *find_library_by_adlt_index( + const struct adlt *adlt, const ns_t *ns, bool check_inherited, ssize_t library_index) {return NULL;}; +static void free_adlt(struct adlt *adlt) {return; }; +static void init_adlt(struct adlt *adlt){return ;}; +static void unmap_adlt_library(struct dso *dso) {return ;}; +ssize_t get_adlt_common_ph(struct adlt *adlt, adlt_phindex_t **ph_indexes) {return 0;}; +static ssize_t get_adlt_library_index(unsigned char *strtab_addr, unsigned char *sa_addr, const char *pathname) {return 0;}; +static ssize_t get_adlt_library_index2(struct adlt *adlt, const char *pathname) {return 0;}; +static adlt_psod_t *get_adlt_library_entry(struct adlt *adlt, ssize_t library_index, char **blob) {return NULL;}; +ssize_t get_adlt_library_ph(struct adlt *adlt, ssize_t library_index, adlt_phindex_t **ph_indexes) {return 0;}; +static ssize_t get_adlt_library_dt_needed(struct adlt *adlt, ssize_t library_index, adlt_dt_needed_index_t **dt_needed) {return 0;}; +static ssize_t get_adlt_library_rela_dyn(struct adlt *adlt, ssize_t library_index, adlt_relindex_t **rela_dyn) {return 0;}; +static ssize_t get_adlt_library_rela_plt(struct adlt *adlt, ssize_t library_index, adlt_relindex_t **rela_plt) {return 0;}; +static ssize_t get_adlt_library_relr_dyn(struct adlt *adlt, ssize_t library_index, adlt_relindex_t **relr_dyn) {return 0;}; +static size_t get_adlt_library_init_array( + struct adlt *adlt, ssize_t library_index, adlt_cross_section_array_t **init_cross) {return 0;}; + +static void adlt_clean_gotentry(struct dso *p, struct adlt *adlt) {return;}; +static size_t get_adlt_library_fini_array( + struct adlt *adlt, ssize_t library_index, adlt_cross_section_array_t **fini_cross) {return 0;}; +static ssize_t get_adlt_library_final_sym_indexes( + struct adlt *adlt, ssize_t library_index, struct adlt_dso_sym_index *idx) {return 0;}; +static adlt_secindex_t get_adlt_symbol_sec_index(struct adlt *adlt) {return NULL;}; +static ssize_t get_adlt_objects_num(struct adlt *adlt) {return 0;}; +static ssize_t merge_sort_arrays(adlt_phindex_t **ph_indexes, ssize_t ph_count, + adlt_phindex_t **phl_indexes, ssize_t phl_count, + adlt_phindex_t **phc_indexes, ssize_t phc_count) {return 0;}; +static bool replace_to_adlt_duplicate(struct dso *dso, Sym **sym, const char **name) {return false;}; +static bool replace_to_adlt_duplicate2(struct dso *dso, Sym **sym, const char **name) {return false;}; +static bool is_adlt_partly_load() {return false;}; +static bool is_adlt_dso_sym(struct dso *dso, uint32_t idx) {return true;}; +static void add_adlt(struct adlt* adlt) {return ;}; +static void del_adlt_from_gadlt(struct adlt* adlt) {return ;}; +static bool is_same_adlt(struct adlt* adlt, struct stat* st) {return false;}; +static struct adlt* find_adlt_by_fstat(struct stat* st) {return NULL;}; +static char *create_realpath_from_fd(int fd) {return NULL;}; +static void adlt_reclaim_gaps(struct dso *dso) {return ;}; +static void adlt_reloc(struct dso *p, size_t dyn[],const dl_extinfo *extinfo, ssize_t *relro_fd_offset) {return ;}; +static void adlt_find_and_set_bss_name(struct dso *p, Phdr *phdr) {return ;}; +void *bolt_remap_addr_func_adlt(size_t a) {return a;}; +static bool adlt_find_in_dso(struct dso *p, Phdr *phdr, struct adlt *adlt, size_t entsz, size_t addr) {return false;}; +static int handle_adlt_phdr(struct dso *current, struct dl_phdr_info *info, struct adlt_phdr_info *phdr_info){return 0;}; +static struct dso *search_dso_by_adlt_lstat(const struct stat *st, const ns_t *ns, uint64_t file_offset) {return NULL;}; +static struct dso *search_dso_by_adlt_index(const struct adlt *adlt, const ns_t *ns, ssize_t library_index) {return NULL;}; +static void free_record_entry(struct adlt_got_entry *entry) {return;}; +char *next_link_name(char **fullpath, char *buf, ssize_t bufsize) {return NULL;}; +static void set_adlt_symindex_map_to_library(struct dso *p) {return;}; +static Relocated_Flag check_and_set_bit(struct adlt_got_entry *et, size_t *reloc_addr , ssize_t ndso_index) {return NOT_GOT;}; +static bool has_relocation(struct dso *dso, size_t *reloc_addr) {return false;}; +static void adlt_do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stride, adlt_relindex_t *rel_index) {return;}; +static void adlt_do_android_relocs( + struct dso *p, size_t dt_name, size_t dt_size, size_t rel_cnt, adlt_relindex_t *rel_index) {return;}; + +static size_t bolt_remap_addr_func(size_t in_addr, struct adlt *adlt) {return 0;}; +static int update_adlt_mapping(struct dso *current, struct adlt_phdr_info *phdr_info) {return 0;}; + +#ifdef LOAD_ORDER_RANDOMIZATION +void init_entry(struct adlt_got_entry *entry, Shdr *sh) {return;}; +void init_gotentry(struct adlt *adlt, Shdr *sh, struct loadtask *task, unsigned char *shstr_addr) {return;}; +static void adlt_clean_dso_flag(struct adlt_got_entry *entry, ssize_t ndso_index) {return;}; +static bool parse_adlt_library_header(struct loadtask *task, Phdr *ph) {return true;}; +static void set_start_end_addr(struct loadtask *task, Shdr *sh) {return;}; +static bool map_remap_strtab(struct loadtask *task, Shdr *sh2, size_t bsl_bolt_remap_index, size_t strtab_sec_index) {return true;}; +static bool lookup_strtab_map(struct loadtask *task, Shdr *sh2) {return true;}; +static bool lookup_ndso(struct loadtask *task, Shdr *sh2) {return true;}; +static void lookup_tls(struct loadtask *task, bool tls_appeared) {return;}; +static bool lookup_adlt_library(struct loadtask *task, Shdr *sh2, bool tls_appeared) {return true;}; +static bool adlt_init_rw_seg(struct loadtask *task) {return true;}; + +#endif + +#endif \ No newline at end of file diff --git a/ldso/linux/dynlink_rand.c b/ldso/linux/dynlink_rand.c index d5cf989d3..8faebe62d 100644 --- a/ldso/linux/dynlink_rand.c +++ b/ldso/linux/dynlink_rand.c @@ -160,6 +160,10 @@ void free_task(struct loadtask *task) __libc_free((void *)task->name); task->name = NULL; } + if (task->fullname) { + __libc_free(task->fullname); + task->fullname = NULL; + } if (task->allocated_buf) { __libc_free(task->allocated_buf); task->allocated_buf = NULL; @@ -245,6 +249,23 @@ struct loadtask *create_loadtask(const char *name, struct dso *needed_by, ns_t * task->needed_by = needed_by; task->namespace = ns; task->check_inherited = check_inherited; + task->fd = -1; task->shdr_allocated_buf = MAP_FAILED; + task->adlt = NULL; + task->adlt_ndso_index = -1; + task->init_array_off = 0; + task->fini_array_off = 0; return task; } + +struct loadtask *create_loadtask_adlt(const char *name, struct dso *needed_by, ns_t *ns, bool check_inherited, + struct adlt *adlt, ssize_t library_index) +{ + struct loadtask *task = create_loadtask(name, needed_by, ns, check_inherited); + if (task && adlt && library_index >= 0) + { + task->adlt = adlt; + task->adlt_ndso_index = library_index; + } + return task; +} \ No newline at end of file diff --git a/ldso/linux/dynlink_rand.h b/ldso/linux/dynlink_rand.h index 315fc624d..be2052af8 100644 --- a/ldso/linux/dynlink_rand.h +++ b/ldso/linux/dynlink_rand.h @@ -36,6 +36,14 @@ struct dso; struct loadtask { // parameters const char *name; + // Necessity of fullname: + // task->name may be short - without env->path so we + // cannot use it for opening symlink + // task->pathname sometimes keeps path of ADLT library + // file and can not be used for finding nDSO in adlt + // So we need additional task->fullname (env->path + task->name) + // to open a symlink + const char *fullname; struct dso *needed_by; ns_t *namespace; bool check_inherited; @@ -47,7 +55,10 @@ struct loadtask { struct dso *p; int fd; uint64_t file_offset; /* Used to read an uncompress library from a zip file, file_offset is relative offset of start of zip file. */ - + struct adlt *adlt; + ssize_t adlt_ndso_index; + size_t init_array_off; + size_t fini_array_off; // variables for map library Ehdr ehdr_buf[(READ_ELF_LENGTH + sizeof(Ehdr)) / sizeof(Ehdr)]; void *allocated_buf; @@ -90,7 +101,8 @@ hidden struct loadtask *get_loadtask(struct loadtasks *tasks, size_t index); hidden void free_loadtasks(struct loadtasks *tasks); hidden void shuffle_loadtasks(struct loadtasks *tasks); hidden struct loadtask *create_loadtask(const char *name, struct dso *needed_by, ns_t *ns, bool check_inherited); - +hidden struct loadtask *create_loadtask_adlt(const char *name, struct dso *needed_by, ns_t *ns, bool check_inherited, + struct adlt *adlt, ssize_t library_index); #ifdef __cplusplus } #endif diff --git a/libc-test/src/api/BUILD.gn b/libc-test/src/api/BUILD.gn index 03724dbad..02abcaca4 100644 --- a/libc-test/src/api/BUILD.gn +++ b/libc-test/src/api/BUILD.gn @@ -48,4 +48,8 @@ config("config_main") { "-g", "-nostdlib", ] + + if (is_llvm_build) { + ldflags += [ "-Wl,--dynamic-linker=/data/tests/ld-musl-${musl_arch}.so.1" ] + } } diff --git a/libc-test/src/common/BUILD.gn b/libc-test/src/common/BUILD.gn index 48cdfb377..636cbb327 100644 --- a/libc-test/src/common/BUILD.gn +++ b/libc-test/src/common/BUILD.gn @@ -79,6 +79,10 @@ config("config_runtest") { ldflags = [ "-nostdlib" ] + if (is_llvm_build) { + ldflags += [ "-Wl,--dynamic-linker=/data/tests/ld-musl-${musl_arch}.so.1" ] + } + libs = [ "//${target_out_dir}/libtest.a" ] } diff --git a/libc-test/src/functionalext/supplement/BUILD.gn b/libc-test/src/functionalext/supplement/BUILD.gn index 731e835fa..c3f2c089c 100644 --- a/libc-test/src/functionalext/supplement/BUILD.gn +++ b/libc-test/src/functionalext/supplement/BUILD.gn @@ -360,6 +360,10 @@ ohos_executable("musl_unittest") { "-Wl,-rpath=/data/tmp/libcgtest/libs:/data/tmp/libcgtest/libs/rpath-test/", ] + if (is_llvm_build) { + ldflags += [ "-Wl,--dynamic-linker=/data/tests/ld-musl-${musl_arch}.so.1" ] + } + include_dirs = [ "//third_party/musl" ] configs = [ ":module_private_config" ] diff --git a/libc-test/src/functionalext/supplement/hook/hook_gtest/hook_realloc_test.cpp b/libc-test/src/functionalext/supplement/hook/hook_gtest/hook_realloc_test.cpp index 6d9d50f4e..fe6888525 100644 --- a/libc-test/src/functionalext/supplement/hook/hook_gtest/hook_realloc_test.cpp +++ b/libc-test/src/functionalext/supplement/hook/hook_gtest/hook_realloc_test.cpp @@ -4,7 +4,6 @@ using namespace testing::ext; constexpr int SIZE = 128; -constexpr int ILLEGAL_SIZE = -128; class HookReallocTest : public testing::Test { void SetUp() override {} @@ -41,11 +40,7 @@ HWTEST_F(HookReallocTest, realloc_002, TestSize.Level1) * ensuring that realloc correctly handles illegal size scenarios and returns a null pointer. * @tc.type: FUNC */ -HWTEST_F(HookReallocTest, realloc_003, TestSize.Level1) -{ - void* ptr = realloc(nullptr, ILLEGAL_SIZE); - EXPECT_EQ(ptr, nullptr); -} + /** * @tc.name: realloc_004 * @tc.desc: Validate the behavior of the realloc function when reallocation is performed on an already allocated memory diff --git a/libc-test/src/functionalext/test_src_functionalext.gni b/libc-test/src/functionalext/test_src_functionalext.gni index bbf5752f5..8aee403d7 100644 --- a/libc-test/src/functionalext/test_src_functionalext.gni +++ b/libc-test/src/functionalext/test_src_functionalext.gni @@ -33,7 +33,6 @@ functionalext_list = [ "sigchain:functionalext_sigchain_test", "queue:functionalext_queue_test", "crypt:functionalext_crypt_test", - "backtrace:functionalext_backtrace_test", "ldso_debug:functionalext_ldso_debug_test", "ldso_same_name_symbol:ldso_same_symbol_name_with_different_version", "dl_different_hash:dl_different_hash", @@ -42,3 +41,9 @@ functionalext_list = [ "string:functionalext_string_test", "adlt:functionalext_adlt_test", ] + +if (!is_llvm_build) { + functionalext_list += [ + "backtrace:functionalext_backtrace_test", + ] +} \ No newline at end of file diff --git a/libc-test/src/nativehook/BUILD.gn b/libc-test/src/nativehook/BUILD.gn index ec4048cc1..f6213de82 100644 --- a/libc-test/src/nativehook/BUILD.gn +++ b/libc-test/src/nativehook/BUILD.gn @@ -38,4 +38,8 @@ config("config_runtest") { ] ldflags = [ "-nostdlib" ] + + if (is_llvm_build) { + ldflags += [ "-Wl,--dynamic-linker=/data/tests/ld-musl-${musl_arch}.so.1" ] + } } diff --git a/libc-test/test_template.gni b/libc-test/test_template.gni index 60eea22cc..fc50790df 100644 --- a/libc-test/test_template.gni +++ b/libc-test/test_template.gni @@ -93,6 +93,11 @@ template("test_unittest") { ldflags = [ "-nostdlib" ] + if (is_llvm_build) { + ldflags += + [ "-Wl,--dynamic-linker=/data/tests/ld-musl-${musl_arch}.so.1" ] + } + libs = [ "//${out_test_dir}/src/common/libtest.a" ] if (!musl_unit_test_flag) { libs += [ "${musl_lib_dir}/libc.a" ] diff --git a/scripts/run_libcgtest_linux.sh b/scripts/run_libcgtest_linux.sh index 2a57d5218..307f84592 100755 --- a/scripts/run_libcgtest_linux.sh +++ b/scripts/run_libcgtest_linux.sh @@ -1,18 +1,18 @@ # Local storage directory of dynamic link library -LOCAL_DYNLIB="your_local_dir" - +LOCAL_DYNLIB="${SOURCE_DIR}" + # Remote transmission target directory -REMOTE_ROOT=/data/tmp/libcgtest -REMOTE=/data/tmp/libcgtest/libs -RPATH_TEST_DIR=${REMOTE}/rpath-test -NS_LIB_ONE_DIR=${REMOTE}/namespace_one_libs -NS_LIB_TWO_DIR=${REMOTE}/namespace_two_libs -NS_LIB_TWO_IMPL_DIR=${REMOTE}/namespace_two_impl_libs - -CMD=hdc - +REMOTE_ROOT="${TARGET_DIR:-/data/tmp/libcgtest}" +REMOTE="${REMOTE_ROOT}/libs" +RPATH_TEST_DIR=${REMOTE_ROOT}/libs/rpath-test +NS_LIB_ONE_DIR=${REMOTE_ROOT}/libs/namespace_one_libs +NS_LIB_TWO_DIR=${REMOTE_ROOT}/libs/namespace_two_libs +NS_LIB_TWO_IMPL_DIR=${REMOTE_ROOT}/libs/namespace_two_impl_libs + +CMD="${HDC_CMD:-hdc}" + ${CMD} shell mount -o remount,rw / -${CMD} shell mkdir data/tmp +${CMD} shell mkdir /data/tmp ${CMD} shell rm -rf ${REMOTE_ROOT} ${CMD} shell mkdir ${REMOTE_ROOT} ${CMD} shell mkdir ${REMOTE} diff --git a/scripts/runtest.sh b/scripts/runtest.sh index d542d9940..ef056ff0a 100755 --- a/scripts/runtest.sh +++ b/scripts/runtest.sh @@ -1,11 +1,15 @@ -cd /data/tests/libc-test/src -rm /data/tests/libc-test/REPORT -rm /data/tests/libc-test/FileList.txt -rm /data/tests/libc-test/SkipList.txt -touch /data/tests/libc-test/REPORT -touch /data/tests/libc-test/FileList.txt -touch /data/tests/libc-test/SkipList.txt +ARCH="$1" +REMOTE="$2" + +cd "${REMOTE}/src" +rm ../REPORT +rm ../FileList.txt +rm ../SkipList.txt +touch ../REPORT +touch ../FileList.txt +touch ../SkipList.txt +echo 'root:This.is.a.test:18997:0:99999:7:::'>/etc/shadow param set debug.hitrace.tags.enableflags 1 ARCH=arm @@ -43,7 +47,7 @@ if [ $ARCH == "aarch64" ]; then fi for skiped in ${ShieldedList[*]};do - echo $skiped >> /data/tests/libc-test/SkipList.txt + echo $skiped >> "${REMOTE}/SkipList.txt" done function ShieldedCases() { @@ -88,18 +92,18 @@ do continue elif [ -x $file ] && [ -s $file ] then - echo $file >> /data/tests/libc-test/FileList.txt - ./runtest -w '' -t 30 $file >> /data/tests/libc-test/REPORT + echo $file >> "${REMOTE}/FileList.txt" + ./runtest -w '' -t 30 $file >> "${REMOTE}/REPORT" fi done -echo "--- gwp_asan test running --- " >> /data/tests/libc-test/REPORT +echo "--- gwp_asan test running --- " >> "${REMOTE}/REPORT" # gwp_asan test need to be executed at last. for file in `ls *` do if [ "$(IsGwpasanTest ${file})" = "yes" ] then - echo $file >> /data/tests/libc-test/FileList.txt + echo $file >> "${REMOTE}/FileList.txt" param set gwp_asan.log.path file param set gwp_asan.enable.app.${file} true @@ -108,9 +112,9 @@ do param set gwp_asan.sample.all true fi - echo "*** ${file} running ***" >> /data/tests/libc-test/REPORT - ./${file} >> /data/tests/libc-test/REPORT - echo "*** ${file} done *** " >> /data/tests/libc-test/REPORT + echo "*** ${file} running ***" >> "${REMOTE}/REPORT" + ./${file} >> "${REMOTE}/REPORT" + echo "*** ${file} done *** " >> "${REMOTE}/REPORT" param set gwp_asan.log.path default param set gwp_asan.enable.app.${file} false if [ "${file}" != "gwp_asan_random_sample_test" ] @@ -119,4 +123,4 @@ do fi fi done -echo "--- gwp_asan test done ---" >> /data/tests/libc-test/REPORT \ No newline at end of file +echo "--- gwp_asan test done ---" >> "${REMOTE}/REPORT" \ No newline at end of file diff --git a/scripts/runtest_Windows.bat b/scripts/runtest_Windows.bat index f7720a869..a5733714c 100644 --- a/scripts/runtest_Windows.bat +++ b/scripts/runtest_Windows.bat @@ -130,7 +130,7 @@ hdc shell mv %REMOTE%/src/zh_CN /tmp/zh_CN hdc file send %SHDIR%\runtest.sh %REMOTE%/runtest.sh hdc shell chmod +x %REMOTE%/runtest.sh -hdc shell %REMOTE%/runtest.sh +hdc shell %REMOTE%/runtest.sh %ARCH% %REMOTE% :Summary diff --git a/scripts/runtest_linux.sh b/scripts/runtest_linux.sh index 7689a769a..da0947a13 100755 --- a/scripts/runtest_linux.sh +++ b/scripts/runtest_linux.sh @@ -15,7 +15,7 @@ LOCAL="unknown_dir" OUTDIR=out/rk3568 -CMD=hdc_std +CMD="${HDC_CMD:-hdc_std}" ARCH=arm function usage { @@ -43,7 +43,7 @@ done TESTDIR=${LOCAL}/${OUTDIR}/musl/libc-test DYNLIB=${LOCAL}/${OUTDIR}/musl/libc-test-lib SHDIR=${LOCAL}/third_party/musl/scripts -REMOTE=/data/tests/libc-test +REMOTE="${TARGET_DIR:-/data/tests}/libc-test" REMOTELOCAL=/data/local/tmp REMOTESYSTEM=/system/lib @@ -83,7 +83,7 @@ fi echo now mkdir ${CMD} shell rm -rf ${REMOTE} -${CMD} shell mkdir /data/tests +${CMD} shell mkdir -p ${REMOTE} ${CMD} shell mkdir ${REMOTE} #mk temp directory @@ -150,7 +150,7 @@ ${CMD} shell mv ${REMOTE}/src/zh_CN /tmp/zh_CN ${CMD} file send ${SHDIR}/runtest.sh ${REMOTE}/runtest.sh ${CMD} shell chmod +x ${REMOTE}/runtest.sh -${CMD} shell ${REMOTE}/runtest.sh +${CMD} shell ${REMOTE}/runtest.sh ${ARCH} ${REMOTE} echo hdc file recv ${REMOTE}/REPORT ${SHDIR}/REPORT @@ -190,3 +190,7 @@ $(cat -t ${SHDIR}/REPORT | grep 'FAIL ') echo "[Skip List]: " | tee -a Summary.txt cat ${SHDIR}/SkipList.txt | tee -a Summary.txt + +if [ "fail" -ne 0 ]; then + exit 1 +fi diff --git a/src/internal/ADLTSection.h b/src/internal/ADLTSection.h new file mode 100644 index 000000000..22e06f954 --- /dev/null +++ b/src/internal/ADLTSection.h @@ -0,0 +1,150 @@ +//===- ADLTSection.h - ADLT Section data types --------------------*- C -*-===// +// +// Copyright (C) 2024 Huawei Device Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_BINARYFORMAT_ADLTSECTION_H +#define LLVM_BINARYFORMAT_ADLTSECTION_H + +#ifdef __cplusplus +#include + +namespace llvm { +namespace adlt { + +#else // __cplusplus +#include +#endif // __cplusplus + +#ifndef _ELF_H +// part of #include +typedef uint16_t Elf64_Half; +typedef uint64_t Elf64_Off; +typedef uint64_t Elf64_Addr; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Xword; +typedef uint8_t Elf64_Byte; +#endif // _ELF_H + +typedef Elf64_Word adlt_secindex_t; // section index type +typedef Elf64_Off adlt_symindex_t; // symbol index type +typedef uint32_t adlt_relindex_t; // reloc index type +typedef Elf64_Half adlt_phindex_t; // ph index type + +typedef struct { + adlt_secindex_t secIndex; + Elf64_Off offset; // from section start +} adlt_cross_section_ref_t; + +typedef struct { + adlt_secindex_t secIndex; + Elf64_Off offset; // from section start + Elf64_Xword size; // size in bytes +} adlt_cross_section_array_t; + +typedef struct { + Elf64_Off offset; // relative to header.blobStart + Elf64_Xword size; // size in bytes, make convertions for data type +} adlt_blob_array_t; + +// plain-C has no strict typedefs, but aliases used to interpred underlying data +typedef adlt_blob_array_t adlt_blob_u8_array_t; // uint8_t[] +typedef adlt_blob_array_t adlt_blob_u16_array_t; // uint16_t[] +typedef adlt_blob_array_t adlt_blob_u32_array_t; // uint32_t[] +typedef adlt_blob_array_t adlt_blob_u64_array_t; // uint64_t[] +typedef adlt_blob_u32_array_t adlt_blob_rel_array_t; // uint32_t[] (adlt_relindex_t[]) + +typedef struct { + Elf64_Half major : 6; + Elf64_Half minor : 6; + Elf64_Half patch : 4; +} adlt_semver_t; + +// DT_NEEDED string index with embedded PSOD index if available +typedef struct { + Elf64_Off hasInternalPSOD : 1; // true if soname + Elf64_Off PSODindex : 16; // PSOD in the current ADLT image + Elf64_Off sonameOffset : 47; // string start in bound .adlt.strtab +} adlt_dt_needed_index_t; + +typedef enum { + ADLT_HASH_TYPE_NONE = 0, + ADLT_HASH_TYPE_GNU_HASH = 1, + ADLT_HASH_TYPE_SYSV_HASH = 2, + ADLT_HASH_TYPE_DEBUG_CONST = 0xfe, + ADLT_HASH_TYPE_MAX = 0xff, +} adlt_hash_type_enum_t; + +typedef uint8_t adlt_hash_type_t; + +// Data chunk descriptor (e.g. for merged sections) +typedef struct { + Elf64_Off offset; // data offset within the segment + Elf64_Xword size; // data size + adlt_secindex_t secIndex; // section index + adlt_phindex_t phIndex; // segment index +} adlt_chunk_t; + +// Serializable representation per-shared-object-data in .adlt section +typedef struct { + Elf64_Off soName; // offset in .adlt.strtab + Elf64_Off soFileName; + Elf64_Xword soNameHash; // algorithm according to + // hdr.stringHashType value + adlt_cross_section_array_t initArray; + adlt_cross_section_array_t finiArray; + adlt_blob_array_t dtNeeded; // array of adlt_dt_needed_index_t[] elems + adlt_cross_section_ref_t sharedLocalSymbolIndex; + adlt_cross_section_ref_t sharedGlobalSymbolIndex; + adlt_blob_u16_array_t phIndexes; // program header indexes, typeof(e_phnum) + adlt_blob_rel_array_t relaDynIndx; // .rela.dyn dependent indexes, raw list + adlt_blob_rel_array_t relaPltIndx; // .rela.plt dependent indexes, raw list + adlt_blob_rel_array_t relrDynIndx; // .relr.dyn dependent indexes, raw list + adlt_secindex_t ehFrameHdrSecIndex; // .eh_frame_hdr index + adlt_blob_array_t + chunkArray; // chunk array (for merged sections); offset and size in blob + adlt_blob_array_t finalSymIndexes; +} adlt_psod_t; + +typedef struct { + adlt_semver_t schemaVersion; // {major, minor, patch} + Elf64_Half schemaHeaderSize; // >= sizeof(adlt_section_header_t) if comp + Elf64_Half schemaPSODSize; // >= sizeof(adlt_psod_t) if compatible + Elf64_Half sharedObjectsNum; // number of PSOD entries + adlt_hash_type_t stringHashType; // contains adlt_hash_type_enum_t value + Elf64_Off blobStart; // offset of binary blob start relative to .adlt + Elf64_Xword blobSize; + Elf64_Xword overallMappedSize; // bytes, required to map the whole ADLT image + adlt_blob_u16_array_t phIndexes; // program header indexes, typeof(e_phnum) + adlt_cross_section_ref_t + sharedEndLocalSymbolIndex; // .symtab's end (after last) local symbol + // index + adlt_cross_section_ref_t + sharedEndGlobalSymbolIndex; // .symtab's end (after last) global symbol + // index + Elf64_Half schemaChunkSize; // >= sizeof(adlt_chunk_t) if compatible +} adlt_section_header_t; + +static const char adltBlobStartMark[4] = {0xA, 0xD, 0x1, 0x7}; + +static const adlt_semver_t adltSchemaVersion = {1, 5, 0}; + +#ifdef __cplusplus +} // namespace adlt +} // namespace llvm +#endif // __cplusplus + +#endif // LLVM_BINARYFORMAT_ADLTSECTION_H diff --git a/src/internal/dynlink.h b/src/internal/dynlink.h index b7e4d807d..6c3a00fb0 100644 --- a/src/internal/dynlink.h +++ b/src/internal/dynlink.h @@ -19,6 +19,8 @@ #endif #endif +#include "ADLTSection.h" + #if UINTPTR_MAX == 0xffffffff typedef Elf32_Ehdr Ehdr; typedef Elf32_Phdr Phdr; @@ -104,6 +106,89 @@ struct icall_item { size_t modifier_end; }; +struct unpack_reloc { + void *map; // map address + size_t map_len; // map length + size_t unpack_num; // unpacking reloc count + off_t unpack_offset; // unpacking procedure address offset +}; + +struct adlt_got_entry{ + unsigned char *entry_addr; // .got section start address + size_t entry_len; // .got section size + uint32_t *record_entry; // Whether the entry in the got table has been relocated + size_t got_map_len; + uint8_t *got_map; // got/got.plt map + size_t *got_entry; // initial got/got.plt entry +}; + +struct bolt_remap_data{ + size_t new_addr; + size_t old_addr; +}; + +struct adlt { + unsigned char *base; + char *name; // real path + uint64_t file_offset; // > 0 when opening library from zip file; PAGE_SIZE aligned + bool partly_load; // true when nDSOs are loaded separately + unsigned char *map; // map address + size_t map_len; // map length + size_t addr_min; // min address (mapping result) + bool hugepage_enabled; // hugepage (mapping result) + uint32_t npsod_load; + unsigned char *sa_map; // .adlt section map address + size_t sa_map_len; // .adlt section map size + unsigned char *sa_addr; // .adlt section address + struct adlt_got_entry gotEntry; + struct adlt_got_entry gotPltEntry; + unsigned char *strtab_map; // .adlt.strtab section map address + size_t strtab_map_len; // .adlt.strtab section map size + unsigned char *strtab_addr; // .adlt.strtab section address + unsigned char *bolt_remap; // .bolt.remap section map address + size_t bolt_remap_len; // .bolt.remap section map size + unsigned char *bolt_remap_addr; // .bolt.remap section address + dev_t dev; // + ino_t ino; // + off_t file_size; // + Phdr *phdr; // PH table address + int phnum; // PH count + size_t phentsize; // PH size + struct unpack_reloc android_rel; // unpacked android rel relocs (SHT_ANDROID_REL type section) + struct unpack_reloc android_rela; // unpacked android rela relocs (SHT_ANDROID_RELA type section) + struct unpack_reloc relr_rel; // unpacked relr relocs (SHT_RELR type section) + size_t relro_start, relro_end; // remove + uint8_t *sym_idx_map; // symbol index map to adlt_ndso_index + uint32_t nsym; // symbol count + /* symbol section (.symtab) mapping for backtrace symbol lookup */ + unsigned char *bsl_syms_map; // map address + size_t bsl_syms_map_len; // map size + Sym *bsl_syms; // section address (symbols) + /* string section (.strtab) mapping for backtrace symbol lookup */ + unsigned char *bsl_strings_map; // map address + size_t bsl_strings_map_len; // map size + char *bsl_strings; // section address (strings) + size_t bsl_strings_sec_index; // section index + uint64_t pgbo_addr_start; // pgbo text section sh_addr + uint64_t pgbo_addr_end; // pgbo text section end sh_addr + struct adlt *next; // next adlt + struct adlt *prev; // prev adlt +}; + +struct adlt_phdr_info { + char *map; + size_t map_len; + char *map_ph_addr; + struct adlt *map_adlt; + size_t ph_ndso_index; + int map_prot; +}; + +struct adlt_dso_sym_index { + uint32_t *idx; + uint64_t size; +}; + struct dso { #if DL_FDPIC struct fdpic_loadmap *loadmap; @@ -172,6 +257,16 @@ struct dso { /* mark the dso status */ uint32_t flags; uint32_t nr_dlopen; + + struct adlt *adlt; + ssize_t adlt_ndso_index; + size_t init_array_off; + size_t fini_array_off; + dev_t ldev; // lstat() dev + ino_t lino; // lstat() ino + char* adlt_ndso_name; + struct adlt_dso_sym_index sym_idx; + bool is_global; bool is_preload; bool is_reloc_head_so_dep; @@ -327,6 +422,10 @@ struct symdef find_sym_impl( hidden void *__dlsym(void *restrict, const char *restrict, void *restrict); hidden void *__dlvsym(void *restrict, const char *restrict, const char *restrict, void *restrict); hidden int __dlclose(void *p); + +hidden ssize_t get_adlt_library_ph(struct adlt *adlt, ssize_t library_index, adlt_phindex_t **ph_indexes); +hidden ssize_t get_adlt_common_ph(struct adlt *adlt, adlt_phindex_t **ph_indexes); + #else #define DYN_CNT 37 -- Gitee