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: }