From d9221e73f52ebae1d44996d9f1a87904d43f67d7 Mon Sep 17 00:00:00 2001 From: Zhou Kang Date: Tue, 20 Jun 2023 14:21:50 +0000 Subject: [PATCH] fix addr of ld.so symbol --- src/elf_link_common.c | 61 ++++++++++++++++++++++++++---------- src/elf_link_common.h | 1 + src/elf_link_elf.c | 13 +++++--- src/elf_read_elf.c | 61 ++++++++++++++++++++++-------------- src/elf_read_elf.h | 1 + src/elf_relocation_aarch64.c | 2 -- src/elf_write_elf.c | 5 +-- 7 files changed, 95 insertions(+), 49 deletions(-) diff --git a/src/elf_link_common.c b/src/elf_link_common.c index b31d005..3d505d0 100644 --- a/src/elf_link_common.c +++ b/src/elf_link_common.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "elf_link_common.h" #include @@ -127,14 +128,33 @@ static void init_static_mode_symbol_change(elf_link_t *elf_link) // layout for vdso and app and ld.so // ld.so | vvar | vdso | app -// xxK | 8K 4K 2M+ +// xxK | 8K | 4K | 2M+ // without ld.so // vvar | vdso | app -// 8K 4K 2M+ +// 8K | 4K | 2M+ +static unsigned long ld_hdr_addr_to_main_elf(elf_file_t *ef) +{ + Elf64_Phdr *p = ef->data_Phdr; + if (p == NULL) { + si_panic("ld.so data segment is NULL\n"); + } + if (p->p_align != PAGE_SIZE) { + si_panic("ld.so is not align 4K\n"); + } + unsigned long load_len = p->p_vaddr + p->p_memsz; + load_len = ALIGN(load_len, PAGE_SIZE); + return 0UL - (PAGE_SIZE * 3) - load_len; +} + +static unsigned long ld_get_new_addr(unsigned long hdr_addr, Elf64_Sym *sym) +{ + return hdr_addr + (unsigned long)sym->st_value; +} static unsigned long vdso_get_new_addr(Elf64_Sym *sym) { - return 0UL - 4096UL + (unsigned long)sym->st_value; + // user space PAGE_SIZE is 4K + return 0UL - PAGE_SIZE + (unsigned long)sym->st_value; } #define VDSO_PREFIX_LEN (sizeof("__kernel_") - 1) @@ -143,15 +163,24 @@ static char *vdso_name_to_syscall_name(char *name) return name + VDSO_PREFIX_LEN; } +static unsigned long vdso_hdr_addr_cur() +{ + // find func in vdso, vdso is only 4K, so get elf hdr by align + unsigned long func = (unsigned long)dlsym(RTLD_DEFAULT, "__kernel_clock_gettime"); + char *error = dlerror(); + if (error != NULL) { + si_panic("%s\n", error); + } + + return ALIGN(func, PAGE_SIZE) - PAGE_SIZE; +} + void init_vdso_symbol_addr(elf_link_t *elf_link) { elf_file_t *vdso_ef = &elf_link->vdso_ef; - // TODO: feature, probe AUX parameter - //elf_link->direct_vdso_optimize = false; - vdso_ef->file_name = "vdso"; - vdso_ef->hdr = (Elf64_Ehdr *)0xfffff7ffb000UL; + vdso_ef->hdr = (Elf64_Ehdr *)vdso_hdr_addr_cur(); elf_parse_hdr(vdso_ef); if (vdso_ef->dynsym_sec == NULL) { @@ -179,13 +208,7 @@ void init_vdso_symbol_addr(elf_link_t *elf_link) void init_ld_symbol_addr(elf_link_t *elf_link) { - elf_file_t *ef = &elf_link->vdso_ef; - - // TODO: feature, probe AUX parameter - - ef->file_name = "ld.so"; - ef->hdr = (Elf64_Ehdr *)0xfffff7ffb000UL; - elf_parse_hdr(ef); + elf_file_t *ef = &elf_link->ld_ef; if (ef->dynsym_sec == NULL) { si_panic(".dynsym not exist\n"); @@ -193,12 +216,15 @@ void init_ld_symbol_addr(elf_link_t *elf_link) elf_show_dynsym(ef); + // addr relative to main ELF + unsigned long hdr_addr = ld_hdr_addr_to_main_elf(ef); + int sym_count = ef->dynsym_sec->sh_size / sizeof(Elf64_Sym); Elf64_Sym *syms = (Elf64_Sym *)(((void *)ef->hdr) + ef->dynsym_sec->sh_offset); for (int j = 0; j < sym_count; j++) { Elf64_Sym *sym = &syms[j]; char *name = elf_get_dynsym_name(ef, sym); - unsigned long symbol_addr = (unsigned long)ef->hdr + (unsigned long)sym->st_value; + unsigned long symbol_addr = ld_get_new_addr(hdr_addr, sym); append_symbol_mapping(elf_link, name, symbol_addr); } @@ -631,11 +657,12 @@ static unsigned long _get_ifunc_new_addr(elf_link_t *elf_link, char *sym_name) static unsigned long append_ifunc_symbol(elf_link_t *elf_link, elf_file_t *ef, Elf64_Sym *sym, char *sym_name) { unsigned long ret; - if (is_static_nolibc_mode(elf_link)) + if (is_static_nolibc_mode(elf_link)) { ret = _get_ifunc_new_addr(elf_link, sym_name); - else + } else { // use ifunc return value ret = _get_ifunc_new_addr_by_dl(elf_link, ef, sym, sym_name); + } append_symbol_mapping(elf_link, sym_name, ret); SI_LOG_DEBUG("ifunc %s %16lx\n", sym_name, ret); diff --git a/src/elf_link_common.h b/src/elf_link_common.h index 63eda08..d8b21ce 100644 --- a/src/elf_link_common.h +++ b/src/elf_link_common.h @@ -56,6 +56,7 @@ typedef struct { unsigned int link_mode; elf_file_t vdso_ef; + elf_file_t ld_ef; elf_file_t *hook_func_ef; elf_file_t *libc_ef; diff --git a/src/elf_link_elf.c b/src/elf_link_elf.c index 683c819..d62969b 100644 --- a/src/elf_link_elf.c +++ b/src/elf_link_elf.c @@ -20,9 +20,9 @@ #include #ifdef __aarch64__ -#define LD_SO_STATIC_TEMPLATE "/lib/ld-linux-aarch64.so.1" +#define LD_SO_PATH "/lib/ld-linux-aarch64.so.1" #else -#define LD_SO_STATIC_TEMPLATE "/lib64/ld-linux-x86-64.so.2" +#define LD_SO_PATH "/lib64/ld-linux-x86-64.so.2" #endif // mode: static share @@ -96,6 +96,11 @@ int elf_link_set_mode(elf_link_t *elf_link, unsigned int mode) } if (mode == ELF_LINK_STATIC_NOLD) { + int ret = elf_read_file(LD_SO_PATH, &elf_link->ld_ef, true); + if (ret != 0) { + SI_LOG_ERR("elf_read_file fail, %s\n", LD_SO_PATH); + return -1; + } return 0; } @@ -103,7 +108,7 @@ int elf_link_set_mode(elf_link_t *elf_link, unsigned int mode) if (mode == ELF_LINK_STATIC_NOLIBC) { ef = elf_link_add_infile(elf_link, RELOCATION_ROOT_DIR "/sysboost_static_template.relocation"); } else { - ef = elf_link_add_infile(elf_link, LD_SO_STATIC_TEMPLATE); + ef = elf_link_add_infile(elf_link, LD_SO_PATH); } if (ef == NULL) { @@ -138,7 +143,7 @@ static int elf_link_prepare(elf_link_t *elf_link) elf_file_t *elf_link_add_infile(elf_link_t *elf_link, char *path) { elf_file_t *ef = &elf_link->in_efs[elf_link->in_ef_nr]; - int ret = elf_read_file(path, ef, true); + int ret = elf_read_file_relocation(path, ef); if (ret != 0) { return NULL; } diff --git a/src/elf_read_elf.c b/src/elf_read_elf.c index ecc4e4f..4d0429a 100644 --- a/src/elf_read_elf.c +++ b/src/elf_read_elf.c @@ -486,7 +486,7 @@ static int read_elf_info(elf_file_t *ef, bool is_readonly) return 0; } -static int _elf_read_file(char *file_name, elf_file_t *ef, bool is_readonly) +int elf_read_file(char *file_name, elf_file_t *ef, bool is_readonly) { int fd = -1; int ret = 0; @@ -514,12 +514,31 @@ static int _elf_read_file(char *file_name, elf_file_t *ef, bool is_readonly) return -1; } + // check elf arch + if (ef->hdr->e_machine != LOCAL_RUNNING_ARCH) { + SI_LOG_ERR("ELF arch is wrong, %s\n", file_name); + return -1; + } + + // ELF must pie, we read insn with offset + if (ef->hdr_Phdr->p_vaddr != 0UL) { + SI_LOG_ERR("ELF must compile with pie, %s\n", file_name); + return -1; + } + + // this memory will free by process exit + ef->file_name = strdup(file_name); return 0; } static void _elf_close_file(elf_file_t *ef) { close(ef->fd); + if (ef->file_name != NULL) { + free(ef->file_name); + ef->file_name = NULL; + } + if (ef->is_xz_file) { elf_unload_xz(ef); } else { @@ -549,9 +568,9 @@ static int read_relocation_file(char *file_name, elf_file_t *ef) } (void *)memset(ef, 0, sizeof(elf_file_t)); - ret = _elf_read_file(rel_file_name, ef, true); + ret = elf_read_file(rel_file_name, ef, true); if (ret != 0) { - SI_LOG_ERR("_elf_read_file fail, %s\n", rel_file_name); + SI_LOG_ERR("elf_read_file fail, %s\n", rel_file_name); return -1; } @@ -564,31 +583,28 @@ static int read_relocation_file(char *file_name, elf_file_t *ef) return 0; } -int elf_read_file(char *file_name, elf_file_t *ef, bool is_readonly) +static bool is_elf_have_relocation(elf_file_t *ef) { - int ret = 0; - - ret = _elf_read_file(file_name, ef, is_readonly); - if (ret != 0) { - SI_LOG_ERR("_elf_read_file fail, %s\n", file_name); - return -1; + Elf64_Shdr *sec = elf_find_section_by_name(ef, ".rela.text"); + if (sec == NULL) { + return false; } - // check elf arch - if (ef->hdr->e_machine != LOCAL_RUNNING_ARCH) { - SI_LOG_ERR("ELF arch is wrong, %s\n", file_name); - return -1; - } + return true; +} - // ELF must pie, we read insn with offset - if (ef->hdr_Phdr->p_vaddr != 0UL) { - SI_LOG_ERR("ELF must compile with pie, %s\n", file_name); +int elf_read_file_relocation(char *file_name, elf_file_t *ef) +{ + int ret = 0; + + ret = elf_read_file(file_name, ef, true); + if (ret != 0) { + SI_LOG_ERR("elf_read_file fail, %s\n", file_name); return -1; } // check elf have relocation - Elf64_Shdr *sec = elf_find_section_by_name(ef, ".rela.text"); - if ((sec == NULL) && is_readonly) { + if (is_elf_have_relocation(ef) == false) { ret = read_relocation_file(file_name, ef); if (ret != 0) { return -1; @@ -596,14 +612,11 @@ int elf_read_file(char *file_name, elf_file_t *ef, bool is_readonly) } // ELF must have relocation - sec = elf_find_section_by_name(ef, ".rela.text"); - if ((sec == NULL) && is_readonly) { + if (is_elf_have_relocation(ef) == false) { SI_LOG_ERR("ELF must have .rela.text, %s\n", file_name); return -1; } - // this memory will free by process exit - ef->file_name = strdup(file_name); return 0; } diff --git a/src/elf_read_elf.h b/src/elf_read_elf.h index abb09d0..935eff7 100644 --- a/src/elf_read_elf.h +++ b/src/elf_read_elf.h @@ -96,6 +96,7 @@ bool elf_is_same_area(const elf_file_t *ef, const Elf64_Shdr *a, const Elf64_Shd // ELF void elf_parse_hdr(elf_file_t *ef); int elf_read_file(char *file_name, elf_file_t *elf, bool is_readonly); +int elf_read_file_relocation(char *file_name, elf_file_t *ef); // debug void elf_show_dynsym(elf_file_t *ef); diff --git a/src/elf_relocation_aarch64.c b/src/elf_relocation_aarch64.c index f3840a9..222b0aa 100644 --- a/src/elf_relocation_aarch64.c +++ b/src/elf_relocation_aarch64.c @@ -66,8 +66,6 @@ static unsigned gen_branch_binary(unsigned binary, unsigned addr, unsigned offse #define IMM_LO_SHIFT 29 #define IMM_LO_LEN 2 #define IMM_LO_MASK ((1UL << IMM_LO_LEN) - 1) -#define PAGE_SHIFT 12 -#define PAGE_MASK (~((1UL << PAGE_SHIFT) - 1)) #define OPCODE_ADRP (0x9UL << 28) #define OPCODE_ADRP_MASK (0x9FUL << 24) #define REG_LEN 5U diff --git a/src/elf_write_elf.c b/src/elf_write_elf.c index 250328e..22577a6 100644 --- a/src/elf_write_elf.c +++ b/src/elf_write_elf.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "elf_link_common.h" #include "elf_read_elf.h" @@ -43,10 +44,10 @@ unsigned int elf_align_file_section(elf_link_t *elf_link, Elf64_Shdr *sec, bool } else { // use next PAGE if (is_align_file_offset) { - elf_link->next_file_offset = ALIGN(elf_link->next_file_offset, (1UL << PAGE_SHIFT)); + elf_link->next_file_offset = ALIGN(elf_link->next_file_offset, PAGE_SIZE); elf_link->next_file_offset += old_offset_in_page; } - elf_link->next_mem_addr = ALIGN(elf_link->next_mem_addr, (1UL << PAGE_SHIFT)); + elf_link->next_mem_addr = ALIGN(elf_link->next_mem_addr, PAGE_SIZE); elf_link->next_mem_addr += old_offset_in_page; } -- Gitee