Annotation of src/usr.bin/ctfconv/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);
29: static void elf_reloc_apply(const char *, const char *, size_t, ssize_t,
30: char *, size_t);
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
106: elf_getsymtab(const char *p, const char *shstab, size_t shstabsz,
107: const Elf_Sym **symtab, size_t *nsymb)
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:
125: if (strncmp(shstab + sh->sh_name, ELF_SYMTAB, snlen) == 0) {
126: if (symtab != NULL)
127: *symtab = (Elf_Sym *)(p + sh->sh_offset);
128: if (nsymb != NULL)
129: *nsymb = (sh->sh_size / sh->sh_entsize);
130:
131: return i;
132: }
133: }
134:
135: return -1;
136: }
137:
138: ssize_t
1.4 ! jsg 139: elf_getsection(char *p, size_t filesize, const char *sname, const char *shstab,
1.1 mpi 140: size_t shstabsz, const char **psdata, size_t *pssz)
141: {
142: Elf_Ehdr *eh = (Elf_Ehdr *)p;
143: Elf_Shdr *sh;
144: char *sdata = NULL;
145: size_t snlen, ssz = 0;
146: ssize_t sidx, i;
147:
148: snlen = strlen(sname);
149: if (snlen == 0)
150: return -1;
151:
152: /* Find the given section. */
153: for (i = 0; i < eh->e_shnum; i++) {
154: sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
155:
156: if ((sh->sh_link >= eh->e_shnum) || (sh->sh_name >= shstabsz))
1.4 ! jsg 157: continue;
! 158:
! 159: if (sh->sh_offset >= filesize)
1.1 mpi 160: continue;
161:
162: if (strncmp(shstab + sh->sh_name, sname, snlen) == 0) {
163: sidx = i;
164: sdata = p + sh->sh_offset;
165: ssz = sh->sh_size;
166: elf_reloc_apply(p, shstab, shstabsz, sidx, sdata, ssz);
167: break;
168: }
169: }
170:
171: if (sdata == NULL)
172: return -1;
173:
174: if (psdata != NULL)
175: *psdata = sdata;
176: if (pssz != NULL)
177: *pssz = ssz;
178:
179: return sidx;
180: }
181:
182: static int
183: elf_reloc_size(unsigned long type)
184: {
185: switch (type) {
186: #ifdef R_X86_64_64
187: case R_X86_64_64:
188: return sizeof(uint64_t);
189: #endif
190: #ifdef R_X86_64_32
191: case R_X86_64_32:
192: return sizeof(uint32_t);
193: #endif
194: #ifdef RELOC_32
195: case RELOC_32:
196: return sizeof(uint32_t);
197: #endif
198: default:
199: break;
200: }
201:
202: return -1;
203: }
204:
205: #define ELF_WRITE_RELOC(buf, val, rsize) \
206: do { \
207: if (rsize == 4) { \
208: uint32_t v32 = val; \
209: memcpy(buf, &v32, sizeof(v32)); \
210: } else { \
211: uint64_t v64 = val; \
212: memcpy(buf, &v64, sizeof(v64)); \
213: } \
214: } while (0)
215:
216: static void
217: elf_reloc_apply(const char *p, const char *shstab, size_t shstabsz,
218: ssize_t sidx, char *sdata, size_t ssz)
219: {
220: Elf_Ehdr *eh = (Elf_Ehdr *)p;
221: Elf_Shdr *sh;
222: Elf_Rel *rel = NULL;
223: Elf_RelA *rela = NULL;
224: const Elf_Sym *symtab, *sym;
225: ssize_t symtabidx;
226: size_t nsymb, rsym, rtyp, roff;
227: size_t i, j;
228: uint64_t value;
229: int rsize;
230:
231: /* Find symbol table location and number of symbols. */
232: symtabidx = elf_getsymtab(p, shstab, shstabsz, &symtab, &nsymb);
233: if (symtabidx == -1) {
234: warnx("symbol table not found");
235: return;
236: }
237:
238: /* Apply possible relocation. */
239: for (i = 0; i < eh->e_shnum; i++) {
240: sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
241:
242: if (sh->sh_size == 0)
243: continue;
244:
245: if ((sh->sh_info != sidx) || (sh->sh_link != symtabidx))
246: continue;
247:
248: switch (sh->sh_type) {
249: case SHT_RELA:
250: rela = (Elf_RelA *)(p + sh->sh_offset);
251: for (j = 0; j < (sh->sh_size / sizeof(Elf_RelA)); j++) {
252: rsym = ELF_R_SYM(rela[j].r_info);
253: rtyp = ELF_R_TYPE(rela[j].r_info);
254: roff = rela[j].r_offset;
255: if (rsym >= nsymb)
256: continue;
257: sym = &symtab[rsym];
258: value = sym->st_value + rela[j].r_addend;
259:
260: rsize = elf_reloc_size(rtyp);
261: if (rsize == -1 || roff + rsize >= ssz)
262: continue;
263:
264: ELF_WRITE_RELOC(sdata + roff, value, rsize);
265: }
266: break;
267: case SHT_REL:
268: rel = (Elf_Rel *)(p + sh->sh_offset);
269: for (j = 0; j < (sh->sh_size / sizeof(Elf_Rel)); j++) {
270: rsym = ELF_R_SYM(rel[j].r_info);
271: rtyp = ELF_R_TYPE(rel[j].r_info);
272: roff = rel[j].r_offset;
273: if (rsym >= nsymb)
274: continue;
275: sym = &symtab[rsym];
276: value = sym->st_value;
277:
278: rsize = elf_reloc_size(rtyp);
279: if (rsize == -1 || roff + rsize >= ssz)
280: continue;
281:
282: ELF_WRITE_RELOC(sdata + roff, value, rsize);
283: }
284: break;
285: default:
286: continue;
287: }
288: }
289: }