Skip to content

Commit 506dbc6

Browse files
authored
[dlmodule] fix: uninitialized globals in relocatable modules (#11915)
1 parent c89121a commit 506dbc6

2 files changed

Lines changed: 215 additions & 45 deletions

File tree

‎components/libc/posix/libdl/dlelf.c‎

Lines changed: 213 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,48 @@ rt_err_t dlmodule_load_shared_object(struct rt_dlmodule* module, void *module_pt
300300
return RT_EOK;
301301
}
302302

303+
/**
304+
* @brief Compute the size of the common block of a symbol table, and
305+
* optionally the offset of one specific SHN_COMMON symbol inside it.
306+
*
307+
* SHN_COMMON symbols are tentative definitions of uninitialized global
308+
* variables. The loader must allocate storage for them just like a static
309+
* linker does: every common symbol is aligned to its st_value alignment
310+
* requirement and occupies st_size bytes, packed one after another.
311+
*
312+
* @param symtab pointer to the symbol table
313+
* @param nsym number of symbols in the table
314+
* @param target symbol whose offset is wanted, or RT_NULL to get the total
315+
* size of the common block
316+
* @return offset of target in the common block, or the total size of the
317+
* block when target is RT_NULL
318+
*/
319+
static rt_ubase_t dlmodule_common_block(Elf_Sym *symtab, rt_ubase_t nsym,
320+
Elf_Sym *target)
321+
{
322+
rt_ubase_t i, offset = 0;
323+
324+
for (i = 0; i < nsym; i++)
325+
{
326+
if (symtab[i].st_shndx != SHN_COMMON)
327+
{
328+
continue;
329+
}
330+
331+
/* st_value of a SHN_COMMON symbol holds its alignment requirement */
332+
offset = RT_ALIGN(offset, symtab[i].st_value > 1 ? symtab[i].st_value : 1);
333+
334+
if (target == &symtab[i])
335+
{
336+
return offset;
337+
}
338+
339+
offset += symtab[i].st_size;
340+
}
341+
342+
return offset;
343+
}
344+
303345
/**
304346
* @brief Load a relocatable file into memory.
305347
*
@@ -319,8 +361,9 @@ rt_err_t dlmodule_load_shared_object(struct rt_dlmodule* module, void *module_pt
319361
*/
320362
rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module_ptr)
321363
{
322-
rt_ubase_t index, rodata_addr = 0, bss_addr = 0, data_addr = 0;
323-
rt_ubase_t module_addr = 0, module_size = 0;
364+
rt_ubase_t index, common_addr = 0;
365+
rt_ubase_t module_addr = 0, module_size = 0, common_align = 1;
366+
rt_ubase_t *section_load_addr = RT_NULL;
324367
rt_uint8_t *ptr, *strtab, *shstrab;
325368

326369
/* get the ELF image size */
@@ -349,6 +392,38 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module
349392
}
350393
}
351394

395+
/* account for common symbols (uninitialized global variables) */
396+
for (index = 0; index < elf_module->e_shnum; index++)
397+
{
398+
Elf_Sym *symtab;
399+
rt_ubase_t i, nsym;
400+
401+
if (shdr[index].sh_type != SHT_SYMTAB)
402+
{
403+
continue;
404+
}
405+
406+
symtab = (Elf_Sym *)((rt_uint8_t *)elf_module + shdr[index].sh_offset);
407+
nsym = (rt_ubase_t)(shdr[index].sh_size / sizeof(Elf_Sym));
408+
for (i = 0; i < nsym; i++)
409+
{
410+
if ((symtab[i].st_shndx == SHN_COMMON) &&
411+
(symtab[i].st_value > common_align))
412+
{
413+
common_align = symtab[i].st_value;
414+
}
415+
}
416+
module_size += RT_ALIGN(dlmodule_common_block(symtab, nsym, RT_NULL),
417+
sizeof(rt_ubase_t));
418+
}
419+
420+
/* The actual base is known only after allocation. Reserve the worst-case
421+
* padding needed to align the common block after all sections are loaded. */
422+
if (common_align > 1)
423+
{
424+
module_size += common_align - 1;
425+
}
426+
352427
/* no text, data and bss on image */
353428
if (module_size == 0) return RT_NULL;
354429

@@ -363,6 +438,14 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module
363438
}
364439
module->mem_size = module_size;
365440

441+
section_load_addr = rt_calloc(elf_module->e_shnum,
442+
sizeof(*section_load_addr));
443+
if (section_load_addr == RT_NULL)
444+
{
445+
LOG_E("Module: allocate section address table failed.\n");
446+
return -RT_ENOMEM;
447+
}
448+
366449
/* zero all space */
367450
ptr = module->mem_space;
368451
rt_memset(ptr, 0, module_size);
@@ -373,6 +456,7 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module
373456
/* load text section */
374457
if (IS_PROG(shdr[index]) && IS_AX(shdr[index]))
375458
{
459+
section_load_addr[index] = (rt_ubase_t)ptr;
376460
rt_memcpy(ptr,
377461
(rt_uint8_t *)elf_module + shdr[index].sh_offset,
378462
shdr[index].sh_size);
@@ -383,36 +467,39 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module
383467
/* load rodata section */
384468
if (IS_PROG(shdr[index]) && IS_ALLOC(shdr[index]))
385469
{
470+
section_load_addr[index] = (rt_ubase_t)ptr;
386471
rt_memcpy(ptr,
387472
(rt_uint8_t *)elf_module + shdr[index].sh_offset,
388473
shdr[index].sh_size);
389-
rodata_addr = (rt_ubase_t)ptr;
390-
LOG_D("load rodata 0x%x, size %d, rodata 0x%x", ptr,
391-
shdr[index].sh_size, *(rt_ubase_t *)rodata_addr);
474+
LOG_D("load rodata 0x%x, size %d", ptr, shdr[index].sh_size);
392475
ptr += shdr[index].sh_size;
393476
}
394477

395478
/* load data section */
396479
if (IS_PROG(shdr[index]) && IS_AW(shdr[index]))
397480
{
481+
section_load_addr[index] = (rt_ubase_t)ptr;
398482
rt_memcpy(ptr,
399483
(rt_uint8_t *)elf_module + shdr[index].sh_offset,
400484
shdr[index].sh_size);
401-
data_addr = (rt_ubase_t)ptr;
402-
LOG_D("load data 0x%x, size %d, data 0x%x", ptr,
403-
shdr[index].sh_size, *(rt_ubase_t *)data_addr);
485+
LOG_D("load data 0x%x, size %d", ptr, shdr[index].sh_size);
404486
ptr += shdr[index].sh_size;
405487
}
406488

407489
/* load bss section */
408490
if (IS_NOPROG(shdr[index]) && IS_AW(shdr[index]))
409491
{
492+
section_load_addr[index] = (rt_ubase_t)ptr;
410493
rt_memset(ptr, 0, shdr[index].sh_size);
411-
bss_addr = (rt_ubase_t)ptr;
412494
LOG_D("load bss 0x%x, size %d", ptr, shdr[index].sh_size);
495+
ptr += shdr[index].sh_size;
413496
}
414497
}
415498

499+
/* the common block (uninitialized global variables) starts right after
500+
* the loaded sections; it was zeroed together with the module space */
501+
common_addr = RT_ALIGN((rt_ubase_t)ptr, common_align);
502+
416503
/* set module entry */
417504
module->entry_addr = (rt_dlmodule_entry_func_t)((rt_uint8_t *)module->mem_space + elf_module->e_entry - module_addr);
418505

@@ -431,6 +518,12 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module
431518
continue;
432519
#endif
433520

521+
/* Only relocate sections that were loaded into module memory. */
522+
if ((shdr[index].sh_info >= elf_module->e_shnum) ||
523+
(section_load_addr[shdr[index].sh_info] == 0))
524+
{
525+
continue;
526+
}
434527

435528
/* get relocate item */
436529
rel = (Elf_Rel *)((rt_uint8_t *)module_ptr + shdr[index].sh_offset);
@@ -452,56 +545,52 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module
452545
#elif (defined(__aarch64__) || defined(__x86_64__) || (__riscv_xlen == 64))
453546
Elf_Sym *sym = &symtab[ELF64_R_SYM(rel->r_info)];
454547
#endif
548+
Elf_Rel target_rel = *rel;
549+
550+
/* r_offset is relative to the section being relocated. Convert it
551+
* to the module-relative offset expected by the arch relocator. */
552+
target_rel.r_offset += section_load_addr[shdr[index].sh_info] -
553+
(rt_ubase_t)module->mem_space;
455554

456555
LOG_D("relocate symbol: %s", strtab + sym->st_name);
457556

458557
if (sym->st_shndx != STN_UNDEF)
459558
{
460559
Elf_Addr addr = 0;
461560

462-
if ((ELF_ST_TYPE(sym->st_info) == STT_SECTION) ||
463-
(ELF_ST_TYPE(sym->st_info) == STT_OBJECT))
561+
if (sym->st_shndx == SHN_COMMON)
464562
{
465-
if (rt_strncmp((const char *)(shstrab +
466-
shdr[sym->st_shndx].sh_name), ELF_RODATA, 8) == 0)
467-
{
468-
/* relocate rodata section */
469-
LOG_D("rodata");
470-
addr = (Elf_Addr)(rodata_addr + sym->st_value);
471-
}
472-
else if (rt_strncmp((const char *)
473-
(shstrab + shdr[sym->st_shndx].sh_name), ELF_BSS, 5) == 0)
474-
{
475-
/* relocate bss section */
476-
LOG_D("bss");
477-
addr = (Elf_Addr)bss_addr + sym->st_value;
478-
}
479-
else if (rt_strncmp((const char *)(shstrab + shdr[sym->st_shndx].sh_name),
480-
ELF_DATA, 6) == 0)
481-
{
482-
/* relocate data section */
483-
LOG_D("data");
484-
addr = (Elf_Addr)data_addr + sym->st_value;
485-
}
486-
487-
if (addr != 0) dlmodule_relocate(module, rel, addr);
563+
/* SHN_COMMON is not a real section index. */
564+
LOG_D("common symbol");
565+
addr = (Elf_Addr)(common_addr + dlmodule_common_block(
566+
symtab,
567+
(rt_ubase_t)(shdr[shdr[index].sh_link].sh_size / sizeof(Elf_Sym)),
568+
sym));
488569
}
489-
else if (ELF_ST_TYPE(sym->st_info) == STT_FUNC)
570+
else if (((ELF_ST_TYPE(sym->st_info) == STT_SECTION) ||
571+
(ELF_ST_TYPE(sym->st_info) == STT_OBJECT) ||
572+
(ELF_ST_TYPE(sym->st_info) == STT_FUNC)) &&
573+
(sym->st_shndx < elf_module->e_shnum) &&
574+
(section_load_addr[sym->st_shndx] != 0))
490575
{
491-
addr = (Elf_Addr)((rt_uint8_t *) module->mem_space - module_addr + sym->st_value);
576+
/* For ET_REL, st_value is already the offset within the
577+
* symbol's section; sh_addr must not be subtracted. */
578+
addr = (Elf_Addr)(section_load_addr[sym->st_shndx] +
579+
sym->st_value);
580+
}
492581

493-
/* relocate function */
494-
dlmodule_relocate(module, rel, addr);
582+
if (addr != 0)
583+
{
584+
dlmodule_relocate(module, &target_rel, addr);
495585
}
496586
}
497587
else if (ELF_ST_TYPE(sym->st_info) == STT_FUNC)
498588
{
499589
/* relocate function */
500-
dlmodule_relocate(module, rel,
501-
(Elf_Addr)((rt_uint8_t *)
502-
module->mem_space
503-
- module_addr
504-
+ sym->st_value));
590+
dlmodule_relocate(module, &target_rel,
591+
(Elf_Addr)((rt_uint8_t *)
592+
module->mem_space -
593+
module_addr + sym->st_value));
505594
}
506595
else
507596
{
@@ -515,7 +604,7 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module
515604
addr = dlmodule_symbol_find((const char *)(strtab + sym->st_name));
516605
if (addr != (Elf_Addr)RT_NULL)
517606
{
518-
dlmodule_relocate(module, rel, addr);
607+
dlmodule_relocate(module, &target_rel, addr);
519608
LOG_D("symbol addr 0x%x", addr);
520609
}
521610
else
@@ -525,13 +614,92 @@ rt_err_t dlmodule_load_relocated_object(struct rt_dlmodule* module, void *module
525614
else
526615
{
527616
addr = (Elf_Addr)((rt_uint8_t *) module->mem_space - module_addr + sym->st_value);
528-
dlmodule_relocate(module, rel, addr);
617+
dlmodule_relocate(module, &target_rel, addr);
529618
}
530619
}
531620

532621
rel ++;
533622
}
534623
}
535624

625+
/* construct the module symbol table from .symtab so that lookups such as
626+
* dlsym() can resolve the module's global functions */
627+
shstrab = (rt_uint8_t *)module_ptr + shdr[elf_module->e_shstrndx].sh_offset;
628+
for (index = 0; index < elf_module->e_shnum; index++)
629+
{
630+
if ((shdr[index].sh_type == SHT_SYMTAB) &&
631+
(rt_strcmp((const char *)(shstrab + shdr[index].sh_name), ELF_SYMTAB) == 0))
632+
{
633+
break;
634+
}
635+
}
636+
637+
if (index != elf_module->e_shnum)
638+
{
639+
Elf_Sym *symtab;
640+
rt_ubase_t i, count = 0;
641+
642+
symtab = (Elf_Sym *)((rt_uint8_t *)module_ptr + shdr[index].sh_offset);
643+
strtab = (rt_uint8_t *)module_ptr + shdr[shdr[index].sh_link].sh_offset;
644+
645+
for (i = 0; i < shdr[index].sh_size / sizeof(Elf_Sym); i++)
646+
{
647+
if ((ELF_ST_BIND(symtab[i].st_info) == STB_GLOBAL) &&
648+
(ELF_ST_TYPE(symtab[i].st_info) == STT_FUNC) &&
649+
(symtab[i].st_shndx != SHN_UNDEF) &&
650+
(symtab[i].st_shndx < elf_module->e_shnum) &&
651+
(section_load_addr[symtab[i].st_shndx] != 0))
652+
{
653+
count++;
654+
}
655+
}
656+
657+
module->nsym = 0;
658+
if (count > 0)
659+
{
660+
module->symtab = (struct rt_module_symtab *)rt_malloc(
661+
count * sizeof(struct rt_module_symtab));
662+
if (module->symtab == RT_NULL)
663+
{
664+
LOG_E("Module: allocate symbol table failed.\n");
665+
rt_free(section_load_addr);
666+
return -RT_ENOMEM;
667+
}
668+
669+
for (i = 0; i < shdr[index].sh_size / sizeof(Elf_Sym); i++)
670+
{
671+
rt_size_t length;
672+
673+
if ((ELF_ST_BIND(symtab[i].st_info) != STB_GLOBAL) ||
674+
(ELF_ST_TYPE(symtab[i].st_info) != STT_FUNC) ||
675+
(symtab[i].st_shndx == SHN_UNDEF) ||
676+
(symtab[i].st_shndx >= elf_module->e_shnum) ||
677+
(section_load_addr[symtab[i].st_shndx] == 0))
678+
{
679+
continue;
680+
}
681+
682+
length = rt_strlen((const char *)(strtab + symtab[i].st_name)) + 1;
683+
684+
module->symtab[module->nsym].addr =
685+
(void *)(section_load_addr[symtab[i].st_shndx] +
686+
symtab[i].st_value);
687+
module->symtab[module->nsym].name = rt_malloc(length);
688+
if (module->symtab[module->nsym].name == RT_NULL)
689+
{
690+
LOG_E("Module: allocate symbol name failed.\n");
691+
rt_free(section_load_addr);
692+
return -RT_ENOMEM;
693+
}
694+
rt_memset((void *)module->symtab[module->nsym].name, 0, length);
695+
rt_memcpy((void *)module->symtab[module->nsym].name,
696+
strtab + symtab[i].st_name,
697+
length);
698+
module->nsym++;
699+
}
700+
}
701+
}
702+
703+
rt_free(section_load_addr);
536704
return RT_EOK;
537705
}

‎components/libc/posix/libdl/dlelf.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ typedef struct
202202
#define STT_HIPROC 15
203203

204204
#define STN_UNDEF 0 /* undefined */
205+
#define SHN_UNDEF 0x0000 /* undefined section */
206+
#define SHN_COMMON 0xfff2 /* common symbols (uninitialized globals) */
205207

206208
#define ELF_ST_BIND(info) ((info) >> 4)
207209
#define ELF_ST_TYPE(info) ((info) & 0xf)

0 commit comments

Comments
 (0)