Repository navigation
[libc][libdl] reject out-of-bounds ELF relocation targets #12016
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,6 +16,34 @@ | |
| #define DBG_LVL DBG_INFO | ||
| #include <rtdbg.h> /* must after of DEBUG_ENABLE or some other options*/ | ||
|
|
||
| rt_err_t dlmodule_check_rel_target(struct rt_dlmodule *module, rt_ubase_t r_offset, rt_size_t width) | ||
| { | ||
| rt_ubase_t offset; | ||
|
|
||
| if (!module || !module->mem_space || module->mem_size == 0) | ||
| { | ||
| LOG_E("Module: invalid module memory space"); | ||
| return -RT_ERROR; | ||
| } | ||
|
|
||
| if (r_offset < module->vstart_addr) | ||
| { | ||
| LOG_E("Module: relocation offset 0x%lx underflows vstart_addr 0x%lx", | ||
| (unsigned long)r_offset, (unsigned long)module->vstart_addr); | ||
| return -RT_ERROR; | ||
| } | ||
|
|
||
| offset = r_offset - module->vstart_addr; | ||
| if (width == 0 || width > module->mem_size || offset > module->mem_size - width) | ||
| { | ||
| LOG_E("Module: relocation target out of bounds (offset: 0x%lx, width: %lu, mem_size: 0x%lx)", | ||
| (unsigned long)offset, (unsigned long)width, (unsigned long)module->mem_size); | ||
| return -RT_ERROR; | ||
| } | ||
|
|
||
| return RT_EOK; | ||
| } | ||
|
|
||
| /** | ||
| * @brief Load a shared object file into memory. | ||
| * | ||
|
|
@@ -144,11 +172,11 @@ rt_err_t dlmodule_load_shared_object(struct rt_dlmodule* module, void *module_pt | |
| /* handle relocation section */ | ||
| for (index = 0; index < elf_module->e_shnum; index ++) | ||
| { | ||
| rt_ubase_t i, nr_reloc; | ||
| rt_ubase_t i, nr_reloc, nr_sym; | ||
| rt_ubase_t symtab_shndx, strtab_shndx; | ||
| Elf_Sym *symtab; | ||
| Elf_Rel *rel; | ||
| rt_uint8_t *strtab; | ||
| static rt_bool_t unsolved = RT_FALSE; | ||
| #if (defined(__arm__) || defined(__i386__) || (__riscv_xlen == 32)) | ||
| if (!IS_REL(shdr[index])) | ||
| continue; | ||
|
|
@@ -157,32 +185,61 @@ rt_err_t dlmodule_load_shared_object(struct rt_dlmodule* module, void *module_pt | |
| continue; | ||
| #endif | ||
|
|
||
| symtab_shndx = shdr[index].sh_link; | ||
| if (symtab_shndx >= elf_module->e_shnum) | ||
| { | ||
| LOG_E("Module: invalid relocation symtab section index %d", symtab_shndx); | ||
| return -RT_ERROR; | ||
| } | ||
|
|
||
| strtab_shndx = shdr[symtab_shndx].sh_link; | ||
| if (strtab_shndx >= elf_module->e_shnum) | ||
| { | ||
| LOG_E("Module: invalid relocation strtab section index %d", strtab_shndx); | ||
| return -RT_ERROR; | ||
| } | ||
|
|
||
| /* get relocate item */ | ||
| rel = (Elf_Rel *)((rt_uint8_t *)module_ptr + shdr[index].sh_offset); | ||
|
|
||
| /* locate .rel.plt and .rel.dyn section */ | ||
| symtab = (Elf_Sym *)((rt_uint8_t *)module_ptr + | ||
| shdr[shdr[index].sh_link].sh_offset); | ||
| shdr[symtab_shndx].sh_offset); | ||
| strtab = (rt_uint8_t *)module_ptr + | ||
| shdr[shdr[shdr[index].sh_link].sh_link].sh_offset; | ||
| shdr[strtab_shndx].sh_offset; | ||
| nr_reloc = (rt_ubase_t)(shdr[index].sh_size / sizeof(Elf_Rel)); | ||
| nr_sym = (rt_ubase_t)(shdr[symtab_shndx].sh_size / sizeof(Elf_Sym)); | ||
|
|
||
| /* relocate every items */ | ||
| for (i = 0; i < nr_reloc; i ++) | ||
| { | ||
| #if (defined(__arm__) || defined(__i386__) || (__riscv_xlen == 32)) | ||
| Elf_Sym *sym = &symtab[ELF32_R_SYM(rel->r_info)]; | ||
| #elif (defined(__aarch64__) || defined(__x86_64__) || (__riscv_xlen == 64)) | ||
| Elf_Sym *sym = &symtab[ELF64_R_SYM(rel->r_info)]; | ||
| #endif | ||
| rt_ubase_t sym_index = ELF32_R_SYM(rel->r_info); | ||
| #elif (defined(__aarch64__) || defined(__x86_64__) || (__riscv_xlen == 64)) | ||
| rt_ubase_t sym_index = ELF64_R_SYM(rel->r_info); | ||
| #endif | ||
| Elf_Sym *sym; | ||
|
|
||
| if (sym_index >= nr_sym) | ||
| { | ||
| LOG_E("Module: symbol index %lu out of symtab bounds (%lu)", | ||
| (unsigned long)sym_index, (unsigned long)nr_sym); | ||
| return -RT_ERROR; | ||
| } | ||
| sym = &symtab[sym_index]; | ||
|
|
||
| LOG_D("relocate symbol %s shndx %d", strtab + sym->st_name, sym->st_shndx); | ||
|
|
||
| if ((sym->st_shndx != SHT_NULL) ||(ELF_ST_BIND(sym->st_info) == STB_LOCAL)) | ||
| { | ||
| Elf_Addr addr; | ||
|
|
||
| addr = (Elf_Addr)(module->mem_space + sym->st_value - vstart_addr); | ||
| dlmodule_relocate(module, rel, addr); | ||
| if (dlmodule_relocate(module, rel, addr) != 0) | ||
| { | ||
| LOG_E("Module: relocate failed"); | ||
| return -RT_ERROR; | ||
| } | ||
| } | ||
| else if (!linked) | ||
| { | ||
|
|
@@ -194,21 +251,25 @@ rt_err_t dlmodule_load_shared_object(struct rt_dlmodule* module, void *module_pt | |
| if (addr == 0) | ||
| { | ||
| LOG_E("Module: can't find %s in kernel symbol table", strtab + sym->st_name); | ||
| unsolved = RT_TRUE; | ||
| return -RT_ERROR; | ||
| } | ||
| else | ||
| { | ||
| dlmodule_relocate(module, rel, addr); | ||
| if (dlmodule_relocate(module, rel, addr) != 0) | ||
| { | ||
| LOG_E("Module: relocate failed"); | ||
| return -RT_ERROR; | ||
| } | ||
| } | ||
| } | ||
| rel ++; | ||
| } | ||
| } | ||
|
|
||
| if (unsolved) | ||
| { | ||
| unsolved = RT_FALSE; | ||
| return -RT_ERROR; | ||
| } | ||
| if (elf_module->e_shstrndx >= elf_module->e_shnum) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P2] 此检查会拒绝无节头表的共享对象 ELF 允许共享对象省略节头表,此时 用基线和本 PR 源码做宿主侧对照测试,该用例在基线返回 |
||
| { | ||
| LOG_E("Module: invalid e_shstrndx %d", elf_module->e_shstrndx); | ||
| return -RT_ERROR; | ||
| } | ||
|
|
||
| /* construct module symbol table */ | ||
|
|
@@ -229,6 +290,12 @@ rt_err_t dlmodule_load_shared_object(struct rt_dlmodule* module, void *module_pt | |
| Elf_Sym *symtab = RT_NULL; | ||
| rt_uint8_t *strtab = RT_NULL; | ||
|
|
||
| if (shdr[index].sh_link >= elf_module->e_shnum) | ||
| { | ||
| LOG_E("Module: invalid dynsym strtab section index %d", shdr[index].sh_link); | ||
| return -RT_ERROR; | ||
| } | ||
|
|
||
| symtab = (Elf_Sym *)((rt_uint8_t *)module_ptr + shdr[index].sh_offset); | ||
| strtab = (rt_uint8_t *)module_ptr + shdr[shdr[index].sh_link].sh_offset; | ||
|
|
||
|
|
@@ -506,7 +573,8 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module | |
| /* handle relocation section */ | ||
| for (index = 0; index < elf_module->e_shnum; index ++) | ||
| { | ||
| rt_ubase_t i, nr_reloc; | ||
| rt_ubase_t i, nr_reloc, nr_sym; | ||
| rt_ubase_t symtab_shndx, strtab_shndx; | ||
| Elf_Sym *symtab; | ||
| Elf_Rel *rel; | ||
|
|
||
|
|
@@ -525,27 +593,62 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module | |
| continue; | ||
| } | ||
|
|
||
| symtab_shndx = shdr[index].sh_link; | ||
| if (symtab_shndx >= elf_module->e_shnum) | ||
| { | ||
| LOG_E("Module: invalid relocation symtab section index %d", symtab_shndx); | ||
| rt_free(section_load_addr); | ||
| return -RT_ERROR; | ||
| } | ||
|
|
||
| strtab_shndx = shdr[symtab_shndx].sh_link; | ||
| if (strtab_shndx >= elf_module->e_shnum) | ||
| { | ||
| LOG_E("Module: invalid relocation strtab section index %d", strtab_shndx); | ||
| rt_free(section_load_addr); | ||
| return -RT_ERROR; | ||
| } | ||
|
|
||
| /* get relocate item */ | ||
| rel = (Elf_Rel *)((rt_uint8_t *)module_ptr + shdr[index].sh_offset); | ||
|
|
||
| /* locate .dynsym and .dynstr */ | ||
| symtab = (Elf_Sym *)((rt_uint8_t *)module_ptr + | ||
| shdr[shdr[index].sh_link].sh_offset); | ||
| strtab = (rt_uint8_t *)module_ptr + | ||
| shdr[shdr[shdr[index].sh_link].sh_link].sh_offset; | ||
| shstrab = (rt_uint8_t *)module_ptr + | ||
| shdr[elf_module->e_shstrndx].sh_offset; | ||
| symtab = (Elf_Sym *)((rt_uint8_t *)module_ptr + | ||
| shdr[symtab_shndx].sh_offset); | ||
| strtab = (rt_uint8_t *)module_ptr + | ||
| shdr[strtab_shndx].sh_offset; | ||
| nr_reloc = (rt_uint32_t)(shdr[index].sh_size / sizeof(Elf_Rel)); | ||
| nr_sym = (rt_ubase_t)(shdr[symtab_shndx].sh_size / sizeof(Elf_Sym)); | ||
|
|
||
| /* relocate every items */ | ||
| for (i = 0; i < nr_reloc; i ++) | ||
| { | ||
| #if (defined(__arm__) || defined(__i386__) || (__riscv_xlen == 32)) | ||
| Elf_Sym *sym = &symtab[ELF32_R_SYM(rel->r_info)]; | ||
| #elif (defined(__aarch64__) || defined(__x86_64__) || (__riscv_xlen == 64)) | ||
| Elf_Sym *sym = &symtab[ELF64_R_SYM(rel->r_info)]; | ||
| #endif | ||
| Elf_Rel target_rel = *rel; | ||
| rt_ubase_t sym_index = ELF32_R_SYM(rel->r_info); | ||
| #elif (defined(__aarch64__) || defined(__x86_64__) || (__riscv_xlen == 64)) | ||
| rt_ubase_t sym_index = ELF64_R_SYM(rel->r_info); | ||
| #endif | ||
| Elf_Rel target_rel; | ||
| Elf_Sym *sym; | ||
|
|
||
| if (sym_index >= nr_sym) | ||
| { | ||
| LOG_E("Module: symbol index %lu out of symtab bounds (%lu)", | ||
| (unsigned long)sym_index, (unsigned long)nr_sym); | ||
| rt_free(section_load_addr); | ||
| return -RT_ERROR; | ||
| } | ||
|
|
||
| sym = &symtab[sym_index]; | ||
|
|
||
| if (rel->r_offset >= shdr[shdr[index].sh_info].sh_size) | ||
| { | ||
| LOG_E("Module: relocation offset out of section bounds"); | ||
| rt_free(section_load_addr); | ||
| return -RT_ERROR; | ||
| } | ||
|
|
||
| target_rel = *rel; | ||
|
|
||
| /* r_offset is relative to the section being relocated. Convert it | ||
| * to the module-relative offset expected by the arch relocator. */ | ||
|
|
@@ -564,7 +667,7 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module | |
| LOG_D("common symbol"); | ||
| addr = (Elf_Addr)(common_addr + dlmodule_common_block( | ||
| symtab, | ||
| (rt_ubase_t)(shdr[shdr[index].sh_link].sh_size / sizeof(Elf_Sym)), | ||
| nr_sym, | ||
| sym)); | ||
| } | ||
| else if (((ELF_ST_TYPE(sym->st_info) == STT_SECTION) || | ||
|
|
@@ -581,16 +684,26 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module | |
|
|
||
| if (addr != 0) | ||
| { | ||
| dlmodule_relocate(module, &target_rel, addr); | ||
| if (dlmodule_relocate(module, &target_rel, addr) != 0) | ||
| { | ||
| LOG_E("Module: relocate failed"); | ||
| rt_free(section_load_addr); | ||
| return -RT_ERROR; | ||
| } | ||
| } | ||
| } | ||
| else if (ELF_ST_TYPE(sym->st_info) == STT_FUNC) | ||
| { | ||
| /* relocate function */ | ||
| dlmodule_relocate(module, &target_rel, | ||
| (Elf_Addr)((rt_uint8_t *) | ||
| module->mem_space - | ||
| module_addr + sym->st_value)); | ||
| if (dlmodule_relocate(module, &target_rel, | ||
| (Elf_Addr)((rt_uint8_t *) | ||
| module->mem_space - | ||
| module_addr + sym->st_value)) != 0) | ||
| { | ||
| LOG_E("Module: relocate failed"); | ||
| rt_free(section_load_addr); | ||
| return -RT_ERROR; | ||
| } | ||
| } | ||
| else | ||
| { | ||
|
|
@@ -604,24 +717,45 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module | |
| addr = dlmodule_symbol_find((const char *)(strtab + sym->st_name)); | ||
| if (addr != (Elf_Addr)RT_NULL) | ||
| { | ||
| dlmodule_relocate(module, &target_rel, addr); | ||
| if (dlmodule_relocate(module, &target_rel, addr) != 0) | ||
| { | ||
| LOG_E("Module: relocate failed"); | ||
| rt_free(section_load_addr); | ||
| return -RT_ERROR; | ||
| } | ||
| LOG_D("symbol addr 0x%x", addr); | ||
| } | ||
| else | ||
| { | ||
| LOG_E("Module: can't find %s in kernel symbol table", | ||
| strtab + sym->st_name); | ||
| strtab + sym->st_name); | ||
| rt_free(section_load_addr); | ||
| return -RT_ERROR; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P2] 此处会拒绝合法的空操作重定位和未定义弱符号
用基线和本 PR 源码做宿主侧对照测试,上述两个用例在基线返回 |
||
| } | ||
| } | ||
| else | ||
| { | ||
| addr = (Elf_Addr)((rt_uint8_t *) module->mem_space - module_addr + sym->st_value); | ||
| dlmodule_relocate(module, &target_rel, addr); | ||
| if (dlmodule_relocate(module, &target_rel, addr) != 0) | ||
| { | ||
| LOG_E("Module: relocate failed"); | ||
| rt_free(section_load_addr); | ||
| return -RT_ERROR; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| rel ++; | ||
| } | ||
| } | ||
|
|
||
| if (elf_module->e_shstrndx >= elf_module->e_shnum) | ||
| { | ||
| LOG_E("Module: invalid e_shstrndx %d", elf_module->e_shstrndx); | ||
| rt_free(section_load_addr); | ||
| return -RT_ERROR; | ||
| } | ||
|
|
||
| /* construct the module symbol table from .symtab so that lookups such as | ||
| * dlsym() can resolve the module's global functions */ | ||
| shstrab = (rt_uint8_t *)module_ptr + shdr[elf_module->e_shstrndx].sh_offset; | ||
|
|
@@ -639,6 +773,13 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module | |
| Elf_Sym *symtab; | ||
| rt_ubase_t i, count = 0; | ||
|
|
||
| if (shdr[index].sh_link >= elf_module->e_shnum) | ||
| { | ||
| LOG_E("Module: invalid symtab strtab section index %d", shdr[index].sh_link); | ||
| rt_free(section_load_addr); | ||
| return -RT_ERROR; | ||
| } | ||
|
|
||
| symtab = (Elf_Sym *)((rt_uint8_t *)module_ptr + shdr[index].sh_offset); | ||
| strtab = (rt_uint8_t *)module_ptr + shdr[shdr[index].sh_link].sh_offset; | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[P1] Thumb 重定位的写入范围仍超出此处检查
R_ARM_THM_CALL/R_ARM_THM_JUMP24分支用*(rt_uint16_t *)(where + 2)写第二个半字。where的类型是Elf32_Addr *,所以该写入位于目标地址后 8 字节,而此处只校验 4 字节。目标位于模块尾部时仍可能越界写入。建议将第二个半字的写入改为*((rt_uint16_t *)where + 1),使实际写入范围与校验一致。对应写入位于 arm.c 第 123 行。此问题通过指针运算检查确认。