From e9ddc043379208949860b36c1ae5ba395a6a5d12 Mon Sep 17 00:00:00 2001 From: seteiro <276597748+cms19859230182-lang@users.noreply.github.com> Date: Tue, 10 Nov 2026 09:32:47 +0800 Subject: [PATCH] [libc][libdl] reject out-of-bounds ELF relocation targets - Validate relocation target range against module memory bounds to prevent out-of-bounds writes - Add dlmodule_check_rel_target helper and apply checks to ARM, RISC-V, and x86 arch relocators - Add bounds checks for ELF section header indices and symbol table indices - Abort module load and ensure proper cleanup (freeing section_load_addr) on relocation failure - Fix #11898 --- components/libc/posix/libdl/arch/arm.c | 10 ++ components/libc/posix/libdl/arch/riscv.c | 10 ++ components/libc/posix/libdl/arch/x86.c | 5 + components/libc/posix/libdl/dlelf.c | 215 +++++++++++++++++++---- components/libc/posix/libdl/dlmodule.h | 2 + 5 files changed, 205 insertions(+), 37 deletions(-) diff --git a/components/libc/posix/libdl/arch/arm.c b/components/libc/posix/libdl/arch/arm.c index 7914df28e7dd..19a3d2189c45 100644 --- a/components/libc/posix/libdl/arch/arm.c +++ b/components/libc/posix/libdl/arch/arm.c @@ -23,6 +23,16 @@ int dlmodule_relocate(struct rt_dlmodule *module, Elf32_Rel *rel, Elf32_Addr sym Elf32_Sword addend, offset; rt_uint32_t upper, lower, sign, j1, j2; + if (ELF32_R_TYPE(rel->r_info) == R_ARM_NONE) + { + return 0; + } + + if (dlmodule_check_rel_target(module, (rt_ubase_t)rel->r_offset, sizeof(Elf32_Addr)) != RT_EOK) + { + return -1; + } + where = (Elf32_Addr *)((rt_uint8_t *)module->mem_space + rel->r_offset - module->vstart_addr); diff --git a/components/libc/posix/libdl/arch/riscv.c b/components/libc/posix/libdl/arch/riscv.c index 13a4edac3efe..85ce08048214 100644 --- a/components/libc/posix/libdl/arch/riscv.c +++ b/components/libc/posix/libdl/arch/riscv.c @@ -36,6 +36,16 @@ int dlmodule_relocate(struct rt_dlmodule *module, Elf_Rel *rel, Elf_Addr sym_val Elf64_Sword addend, offset; rt_uint64_t upper, lower, sign, j1, j2; + if (ELF64_R_TYPE(rel->r_info) == R_RISCV_NONE) + { + return 0; + } + + if (dlmodule_check_rel_target(module, (rt_ubase_t)rel->r_offset, sizeof(Elf64_Addr)) != RT_EOK) + { + return -1; + } + where = (Elf64_Addr *)((rt_uint8_t *)module->mem_space + rel->r_offset - module->vstart_addr); diff --git a/components/libc/posix/libdl/arch/x86.c b/components/libc/posix/libdl/arch/x86.c index 7d5914687c20..e752f481ceb5 100644 --- a/components/libc/posix/libdl/arch/x86.c +++ b/components/libc/posix/libdl/arch/x86.c @@ -26,6 +26,11 @@ int dlmodule_relocate(struct rt_dlmodule *module, Elf32_Rel *rel, Elf32_Addr sym Elf32_Sword addend, offset; rt_uint32_t upper, lower, sign, j1, j2; + if (dlmodule_check_rel_target(module, (rt_ubase_t)rel->r_offset, sizeof(Elf32_Addr)) != RT_EOK) + { + return -1; + } + where = (Elf32_Addr *)((rt_uint8_t *)module->mem_space + rel->r_offset - module->vstart_addr); diff --git a/components/libc/posix/libdl/dlelf.c b/components/libc/posix/libdl/dlelf.c index be4e9c776cf1..dae6c996e01d 100644 --- a/components/libc/posix/libdl/dlelf.c +++ b/components/libc/posix/libdl/dlelf.c @@ -16,6 +16,34 @@ #define DBG_LVL DBG_INFO #include /* 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,24 +185,49 @@ 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)) @@ -182,7 +235,11 @@ rt_err_t dlmodule_load_shared_object(struct rt_dlmodule* module, void *module_pt 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) + { + 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,17 +717,31 @@ 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; + } } 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; + } } } @@ -622,6 +749,13 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module } } + 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; diff --git a/components/libc/posix/libdl/dlmodule.h b/components/libc/posix/libdl/dlmodule.h index 418c1a95c7d1..f30b0f13cebe 100644 --- a/components/libc/posix/libdl/dlmodule.h +++ b/components/libc/posix/libdl/dlmodule.h @@ -86,4 +86,6 @@ void dlmodule_extract_name(const char *path, char *name, int name_size); rt_ubase_t dlmodule_symbol_find(const char *sym_str); +rt_err_t dlmodule_check_rel_target(struct rt_dlmodule *module, rt_ubase_t r_offset, rt_size_t width); + #endif