Mercurial > illumos > illumos-gate
changeset 942:8cf53d6a7d2e
PSARC 2005/689 ELF Extended Program Headers
6317969 elfheader limited to 65535 segments
6317980 coredump elfheader doesn't reflect the correct number of dumped segments
6343698 p-tools affected by 6317980 : coredump elfheader incorrectly states number of dumped segments
6350070 stub for shmgetid() returns the wrong default value
line wrap: on
line diff
--- a/usr/src/cmd/mdb/common/mdb/mdb_gelf.c Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/cmd/mdb/common/mdb/mdb_gelf.c Thu Nov 17 11:42:26 2005 -0800 @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -48,15 +48,15 @@ static mdb_gelf_file_t * gelf_sect_init(mdb_gelf_file_t *gf) { - mdb_gelf_sect_t *gsp, *shstr = &gf->gf_sects[gf->gf_ehdr.e_shstrndx]; + mdb_gelf_sect_t *gsp, *shstr = &gf->gf_sects[gf->gf_shstrndx]; GElf_Half i, npbit = 0; GElf_Shdr *shp; GElf_Phdr *gpp; if (gf->gf_mode == GF_PROGRAM) - gf->gf_ehdr.e_shnum = 0; /* Simplifies other code paths */ + gf->gf_shnum = 0; /* Simplifies other code paths */ - if (gf->gf_ehdr.e_shnum == 0) + if (gf->gf_shnum == 0) return (gf); /* If no section headers we're done here */ if (IOP_SEEK(gf->gf_io, shstr->gs_shdr.sh_offset, SEEK_SET) == -1) { @@ -73,7 +73,7 @@ return (NULL); } - for (gsp = gf->gf_sects, i = 0; i < gf->gf_ehdr.e_shnum; i++, gsp++) { + for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) { shp = &gsp->gs_shdr; gsp->gs_name = (const char *)shstr->gs_data + shp->sh_name; @@ -101,13 +101,13 @@ */ if (gf->gf_ehdr.e_type == ET_REL && npbit != 0) { gf->gf_phdrs = mdb_zalloc(sizeof (GElf_Phdr) * npbit, UM_SLEEP); - gf->gf_ehdr.e_phnum = npbit; + gf->gf_phnum = npbit; gf->gf_npload = npbit; gpp = gf->gf_phdrs; gsp = gf->gf_sects; - for (i = 0; i < gf->gf_ehdr.e_shnum; i++, gsp++) { + for (i = 0; i < gf->gf_shnum; i++, gsp++) { shp = &gsp->gs_shdr; if ((shp->sh_type == SHT_PROGBITS) && @@ -238,9 +238,9 @@ size_t nbytes; mdb_dprintf(MDB_DBG_ELF, "loading %s section headers (%hu entries)\n", - IOP_NAME(gf->gf_io), gf->gf_ehdr.e_shnum); + IOP_NAME(gf->gf_io), gf->gf_shnum); - if (gf->gf_ehdr.e_shnum == 0) + if (gf->gf_shnum == 0) return (gf); if (IOP_SEEK(gf->gf_io, (off64_t)gf->gf_ehdr.e_shoff, SEEK_SET) == -1) { @@ -248,7 +248,7 @@ return (NULL); } - nbytes = shdr_size * gf->gf_ehdr.e_shnum; + nbytes = shdr_size * gf->gf_shnum; shdrs = mdb_alloc(nbytes, UM_SLEEP); if (IOP_READ(gf->gf_io, shdrs, nbytes) != nbytes) { @@ -257,13 +257,13 @@ return (NULL); } - gf->gf_sects = mdb_zalloc(sizeof (mdb_gelf_sect_t) * - gf->gf_ehdr.e_shnum, UM_SLEEP); + gf->gf_sects = mdb_zalloc(sizeof (mdb_gelf_sect_t) * gf->gf_shnum, + UM_SLEEP); shp = shdrs; gsp = gf->gf_sects; - for (i = 0; i < gf->gf_ehdr.e_shnum; i++, shp += shdr_size, gsp++) + for (i = 0; i < gf->gf_shnum; i++, shp += shdr_size, gsp++) (void) elf2gelf(shp, &gsp->gs_shdr); mdb_free(shdrs, nbytes); @@ -359,10 +359,10 @@ GElf_Phdr *gpp; size_t nbytes; - mdb_dprintf(MDB_DBG_ELF, "loading %s program headers (%hu entries)\n", - IOP_NAME(gf->gf_io), gf->gf_ehdr.e_phnum); + mdb_dprintf(MDB_DBG_ELF, "loading %s program headers (%lu entries)\n", + IOP_NAME(gf->gf_io), gf->gf_phnum); - if (gf->gf_ehdr.e_phnum == 0) + if (gf->gf_phnum == 0) return (gf); if (IOP_SEEK(gf->gf_io, (off64_t)gf->gf_ehdr.e_phoff, SEEK_SET) == -1) { @@ -370,7 +370,7 @@ return (NULL); } - nbytes = phdr_size * gf->gf_ehdr.e_phnum; + nbytes = phdr_size * gf->gf_phnum; phdrs = mdb_alloc(nbytes, UM_SLEEP); if (IOP_READ(gf->gf_io, phdrs, nbytes) != nbytes) { @@ -379,8 +379,7 @@ return (NULL); } - gf->gf_phdrs = mdb_zalloc(sizeof (GElf_Phdr) * - gf->gf_ehdr.e_phnum, UM_SLEEP); + gf->gf_phdrs = mdb_zalloc(sizeof (GElf_Phdr) * gf->gf_phnum, UM_SLEEP); php = phdrs; gpp = gf->gf_phdrs; @@ -389,7 +388,7 @@ * Iterate through the list of phdrs locating those that are of type * PT_LOAD; increment gf_npload so we know how many are loadable. */ - for (i = 0; i < gf->gf_ehdr.e_phnum; i++, php += phdr_size, gpp++) { + for (i = 0; i < gf->gf_phnum; i++, php += phdr_size, gpp++) { (void) elf2gelf(php, gpp); if (gpp->p_type != PT_LOAD) continue; @@ -407,18 +406,18 @@ * arranges for the PT_LOAD phdrs with non-zero virtual addresses * to come first sorted by virtual address. This means that we * can access the complete phdr table by examining the array - * gf->gf_phdrs[0 .. gf->gf_ehdr.e_phnum - 1], and we can access a - * sorted array of valid PT_LOAD pdhrs by examining the array + * gf->gf_phdrs[0 .. gf->gf_phnum - 1], and we can access a sorted + * array of valid PT_LOAD pdhrs by examining the array * gf->gf_phdrs[0 .. gf->gf_npload - 1]. */ - qsort(gf->gf_phdrs, gf->gf_ehdr.e_phnum, sizeof (GElf_Phdr), + qsort(gf->gf_phdrs, gf->gf_phnum, sizeof (GElf_Phdr), gelf_phdr_compare); /* * Locate the PT_DYNAMIC Phdr if one is present; we save this * Phdr pointer in gf->gf_dynp for future use. */ - for (gpp = gf->gf_phdrs, i = 0; i < gf->gf_ehdr.e_phnum; i++, gpp++) { + for (gpp = gf->gf_phdrs, i = 0; i < gf->gf_phnum; i++, gpp++) { if (gpp->p_type == PT_DYNAMIC) { mdb_dprintf(MDB_DBG_ELF, "PT_DYNAMIC " "filesize = %lluULL off=%lluULL\n", @@ -502,14 +501,14 @@ } else { mdb_gelf_sect_t *gsp = gf->gf_sects; - for (i = 0; i < gf->gf_ehdr.e_shnum; i++, gsp++) { + for (i = 0; i < gf->gf_shnum; i++, gsp++) { if (gsp->gs_shdr.sh_type == SHT_DYNAMIC) { dyn_addr = gsp->gs_shdr.sh_offset; break; } } - if (i == gf->gf_ehdr.e_shnum) + if (i == gf->gf_shnum) return (NULL); /* No SHT_DYNAMIC entry was found */ } @@ -543,7 +542,7 @@ } static mdb_gelf_file_t * -gelf32_init(mdb_gelf_file_t *gf, const Elf32_Ehdr *ehdr) +gelf32_init(mdb_gelf_file_t *gf, mdb_io_t *io, const Elf32_Ehdr *ehdr) { /* * Convert the Elf32_Ehdr to a GElf_Ehdr @@ -564,6 +563,38 @@ gf->gf_ehdr.e_shnum = ehdr->e_shnum; gf->gf_ehdr.e_shstrndx = ehdr->e_shstrndx; + gf->gf_shnum = gf->gf_ehdr.e_shnum; + gf->gf_shstrndx = gf->gf_ehdr.e_shstrndx; + gf->gf_phnum = gf->gf_ehdr.e_phnum; + + if ((gf->gf_shnum == 0 && ehdr->e_shoff != 0) || + gf->gf_shstrndx == SHN_XINDEX || gf->gf_phnum == PN_XNUM) { + Elf32_Shdr shdr0; + + if (ehdr->e_shoff == 0) + return (NULL); + + if (IOP_SEEK(io, (off64_t)ehdr->e_shoff, SEEK_SET) == -1) { + warn("failed to seek %s", IOP_NAME(io)); + return (NULL); + } + + if (IOP_READ(io, &shdr0, sizeof (shdr0)) != sizeof (shdr0)) { + warn("failed to read extended ELF header from %s", + IOP_NAME(io)); + return (NULL); + } + + if (gf->gf_shnum == 0) + gf->gf_shnum = shdr0.sh_size; + + if (gf->gf_shstrndx == SHN_XINDEX) + gf->gf_shstrndx = shdr0.sh_link; + + if (gf->gf_phnum == PN_XNUM) + gf->gf_phnum = shdr0.sh_info; + } + /* * Initialize the section and program headers. We skip initializing * the section headers if this is a program image because they are @@ -584,13 +615,45 @@ } static mdb_gelf_file_t * -gelf64_init(mdb_gelf_file_t *gf, Elf64_Ehdr *ehdr) +gelf64_init(mdb_gelf_file_t *gf, mdb_io_t *io, Elf64_Ehdr *ehdr) { /* * Save a copy of the ELF file header */ bcopy(ehdr, &gf->gf_ehdr, sizeof (Elf64_Ehdr)); + gf->gf_shnum = gf->gf_ehdr.e_shnum; + gf->gf_shstrndx = gf->gf_ehdr.e_shstrndx; + gf->gf_phnum = gf->gf_ehdr.e_phnum; + + if ((gf->gf_shnum == 0 && ehdr->e_shoff != 0) || + gf->gf_shstrndx == SHN_XINDEX || gf->gf_phnum == PN_XNUM) { + Elf64_Shdr shdr0; + + if (ehdr->e_shoff == 0) + return (NULL); + + if (IOP_SEEK(io, (off64_t)ehdr->e_shoff, SEEK_SET) == -1) { + warn("failed to seek %s", IOP_NAME(io)); + return (NULL); + } + + if (IOP_READ(io, &shdr0, sizeof (shdr0)) != sizeof (shdr0)) { + warn("failed to read extended ELF header from %s", + IOP_NAME(io)); + return (NULL); + } + + if (gf->gf_shnum == 0) + gf->gf_shnum = shdr0.sh_size; + + if (gf->gf_shstrndx == SHN_XINDEX) + gf->gf_shstrndx = shdr0.sh_link; + + if (gf->gf_phnum == PN_XNUM) + gf->gf_phnum = shdr0.sh_info; + } + /* * Initialize the section and program headers. We skip initializing * the section headers if this is a program image because they are @@ -682,7 +745,7 @@ switch (ehdr.h32.e_ident[EI_CLASS]) { case ELFCLASS32: - gf = gelf32_init(gf, &ehdr.h32); + gf = gelf32_init(gf, io, &ehdr.h32); break; case ELFCLASS64: @@ -697,7 +760,7 @@ goto err; } - gf = gelf64_init(gf, &ehdr.h64); + gf = gelf64_init(gf, io, &ehdr.h64); break; default: @@ -714,7 +777,7 @@ err: if (gf != NULL) { if (gf->gf_sects != NULL) { - mdb_free(gf->gf_sects, gf->gf_ehdr.e_shnum * + mdb_free(gf->gf_sects, gf->gf_shnum * sizeof (mdb_gelf_sect_t)); } mdb_free(gf, sizeof (mdb_gelf_file_t)); @@ -728,16 +791,15 @@ mdb_gelf_sect_t *gsp; GElf_Half i; - for (gsp = gf->gf_sects, i = 0; i < gf->gf_ehdr.e_shnum; i++, gsp++) { + for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) { if (gsp->gs_data != NULL) mdb_free(gsp->gs_data, gsp->gs_shdr.sh_size); } mdb_free(gf->gf_sects, - gf->gf_ehdr.e_shnum * sizeof (mdb_gelf_sect_t)); + gf->gf_shnum * sizeof (mdb_gelf_sect_t)); - mdb_free(gf->gf_phdrs, - gf->gf_ehdr.e_phnum * sizeof (GElf_Phdr)); + mdb_free(gf->gf_phdrs, gf->gf_phnum * sizeof (GElf_Phdr)); mdb_io_rele(gf->gf_io); mdb_free(gf, sizeof (mdb_gelf_file_t)); @@ -871,7 +933,7 @@ } if (gst->gst_ehdr->e_type == ET_REL && gst->gst_file != NULL) { - GElf_Word smax = gst->gst_ehdr->e_shnum; + GElf_Word smax = gst->gst_file->gf_shnum; mdb_gelf_sect_t *gsp; for (sym = gst->gst_dsect->gs_data, i = 0; i < n; i++, sym++) { @@ -964,7 +1026,7 @@ } if (gst->gst_ehdr->e_type == ET_REL && gst->gst_file != NULL) { - GElf_Word smax = gst->gst_ehdr->e_shnum; + GElf_Word smax = gst->gst_file->gf_shnum; mdb_gelf_sect_t *gsp; for (sym = gst->gst_dsect->gs_data, i = 0; i < n; i++, sym++) { @@ -999,7 +1061,7 @@ * Examine the sh_link field in the the Elf header to get the name * of the corresponding strings section */ - for (gsp = gf->gf_sects, i = 0; i < gf->gf_ehdr.e_shnum; i++, gsp++) { + for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) { if (gsp->gs_shdr.sh_type == elftype) { dsname = gsp->gs_name; link = gsp->gs_shdr.sh_link; @@ -1010,12 +1072,12 @@ if (dsname == NULL) return (NULL); - if (link > gf->gf_ehdr.e_shnum) { + if (link > gf->gf_shnum) { /* * Invalid link number due to corrupt elf file. */ warn("link number %ud larger than number of sections %d\n", - link, gf->gf_ehdr.e_shnum); + link, gf->gf_shnum); return (NULL); } @@ -1045,14 +1107,14 @@ gst->gst_id = 0; gst->gst_tabid = tabid; - for (gsp = gf->gf_sects, i = 0; i < gf->gf_ehdr.e_shnum; i++, gsp++) { + for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) { if (strcmp(gsp->gs_name, dsname) == 0) { gst->gst_dsect = gsp; break; } } - for (gsp = gf->gf_sects, i = 0; i < gf->gf_ehdr.e_shnum; i++, gsp++) { + for (gsp = gf->gf_sects, i = 0; i < gf->gf_shnum; i++, gsp++) { if (strcmp(gsp->gs_name, ssname) == 0) { gst->gst_ssect = gsp; break;
--- a/usr/src/cmd/mdb/common/mdb/mdb_gelf.h Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/cmd/mdb/common/mdb/mdb_gelf.h Thu Nov 17 11:42:26 2005 -0800 @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -61,6 +61,9 @@ GElf_Phdr *gf_dynp; /* Pointer to PT_DYNAMIC phdr */ GElf_Dyn *gf_dyns; /* Array of dynamic entries */ size_t gf_ndyns; /* Number of dynamic entries */ + size_t gf_shnum; /* Number of section headers */ + size_t gf_shstrndx; /* Index of section string table */ + size_t gf_phnum; /* Number of program headers */ mdb_gelf_sect_t *gf_sects; /* Array of section structs */ mdb_io_t *gf_io; /* I/o backend for ELF file */ int gf_mode; /* Mode flag (see above) */
--- a/usr/src/cmd/sgs/elfdump/common/elfdump.c Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/cmd/sgs/elfdump/common/elfdump.c Thu Nov 17 11:42:26 2005 -0800 @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -309,8 +309,8 @@ * Print section headers. */ static void -sections(const char *file, Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, - const char *name) +sections(const char *file, Cache *cache, GElf_Word shnum, GElf_Word phnum, + GElf_Ehdr *ehdr, const char *name) { GElf_Word cnt; Cache * _cache; @@ -354,8 +354,8 @@ } static void -unwind(Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, const char *name, - const char *file, Elf *elf) +unwind(Cache *cache, GElf_Word shnum, GElf_Word phnum, GElf_Ehdr *ehdr, + const char *name, const char *file, Elf *elf) { GElf_Word cnt; GElf_Phdr unwind_phdr; @@ -368,7 +368,7 @@ unwind_phdr.p_type = PT_NULL; - for (cnt = 0; cnt < ehdr->e_phnum; cnt++) { + for (cnt = 0; cnt < phnum; cnt++) { GElf_Phdr phdr; if (gelf_getphdr(elf, cnt, &phdr) == NULL) { @@ -661,8 +661,8 @@ * this should be accompanied with a program header. */ static void -cap(const char *file, Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, - Elf *elf) +cap(const char *file, Cache *cache, GElf_Word shnum, GElf_Word phnum, + GElf_Ehdr *ehdr, Elf *elf) { GElf_Word cnt; GElf_Shdr * cshdr = 0; @@ -673,7 +673,7 @@ /* * Determine if a hardware/software capabilities header exists. */ - for (cnt = 0; cnt < ehdr->e_phnum; cnt++) { + for (cnt = 0; cnt < phnum; cnt++) { GElf_Phdr phdr; if (gelf_getphdr(elf, cnt, &phdr) == NULL) { @@ -763,8 +763,8 @@ * Print the interpretor. */ static void -interp(const char *file, Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, - Elf *elf) +interp(const char *file, Cache *cache, GElf_Word shnum, GElf_Word phnum, + GElf_Ehdr *ehdr, Elf *elf) { GElf_Word cnt; GElf_Shdr * ishdr = 0; @@ -775,7 +775,7 @@ /* * Determine if an interp header exists. */ - for (cnt = 0; cnt < ehdr->e_phnum; cnt++) { + for (cnt = 0; cnt < phnum; cnt++) { GElf_Phdr phdr; if (gelf_getphdr(elf, cnt, &phdr) == NULL) { @@ -1151,8 +1151,8 @@ * Search for and process any symbol tables. */ static void -symbols(Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, const char *name, - Cache *versymcache, const char *file) +symbols(Cache *cache, GElf_Word shnum, GElf_Word phnum, GElf_Ehdr *ehdr, + const char *name, Cache *versymcache, const char *file) { GElf_Word cnt; char is_core = (ehdr->e_type == ET_CORE); @@ -1371,8 +1371,8 @@ * Search for and process any relocation sections. */ static void -reloc(Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, const char *name, - const char *file, uint32_t flags) +reloc(Cache *cache, GElf_Word shnum, GElf_Word phnum, GElf_Ehdr *ehdr, + const char *name, const char *file, uint32_t flags) { GElf_Word cnt; @@ -2281,7 +2281,8 @@ static void -got(Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, const char *file) +got(Cache *cache, GElf_Word shnum, GElf_Word phnum, GElf_Ehdr *ehdr, + const char *file) { Cache *gotcache = 0, *symtab = 0, *_cache; GElf_Addr gotbgn, gotend; @@ -2524,8 +2525,8 @@ GElf_Ehdr ehdr; Elf_Data *data; uint_t cnt; - GElf_Word shnum; - size_t shstrndx, _shnum; + GElf_Word shnum, phnum; + size_t shstrndx, _shnum, _phnum; GElf_Shdr nameshdr; GElf_Shdr shdr0; GElf_Shdr *_shdr0; @@ -2538,17 +2539,25 @@ return; } - if (elf_getshnum(elf, &_shnum) == NULL) { + if (elf_getshnum(elf, &_shnum) == 0) { failure(file, MSG_ORIG(MSG_ELF_GETSHNUM)); return; } /* LINTED */ shnum = (GElf_Word)_shnum; - if (elf_getshstrndx(elf, &shstrndx) == NULL) { + if (elf_getshstrndx(elf, &shstrndx) == 0) { failure(file, MSG_ORIG(MSG_ELF_GETSHSTRNDX)); return; } + + if (elf_getphnum(elf, &_phnum) == 0) { + failure(file, MSG_ORIG(MSG_ELF_GETPHNUM)); + return; + } + /* LINTED */ + phnum = (GElf_Word)_phnum; + if ((scn = elf_getscn(elf, 0)) != NULL) { if ((_shdr0 = gelf_getshdr(scn, &shdr0)) == NULL) { failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); @@ -2568,10 +2577,10 @@ /* * Print the program headers. */ - if ((flags & FLG_PHDR) && ehdr.e_phnum) { + if ((flags & FLG_PHDR) && phnum != 0) { GElf_Phdr phdr; - for (cnt = 0; cnt < ehdr.e_phnum; cnt++) { + for (cnt = 0; cnt < phnum; cnt++) { if (gelf_getphdr(elf, cnt, &phdr) == NULL) { failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); return; @@ -2585,16 +2594,16 @@ /* - * If there are no sections (core files), or if we don't want - * any section information we might as well return now. + * Return now if there are no section, if there's just one section to + * act as an extension of the ELF header, or if on section information + * was requested. */ - if ((shnum == 0) || (flags && (flags & ~(FLG_EHDR | FLG_PHDR)) == 0)) { + if ((shnum <= 1) || (flags && (flags & ~(FLG_EHDR | FLG_PHDR)) == 0)) { if ((ehdr.e_type == ET_CORE) && (flags & FLG_NOTE)) note(0, shnum, 0, file); return; } - /* * Obtain the .shstrtab data buffer to provide the required section * name strings. @@ -2704,21 +2713,21 @@ } if (flags & FLG_SHDR) - sections(file, cache, shnum, &ehdr, Nname); + sections(file, cache, shnum, phnum, &ehdr, Nname); if (flags & FLG_INTERP) - interp(file, cache, shnum, &ehdr, elf); + interp(file, cache, shnum, phnum, &ehdr, elf); versymcache = versions(cache, shnum, file, flags); if (flags & FLG_SYMBOLS) - symbols(cache, shnum, &ehdr, Nname, versymcache, file); + symbols(cache, shnum, phnum, &ehdr, Nname, versymcache, file); if (flags & FLG_HASH) hash(cache, shnum, Nname, file, flags); if (flags & FLG_GOT) - got(cache, shnum, &ehdr, file); + got(cache, shnum, phnum, &ehdr, file); if (flags & FLG_GROUP) group(cache, shnum, Nname, file, flags); @@ -2727,7 +2736,7 @@ syminfo(cache, shnum, file); if (flags & FLG_RELOC) - reloc(cache, shnum, &ehdr, Nname, file, flags); + reloc(cache, shnum, phnum, &ehdr, Nname, file, flags); if (flags & FLG_DYNAMIC) dynamic(cache, shnum, &ehdr, file); @@ -2742,10 +2751,10 @@ checksum(elf); if (flags & FLG_CAP) - cap(file, cache, shnum, &ehdr, elf); + cap(file, cache, shnum, phnum, &ehdr, elf); if (flags & FLG_UNWIND) - unwind(cache, shnum, &ehdr, Nname, file, elf); + unwind(cache, shnum, phnum, &ehdr, Nname, file, elf); free(cache); }
--- a/usr/src/cmd/sgs/elfdump/common/elfdump.msg Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/cmd/sgs/elfdump/common/elfdump.msg Thu Nov 17 11:42:26 2005 -0800 @@ -229,6 +229,7 @@ @ MSG_ELF_GETARSYM "elf_getarsym" @ MSG_ELF_RAND "elf_rand" @ MSG_ELF_BEGIN "elf_begin" +@ MSG_ELF_GETPHNUM "elf_getphnum" @ MSG_ELF_GETSHNUM "elf_getshnum" @ MSG_ELF_GETSHSTRNDX "elf_getshstrndx" @ MSG_ELF_ARSYM "ARSYM"
--- a/usr/src/cmd/sgs/libelf/Makefile.com Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/cmd/sgs/libelf/Makefile.com Thu Nov 17 11:42:26 2005 -0800 @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -36,7 +36,7 @@ getarhdr.o getarsym.o getbase.o getdata.o \ getehdr.o getident.o getphdr.o getscn.o \ getshdr.o \ - getshnum.o getshstrndx.o \ + getphnum.o getshnum.o getshstrndx.o \ hash.o input.o kind.o \ ndxscn.o newdata.o newehdr.o newphdr.o \ newscn.o next.o nextscn.o output.o \
--- a/usr/src/cmd/sgs/libelf/common/gelf.c Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/cmd/sgs/libelf/common/gelf.c Thu Nov 17 11:42:26 2005 -0800 @@ -219,15 +219,15 @@ gelf_getphdr(Elf *elf, int ndx, GElf_Phdr *dst) { int class; - GElf_Ehdr ehdr; + size_t phnum; if (elf == NULL) return (NULL); - if (gelf_getehdr(elf, &ehdr) == NULL) + if (elf_getphnum(elf, &phnum) == 0) return (NULL); - if (ehdr.e_phnum < ndx) { + if (phnum <= ndx) { _elf_seterr(EREQ_RAND, 0); return (NULL); } @@ -266,15 +266,15 @@ gelf_update_phdr(Elf *elf, int ndx, GElf_Phdr *src) { int class; - GElf_Ehdr ehdr; + size_t phnum; if (elf == NULL) return (0); - if (gelf_getehdr(elf, &ehdr) == NULL) - return (0); + if (elf_getphnum(elf, &phnum) == 0) + return (NULL); - if (ehdr.e_phnum < ndx) { + if (phnum < ndx) { _elf_seterr(EREQ_RAND, 0); return (0); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/sgs/libelf/common/getphnum.c Thu Nov 17 11:42:26 2005 -0800 @@ -0,0 +1,59 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <string.h> +#include <gelf.h> +#include <decl.h> +#include <msg.h> + +int +elf_getphnum(Elf *elf, size_t *phnum) +{ + GElf_Ehdr ehdr; + Elf_Scn *scn; + GElf_Shdr shdr0; + + if (gelf_getehdr(elf, &ehdr) == NULL) + return (0); + + if (ehdr.e_phnum != PN_XNUM) { + *phnum = ehdr.e_phnum; + return (1); + } + + if ((scn = elf_getscn(elf, 0)) == NULL || + gelf_getshdr(scn, &shdr0) == NULL) + return (0); + + if (shdr0.sh_info == 0) + *phnum = ehdr.e_phnum; + else + *phnum = shdr0.sh_info; + + return (1); +}
--- a/usr/src/cmd/sgs/libelf/common/llib-lelf Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/cmd/sgs/libelf/common/llib-lelf Thu Nov 17 11:42:26 2005 -0800 @@ -23,7 +23,7 @@ /* PROTOLIB1 */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -144,6 +144,7 @@ Elf_Data * _elf_getdata(Elf_Scn *, Elf_Data *); char * elf_getident(Elf *, size_t *); char * _elf_getident(Elf *, size_t *); +int elf_getphnum(Elf *, size_t *); int elf_getshnum(Elf *, size_t *); int elf_getshstrndx(Elf *, size_t *); Elf_Scn * elf_getscn(Elf *elf, size_t);
--- a/usr/src/cmd/sgs/libelf/demo/dcom.c Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/cmd/sgs/libelf/demo/dcom.c Thu Nov 17 11:42:26 2005 -0800 @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -101,6 +101,7 @@ GElf_Phdr tphdr; size_t shstrndx; size_t shnum; + size_t phnum; int *shndx; int ndx = 1; int off = 0; @@ -124,6 +125,12 @@ return; } + if (elf_getphnum(elf, &phnum) == 0) { + (void) fprintf(stderr, "%s: elf_getphnum() failed: %s\n", + file, elf_errmsg(0)); + return; + } + /* * shndx is an array used to map the current section * indexes to the new section indexes. @@ -313,14 +320,14 @@ /* * Duplicate all program headers contained in the ELF file. */ - if (ehdr.e_phnum) { - if (gelf_newphdr(telf, ehdr.e_phnum) == 0) { + if (phnum != 0) { + if (gelf_newphdr(telf, phnum) == 0) { (void) fprintf(stderr, "%s: elf_newphdr() failed: %s\n", file, elf_errmsg(0)); return; } - for (ndx = 0; ndx < (int)ehdr.e_phnum; ndx++) { + for (ndx = 0; ndx < (int)phnum; ndx++) { if (gelf_getphdr(elf, ndx, &phdr) == 0 || gelf_getphdr(telf, ndx, &tphdr) == 0) { (void) fprintf(stderr,
--- a/usr/src/cmd/sgs/libelf/spec/elf.spec Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/cmd/sgs/libelf/spec/elf.spec Thu Nov 17 11:42:26 2005 -0800 @@ -27,6 +27,12 @@ # cmd/sgs/libelf/spec/elf.spec +function elf_getphnum +include <libelf.h> +declaration int elf_getphnum(Elf *elf, size_t *phnum) +version SUNW_1.6 +end + function elf_getshnum include <libelf.h> declaration int elf_getshnum(Elf *elf, size_t *shnum)
--- a/usr/src/cmd/sgs/libelf/spec/versions Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/cmd/sgs/libelf/spec/versions Thu Nov 17 11:42:26 2005 -0800 @@ -30,6 +30,7 @@ # (when it did contain symbols explicitly) may depend on it. # sparc { + SUNW_1.6: {SUNW_1.5}; SUNW_1.5: {SUNW_1.4}; SUNW_1.4: {SUNW_1.3}; SUNW_1.3: {SUNW_1.2}; @@ -39,6 +40,7 @@ SUNWprivate_1.1; } sparcv9 { + SUNW_1.6: {SUNW_1.5}; SUNW_1.5: {SUNW_1.4}; SUNW_1.4: {SUNW_1.3}; SUNW_1.3: {SUNW_1.2}; @@ -48,6 +50,7 @@ SUNWprivate_1.1; } i386 { + SUNW_1.6: {SUNW_1.5}; SUNW_1.5: {SUNW_1.4}; SUNW_1.4: {SUNW_1.3}; SUNW_1.3: {SUNW_1.2}; @@ -57,6 +60,7 @@ SUNWprivate_1.1; } amd64 { + SUNW_1.6: {SUNW_1.5}; SUNW_1.5: {SUNW_1.4}; SUNW_1.4: {SUNW_1.3}; SUNW_1.3: {SUNW_1.2};
--- a/usr/src/cmd/sgs/liblddbg/common/elf.c Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/cmd/sgs/liblddbg/common/elf.c Thu Nov 17 11:42:26 2005 -0800 @@ -20,8 +20,8 @@ * CDDL HEADER END */ /* - * Copyright 1998-2003 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -124,11 +124,16 @@ dbg_print(MSG_ORIG(MSG_ELF_SHOFF), EC_OFF(ehdr->e_shoff), ehdr->e_shentsize, ehdr->e_shnum); - dbg_print(MSG_ORIG(MSG_ELF_PHOFF), EC_OFF(ehdr->e_phoff), - ehdr->e_phentsize, ehdr->e_phnum); + if (ehdr->e_phnum == PN_XNUM) + dbg_print(MSG_ORIG(MSG_ELFX_PHOFF), EC_OFF(ehdr->e_phoff), + ehdr->e_phentsize); + else + dbg_print(MSG_ORIG(MSG_ELF_PHOFF), EC_OFF(ehdr->e_phoff), + ehdr->e_phentsize, ehdr->e_phnum); - if ((ehdr->e_shnum != 0) || (shdr0 == NULL) || - (shdr0->sh_size == 0)) + if (shdr0 == NULL || + (ehdr->e_phnum != PN_XNUM && + (ehdr->e_shnum != 0 || shdr0->sh_size))) return; /* @@ -138,17 +143,27 @@ dbg_print(MSG_ORIG(MSG_SHD_ADDR), EC_ADDR(shdr0->sh_addr), /* LINTED */ conv_secflg_str(ehdr->e_machine, shdr0->sh_flags)); - dbg_print(MSG_ORIG(MSG_SHD0_SIZE), EC_XWORD(shdr0->sh_size), - conv_sectyp_str(ehdr->e_machine, shdr0->sh_type)); + if (ehdr->e_shnum == 0) + dbg_print(MSG_ORIG(MSG_SHD0_SIZE), EC_XWORD(shdr0->sh_size), + conv_sectyp_str(ehdr->e_machine, shdr0->sh_type)); + else + dbg_print(MSG_ORIG(MSG_SHD_SIZE), EC_XWORD(shdr0->sh_size), + conv_sectyp_str(ehdr->e_machine, shdr0->sh_type)); dbg_print(MSG_ORIG(MSG_SHD_OFFSET), EC_OFF(shdr0->sh_offset), EC_XWORD(shdr0->sh_entsize)); - if (ehdr->e_shstrndx == SHN_XINDEX) - dbg_print(MSG_ORIG(MSG_SHD0_LINK), EC_WORD(shdr0->sh_link), - /* LINTED */ - conv_secinfo_str(shdr0->sh_info, shdr0->sh_flags)); + + if (ehdr->e_shstrndx == SHN_XINDEX && ehdr->e_phnum == PN_XNUM) + dbg_print(MSG_ORIG(MSG_SHD0_LINK1), EC_WORD(shdr0->sh_link), + EC_WORD(shdr0->sh_info)); + else if (ehdr->e_shstrndx == SHN_XINDEX) + dbg_print(MSG_ORIG(MSG_SHD0_LINK2), EC_WORD(shdr0->sh_link), + EC_WORD(shdr0->sh_info)); + else if (ehdr->e_phnum == PN_XNUM) + dbg_print(MSG_ORIG(MSG_SHD0_LINK3), EC_WORD(shdr0->sh_link), + EC_WORD(shdr0->sh_info)); else - dbg_print(MSG_ORIG(MSG_SHD_LINK), EC_WORD(shdr0->sh_link), - /* LINTED */ - conv_secinfo_str(shdr0->sh_info, shdr0->sh_flags)); + dbg_print(MSG_ORIG(MSG_SHD0_LINK4), EC_WORD(shdr0->sh_link), + EC_WORD(shdr0->sh_info)); + dbg_print(MSG_ORIG(MSG_SHD_ALIGN), EC_XWORD(shdr0->sh_addralign)); }
--- a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg Thu Nov 17 11:42:26 2005 -0800 @@ -793,11 +793,16 @@ e_shnum: [sh[0].sh_size]" @ MSG_ELF_PHOFF " e_phoff: %#18llx e_phentsize: %2d \ e_phnum: %2d" +@ MSG_ELFX_PHOFF " e_phoff: %#18llx e_phentsize: %2d \ + e_phnum: [sh[0].sh_info]" # Shdr[0] messages @ MSG_SHD0_TITLE "Section Header[0]: {ELF Ehdr extensions}" @ MSG_SHD0_SIZE " sh_size: %-6lld [shnum] sh_type: %s" -@ MSG_SHD0_LINK " sh_link: %-6d [strndx] sh_info: %s" +@ MSG_SHD0_LINK1 " sh_link: %-6d [strndx] sh_info: %d [phnum]" +@ MSG_SHD0_LINK2 " sh_link: %-6d [strndx] sh_info: %d" +@ MSG_SHD0_LINK3 " sh_link: %-14d sh_info: %d [phnum]" +@ MSG_SHD0_LINK4 " sh_link: %-14d sh_info: %d" # Section header messages
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README Thu Nov 17 11:42:26 2005 -0800 @@ -1068,3 +1068,4 @@ Solaris/SunOS 5.8_x86 patch T109148-40 -------------------------------------------------------------------------------- 6307274 crle bug with LD_LIBRARY_PATH +6317969 elfheader limited to 65535 segments (link-editor components only)
--- a/usr/src/head/libelf.h Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/head/libelf.h Thu Nov 17 11:42:26 2005 -0800 @@ -22,10 +22,9 @@ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ - /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #ifndef _LIBELF_H @@ -192,6 +191,7 @@ Elf32_Phdr *elf32_getphdr _((Elf *)); Elf_Scn *elf_getscn _((Elf *elf, size_t)); Elf32_Shdr *elf32_getshdr _((Elf_Scn *)); +int elf_getphnum _((Elf *, size_t *)); int elf_getshnum _((Elf *, size_t *)); int elf_getshstrndx _((Elf *, size_t *)); unsigned long elf_hash _((const char *));
--- a/usr/src/lib/libproc/common/Pcontrol.h Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/lib/libproc/common/Pcontrol.h Thu Nov 17 11:42:26 2005 -0800 @@ -53,15 +53,15 @@ * These may change without affecting clients of libproc. */ -typedef struct { /* symbol table */ +typedef struct sym_tbl { /* symbol table */ Elf_Data *sym_data; /* start of table */ size_t sym_symn; /* number of entries */ char *sym_strs; /* ptr to strings */ size_t sym_strsz; /* size of string table */ GElf_Shdr sym_hdr; /* symbol table section header */ GElf_Shdr sym_strhdr; /* string table section header */ - Elf *sym_elf; /* faked-up elf handle from core file */ - void *sym_elfmem; /* data for faked-up elf handle */ + Elf *sym_elf; /* faked-up ELF handle from core file */ + void *sym_elfmem; /* data for faked-up ELF handle */ uint_t *sym_byname; /* symbols sorted by name */ uint_t *sym_byaddr; /* symbols sorted by addr */ size_t sym_count; /* number of symbols in each sorted list */ @@ -79,8 +79,8 @@ rd_loadobj_t *file_lo; /* load object structure from rtld_db */ char *file_lname; /* load object name from rtld_db */ char *file_lbase; /* pointer to basename of file_lname */ - Elf *file_elf; /* elf handle so we can close */ - void *file_elfmem; /* data for faked-up elf handle */ + Elf *file_elf; /* ELF handle so we can close */ + void *file_elfmem; /* data for faked-up ELF handle */ sym_tbl_t file_symtab; /* symbol table */ sym_tbl_t file_dynsym; /* dynamic symbol table */ uintptr_t file_dyn_base; /* load address for ET_DYN files */ @@ -135,8 +135,25 @@ #endif } core_info_t; +typedef struct elf_file_header { /* extended ELF header */ + unsigned char e_ident[EI_NIDENT]; + Elf64_Half e_type; + Elf64_Half e_machine; + Elf64_Word e_version; + Elf64_Addr e_entry; + Elf64_Off e_phoff; + Elf64_Off e_shoff; + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_shentsize; + Elf64_Word e_phnum; /* phdr count extended to 32 bits */ + Elf64_Word e_shnum; /* shdr count extended to 32 bits */ + Elf64_Word e_shstrndx; /* shdr string index extended to 32 bits */ +} elf_file_header_t; + typedef struct elf_file { /* convenience for managing ELF files */ - GElf_Ehdr e_hdr; /* ELF file header information */ + elf_file_header_t e_hdr; /* Extended ELF header */ Elf *e_elf; /* ELF library handle */ int e_fd; /* file descriptor */ } elf_file_t;
--- a/usr/src/lib/libproc/common/Pcore.c Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/lib/libproc/common/Pcore.c Thu Nov 17 11:42:26 2005 -0800 @@ -800,7 +800,7 @@ * in a memory backed elf file. */ static void -fake_up_symtab(struct ps_prochandle *P, GElf_Ehdr *ehdr, +fake_up_symtab(struct ps_prochandle *P, const elf_file_header_t *ehdr, GElf_Shdr *symtab, GElf_Shdr *strtab) { size_t size; @@ -829,7 +829,12 @@ if ((b = calloc(1, size)) == NULL) return; - (void) memcpy(&b->ehdr, ehdr, offsetof(GElf_Ehdr, e_entry)); + (void) memcpy(b->ehdr.e_ident, ehdr->e_ident, + sizeof (ehdr->e_ident)); + b->ehdr.e_type = ehdr->e_type; + b->ehdr.e_machine = ehdr->e_machine; + b->ehdr.e_version = ehdr->e_version; + b->ehdr.e_flags = ehdr->e_flags; b->ehdr.e_ehsize = sizeof (b->ehdr); b->ehdr.e_shoff = sizeof (b->ehdr); b->ehdr.e_shentsize = sizeof (b->shdr[0]); @@ -888,7 +893,12 @@ if ((b = calloc(1, size)) == NULL) return; - (void) memcpy(&b->ehdr, ehdr, offsetof(GElf_Ehdr, e_entry)); + (void) memcpy(b->ehdr.e_ident, ehdr->e_ident, + sizeof (ehdr->e_ident)); + b->ehdr.e_type = ehdr->e_type; + b->ehdr.e_machine = ehdr->e_machine; + b->ehdr.e_version = ehdr->e_version; + b->ehdr.e_flags = ehdr->e_flags; b->ehdr.e_ehsize = sizeof (b->ehdr); b->ehdr.e_shoff = sizeof (b->ehdr); b->ehdr.e_shentsize = sizeof (b->shdr[0]); @@ -959,25 +969,6 @@ } static void -core_ehdr_to_gelf(const Elf32_Ehdr *src, GElf_Ehdr *dst) -{ - (void) memcpy(dst->e_ident, src->e_ident, EI_NIDENT); - dst->e_type = src->e_type; - dst->e_machine = src->e_machine; - dst->e_version = src->e_version; - dst->e_entry = (Elf64_Addr)src->e_entry; - dst->e_phoff = (Elf64_Off)src->e_phoff; - dst->e_shoff = (Elf64_Off)src->e_shoff; - dst->e_flags = src->e_flags; - dst->e_ehsize = src->e_ehsize; - dst->e_phentsize = src->e_phentsize; - dst->e_phnum = src->e_phnum; - dst->e_shentsize = src->e_shentsize; - dst->e_shnum = src->e_shnum; - dst->e_shstrndx = src->e_shstrndx; -} - -static void core_phdr_to_gelf(const Elf32_Phdr *src, GElf_Phdr *dst) { dst->p_type = src->p_type; @@ -1044,24 +1035,180 @@ /* * If the file is 64-bit and we are 32-bit, fail with G_LP64. If the - * file is 64-bit and we are 64-bit, re-read the header as a Elf64_Ehdr. - * Otherwise, the file is 32-bit, so convert e32 to a GElf_Ehdr. + * file is 64-bit and we are 64-bit, re-read the header as a Elf64_Ehdr, + * and convert it to a elf_file_header_t. Otherwise, the file is + * 32-bit, so convert e32 to a elf_file_header_t. */ if (e32.e_ident[EI_CLASS] == ELFCLASS64) { #ifdef _LP64 - if (pread64(efp->e_fd, &efp->e_hdr, - sizeof (GElf_Ehdr), 0) != sizeof (GElf_Ehdr)) { + Elf64_Ehdr e64; + + if (pread64(efp->e_fd, &e64, sizeof (e64), 0) != sizeof (e64)) { if (perr != NULL) *perr = G_FORMAT; goto err; } + + (void) memcpy(efp->e_hdr.e_ident, e64.e_ident, EI_NIDENT); + efp->e_hdr.e_type = e64.e_type; + efp->e_hdr.e_machine = e64.e_machine; + efp->e_hdr.e_version = e64.e_version; + efp->e_hdr.e_entry = e64.e_entry; + efp->e_hdr.e_phoff = e64.e_phoff; + efp->e_hdr.e_shoff = e64.e_shoff; + efp->e_hdr.e_flags = e64.e_flags; + efp->e_hdr.e_ehsize = e64.e_ehsize; + efp->e_hdr.e_phentsize = e64.e_phentsize; + efp->e_hdr.e_phnum = (Elf64_Word)e64.e_phnum; + efp->e_hdr.e_shentsize = e64.e_shentsize; + efp->e_hdr.e_shnum = (Elf64_Word)e64.e_shnum; + efp->e_hdr.e_shstrndx = (Elf64_Word)e64.e_shstrndx; #else /* _LP64 */ if (perr != NULL) *perr = G_LP64; goto err; #endif /* _LP64 */ - } else - core_ehdr_to_gelf(&e32, &efp->e_hdr); + } else { + (void) memcpy(efp->e_hdr.e_ident, e32.e_ident, EI_NIDENT); + efp->e_hdr.e_type = e32.e_type; + efp->e_hdr.e_machine = e32.e_machine; + efp->e_hdr.e_version = e32.e_version; + efp->e_hdr.e_entry = (Elf64_Addr)e32.e_entry; + efp->e_hdr.e_phoff = (Elf64_Off)e32.e_phoff; + efp->e_hdr.e_shoff = (Elf64_Off)e32.e_shoff; + efp->e_hdr.e_flags = e32.e_flags; + efp->e_hdr.e_ehsize = e32.e_ehsize; + efp->e_hdr.e_phentsize = e32.e_phentsize; + efp->e_hdr.e_phnum = (Elf64_Word)e32.e_phnum; + efp->e_hdr.e_shentsize = e32.e_shentsize; + efp->e_hdr.e_shnum = (Elf64_Word)e32.e_shnum; + efp->e_hdr.e_shstrndx = (Elf64_Word)e32.e_shstrndx; + } + + /* + * If the number of section headers or program headers or the section + * header string table index would overflow their respective fields + * in the ELF header, they're stored in the section header at index + * zero. To simplify use elsewhere, we look for those sentinel values + * here. + */ + if ((efp->e_hdr.e_shnum == 0 && efp->e_hdr.e_shoff != 0) || + efp->e_hdr.e_shstrndx == SHN_XINDEX || + efp->e_hdr.e_phnum == PN_XNUM) { + GElf_Shdr shdr; + + dprintf("extended ELF header\n"); + + if (efp->e_hdr.e_shoff == 0) { + if (perr != NULL) + *perr = G_FORMAT; + goto err; + } + + if (efp->e_hdr.e_ident[EI_CLASS] == ELFCLASS32) { + Elf32_Shdr shdr32; + + if (pread64(efp->e_fd, &shdr32, sizeof (shdr32), + efp->e_hdr.e_shoff) != sizeof (shdr32)) { + if (perr != NULL) + *perr = G_FORMAT; + goto err; + } + + core_shdr_to_gelf(&shdr32, &shdr); + } else { + if (pread64(efp->e_fd, &shdr, sizeof (shdr), + efp->e_hdr.e_shoff) != sizeof (shdr)) { + if (perr != NULL) + *perr = G_FORMAT; + goto err; + } + } + + if (efp->e_hdr.e_shnum == 0) { + efp->e_hdr.e_shnum = shdr.sh_size; + dprintf("section header count %lu\n", + (ulong_t)shdr.sh_size); + } + + if (efp->e_hdr.e_shstrndx == SHN_XINDEX) { + efp->e_hdr.e_shstrndx = shdr.sh_link; + dprintf("section string index %u\n", shdr.sh_link); + } + + if (efp->e_hdr.e_phnum == PN_XNUM && shdr.sh_info != 0) { + efp->e_hdr.e_phnum = shdr.sh_info; + dprintf("program header count %u\n", shdr.sh_info); + } + + } else if (efp->e_hdr.e_phoff != 0) { + GElf_Phdr phdr; + uint64_t phnum; + + /* + * It's possible this core file came from a system that + * accidentally truncated the e_phnum field without correctly + * using the extended format in the section header at index + * zero. We try to detect and correct that specific type of + * corruption by using the knowledge that the core dump + * routines usually place the data referenced by the first + * program header immediately after the last header element. + */ + if (efp->e_hdr.e_ident[EI_CLASS] == ELFCLASS32) { + Elf32_Phdr phdr32; + + if (pread64(efp->e_fd, &phdr32, sizeof (phdr32), + efp->e_hdr.e_phoff) != sizeof (phdr32)) { + if (perr != NULL) + *perr = G_FORMAT; + goto err; + } + + core_phdr_to_gelf(&phdr32, &phdr); + } else { + if (pread64(efp->e_fd, &phdr, sizeof (phdr), + efp->e_hdr.e_phoff) != sizeof (phdr)) { + if (perr != NULL) + *perr = G_FORMAT; + goto err; + } + } + + phnum = phdr.p_offset - efp->e_hdr.e_ehsize - + (uint64_t)efp->e_hdr.e_shnum * efp->e_hdr.e_shentsize; + phnum /= efp->e_hdr.e_phentsize; + + if (phdr.p_offset != 0 && phnum != efp->e_hdr.e_phnum) { + dprintf("suspicious program header count %u %u\n", + (uint_t)phnum, efp->e_hdr.e_phnum); + + /* + * If the new program header count we computed doesn't + * jive with count in the ELF header, we'll use the + * data that's there and hope for the best. + * + * If it does, it's also possible that the section + * header offset is incorrect; we'll check that and + * possibly try to fix it. + */ + if (phnum <= INT_MAX && + (uint16_t)phnum == efp->e_hdr.e_phnum) { + + if (efp->e_hdr.e_shoff == efp->e_hdr.e_phoff + + efp->e_hdr.e_phentsize * + (uint_t)efp->e_hdr.e_phnum) { + efp->e_hdr.e_shoff = + efp->e_hdr.e_phoff + + efp->e_hdr.e_phentsize * phnum; + } + + efp->e_hdr.e_phnum = (Elf64_Word)phnum; + dprintf("using new program header count\n"); + } else { + dprintf("inconsistent program header count\n"); + } + } + } /* * The libelf implementation was never ported to be large-file aware. @@ -1132,17 +1279,18 @@ static map_info_t * core_find_text(struct ps_prochandle *P, Elf *elf, rd_loadobj_t *rlp) { - GElf_Ehdr ehdr; GElf_Phdr phdr; uint_t i; + size_t nphdrs; - if (gelf_getehdr(elf, &ehdr) != NULL) { - for (i = 0; i < ehdr.e_phnum; i++) { - if (gelf_getphdr(elf, i, &phdr) != NULL && - phdr.p_type == PT_LOAD && (phdr.p_flags & PF_X)) { - rlp->rl_base = phdr.p_vaddr; - return (Paddr2mptr(P, rlp->rl_base)); - } + if (elf_getphnum(elf, &nphdrs) == 0) + return (NULL); + + for (i = 0; i < nphdrs; i++) { + if (gelf_getphdr(elf, i, &phdr) != NULL && + phdr.p_type == PT_LOAD && (phdr.p_flags & PF_X)) { + rlp->rl_base = phdr.p_vaddr; + return (Paddr2mptr(P, rlp->rl_base)); } } @@ -1159,9 +1307,9 @@ { GElf_Ehdr ehdr; GElf_Phdr phdr; - map_info_t *mp; uint_t i, pagemask; + size_t nphdrs; rlp->rl_data_base = NULL; @@ -1169,16 +1317,17 @@ * Find the first loadable, writeable Phdr and compute rl_data_base * as the virtual address at which is was loaded. */ - if (gelf_getehdr(elf, &ehdr) != NULL) { - for (i = 0; i < ehdr.e_phnum; i++) { - if (gelf_getphdr(elf, i, &phdr) != NULL && - phdr.p_type == PT_LOAD && (phdr.p_flags & PF_W)) { + if (gelf_getehdr(elf, &ehdr) == NULL || + elf_getphnum(elf, &nphdrs) == 0) + return (NULL); - rlp->rl_data_base = phdr.p_vaddr; - if (ehdr.e_type == ET_DYN) - rlp->rl_data_base += rlp->rl_base; - break; - } + for (i = 0; i < nphdrs; i++) { + if (gelf_getphdr(elf, i, &phdr) != NULL && + phdr.p_type == PT_LOAD && (phdr.p_flags & PF_W)) { + rlp->rl_data_base = phdr.p_vaddr; + if (ehdr.e_type == ET_DYN) + rlp->rl_data_base += rlp->rl_base; + break; } } @@ -1357,7 +1506,7 @@ if (efp->e_hdr.e_shstrndx >= efp->e_hdr.e_shnum) { dprintf("corrupt shstrndx (%u) exceeds shnum (%u)\n", - (uint_t)efp->e_hdr.e_shstrndx, (uint_t)efp->e_hdr.e_shnum); + efp->e_hdr.e_shstrndx, efp->e_hdr.e_shnum); return; }
--- a/usr/src/lib/libproc/common/Pgcore.c Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/lib/libproc/common/Pgcore.c Thu Nov 17 11:42:26 2005 -0800 @@ -46,6 +46,7 @@ #include "P32ton.h" typedef enum { + STR_NONE, STR_CTF, STR_SYMTAB, STR_DYNSYM, @@ -56,6 +57,7 @@ } shstrtype_t; static const char *shstrtab_data[] = { + "", ".SUNW_ctf", ".symtab", ".dynsym", @@ -94,7 +96,7 @@ { int ret; - if ((ret = s->sst_ndx[type]) != 0) + if ((ret = s->sst_ndx[type]) != 0 || type == STR_NONE) return (ret); ret = s->sst_ndx[type] = s->sst_cur; @@ -908,15 +910,12 @@ (void) shstrtab_ndx(&pgc->pgc_shstrtab, STR_SHSTRTAB); size = shstrtab_size(s); - if (pwrite64(pgc->pgc_fd, "", 1, off) != 1) - return (1); - /* * Dump all the strings that we used being sure we include the * terminating null character. */ for (i = 0; i < STR_NUM; i++) { - if ((ndx = s->sst_ndx[i]) != 0) { + if ((ndx = s->sst_ndx[i]) != 0 || i == STR_NONE) { const char *str = shstrtab_data[i]; size_t len = strlen(str) + 1; if (pwrite64(pgc->pgc_fd, str, len, off + ndx) != len) @@ -1020,6 +1019,14 @@ zonename[0] = '\0'; /* + * The core file contents may required zero section headers, but if we + * overflow the 16 bits allotted to the program header count in the ELF + * header, we'll need that program header at index zero. + */ + if (nshdrs == 0 && nphdrs >= PN_XNUM) + nshdrs = 1; + + /* * Set up the ELF header. */ if (P->status.pr_dmodel == PR_MODEL_ILP32) { @@ -1046,26 +1053,38 @@ ehdr.e_version = EV_CURRENT; ehdr.e_ehsize = sizeof (ehdr); + + if (nphdrs >= PN_XNUM) + ehdr.e_phnum = PN_XNUM; + else + ehdr.e_phnum = (unsigned short)nphdrs; + ehdr.e_phentsize = sizeof (Elf32_Phdr); - ehdr.e_phnum = (unsigned short)nphdrs; ehdr.e_phoff = ehdr.e_ehsize; - if (nshdrs != 0) { + if (nshdrs > 0) { + if (nshdrs >= SHN_LORESERVE) + ehdr.e_shnum = 0; + else + ehdr.e_shnum = (unsigned short)nshdrs; + + if (nshdrs - 1 >= SHN_LORESERVE) + ehdr.e_shstrndx = SHN_XINDEX; + else + ehdr.e_shstrndx = (unsigned short)(nshdrs - 1); + ehdr.e_shentsize = sizeof (Elf32_Shdr); - ehdr.e_shnum = (unsigned short)nshdrs; - ehdr.e_shoff = ehdr.e_phoff + - ehdr.e_phentsize * ehdr.e_phnum; - ehdr.e_shstrndx = nshdrs - 1; + ehdr.e_shoff = ehdr.e_phoff + ehdr.e_phentsize * nphdrs; } if (pwrite64(fd, &ehdr, sizeof (ehdr), 0) != sizeof (ehdr)) goto err; poff = ehdr.e_phoff; - soff = ehdr.e_shoff + ehdr.e_shentsize; + soff = ehdr.e_shoff; doff = boff = ehdr.e_ehsize + - ehdr.e_phentsize * ehdr.e_phnum + - ehdr.e_shentsize * ehdr.e_shnum; + ehdr.e_phentsize * nphdrs + + ehdr.e_shentsize * nshdrs; #ifdef _LP64 } else { @@ -1092,31 +1111,52 @@ ehdr.e_version = EV_CURRENT; ehdr.e_ehsize = sizeof (ehdr); + + if (nphdrs >= PN_XNUM) + ehdr.e_phnum = PN_XNUM; + else + ehdr.e_phnum = (unsigned short)nphdrs; + ehdr.e_phentsize = sizeof (Elf64_Phdr); - ehdr.e_phnum = (unsigned short)nphdrs; ehdr.e_phoff = ehdr.e_ehsize; - if (nshdrs != 0) { + if (nshdrs > 0) { + if (nshdrs >= SHN_LORESERVE) + ehdr.e_shnum = 0; + else + ehdr.e_shnum = (unsigned short)nshdrs; + + if (nshdrs - 1 >= SHN_LORESERVE) + ehdr.e_shstrndx = SHN_XINDEX; + else + ehdr.e_shstrndx = (unsigned short)(nshdrs - 1); + ehdr.e_shentsize = sizeof (Elf64_Shdr); - ehdr.e_shnum = (unsigned short)nshdrs; - ehdr.e_shoff = ehdr.e_phoff + - ehdr.e_phentsize * ehdr.e_phnum; - ehdr.e_shstrndx = nshdrs - 1; + ehdr.e_shoff = ehdr.e_phoff + ehdr.e_phentsize * nphdrs; } if (pwrite64(fd, &ehdr, sizeof (ehdr), 0) != sizeof (ehdr)) goto err; poff = ehdr.e_phoff; - soff = ehdr.e_shoff + ehdr.e_shentsize; - doff = boff = sizeof (ehdr) + - ehdr.e_phentsize * ehdr.e_phnum + - ehdr.e_shentsize * ehdr.e_shnum; + soff = ehdr.e_shoff; + doff = boff = ehdr.e_ehsize + + ehdr.e_phentsize * nphdrs + + ehdr.e_shentsize * nshdrs; #endif /* _LP64 */ } /* + * Write the zero indexed section if it exists. + */ + if (nshdrs > 0 && write_shdr(&pgc, STR_NONE, 0, 0, 0, 0, + nshdrs >= SHN_LORESERVE ? nshdrs : 0, + nshdrs - 1 >= SHN_LORESERVE ? nshdrs - 1 : 0, + nphdrs >= PN_XNUM ? nphdrs : 0, 0, 0) != 0) + goto err; + + /* * Construct the old-style note header and section. */
--- a/usr/src/lib/libproc/common/Pidle.c Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/lib/libproc/common/Pidle.c Thu Nov 17 11:42:26 2005 -0800 @@ -113,6 +113,7 @@ struct ps_prochandle *P = NULL; GElf_Ehdr ehdr; Elf *elf = NULL; + size_t phnum; file_info_t *fp = NULL; int fd; int i; @@ -195,12 +196,17 @@ goto err; } - dprintf("Pgrab_file: ehdr.e_phnum = %d\n", ehdr.e_phnum); + if (elf_getphnum(elf, &phnum) == 0) { + *perr = G_STRANGE; + goto err; + } + + dprintf("Pgrab_file: program header count = %lu\n", (ulong_t)phnum); /* * Sift through the program headers making the relevant maps. */ - for (i = 0; i < ehdr.e_phnum; i++) { + for (i = 0; i < phnum; i++) { GElf_Phdr phdr, *php; if ((php = gelf_getphdr(elf, i, &phdr)) == NULL) {
--- a/usr/src/lib/libproc/common/Psymtab.c Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/lib/libproc/common/Psymtab.c Thu Nov 17 11:42:26 2005 -0800 @@ -56,9 +56,11 @@ static map_info_t *object_name_to_map(struct ps_prochandle *, Lmid_t, const char *); static GElf_Sym *sym_by_name(sym_tbl_t *, const char *, GElf_Sym *, uint_t *); -static int read_ehdr32(struct ps_prochandle *, Elf32_Ehdr *, uintptr_t); +static int read_ehdr32(struct ps_prochandle *, Elf32_Ehdr *, uint_t *, + uintptr_t); #ifdef _LP64 -static int read_ehdr64(struct ps_prochandle *, Elf64_Ehdr *, uintptr_t); +static int read_ehdr64(struct ps_prochandle *, Elf64_Ehdr *, uint_t *, + uintptr_t); #endif #define DATA_TYPES \ @@ -121,13 +123,14 @@ if (P->status.pr_dmodel == PR_MODEL_ILP32) { Elf32_Ehdr ehdr; Elf32_Phdr phdr; - - if (read_ehdr32(P, &ehdr, mptr->map_pmap.pr_vaddr) != 0) + uint_t phnum; + + if (read_ehdr32(P, &ehdr, &phnum, mptr->map_pmap.pr_vaddr) != 0) return (fptr); - addrs = malloc(sizeof (uintptr_t) * ehdr.e_phnum * 2); + addrs = malloc(sizeof (uintptr_t) * phnum * 2); a = mptr->map_pmap.pr_vaddr + ehdr.e_phoff; - for (i = 0; i < ehdr.e_phnum; i++, a += ehdr.e_phentsize) { + for (i = 0; i < phnum; i++, a += ehdr.e_phentsize) { if (Pread(P, &phdr, sizeof (phdr), a) != sizeof (phdr)) goto out; if (phdr.p_type != PT_LOAD || phdr.p_memsz == 0) @@ -145,13 +148,14 @@ } else { Elf64_Ehdr ehdr; Elf64_Phdr phdr; - - if (read_ehdr64(P, &ehdr, mptr->map_pmap.pr_vaddr) != 0) + uint_t phnum; + + if (read_ehdr64(P, &ehdr, &phnum, mptr->map_pmap.pr_vaddr) != 0) return (fptr); - addrs = malloc(sizeof (uintptr_t) * ehdr.e_phnum * 2); + addrs = malloc(sizeof (uintptr_t) * phnum * 2); a = mptr->map_pmap.pr_vaddr + ehdr.e_phoff; - for (i = 0; i < ehdr.e_phnum; i++, a += ehdr.e_phentsize) { + for (i = 0; i < phnum; i++, a += ehdr.e_phentsize) { if (Pread(P, &phdr, sizeof (phdr), a) != sizeof (phdr)) goto out; if (phdr.p_type != PT_LOAD || phdr.p_memsz == 0) @@ -935,7 +939,8 @@ } static int -read_ehdr32(struct ps_prochandle *P, Elf32_Ehdr *ehdr, uintptr_t addr) +read_ehdr32(struct ps_prochandle *P, Elf32_Ehdr *ehdr, uint_t *phnum, + uintptr_t addr) { if (Pread(P, ehdr, sizeof (*ehdr), addr) != sizeof (*ehdr)) return (-1); @@ -953,16 +958,28 @@ ehdr->e_ident[EI_VERSION] != EV_CURRENT) return (-1); + if ((*phnum = ehdr->e_phnum) == PN_XNUM) { + Elf32_Shdr shdr0; + + if (ehdr->e_shoff == 0 || ehdr->e_shentsize < sizeof (shdr0) || + Pread(P, &shdr0, sizeof (shdr0), addr + ehdr->e_shoff) != + sizeof (shdr0)) + return (-1); + + if (shdr0.sh_info != 0) + *phnum = shdr0.sh_info; + } + return (0); } static int read_dynamic_phdr32(struct ps_prochandle *P, const Elf32_Ehdr *ehdr, - Elf32_Phdr *phdr, uintptr_t addr) + uint_t phnum, Elf32_Phdr *phdr, uintptr_t addr) { uint_t i; - for (i = 0; i < ehdr->e_phnum; i++) { + for (i = 0; i < phnum; i++) { uintptr_t a = addr + ehdr->e_phoff + i * ehdr->e_phentsize; if (Pread(P, phdr, sizeof (*phdr), a) != sizeof (*phdr)) return (-1); @@ -976,7 +993,8 @@ #ifdef _LP64 static int -read_ehdr64(struct ps_prochandle *P, Elf64_Ehdr *ehdr, uintptr_t addr) +read_ehdr64(struct ps_prochandle *P, Elf64_Ehdr *ehdr, uint_t *phnum, + uintptr_t addr) { if (Pread(P, ehdr, sizeof (Elf64_Ehdr), addr) != sizeof (Elf64_Ehdr)) return (-1); @@ -994,16 +1012,28 @@ ehdr->e_ident[EI_VERSION] != EV_CURRENT) return (-1); + if ((*phnum = ehdr->e_phnum) == PN_XNUM) { + Elf64_Shdr shdr0; + + if (ehdr->e_shoff == 0 || ehdr->e_shentsize < sizeof (shdr0) || + Pread(P, &shdr0, sizeof (shdr0), addr + ehdr->e_shoff) != + sizeof (shdr0)) + return (-1); + + if (shdr0.sh_info != 0) + *phnum = shdr0.sh_info; + } + return (0); } static int read_dynamic_phdr64(struct ps_prochandle *P, const Elf64_Ehdr *ehdr, - Elf64_Phdr *phdr, uintptr_t addr) + uint_t phnum, Elf64_Phdr *phdr, uintptr_t addr) { uint_t i; - for (i = 0; i < ehdr->e_phnum; i++) { + for (i = 0; i < phnum; i++) { uintptr_t a = addr + ehdr->e_phoff + i * ehdr->e_phentsize; if (Pread(P, phdr, sizeof (*phdr), a) != sizeof (*phdr)) return (-1); @@ -1113,10 +1143,10 @@ Elf32_Ehdr ehdr; Elf32_Phdr phdr; Elf32_Dyn dync, *dynp; - uint_t i; - - if (read_ehdr32(P, &ehdr, addr) != 0 || - read_dynamic_phdr32(P, &ehdr, &phdr, addr) != 0) + uint_t phnum, i; + + if (read_ehdr32(P, &ehdr, &phnum, addr) != 0 || + read_dynamic_phdr32(P, &ehdr, phnum, &phdr, addr) != 0) return (0); if (ehdr.e_type == ET_DYN) @@ -1148,10 +1178,10 @@ Elf64_Ehdr ehdr; Elf64_Phdr phdr; Elf64_Dyn dync, *dynp; - uint_t i; - - if (read_ehdr64(P, &ehdr, addr) != 0 || - read_dynamic_phdr64(P, &ehdr, &phdr, addr) != 0) + uint_t phnum, i; + + if (read_ehdr64(P, &ehdr, &phnum, addr) != 0 || + read_dynamic_phdr64(P, &ehdr, phnum, &phdr, addr) != 0) return (0); if (ehdr.e_type == ET_DYN) @@ -1287,12 +1317,12 @@ Elf32_Shdr *sp; Elf32_Dyn *dp; Elf32_Dyn *d[DI_NENT] = { 0 }; - uint_t i, dcount = 0; + uint_t phnum, i, dcount = 0; uint32_t off; size_t pltsz = 0, pltentsz; - if (read_ehdr32(P, &ehdr, addr) != 0 || - read_dynamic_phdr32(P, &ehdr, &phdr, addr) != 0) + if (read_ehdr32(P, &ehdr, &phnum, addr) != 0 || + read_dynamic_phdr32(P, &ehdr, phnum, &phdr, addr) != 0) return (NULL); if (ehdr.e_type == ET_DYN) @@ -1382,7 +1412,7 @@ size = sizeof (Elf32_Ehdr); /* program headers from in-core elf fragment */ - size += ehdr.e_phnum * ehdr.e_phentsize; + size += phnum * ehdr.e_phentsize; /* unused shdr, and .shstrtab section */ size += sizeof (Elf32_Shdr); @@ -1457,8 +1487,8 @@ ep->e_ehsize = sizeof (Elf32_Ehdr); ep->e_phoff = sizeof (Elf32_Ehdr); ep->e_phentsize = ehdr.e_phentsize; - ep->e_phnum = ehdr.e_phnum; - ep->e_shoff = ep->e_phoff + ep->e_phnum * ep->e_phentsize; + ep->e_phnum = phnum; + ep->e_shoff = ep->e_phoff + phnum * ep->e_phentsize; ep->e_shentsize = sizeof (Elf32_Shdr); ep->e_shnum = (pltsz == 0) ? 5 : 6; ep->e_shstrndx = 1; @@ -1472,9 +1502,8 @@ * address space is a little suspect, but since we only * use them for their address and size values, this is fine. */ - if (Pread(P, &elfdata[ep->e_phoff], - ep->e_phnum * ep->e_phentsize, addr + ehdr.e_phoff) != - ep->e_phnum * ep->e_phentsize) { + if (Pread(P, &elfdata[ep->e_phoff], phnum * ep->e_phentsize, + addr + ehdr.e_phoff) != phnum * ep->e_phentsize) { free(elfdata); goto bad32; } @@ -1610,12 +1639,12 @@ Elf64_Shdr *sp; Elf64_Dyn *dp; Elf64_Dyn *d[DI_NENT] = { 0 }; - uint_t i, dcount = 0; + uint_t phnum, i, dcount = 0; uint64_t off; size_t pltsz = 0, pltentsz; - if (read_ehdr64(P, &ehdr, addr) != 0 || - read_dynamic_phdr64(P, &ehdr, &phdr, addr) != 0) + if (read_ehdr64(P, &ehdr, &phnum, addr) != 0 || + read_dynamic_phdr64(P, &ehdr, phnum, &phdr, addr) != 0) return (NULL); if (ehdr.e_type == ET_DYN) @@ -1705,7 +1734,7 @@ size = sizeof (Elf64_Ehdr); /* program headers from in-core elf fragment */ - size += ehdr.e_phnum * ehdr.e_phentsize; + size += phnum * ehdr.e_phentsize; /* unused shdr, and .shstrtab section */ size += sizeof (Elf64_Shdr); @@ -1780,8 +1809,8 @@ ep->e_ehsize = sizeof (Elf64_Ehdr); ep->e_phoff = sizeof (Elf64_Ehdr); ep->e_phentsize = ehdr.e_phentsize; - ep->e_phnum = ehdr.e_phnum; - ep->e_shoff = ep->e_phoff + ep->e_phnum * ep->e_phentsize; + ep->e_phnum = phnum; + ep->e_shoff = ep->e_phoff + phnum * ep->e_phentsize; ep->e_shentsize = sizeof (Elf64_Shdr); ep->e_shnum = (pltsz == 0) ? 5 : 6; ep->e_shstrndx = 1; @@ -1795,9 +1824,8 @@ * address space is a little suspect, but since we only * use them for their address and size values, this is fine. */ - if (Pread(P, &elfdata[ep->e_phoff], - ep->e_phnum * ep->e_phentsize, addr + ehdr.e_phoff) != - ep->e_phnum * ep->e_phentsize) { + if (Pread(P, &elfdata[ep->e_phoff], phnum * ep->e_phentsize, + addr + ehdr.e_phoff) != phnum * ep->e_phentsize) { free(elfdata); goto bad64; } @@ -2100,6 +2128,7 @@ Elf_Data *shdata; Elf_Scn *scn; Elf *elf; + size_t nshdrs, shstrndx; struct { GElf_Shdr c_shdr; @@ -2150,7 +2179,9 @@ if ((elf = fake_elf(P, fptr)) == NULL || elf_kind(elf) != ELF_K_ELF || gelf_getehdr(elf, &ehdr) == NULL || - (scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL || + elf_getshnum(elf, &nshdrs) == 0 || + elf_getshstrndx(elf, &shstrndx) == 0 || + (scn = elf_getscn(elf, shstrndx)) == NULL || (shdata = elf_getdata(scn, NULL)) == NULL) { dprintf("failed to fake up ELF file\n"); return; @@ -2159,7 +2190,9 @@ } else if ((elf = elf_begin(fptr->file_fd, ELF_C_READ, NULL)) == NULL || elf_kind(elf) != ELF_K_ELF || gelf_getehdr(elf, &ehdr) == NULL || - (scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL || + elf_getshnum(elf, &nshdrs) == 0 || + elf_getshstrndx(elf, &shstrndx) == 0 || + (scn = elf_getscn(elf, shstrndx)) == NULL || (shdata = elf_getdata(scn, NULL)) == NULL) { dprintf("failed to process ELF file %s: %s\n", objectfile, elf_errmsg(elf_errno())); @@ -2167,7 +2200,9 @@ if ((elf = fake_elf(P, fptr)) == NULL || elf_kind(elf) != ELF_K_ELF || gelf_getehdr(elf, &ehdr) == NULL || - (scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL || + elf_getshnum(elf, &nshdrs) == 0 || + elf_getshstrndx(elf, &shstrndx) == 0 || + (scn = elf_getscn(elf, shstrndx)) == NULL || (shdata = elf_getdata(scn, NULL)) == NULL) { dprintf("failed to fake up ELF file\n"); goto bad; @@ -2190,7 +2225,9 @@ if ((newelf = fake_elf(P, fptr)) == NULL || elf_kind(newelf) != ELF_K_ELF || gelf_getehdr(newelf, &ehdr) == NULL || - (scn = elf_getscn(newelf, ehdr.e_shstrndx)) == NULL || + elf_getshnum(newelf, &nshdrs) == 0 || + elf_getshstrndx(newelf, &shstrndx) == 0 || + (scn = elf_getscn(newelf, shstrndx)) == NULL || (shdata = elf_getdata(scn, NULL)) == NULL) { dprintf("failed to fake up ELF file\n"); } else { @@ -2201,7 +2238,7 @@ } } - if ((cache = malloc(ehdr.e_shnum * sizeof (*cache))) == NULL) { + if ((cache = malloc(nshdrs * sizeof (*cache))) == NULL) { dprintf("failed to malloc section cache for %s\n", objectfile); goto bad; } @@ -2232,7 +2269,7 @@ * Now iterate through the section cache in order to locate info * for the .symtab, .dynsym, .dynamic, .plt, and .SUNW_ctf sections: */ - for (i = 1, cp = cache + 1; i < ehdr.e_shnum; i++, cp++) { + for (i = 1, cp = cache + 1; i < nshdrs; i++, cp++) { GElf_Shdr *shp = &cp->c_shdr; if (shp->sh_type == SHT_SYMTAB || shp->sh_type == SHT_DYNSYM) { @@ -2272,7 +2309,7 @@ * to haunt us later. */ if (shp->sh_link == 0 || - shp->sh_link > ehdr.e_shnum || + shp->sh_link >= nshdrs || (cache[shp->sh_link].c_shdr.sh_type != SHT_DYNSYM && cache[shp->sh_link].c_shdr.sh_type != SHT_SYMTAB)) { dprintf("Bad sh_link %d for "
--- a/usr/src/uts/common/exec/elf/elf.c Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/uts/common/exec/elf/elf.c Thu Nov 17 11:42:26 2005 -0800 @@ -69,12 +69,13 @@ #define ORIGIN_STR "ORIGIN" #define ORIGIN_STR_SIZE 6 -static int getelfhead(vnode_t *, cred_t *, Ehdr *); -static int getelfphdr(vnode_t *, cred_t *, const Ehdr *, caddr_t *, ssize_t *); -static int getelfshdr(vnode_t *, cred_t *, const Ehdr *, caddr_t *, ssize_t *, - caddr_t *, ssize_t *); -static size_t elfsize(Ehdr *, caddr_t, uintptr_t *); -static int mapelfexec(vnode_t *, Ehdr *, caddr_t, +static int getelfhead(vnode_t *, cred_t *, Ehdr *, int *, int *, int *); +static int getelfphdr(vnode_t *, cred_t *, const Ehdr *, int, caddr_t *, + ssize_t *); +static int getelfshdr(vnode_t *, cred_t *, const Ehdr *, int, int, caddr_t *, + ssize_t *, caddr_t *, ssize_t *); +static size_t elfsize(Ehdr *, int, caddr_t, uintptr_t *); +static int mapelfexec(vnode_t *, Ehdr *, int, caddr_t, Phdr **, Phdr **, Phdr **, Phdr **, Phdr *, caddr_t *, caddr_t *, intptr_t *, size_t, long *, size_t *); @@ -199,7 +200,8 @@ struct vattr vattr; struct execenv exenv; } *bigwad; /* kmem_alloc this behemoth so we don't blow stack */ - Ehdr *ehdrp; + Ehdr *ehdrp; + int nshdrs, shstrndx, nphdrs; char *dlnp; char *pathbufp; rlim64_t limit; @@ -215,8 +217,10 @@ /* * Obtain ELF and program header information. */ - if ((error = getelfhead(vp, CRED(), ehdrp)) != 0 || - (error = getelfphdr(vp, CRED(), ehdrp, &phdrbase, &phdrsize)) != 0) + if ((error = getelfhead(vp, CRED(), ehdrp, &nshdrs, &shstrndx, + &nphdrs)) != 0 || + (error = getelfphdr(vp, CRED(), ehdrp, nphdrs, &phdrbase, + &phdrsize)) != 0) goto out; /* @@ -250,7 +254,7 @@ */ hsize = ehdrp->e_phentsize; phdrp = (Phdr *)phdrbase; - for (i = ehdrp->e_phnum; i > 0; i--) { + for (i = nphdrs; i > 0; i--) { switch (phdrp->p_type) { case PT_INTERP: hasauxv = hasdy = 1; @@ -358,15 +362,15 @@ * determine its memory size so that mapelfexec() can load it. */ if (ehdrp->e_type == ET_DYN) - len = elfsize(ehdrp, phdrbase, NULL); + len = elfsize(ehdrp, nphdrs, phdrbase, NULL); else len = 0; dtrphdr = NULL; - if ((error = mapelfexec(vp, ehdrp, phdrbase, &uphdr, &dyphdr, &stphdr, - &dtrphdr, dataphdrp, &bssbase, &brkbase, &voffset, len, execsz, - &brksize)) != 0) + if ((error = mapelfexec(vp, ehdrp, nphdrs, phdrbase, &uphdr, &dyphdr, + &stphdr, &dtrphdr, dataphdrp, &bssbase, &brkbase, &voffset, len, + execsz, &brksize)) != 0) goto bad; if (uphdr != NULL && dyphdr == NULL) @@ -483,7 +487,7 @@ ADDAUX(aux, AT_PHDR, uphdr->p_vaddr + voffset) ADDAUX(aux, AT_PHENT, ehdrp->e_phentsize) - ADDAUX(aux, AT_PHNUM, ehdrp->e_phnum) + ADDAUX(aux, AT_PHNUM, nphdrs) ADDAUX(aux, AT_ENTRY, ehdrp->e_entry + voffset) } else { if ((error = execopen(&vp, &fd)) != 0) { @@ -506,8 +510,9 @@ */ kmem_free(phdrbase, phdrsize); phdrbase = NULL; - if ((error = getelfhead(nvp, CRED(), ehdrp)) != 0 || - (error = getelfphdr(nvp, CRED(), ehdrp, &phdrbase, + if ((error = getelfhead(nvp, CRED(), ehdrp, &nshdrs, + &shstrndx, &nphdrs)) != 0 || + (error = getelfphdr(nvp, CRED(), ehdrp, nphdrs, &phdrbase, &phdrsize)) != 0) { VN_RELE(nvp); uprintf("%s: Cannot read %s\n", exec_file, dlnp); @@ -520,7 +525,7 @@ * address of a hole, in the user's address space, large * enough to map the "interpreter". */ - if ((len = elfsize(ehdrp, phdrbase, &lddata)) == 0) { + if ((len = elfsize(ehdrp, nphdrs, phdrbase, &lddata)) == 0) { VN_RELE(nvp); uprintf("%s: Nothing to load in %s\n", exec_file, dlnp); goto bad; @@ -528,8 +533,9 @@ dtrphdr = NULL; - error = mapelfexec(nvp, ehdrp, phdrbase, &junk, &junk, &junk, - &dtrphdr, NULL, NULL, NULL, &voffset, len, execsz, NULL); + error = mapelfexec(nvp, ehdrp, nphdrs, phdrbase, &junk, &junk, + &junk, &dtrphdr, NULL, NULL, NULL, &voffset, len, execsz, + NULL); if (error || junk != NULL) { VN_RELE(nvp); uprintf("%s: Cannot map %s\n", exec_file, dlnp); @@ -681,7 +687,7 @@ * Compute the memory size requirement for the ELF file. */ static size_t -elfsize(Ehdr *ehdrp, caddr_t phdrbase, uintptr_t *lddata) +elfsize(Ehdr *ehdrp, int nphdrs, caddr_t phdrbase, uintptr_t *lddata) { size_t len; Phdr *phdrp = (Phdr *)phdrbase; @@ -693,7 +699,7 @@ uintptr_t lo, hi; int i; - for (i = ehdrp->e_phnum; i > 0; i--) { + for (i = nphdrs; i > 0; i--) { if (phdrp->p_type == PT_LOAD) { lo = phdrp->p_vaddr; hi = lo + phdrp->p_memsz; @@ -735,7 +741,8 @@ * EINVAL Format recognized but execution not supported */ static int -getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr) +getelfhead(vnode_t *vp, cred_t *credp, Ehdr *ehdr, int *nshdrs, int *shstrndx, + int *nphdrs) { int error; ssize_t resid; @@ -758,6 +765,7 @@ ehdr->e_ident[EI_MAG2] != ELFMAG2 || ehdr->e_ident[EI_MAG3] != ELFMAG3) return (ENOEXEC); + if ((ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) || #if defined(_ILP32) || defined(_ELF32_COMPAT) ehdr->e_ident[EI_CLASS] != ELFCLASS32 || @@ -765,9 +773,38 @@ ehdr->e_ident[EI_CLASS] != ELFCLASS64 || #endif !elfheadcheck(ehdr->e_ident[EI_DATA], ehdr->e_machine, - ehdr->e_flags)) + ehdr->e_flags)) return (EINVAL); + *nshdrs = ehdr->e_shnum; + *shstrndx = ehdr->e_shstrndx; + *nphdrs = ehdr->e_phnum; + + /* + * If e_shnum, e_shstrndx, or e_phnum is its sentinel value, we need + * to read in the section header at index zero to acces the true + * values for those fields. + */ + if ((*nshdrs == 0 && ehdr->e_shoff != 0) || + *shstrndx == SHN_XINDEX || *nphdrs == PN_XNUM) { + Shdr shdr; + + if (ehdr->e_shoff == 0) + return (EINVAL); + + if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)&shdr, + sizeof (shdr), (offset_t)ehdr->e_shoff, UIO_SYSSPACE, 0, + (rlim64_t)0, credp, &resid)) != 0) + return (error); + + if (*nshdrs == 0) + *nshdrs = shdr.sh_size; + if (*shstrndx == SHN_XINDEX) + *shstrndx = shdr.sh_link; + if (*nphdrs == PN_XNUM && shdr.sh_info != 0) + *nphdrs = shdr.sh_info; + } + return (0); } @@ -778,7 +815,7 @@ #endif static int -getelfphdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr, +getelfphdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr, int nphdrs, caddr_t *phbasep, ssize_t *phsizep) { ssize_t resid, minsize; @@ -800,7 +837,7 @@ if (ehdr->e_phentsize < minsize || (ehdr->e_phentsize & 3)) return (EINVAL); - *phsizep = ehdr->e_phnum * ehdr->e_phentsize; + *phsizep = nphdrs * ehdr->e_phentsize; if (*phsizep > sizeof (Phdr) * elf_nphdr_max) { if ((*phbasep = kmem_alloc(*phsizep, KM_NOSLEEP)) == NULL) @@ -831,7 +868,7 @@ static int getelfshdr(vnode_t *vp, cred_t *credp, const Ehdr *ehdr, - caddr_t *shbasep, ssize_t *shsizep, + int nshdrs, int shstrndx, caddr_t *shbasep, ssize_t *shsizep, char **shstrbasep, ssize_t *shstrsizep) { ssize_t resid, minsize; @@ -843,15 +880,15 @@ * array of section headers, it must be 8-byte aligned or else * a we might cause a misaligned access. We use all members through * sh_entsize (on both 32- and 64-bit ELF files) so e_shentsize - * must be at least large enough to include that member. The - * index of the string table section must be valid. + * must be at least large enough to include that member. The index + * of the string table section must also be valid. */ minsize = offsetof(Shdr, sh_entsize) + sizeof (shdr->sh_entsize); if (ehdr->e_shentsize < minsize || (ehdr->e_shentsize & 3) || - ehdr->e_shstrndx >= ehdr->e_shnum) + shstrndx >= nshdrs) return (EINVAL); - *shsizep = ehdr->e_shnum * ehdr->e_shentsize; + *shsizep = nshdrs * ehdr->e_shentsize; if (*shsizep > sizeof (Shdr) * elf_nshdr_max) { if ((*shbasep = kmem_alloc(*shsizep, KM_NOSLEEP)) == NULL) @@ -871,7 +908,7 @@ * Pull the section string table out of the vnode; fail if the size * is zero. */ - shdr = (Shdr *)(*shbasep + ehdr->e_shstrndx * ehdr->e_shentsize); + shdr = (Shdr *)(*shbasep + shstrndx * ehdr->e_shentsize); if ((*shstrsizep = shdr->sh_size) == 0) { kmem_free(*shbasep, *shsizep); return (EINVAL); @@ -908,6 +945,7 @@ mapelfexec( vnode_t *vp, Ehdr *ehdr, + int nphdrs, caddr_t phdrbase, Phdr **uphdr, Phdr **dyphdr, @@ -943,7 +981,7 @@ *voffset = 0; } phdr = (Phdr *)phdrbase; - for (i = (int)ehdr->e_phnum; i > 0; i--) { + for (i = nphdrs; i > 0; i--) { switch (phdr->p_type) { case PT_LOAD: if ((*dyphdr != NULL) && (*uphdr == NULL)) @@ -1175,6 +1213,7 @@ size_t segsize; Ehdr ehdr; + int nshdrs, shstrndx, nphdrs; caddr_t shbase; ssize_t shsize; char *shstrbase; @@ -1212,13 +1251,14 @@ if ((prot & (PROT_WRITE | PROT_EXEC)) != PROT_EXEC) continue; - if (getelfhead(mvp, credp, &ehdr) != 0 || - getelfshdr(mvp, credp, &ehdr, &shbase, &shsize, - &shstrbase, &shstrsize) != 0) + if (getelfhead(mvp, credp, &ehdr, &nshdrs, &shstrndx, + &nphdrs) != 0 || + getelfshdr(mvp, credp, &ehdr, nshdrs, shstrndx, + &shbase, &shsize, &shstrbase, &shstrsize) != 0) continue; off = ehdr.e_shentsize; - for (j = 1; j < ehdr.e_shnum; j++, off += ehdr.e_shentsize) { + for (j = 1; j < nshdrs; j++, off += ehdr.e_shentsize) { Shdr *symtab = NULL, *strtab; shdr = (Shdr *)(shbase + off); @@ -1234,7 +1274,7 @@ continue; if (shdr->sh_link > 0 && - shdr->sh_link < ehdr.e_shnum) { + shdr->sh_link < nshdrs) { symtab = (Shdr *)(shbase + shdr->sh_link * ehdr.e_shentsize); } @@ -1298,7 +1338,7 @@ if ((symtab->sh_type != SHT_DYNSYM && symtab->sh_type != SHT_SYMTAB) || symtab->sh_link == 0 || - symtab->sh_link >= ehdr.e_shnum) + symtab->sh_link >= nshdrs) continue; strtab = (Shdr *)(shbase + @@ -1476,6 +1516,16 @@ } AS_LOCK_EXIT(as, &as->a_lock); + ASSERT(nshdrs == 0 || nshdrs > 1); + + /* + * The core file contents may required zero section headers, but if + * we overflow the 16 bits allotted to the program header count in + * the ELF header, we'll need that program header at index zero. + */ + if (nshdrs == 0 && nphdrs >= PN_XNUM) + nshdrs = 1; + phdrsz = nphdrs * sizeof (Phdr); shdrsz = nshdrs * sizeof (Shdr); @@ -1518,18 +1568,37 @@ #endif /* !defined(_LP64) || defined(_ELF32_COMPAT) */ + /* + * If the count of program headers or section headers or the index + * of the section string table can't fit in the mere 16 bits + * shortsightedly allotted to them in the ELF header, we use the + * extended formats and put the real values in the section header + * as index 0. + */ ehdr->e_version = EV_CURRENT; - ehdr->e_phoff = sizeof (Ehdr); ehdr->e_ehsize = sizeof (Ehdr); + + if (nphdrs >= PN_XNUM) + ehdr->e_phnum = PN_XNUM; + else + ehdr->e_phnum = (unsigned short)nphdrs; + + ehdr->e_phoff = sizeof (Ehdr); ehdr->e_phentsize = sizeof (Phdr); - ehdr->e_phnum = (unsigned short)nphdrs; if (nshdrs > 0) { - ehdr->e_shstrndx = (unsigned short)(nshdrs - 1); + if (nshdrs >= SHN_LORESERVE) + ehdr->e_shnum = 0; + else + ehdr->e_shnum = (unsigned short)nshdrs; + + if (nshdrs - 1 >= SHN_LORESERVE) + ehdr->e_shstrndx = SHN_XINDEX; + else + ehdr->e_shstrndx = (unsigned short)(nshdrs - 1); + + ehdr->e_shoff = ehdr->e_phoff + ehdr->e_phentsize * nphdrs; ehdr->e_shentsize = sizeof (Shdr); - ehdr->e_shnum = (unsigned short)nshdrs; - ehdr->e_shoff = ehdr->e_phoff + - ehdr->e_phentsize * ehdr->e_phnum; } if (error = core_write(vp, UIO_SYSSPACE, (offset_t)0, ehdr, @@ -1723,14 +1792,25 @@ if (nshdrs > 0) { bzero(&bigwad->shdr[0], shdrsz); - AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER); - if ((error = process_scns(content, p, credp, vp, - &bigwad->shdr[0], nshdrs, rlimit, &doffset, NULL)) != 0) { + if (nshdrs >= SHN_LORESERVE) + bigwad->shdr[0].sh_size = nshdrs; + + if (nshdrs - 1 >= SHN_LORESERVE) + bigwad->shdr[0].sh_link = nshdrs - 1; + + if (nphdrs >= PN_XNUM) + bigwad->shdr[0].sh_info = nphdrs; + + if (nshdrs > 1) { + AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER); + if ((error = process_scns(content, p, credp, vp, + &bigwad->shdr[0], nshdrs, rlimit, &doffset, + NULL)) != 0) { + AS_LOCK_EXIT(as, &as->a_lock); + goto done; + } AS_LOCK_EXIT(as, &as->a_lock); - goto done; } - AS_LOCK_EXIT(as, &as->a_lock); - if ((error = core_write(vp, UIO_SYSSPACE, soffset, &bigwad->shdr[0], shdrsz, rlimit, credp)) != 0)
--- a/usr/src/uts/common/sys/elf.h Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/uts/common/sys/elf.h Thu Nov 17 11:42:26 2005 -0800 @@ -346,6 +346,8 @@ #define PF_SUNW_FAILURE 0x00100000 /* mapping absent due to failure */ +#define PN_XNUM 0xffff /* extended program header index */ + /* * Section header */
--- a/usr/src/uts/intel/ia32/ml/modstubs.s Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/uts/intel/ia32/ml/modstubs.s Thu Nov 17 11:42:26 2005 -0800 @@ -845,7 +845,7 @@ MODULE(shmsys,sys); WSTUB(shmsys, shmexit, nomod_zero); WSTUB(shmsys, shmfork, nomod_zero); - WSTUB(shmsys, shmgetid, nomod_zero); + WSTUB(shmsys, shmgetid, nomod_minus_one); END_MODULE(shmsys); #endif
--- a/usr/src/uts/sparc/ml/modstubs.s Thu Nov 17 08:46:01 2005 -0800 +++ b/usr/src/uts/sparc/ml/modstubs.s Thu Nov 17 11:42:26 2005 -0800 @@ -765,7 +765,7 @@ MODULE(shmsys,sys); WSTUB(shmsys, shmexit, nomod_zero); WSTUB(shmsys, shmfork, nomod_zero); - WSTUB(shmsys, shmgetid, nomod_zero); + WSTUB(shmsys, shmgetid, nomod_minus_one); END_MODULE(shmsys); #endif