Annotation of src/usr.bin/ctfconv/elf.c, Revision 1.9
1.9 ! mpi 1: /* $OpenBSD: elf.c,v 1.8 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.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;
1.9 ! mpi 83: size_t shoff;
1.1 mpi 84:
1.9 ! 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.5 jsg 113: elf_getsymtab(const char *p, size_t filesize, const char *shstab,
1.8 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.8 mpi 118: Elf_Shdr *sh, *symsh;
1.9 ! mpi 119: size_t snlen, shoff;
1.1 mpi 120: ssize_t i;
121:
122: snlen = strlen(ELF_SYMTAB);
1.8 mpi 123: symsh = NULL;
1.1 mpi 124:
125: for (i = 0; i < eh->e_shnum; i++) {
1.9 ! mpi 126: shoff = eh->e_shoff + i * eh->e_shentsize;
! 127: if (shoff > (filesize - sizeof(*sh)))
! 128: continue;
1.1 mpi 129:
1.9 ! 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.9 ! mpi 137: if (sh->sh_offset > filesize)
! 138: continue;
! 139:
! 140: if (sh->sh_size > (filesize - sh->sh_offset))
1.5 jsg 141: continue;
142:
1.6 jsg 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.8 mpi 151: symsh = sh;
1.1 mpi 152:
1.8 mpi 153: break;
1.1 mpi 154: }
155: }
156:
1.8 mpi 157: if (symsh == NULL || (symsh->sh_link >= eh->e_shnum))
158: return -1;
159:
1.9 ! mpi 160: shoff = eh->e_shoff + symsh->sh_link * eh->e_shentsize;
! 161: if (shoff > (filesize - sizeof(*sh)))
! 162: return -1;
1.8 mpi 163:
1.9 ! mpi 164: sh = (Elf_Shdr *)(p + shoff);
1.8 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.9 ! 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.9 ! mpi 192: shoff = eh->e_shoff + i * eh->e_shentsize;
! 193: if (shoff > (filesize - sizeof(*sh)))
1.6 jsg 194: continue;
195:
1.9 ! 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.9 ! mpi 200: if (sh->sh_offset > filesize)
1.4 jsg 201: continue;
202:
1.9 ! mpi 203: if (sh->sh_size > (filesize - sh->sh_offset))
1.1 mpi 204: continue;
205:
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.5 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.5 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.9 ! 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.5 jsg 277: symtabidx = elf_getsymtab(p, filesize, shstab, shstabsz, &symtab,
1.8 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.9 ! mpi 286: shoff = eh->e_shoff + i * eh->e_shentsize;
! 287: if (shoff > (filesize - sizeof(*sh)))
1.6 jsg 288: continue;
289:
1.9 ! 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.9 ! mpi 297: if (sh->sh_offset > filesize)
! 298: continue;
! 299:
! 300: if (sh->sh_size > (filesize - sh->sh_offset))
1.6 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.6 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.6 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: }