Print this page
4005 libctf can't deal with extended sections

@@ -191,10 +191,11 @@
 ctf_file_t *
 ctf_fdopen(int fd, int *errp)
 {
         ctf_sect_t ctfsect, symsect, strsect;
         ctf_file_t *fp = NULL;
+        size_t shstrndx, shnum;
 
         struct stat64 st;
         ssize_t nbytes;
 
         union {

@@ -253,15 +254,14 @@
 #ifdef  _BIG_ENDIAN
                 uchar_t order = ELFDATA2MSB;
 #else
                 uchar_t order = ELFDATA2LSB;
 #endif
-                GElf_Half i, n;
                 GElf_Shdr *sp;
 
                 void *strs_map;
-                size_t strs_mapsz;
+                size_t strs_mapsz, i;
                 const char *strs;
 
                 if (hdr.e32.e_ident[EI_DATA] != order)
                         return (ctf_set_open_errno(errp, ECTF_ENDIAN));
                 if (hdr.e32.e_version != EV_CURRENT)

@@ -273,15 +273,42 @@
                 } else {
                         Elf32_Ehdr e32 = hdr.e32;
                         ehdr_to_gelf(&e32, &hdr.e64);
                 }
 
-                if (hdr.e64.e_shstrndx >= hdr.e64.e_shnum)
+                shnum = hdr.e64.e_shnum;
+                shstrndx = hdr.e64.e_shstrndx;
+
+                /* Extended ELF sections */
+                if ((shstrndx == SHN_XINDEX) || (shnum == 0)) {
+                        if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) {
+                                Elf32_Shdr x32;
+
+                                if (pread64(fd, &x32, sizeof (x32),
+                                    hdr.e64.e_shoff) != sizeof (x32))
+                                        return (ctf_set_open_errno(errp,
+                                            errno));
+
+                                shnum = x32.sh_size;
+                                shstrndx = x32.sh_link;
+                        } else {
+                                Elf64_Shdr x64;
+
+                                if (pread64(fd, &x64, sizeof (x64),
+                                    hdr.e64.e_shoff) != sizeof (x64))
+                                        return (ctf_set_open_errno(errp,
+                                            errno));
+
+                                shnum = x64.sh_size;
+                                shstrndx = x64.sh_link;
+                        }
+                }
+
+                if (shstrndx >= shnum)
                         return (ctf_set_open_errno(errp, ECTF_CORRUPT));
 
-                n = hdr.e64.e_shnum;
-                nbytes = sizeof (GElf_Shdr) * n;
+                nbytes = sizeof (GElf_Shdr) * shnum;
 
                 if ((sp = malloc(nbytes)) == NULL)
                         return (ctf_set_open_errno(errp, errno));
 
                 /*

@@ -289,19 +316,19 @@
                  * from e_shoff so we can locate sections of interest.
                  */
                 if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) {
                         Elf32_Shdr *sp32;
 
-                        nbytes = sizeof (Elf32_Shdr) * n;
+                        nbytes = sizeof (Elf32_Shdr) * shnum;
 
                         if ((sp32 = malloc(nbytes)) == NULL || pread64(fd,
                             sp32, nbytes, hdr.e64.e_shoff) != nbytes) {
                                 free(sp);
                                 return (ctf_set_open_errno(errp, errno));
                         }
 
-                        for (i = 0; i < n; i++)
+                        for (i = 0; i < shnum; i++)
                                 shdr_to_gelf(&sp32[i], &sp[i]);
 
                         free(sp32);
 
                 } else if (pread64(fd, sp, nbytes, hdr.e64.e_shoff) != nbytes) {

@@ -311,37 +338,37 @@
 
                 /*
                  * Now mmap the section header strings section so that we can
                  * perform string comparison on the section names.
                  */
-                strs_mapsz = sp[hdr.e64.e_shstrndx].sh_size +
-                    (sp[hdr.e64.e_shstrndx].sh_offset & ~_PAGEMASK);
+                strs_mapsz = sp[shstrndx].sh_size +
+                    (sp[shstrndx].sh_offset & ~_PAGEMASK);
 
                 strs_map = mmap64(NULL, strs_mapsz, PROT_READ, MAP_PRIVATE,
-                    fd, sp[hdr.e64.e_shstrndx].sh_offset & _PAGEMASK);
+                    fd, sp[shstrndx].sh_offset & _PAGEMASK);
 
                 strs = (const char *)strs_map +
-                    (sp[hdr.e64.e_shstrndx].sh_offset & ~_PAGEMASK);
+                    (sp[shstrndx].sh_offset & ~_PAGEMASK);
 
                 if (strs_map == MAP_FAILED) {
                         free(sp);
                         return (ctf_set_open_errno(errp, ECTF_MMAP));
                 }
 
                 /*
                  * Iterate over the section header array looking for the CTF
                  * section and symbol table.  The strtab is linked to symtab.
                  */
-                for (i = 0; i < n; i++) {
+                for (i = 0; i < shnum; i++) {
                         const GElf_Shdr *shp = &sp[i];
                         const GElf_Shdr *lhp = &sp[shp->sh_link];
 
-                        if (shp->sh_link >= hdr.e64.e_shnum)
+                        if (shp->sh_link >= shnum)
                                 continue; /* corrupt sh_link field */
 
-                        if (shp->sh_name >= sp[hdr.e64.e_shstrndx].sh_size ||
-                            lhp->sh_name >= sp[hdr.e64.e_shstrndx].sh_size)
+                        if (shp->sh_name >= sp[shstrndx].sh_size ||
+                            lhp->sh_name >= sp[shstrndx].sh_size)
                                 continue; /* corrupt sh_name field */
 
                         if (shp->sh_type == SHT_PROGBITS &&
                             strcmp(strs + shp->sh_name, _CTF_SECTION) == 0) {
                                 ctfsect.cts_name = strs + shp->sh_name;