[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.4

1.4     ! jsg         1: /*     $OpenBSD: elf.c,v 1.3 2017/08/29 21:10:20 deraadt 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: #include <sys/exec_elf.h>
                     21:
                     22: #include <machine/reloc.h>
                     23:
                     24: #include <assert.h>
                     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;
                     83:
                     84:        sh = (Elf_Shdr *)(p + eh->e_shoff + eh->e_shstrndx * eh->e_shentsize);
                     85:        if (sh->sh_type != SHT_STRTAB) {
                     86:                warnx("unexpected string table type");
                     87:                return -1;
                     88:        }
                     89:        if (sh->sh_offset > filesize) {
                     90:                warnx("bogus string table offset");
                     91:                return -1;
                     92:        }
                     93:        if (sh->sh_size > filesize - sh->sh_offset) {
                     94:                warnx("bogus string table size");
                     95:                return -1;
                     96:        }
                     97:        if (shstab != NULL)
                     98:                *shstab = p + sh->sh_offset;
                     99:        if (shstabsize != NULL)
                    100:                *shstabsize = sh->sh_size;
                    101:
                    102:        return 0;
                    103: }
                    104:
                    105: ssize_t
1.4     ! jsg       106: elf_getsymtab(const char *p, size_t filesize, const char *shstab,
        !           107:     size_t shstabsz, const Elf_Sym **symtab, size_t *nsymb)
1.1       mpi       108: {
                    109:        Elf_Ehdr        *eh = (Elf_Ehdr *)p;
                    110:        Elf_Shdr        *sh;
                    111:        size_t           snlen;
                    112:        ssize_t          i;
                    113:
                    114:        snlen = strlen(ELF_SYMTAB);
                    115:
                    116:        for (i = 0; i < eh->e_shnum; i++) {
                    117:                sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
                    118:
                    119:                if (sh->sh_type != SHT_SYMTAB)
                    120:                        continue;
                    121:
                    122:                if ((sh->sh_link >= eh->e_shnum) || (sh->sh_name >= shstabsz))
                    123:                        continue;
                    124:
1.4     ! jsg       125:                if ((sh->sh_offset + sh->sh_size) > filesize)
        !           126:                        continue;
        !           127:
        !           128:                if (sh->sh_entsize == 0)
        !           129:                        continue;
        !           130:
1.1       mpi       131:                if (strncmp(shstab + sh->sh_name, ELF_SYMTAB, snlen) == 0) {
                    132:                        if (symtab != NULL)
                    133:                                *symtab = (Elf_Sym *)(p + sh->sh_offset);
                    134:                        if (nsymb != NULL)
                    135:                                *nsymb = (sh->sh_size / sh->sh_entsize);
                    136:
                    137:                        return i;
                    138:                }
                    139:        }
                    140:
                    141:        return -1;
                    142: }
                    143:
                    144: ssize_t
1.4     ! jsg       145: elf_getsection(char *p, size_t filesize, const char *sname, const char *shstab,
1.1       mpi       146:     size_t shstabsz, const char **psdata, size_t *pssz)
                    147: {
                    148:        Elf_Ehdr        *eh = (Elf_Ehdr *)p;
                    149:        Elf_Shdr        *sh;
                    150:        char            *sdata = NULL;
                    151:        size_t           snlen, ssz = 0;
                    152:        ssize_t          sidx, i;
                    153:
                    154:        snlen = strlen(sname);
                    155:        if (snlen == 0)
                    156:                return -1;
                    157:
                    158:        /* Find the given section. */
                    159:        for (i = 0; i < eh->e_shnum; i++) {
1.4     ! jsg       160:                if ((eh->e_shoff + i * eh->e_shentsize) > filesize)
        !           161:                        continue;
        !           162:
1.1       mpi       163:                sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
                    164:
                    165:                if ((sh->sh_link >= eh->e_shnum) || (sh->sh_name >= shstabsz))
                    166:                        continue;
                    167:
1.4     ! jsg       168:                if ((sh->sh_offset + sh->sh_size) > filesize)
        !           169:                        continue;
        !           170:
1.1       mpi       171:                if (strncmp(shstab + sh->sh_name, sname, snlen) == 0) {
                    172:                        sidx = i;
                    173:                        sdata = p + sh->sh_offset;
                    174:                        ssz = sh->sh_size;
1.4     ! jsg       175:                        elf_reloc_apply(p, filesize, shstab, shstabsz, sidx,
        !           176:                            sdata, ssz);
1.1       mpi       177:                        break;
                    178:                }
                    179:        }
                    180:
                    181:        if (sdata == NULL)
                    182:                return -1;
                    183:
                    184:        if (psdata != NULL)
                    185:                *psdata = sdata;
                    186:        if (pssz != NULL)
                    187:                *pssz = ssz;
                    188:
                    189:        return sidx;
                    190: }
                    191:
                    192: static int
                    193: elf_reloc_size(unsigned long type)
                    194: {
                    195:        switch (type) {
                    196: #ifdef R_X86_64_64
                    197:        case R_X86_64_64:
                    198:                return sizeof(uint64_t);
                    199: #endif
                    200: #ifdef R_X86_64_32
                    201:        case R_X86_64_32:
                    202:                return sizeof(uint32_t);
                    203: #endif
                    204: #ifdef RELOC_32
                    205:        case RELOC_32:
                    206:                return sizeof(uint32_t);
                    207: #endif
                    208:        default:
                    209:                break;
                    210:        }
                    211:
                    212:        return -1;
                    213: }
                    214:
                    215: #define ELF_WRITE_RELOC(buf, val, rsize)                               \
                    216: do {                                                                   \
                    217:        if (rsize == 4) {                                               \
                    218:                uint32_t v32 = val;                                     \
                    219:                memcpy(buf, &v32, sizeof(v32));                         \
                    220:        } else {                                                        \
                    221:                uint64_t v64 = val;                                     \
                    222:                memcpy(buf, &v64, sizeof(v64));                         \
                    223:        }                                                               \
                    224: } while (0)
                    225:
                    226: static void
1.4     ! jsg       227: elf_reloc_apply(const char *p, size_t filesize, const char *shstab,
        !           228:     size_t shstabsz, ssize_t sidx, char *sdata, size_t ssz)
1.1       mpi       229: {
                    230:        Elf_Ehdr        *eh = (Elf_Ehdr *)p;
                    231:        Elf_Shdr        *sh;
                    232:        Elf_Rel         *rel = NULL;
                    233:        Elf_RelA        *rela = NULL;
                    234:        const Elf_Sym   *symtab, *sym;
                    235:        ssize_t          symtabidx;
                    236:        size_t           nsymb, rsym, rtyp, roff;
                    237:        size_t           i, j;
                    238:        uint64_t         value;
                    239:        int              rsize;
                    240:
                    241:        /* Find symbol table location and number of symbols. */
1.4     ! jsg       242:        symtabidx = elf_getsymtab(p, filesize, shstab, shstabsz, &symtab,
        !           243:            &nsymb);
1.1       mpi       244:        if (symtabidx == -1) {
                    245:                warnx("symbol table not found");
                    246:                return;
                    247:        }
                    248:
                    249:        /* Apply possible relocation. */
                    250:        for (i = 0; i < eh->e_shnum; i++) {
1.4     ! jsg       251:                if ((eh->e_shoff + i * eh->e_shentsize) > filesize)
        !           252:                        continue;
        !           253:
1.1       mpi       254:                sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
                    255:
                    256:                if (sh->sh_size == 0)
                    257:                        continue;
                    258:
                    259:                if ((sh->sh_info != sidx) || (sh->sh_link != symtabidx))
                    260:                        continue;
                    261:
1.4     ! jsg       262:                if ((sh->sh_offset + sh->sh_size) > filesize)
        !           263:                        continue;
        !           264:
1.1       mpi       265:                switch (sh->sh_type) {
                    266:                case SHT_RELA:
                    267:                        rela = (Elf_RelA *)(p + sh->sh_offset);
                    268:                        for (j = 0; j < (sh->sh_size / sizeof(Elf_RelA)); j++) {
                    269:                                rsym = ELF_R_SYM(rela[j].r_info);
                    270:                                rtyp = ELF_R_TYPE(rela[j].r_info);
                    271:                                roff = rela[j].r_offset;
                    272:                                if (rsym >= nsymb)
                    273:                                        continue;
1.4     ! jsg       274:                                if (roff >= filesize)
        !           275:                                        continue;
1.1       mpi       276:                                sym = &symtab[rsym];
                    277:                                value = sym->st_value + rela[j].r_addend;
                    278:
                    279:                                rsize = elf_reloc_size(rtyp);
                    280:                                if (rsize == -1 || roff + rsize >= ssz)
                    281:                                        continue;
                    282:
                    283:                                ELF_WRITE_RELOC(sdata + roff, value, rsize);
                    284:                        }
                    285:                        break;
                    286:                case SHT_REL:
                    287:                        rel = (Elf_Rel *)(p + sh->sh_offset);
                    288:                        for (j = 0; j < (sh->sh_size / sizeof(Elf_Rel)); j++) {
                    289:                                rsym = ELF_R_SYM(rel[j].r_info);
                    290:                                rtyp = ELF_R_TYPE(rel[j].r_info);
                    291:                                roff = rel[j].r_offset;
                    292:                                if (rsym >= nsymb)
1.4     ! jsg       293:                                        continue;
        !           294:                                if (roff >= filesize)
1.1       mpi       295:                                        continue;
                    296:                                sym = &symtab[rsym];
                    297:                                value = sym->st_value;
                    298:
                    299:                                rsize = elf_reloc_size(rtyp);
                    300:                                if (rsize == -1 || roff + rsize >= ssz)
                    301:                                        continue;
                    302:
                    303:                                ELF_WRITE_RELOC(sdata + roff, value, rsize);
                    304:                        }
                    305:                        break;
                    306:                default:
                    307:                        continue;
                    308:                }
                    309:        }
                    310: }