Hi,

I would like to report a SEGFAULT in nm(1) that occurs with object-file
with no section headers (e_shnum = 0). This object-file was generated by
eg++ (I am not sure if the object-file is valid or not).

I am also able to reproduce the problem with edited elf object (using
hte [editors/ht]) by manually setting the section header count to zero.


$ readelf -h obj/cciVHsvd-2.o
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          8932544 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         0 (73122)
  Section header string table index: 65535 (73374)

$ gdb -q -args ./obj/nm -n obj/cciVHsvd-2.o
(gdb) r
Starting program: /usr/obj/usr.bin/nm/nm -n obj/cciVHsvd-2.o

Program received signal SIGSEGV, Segmentation fault.
0x000019a9f830728e in elf64_symload (name=0x7f7ffffefe82 "obj/cciVHsvd-2.o", 
fp=0x19aca16c7180, foff=0, eh=0x7f7ffffefbb0,
    shdr=0x19aca4026720, pnames=0x7f7ffffefb38, psnames=0x7f7ffffefb30, 
pstabsize=0x7f7ffffefb28, pnrawnames=0x7f7ffffefb70) at elf64.c:529
529             shstrsize = shdr[eh->e_shstrndx].sh_size;
(gdb) bt
#0  0x000019a9f830728e in elf64_symload (name=0x7f7ffffefe82 
"obj/cciVHsvd-2.o", fp=0x19aca16c7180, foff=0, eh=0x7f7ffffefbb0, 
    shdr=0x19aca4026720, pnames=0x7f7ffffefb38, psnames=0x7f7ffffefb30, 
pstabsize=0x7f7ffffefb28, pnrawnames=0x7f7ffffefb70) at elf64.c:529
#1  0x000019a9f83037ca in show_file (count=1, warn_fmt=1, name=0x7f7ffffefe82 
"obj/cciVHsvd-2.o", fp=0x19aca16c7180, foff=0, 
    head=0x7f7ffffefbb0) at /usr/src/usr.bin/nm/nm.c:636
#2  0x000019a9f8302548 in process_file (count=1, fname=0x7f7ffffefe82 
"obj/cciVHsvd-2.o") at /usr/src/usr.bin/nm/nm.c:267
#3  0x000019a9f83022e3 in main (argc=1, argv=0x7f7ffffefcd8) at 
/usr/src/usr.bin/nm/nm.c:208
(gdb) print eh
$1 = (Elf64_Ehdr *) 0x7f7ffffefbb0
(gdb) print *eh
$2 = {e_ident = "\177ELF\002\001\001\000\000\000\000\000\000\000\000", e_type = 
1, e_machine = 62, e_version = 1, e_entry = 0, e_phoff = 0, 
  e_shoff = 8932544, e_flags = 0, e_ehsize = 64, e_phentsize = 0, e_phnum = 0, 
e_shentsize = 64, e_shnum = 0, e_shstrndx = 65535}
(gdb) print shdr
$3 = (Elf64_Shdr *) 0x19aca4026720
(gdb) print *shdr
Cannot access memory at address 0x19aca4026720
(gdb) quit

The segfault is caused by "shdr[eh->e_shstrndx]" (src/usr.bin/nm/elf.c:528).

shdr is allocated by elf_load_shdrs() (elf.c:152):

>        if ((shdr = calloc(head->e_shentsize, head->e_shnum)) == NULL) {
>               warn("%s: malloc shdr", name);
>               return (NULL);
>       }

Here, the object-file has e_shnum=0 (no section header table), so shdr
is an zero sized object.

The patch adds two check:
  - e_shnum == 0: no section header table
  - a consistency check (should prevent craft object-file to generate
    out-of-bound read).

Maybe a check for overflow would be needed too ?

-- 
Sébastien Marie


Index: elf.c
===================================================================
RCS file: /cvs/src/usr.bin/nm/elf.c,v
retrieving revision 1.28
diff -u -p -r1.28 elf.c
--- elf.c       17 May 2015 20:19:08 -0000      1.28
+++ elf.c       17 Jun 2015 12:05:25 -0000
@@ -149,6 +149,16 @@ elf_load_shdrs(const char *name, FILE *f
 
        elf_fix_header(head);
 
+       if (head->e_shnum == 0) {
+               warnx("%s: no section header table", name);
+               return (NULL);
+       }
+
+       if (head->e_shstrndx >= head->e_shentsize * head->e_shnum) {
+               warnx("%s: inconsistent section header table", name);
+               return (NULL);
+       }
+
        if ((shdr = calloc(head->e_shentsize, head->e_shnum)) == NULL) {
                warn("%s: malloc shdr", name);
                return (NULL);

Reply via email to