Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions components/libc/posix/libdl/arch/arm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Copy link
Copy Markdown
Member

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 行。此问题通过指针运算检查确认。

{
return -1;
}

where = (Elf32_Addr *)((rt_uint8_t *)module->mem_space
+ rel->r_offset
- module->vstart_addr);
Expand Down
10 changes: 10 additions & 0 deletions components/libc/posix/libdl/arch/riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions components/libc/posix/libdl/arch/x86.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
215 changes: 178 additions & 37 deletions components/libc/posix/libdl/dlelf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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;
Expand All @@ -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)
{
Expand All @@ -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)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] 此检查会拒绝无节头表的共享对象

ELF 允许共享对象省略节头表,此时 e_shoff、e_shnum 和 e_shstrndx 均为 0。对于无需重定位、可直接通过 PT_LOAD 加载的 ET_DYN,基线能够完成加载,此处却因 0 >= 0 返回错误。建议先处理节头表缺省的情况,再校验节名表索引。

用基线和本 PR 源码做宿主侧对照测试,该用例在基线返回 RT_EOK,本 PR 返回 -RT_ERROR。节头表缺省的字段约定见 ELF 头规范。

{
LOG_E("Module: invalid e_shstrndx %d", elf_module->e_shstrndx);
return -RT_ERROR;
}

/* construct module symbol table */
Expand All @@ -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;

Expand Down Expand Up @@ -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;

Expand All @@ -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. */
Expand All @@ -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) ||
Expand All @@ -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
{
Expand All @@ -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;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] 此处会拒绝合法的空操作重定位和未定义弱符号

ET_REL 中 R_ARM_NONE 使用符号索引 0 时,加载器会先查找空符号名,并在这里返回错误,无法到达 ARM 实现中新增的空操作分支。引用未定义 STB_WEAK 对象的 R_ARM_ABS32 也会走到此处并失败。建议在解析符号前跳过空操作,并按 ABI 处理未定义弱符号。

用基线和本 PR 源码做宿主侧对照测试,上述两个用例在基线返回 RT_EOK,本 PR 均返回 -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;
}
}
}

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;
Expand All @@ -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;

Expand Down
Loading
Loading