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

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

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