Skip to content

Commit a54c401

Browse files
kaccardiPeter Zijlstra
authored andcommitted
x86/tools/relocs: Support >64K section headers
While the relocs tool already supports finding the total number of section headers if vmlinux exceeds 64K sections, it fails to read the extended symbol table to get section header indexes for symbols, causing incorrect symbol table indexes to be used when there are > 64K symbols. Parse the ELF file to read the extended symbol table info, and then replace all direct references to st_shndx with calls to sym_index(), which will determine whether the value can be read directly or whether the value should be pulled out of the extended table. This is needed for future FGKASLR support, which uses a separate section per function. Signed-off-by: Kristen Carlson Accardi <[email protected]> Signed-off-by: Alexander Lobakin <[email protected]> Signed-off-by: Kees Cook <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Reviewed-by: Kees Cook <[email protected]> Reviewed-by: Tony Luck <[email protected]> Acked-by: H. Peter Anvin (Intel) <[email protected]> Tested-by: Tony Luck <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 541ac97 commit a54c401

File tree

1 file changed

+78
-25
lines changed

1 file changed

+78
-25
lines changed

arch/x86/tools/relocs.c

Lines changed: 78 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
static Elf_Ehdr ehdr;
1515
static unsigned long shnum;
1616
static unsigned int shstrndx;
17+
static unsigned int shsymtabndx;
18+
static unsigned int shxsymtabndx;
19+
20+
static int sym_index(Elf_Sym *sym);
1721

1822
struct relocs {
1923
uint32_t *offset;
@@ -35,6 +39,7 @@ struct section {
3539
Elf_Shdr shdr;
3640
struct section *link;
3741
Elf_Sym *symtab;
42+
Elf32_Word *xsymtab;
3843
Elf_Rel *reltab;
3944
char *strtab;
4045
};
@@ -268,7 +273,7 @@ static const char *sym_name(const char *sym_strtab, Elf_Sym *sym)
268273
name = sym_strtab + sym->st_name;
269274
}
270275
else {
271-
name = sec_name(sym->st_shndx);
276+
name = sec_name(sym_index(sym));
272277
}
273278
return name;
274279
}
@@ -338,6 +343,23 @@ static uint64_t elf64_to_cpu(uint64_t val)
338343
#define elf_xword_to_cpu(x) elf32_to_cpu(x)
339344
#endif
340345

346+
static int sym_index(Elf_Sym *sym)
347+
{
348+
Elf_Sym *symtab = secs[shsymtabndx].symtab;
349+
Elf32_Word *xsymtab = secs[shxsymtabndx].xsymtab;
350+
unsigned long offset;
351+
int index;
352+
353+
if (sym->st_shndx != SHN_XINDEX)
354+
return sym->st_shndx;
355+
356+
/* calculate offset of sym from head of table. */
357+
offset = (unsigned long)sym - (unsigned long)symtab;
358+
index = offset / sizeof(*sym);
359+
360+
return elf32_to_cpu(xsymtab[index]);
361+
}
362+
341363
static void read_ehdr(FILE *fp)
342364
{
343365
if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) {
@@ -471,31 +493,60 @@ static void read_strtabs(FILE *fp)
471493
static void read_symtabs(FILE *fp)
472494
{
473495
int i,j;
496+
474497
for (i = 0; i < shnum; i++) {
475498
struct section *sec = &secs[i];
476-
if (sec->shdr.sh_type != SHT_SYMTAB) {
499+
int num_syms;
500+
501+
switch (sec->shdr.sh_type) {
502+
case SHT_SYMTAB_SHNDX:
503+
sec->xsymtab = malloc(sec->shdr.sh_size);
504+
if (!sec->xsymtab) {
505+
die("malloc of %" FMT " bytes for xsymtab failed\n",
506+
sec->shdr.sh_size);
507+
}
508+
if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
509+
die("Seek to %" FMT " failed: %s\n",
510+
sec->shdr.sh_offset, strerror(errno));
511+
}
512+
if (fread(sec->xsymtab, 1, sec->shdr.sh_size, fp)
513+
!= sec->shdr.sh_size) {
514+
die("Cannot read extended symbol table: %s\n",
515+
strerror(errno));
516+
}
517+
shxsymtabndx = i;
518+
continue;
519+
520+
case SHT_SYMTAB:
521+
num_syms = sec->shdr.sh_size / sizeof(Elf_Sym);
522+
523+
sec->symtab = malloc(sec->shdr.sh_size);
524+
if (!sec->symtab) {
525+
die("malloc of %" FMT " bytes for symtab failed\n",
526+
sec->shdr.sh_size);
527+
}
528+
if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
529+
die("Seek to %" FMT " failed: %s\n",
530+
sec->shdr.sh_offset, strerror(errno));
531+
}
532+
if (fread(sec->symtab, 1, sec->shdr.sh_size, fp)
533+
!= sec->shdr.sh_size) {
534+
die("Cannot read symbol table: %s\n",
535+
strerror(errno));
536+
}
537+
for (j = 0; j < num_syms; j++) {
538+
Elf_Sym *sym = &sec->symtab[j];
539+
540+
sym->st_name = elf_word_to_cpu(sym->st_name);
541+
sym->st_value = elf_addr_to_cpu(sym->st_value);
542+
sym->st_size = elf_xword_to_cpu(sym->st_size);
543+
sym->st_shndx = elf_half_to_cpu(sym->st_shndx);
544+
}
545+
shsymtabndx = i;
546+
continue;
547+
548+
default:
477549
continue;
478-
}
479-
sec->symtab = malloc(sec->shdr.sh_size);
480-
if (!sec->symtab) {
481-
die("malloc of %" FMT " bytes for symtab failed\n",
482-
sec->shdr.sh_size);
483-
}
484-
if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
485-
die("Seek to %" FMT " failed: %s\n",
486-
sec->shdr.sh_offset, strerror(errno));
487-
}
488-
if (fread(sec->symtab, 1, sec->shdr.sh_size, fp)
489-
!= sec->shdr.sh_size) {
490-
die("Cannot read symbol table: %s\n",
491-
strerror(errno));
492-
}
493-
for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Sym); j++) {
494-
Elf_Sym *sym = &sec->symtab[j];
495-
sym->st_name = elf_word_to_cpu(sym->st_name);
496-
sym->st_value = elf_addr_to_cpu(sym->st_value);
497-
sym->st_size = elf_xword_to_cpu(sym->st_size);
498-
sym->st_shndx = elf_half_to_cpu(sym->st_shndx);
499550
}
500551
}
501552
}
@@ -762,7 +813,9 @@ static void percpu_init(void)
762813
*/
763814
static int is_percpu_sym(ElfW(Sym) *sym, const char *symname)
764815
{
765-
return (sym->st_shndx == per_cpu_shndx) &&
816+
int shndx = sym_index(sym);
817+
818+
return (shndx == per_cpu_shndx) &&
766819
strcmp(symname, "__init_begin") &&
767820
strcmp(symname, "__per_cpu_load") &&
768821
strncmp(symname, "init_per_cpu_", 13);
@@ -1095,7 +1148,7 @@ static int do_reloc_info(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
10951148
sec_name(sec->shdr.sh_info),
10961149
rel_type(ELF_R_TYPE(rel->r_info)),
10971150
symname,
1098-
sec_name(sym->st_shndx));
1151+
sec_name(sym_index(sym)));
10991152
return 0;
11001153
}
11011154

0 commit comments

Comments
 (0)