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