[BACK]Return to elf.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ctfdump

Annotation of src/usr.bin/ctfdump/elf.c, Revision 1.8

1.8     ! mpi         1: /*     $OpenBSD: elf.c,v 1.7 2017/11/06 14:59:27 mpi Exp $ */
1.2       jasper      2:
1.1       mpi         3: /*
                      4:  * Copyright (c) 2016 Martin Pieuchot <mpi@openbsd.org>
                      5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
                     18:
1.3       deraadt    19: #include <sys/types.h>
1.1       mpi        20:
                     21: #include <machine/reloc.h>
                     22:
                     23: #include <assert.h>
1.5       mpi        24: #include <elf.h>
1.1       mpi        25: #include <err.h>
                     26: #include <string.h>
                     27:
                     28: static int     elf_reloc_size(unsigned long);
1.4       jsg        29: static void    elf_reloc_apply(const char *, size_t, const char *, size_t,
                     30:                    ssize_t, char *, size_t);
1.1       mpi        31:
                     32: int
                     33: iself(const char *p, size_t filesize)
                     34: {
                     35:        Elf_Ehdr                *eh = (Elf_Ehdr *)p;
                     36:
                     37:        if (filesize < (off_t)sizeof(Elf_Ehdr)) {
                     38:                warnx("file too small to be ELF");
                     39:                return 0;
                     40:        }
                     41:
                     42:        if (eh->e_ehsize < sizeof(Elf_Ehdr) || !IS_ELF(*eh))
                     43:                return 0;
                     44:
                     45:        if (eh->e_ident[EI_CLASS] != ELFCLASS) {
                     46:                warnx("unexpected word size %u", eh->e_ident[EI_CLASS]);
                     47:                return 0;
                     48:        }
                     49:        if (eh->e_ident[EI_VERSION] != ELF_TARG_VER) {
                     50:                warnx("unexpected version %u", eh->e_ident[EI_VERSION]);
                     51:                return 0;
                     52:        }
                     53:        if (eh->e_ident[EI_DATA] >= ELFDATANUM) {
                     54:                warnx("unexpected data format %u", eh->e_ident[EI_DATA]);
                     55:                return 0;
                     56:        }
                     57:        if (eh->e_shoff > filesize) {
                     58:                warnx("bogus section table offset 0x%llx", (off_t)eh->e_shoff);
                     59:                return 0;
                     60:        }
                     61:        if (eh->e_shentsize < sizeof(Elf_Shdr)) {
                     62:                warnx("bogus section header size %u", eh->e_shentsize);
                     63:                return 0;
                     64:        }
                     65:        if (eh->e_shnum > (filesize - eh->e_shoff) / eh->e_shentsize) {
                     66:                warnx("bogus section header count %u", eh->e_shnum);
                     67:                return 0;
                     68:        }
                     69:        if (eh->e_shstrndx >= eh->e_shnum) {
                     70:                warnx("bogus string table index %u", eh->e_shstrndx);
                     71:                return 0;
                     72:        }
                     73:
                     74:        return 1;
                     75: }
                     76:
                     77: int
                     78: elf_getshstab(const char *p, size_t filesize, const char **shstab,
                     79:     size_t *shstabsize)
                     80: {
                     81:        Elf_Ehdr                *eh = (Elf_Ehdr *)p;
                     82:        Elf_Shdr                *sh;
1.8     ! mpi        83:        size_t                   shoff;
1.1       mpi        84:
1.8     ! mpi        85:        shoff = eh->e_shoff + eh->e_shstrndx * eh->e_shentsize;
        !            86:        if (shoff > (filesize - sizeof(*sh))) {
        !            87:                warnx("unexpected string table size");
        !            88:                return -1;
        !            89:        }
        !            90:
        !            91:        sh = (Elf_Shdr *)(p + shoff);
1.1       mpi        92:        if (sh->sh_type != SHT_STRTAB) {
                     93:                warnx("unexpected string table type");
                     94:                return -1;
                     95:        }
                     96:        if (sh->sh_offset > filesize) {
                     97:                warnx("bogus string table offset");
                     98:                return -1;
                     99:        }
                    100:        if (sh->sh_size > filesize - sh->sh_offset) {
                    101:                warnx("bogus string table size");
                    102:                return -1;
                    103:        }
                    104:        if (shstab != NULL)
                    105:                *shstab = p + sh->sh_offset;
                    106:        if (shstabsize != NULL)
                    107:                *shstabsize = sh->sh_size;
                    108:
                    109:        return 0;
                    110: }
                    111:
                    112: ssize_t
1.4       jsg       113: elf_getsymtab(const char *p, size_t filesize, const char *shstab,
1.7       mpi       114:     size_t shstabsz, const Elf_Sym **symtab, size_t *nsymb, const char **strtab,
                    115:     size_t *strtabsz)
1.1       mpi       116: {
                    117:        Elf_Ehdr        *eh = (Elf_Ehdr *)p;
1.7       mpi       118:        Elf_Shdr        *sh, *symsh;
1.8     ! mpi       119:        size_t           snlen, shoff;
1.1       mpi       120:        ssize_t          i;
                    121:
                    122:        snlen = strlen(ELF_SYMTAB);
1.7       mpi       123:        symsh = NULL;
1.1       mpi       124:
                    125:        for (i = 0; i < eh->e_shnum; i++) {
1.8     ! mpi       126:                shoff = eh->e_shoff + i * eh->e_shentsize;
        !           127:                if (shoff > (filesize - sizeof(*sh)))
        !           128:                        continue;
1.1       mpi       129:
1.8     ! mpi       130:                sh = (Elf_Shdr *)(p + shoff);
1.1       mpi       131:                if (sh->sh_type != SHT_SYMTAB)
                    132:                        continue;
                    133:
                    134:                if ((sh->sh_link >= eh->e_shnum) || (sh->sh_name >= shstabsz))
                    135:                        continue;
                    136:
1.8     ! mpi       137:                if (sh->sh_offset > filesize)
        !           138:                        continue;
        !           139:
        !           140:                if (sh->sh_size > (filesize - sh->sh_offset))
1.4       jsg       141:                        continue;
                    142:
                    143:                if (sh->sh_entsize == 0)
                    144:                        continue;
                    145:
1.1       mpi       146:                if (strncmp(shstab + sh->sh_name, ELF_SYMTAB, snlen) == 0) {
                    147:                        if (symtab != NULL)
                    148:                                *symtab = (Elf_Sym *)(p + sh->sh_offset);
                    149:                        if (nsymb != NULL)
                    150:                                *nsymb = (sh->sh_size / sh->sh_entsize);
1.7       mpi       151:                        symsh = sh;
1.1       mpi       152:
1.7       mpi       153:                        break;
1.1       mpi       154:                }
                    155:        }
                    156:
1.7       mpi       157:        if (symsh == NULL || (symsh->sh_link >= eh->e_shnum))
                    158:                return -1;
                    159:
1.8     ! mpi       160:        shoff = eh->e_shoff + symsh->sh_link * eh->e_shentsize;
        !           161:        if (shoff > (filesize - sizeof(*sh)))
        !           162:                return -1;
1.7       mpi       163:
1.8     ! mpi       164:        sh = (Elf_Shdr *)(p + shoff);
1.7       mpi       165:        if ((sh->sh_offset + sh->sh_size) > filesize)
                    166:                return -1;
                    167:
                    168:        if (strtab != NULL)
                    169:                *strtab = p + sh->sh_offset;
                    170:        if (strtabsz != NULL)
                    171:                *strtabsz = sh->sh_size;
                    172:
                    173:        return i;
1.1       mpi       174: }
                    175:
                    176: ssize_t
1.4       jsg       177: elf_getsection(char *p, size_t filesize, const char *sname, const char *shstab,
1.1       mpi       178:     size_t shstabsz, const char **psdata, size_t *pssz)
                    179: {
                    180:        Elf_Ehdr        *eh = (Elf_Ehdr *)p;
                    181:        Elf_Shdr        *sh;
                    182:        char            *sdata = NULL;
1.8     ! mpi       183:        size_t           snlen, shoff, ssz = 0;
1.1       mpi       184:        ssize_t          sidx, i;
                    185:
                    186:        snlen = strlen(sname);
                    187:        if (snlen == 0)
                    188:                return -1;
                    189:
                    190:        /* Find the given section. */
                    191:        for (i = 0; i < eh->e_shnum; i++) {
1.8     ! mpi       192:                shoff = eh->e_shoff + i * eh->e_shentsize;
        !           193:                if (shoff > (filesize - sizeof(*sh)))
1.4       jsg       194:                        continue;
                    195:
1.8     ! mpi       196:                sh = (Elf_Shdr *)(p + shoff);
        !           197:                if ((sh->sh_link >= eh->e_shnum) || (sh->sh_name >= shstabsz))
        !           198:                        continue;
1.1       mpi       199:
1.8     ! mpi       200:                if (sh->sh_offset > filesize)
1.1       mpi       201:                        continue;
                    202:
1.8     ! mpi       203:                if (sh->sh_size > (filesize - sh->sh_offset))
1.4       jsg       204:                        continue;
                    205:
1.1       mpi       206:                if (strncmp(shstab + sh->sh_name, sname, snlen) == 0) {
                    207:                        sidx = i;
                    208:                        sdata = p + sh->sh_offset;
                    209:                        ssz = sh->sh_size;
1.4       jsg       210:                        elf_reloc_apply(p, filesize, shstab, shstabsz, sidx,
                    211:                            sdata, ssz);
1.1       mpi       212:                        break;
                    213:                }
                    214:        }
                    215:
                    216:        if (sdata == NULL)
                    217:                return -1;
                    218:
                    219:        if (psdata != NULL)
                    220:                *psdata = sdata;
                    221:        if (pssz != NULL)
                    222:                *pssz = ssz;
                    223:
                    224:        return sidx;
                    225: }
                    226:
                    227: static int
                    228: elf_reloc_size(unsigned long type)
                    229: {
                    230:        switch (type) {
                    231: #ifdef R_X86_64_64
                    232:        case R_X86_64_64:
                    233:                return sizeof(uint64_t);
                    234: #endif
                    235: #ifdef R_X86_64_32
                    236:        case R_X86_64_32:
                    237:                return sizeof(uint32_t);
                    238: #endif
                    239: #ifdef RELOC_32
                    240:        case RELOC_32:
                    241:                return sizeof(uint32_t);
                    242: #endif
                    243:        default:
                    244:                break;
                    245:        }
                    246:
                    247:        return -1;
                    248: }
                    249:
                    250: #define ELF_WRITE_RELOC(buf, val, rsize)                               \
                    251: do {                                                                   \
                    252:        if (rsize == 4) {                                               \
                    253:                uint32_t v32 = val;                                     \
                    254:                memcpy(buf, &v32, sizeof(v32));                         \
                    255:        } else {                                                        \
                    256:                uint64_t v64 = val;                                     \
                    257:                memcpy(buf, &v64, sizeof(v64));                         \
                    258:        }                                                               \
                    259: } while (0)
                    260:
                    261: static void
1.4       jsg       262: elf_reloc_apply(const char *p, size_t filesize, const char *shstab,
                    263:     size_t shstabsz, ssize_t sidx, char *sdata, size_t ssz)
1.1       mpi       264: {
                    265:        Elf_Ehdr        *eh = (Elf_Ehdr *)p;
                    266:        Elf_Shdr        *sh;
                    267:        Elf_Rel         *rel = NULL;
                    268:        Elf_RelA        *rela = NULL;
                    269:        const Elf_Sym   *symtab, *sym;
                    270:        ssize_t          symtabidx;
                    271:        size_t           nsymb, rsym, rtyp, roff;
1.8     ! mpi       272:        size_t           shoff, i, j;
1.1       mpi       273:        uint64_t         value;
                    274:        int              rsize;
                    275:
                    276:        /* Find symbol table location and number of symbols. */
1.4       jsg       277:        symtabidx = elf_getsymtab(p, filesize, shstab, shstabsz, &symtab,
1.7       mpi       278:            &nsymb, NULL, NULL);
1.1       mpi       279:        if (symtabidx == -1) {
                    280:                warnx("symbol table not found");
                    281:                return;
                    282:        }
                    283:
                    284:        /* Apply possible relocation. */
                    285:        for (i = 0; i < eh->e_shnum; i++) {
1.8     ! mpi       286:                shoff = eh->e_shoff + i * eh->e_shentsize;
        !           287:                if (shoff > (filesize - sizeof(*sh)))
1.4       jsg       288:                        continue;
                    289:
1.8     ! mpi       290:                sh = (Elf_Shdr *)(p + shoff);
1.1       mpi       291:                if (sh->sh_size == 0)
                    292:                        continue;
                    293:
                    294:                if ((sh->sh_info != sidx) || (sh->sh_link != symtabidx))
                    295:                        continue;
                    296:
1.8     ! mpi       297:                if (sh->sh_offset > filesize)
        !           298:                        continue;
        !           299:
        !           300:                if (sh->sh_size > (filesize - sh->sh_offset))
1.4       jsg       301:                        continue;
                    302:
1.1       mpi       303:                switch (sh->sh_type) {
                    304:                case SHT_RELA:
                    305:                        rela = (Elf_RelA *)(p + sh->sh_offset);
                    306:                        for (j = 0; j < (sh->sh_size / sizeof(Elf_RelA)); j++) {
                    307:                                rsym = ELF_R_SYM(rela[j].r_info);
                    308:                                rtyp = ELF_R_TYPE(rela[j].r_info);
                    309:                                roff = rela[j].r_offset;
                    310:                                if (rsym >= nsymb)
                    311:                                        continue;
1.4       jsg       312:                                if (roff >= filesize)
                    313:                                        continue;
1.1       mpi       314:                                sym = &symtab[rsym];
                    315:                                value = sym->st_value + rela[j].r_addend;
                    316:
                    317:                                rsize = elf_reloc_size(rtyp);
                    318:                                if (rsize == -1 || roff + rsize >= ssz)
                    319:                                        continue;
                    320:
                    321:                                ELF_WRITE_RELOC(sdata + roff, value, rsize);
                    322:                        }
                    323:                        break;
                    324:                case SHT_REL:
                    325:                        rel = (Elf_Rel *)(p + sh->sh_offset);
                    326:                        for (j = 0; j < (sh->sh_size / sizeof(Elf_Rel)); j++) {
                    327:                                rsym = ELF_R_SYM(rel[j].r_info);
                    328:                                rtyp = ELF_R_TYPE(rel[j].r_info);
                    329:                                roff = rel[j].r_offset;
                    330:                                if (rsym >= nsymb)
1.4       jsg       331:                                        continue;
                    332:                                if (roff >= filesize)
1.1       mpi       333:                                        continue;
                    334:                                sym = &symtab[rsym];
                    335:                                value = sym->st_value;
                    336:
                    337:                                rsize = elf_reloc_size(rtyp);
                    338:                                if (rsize == -1 || roff + rsize >= ssz)
                    339:                                        continue;
                    340:
                    341:                                ELF_WRITE_RELOC(sdata + roff, value, rsize);
                    342:                        }
                    343:                        break;
                    344:                default:
                    345:                        continue;
                    346:                }
                    347:        }
                    348: }