xref: /freebsd/usr.sbin/kldxref/elf.c (revision 1edb7116)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2021-2023 John Baldwin <jhb@FreeBSD.org>
5  *
6  * This software was developed by SRI International and the University
7  * of Cambridge Computer Laboratory (Department of Computer Science
8  * and Technology) under Defense Advanced Research Projects Agency
9  * (DARPA) contract HR0011-18-C-0016 ("ECATS"), as part of the DARPA
10  * SSITH research programme and under DARPA Contract No. HR001123C0031
11  * ("MTSS").
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include <sys/param.h>
36 #include <sys/endian.h>
37 
38 #include <err.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <gelf.h>
42 #include <libelf.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 
47 #include "ef.h"
48 
49 SET_DECLARE(elf_reloc, struct elf_reloc_data);
50 
51 static elf_reloc_t *
52 elf_find_reloc(const GElf_Ehdr *hdr)
53 {
54 	struct elf_reloc_data **erd;
55 
56 	SET_FOREACH(erd, elf_reloc) {
57 		if (hdr->e_ident[EI_CLASS] == (*erd)->class &&
58 		    hdr->e_ident[EI_DATA] == (*erd)->data &&
59 		    hdr->e_machine == (*erd)->machine)
60 			return ((*erd)->reloc);
61 	}
62 	return (NULL);
63 }
64 
65 int
66 elf_open_file(struct elf_file *efile, const char *filename, int verbose)
67 {
68 	int error;
69 
70 	memset(efile, 0, sizeof(*efile));
71 	efile->ef_filename = filename;
72 	efile->ef_fd = open(filename, O_RDONLY);
73 	if (efile->ef_fd == -1) {
74 		if (verbose)
75 			warn("open(%s)", filename);
76 		return (errno);
77 	}
78 
79 	efile->ef_elf = elf_begin(efile->ef_fd, ELF_C_READ, NULL);
80 	if (efile->ef_elf == NULL) {
81 		if (verbose)
82 			warnx("elf_begin(%s): %s", filename, elf_errmsg(0));
83 		elf_close_file(efile);
84 		return (EINVAL);
85 	}
86 
87 	if (elf_kind(efile->ef_elf) != ELF_K_ELF) {
88 		if (verbose)
89 			warnx("%s: not an ELF file", filename);
90 		elf_close_file(efile);
91 		return (EINVAL);
92 	}
93 
94 	if (gelf_getehdr(efile->ef_elf, &efile->ef_hdr) == NULL) {
95 		if (verbose)
96 			warnx("gelf_getehdr(%s): %s", filename, elf_errmsg(0));
97 		elf_close_file(efile);
98 		return (EINVAL);
99 	}
100 
101 	efile->ef_reloc = elf_find_reloc(&efile->ef_hdr);
102 	if (efile->ef_reloc == NULL) {
103 		if (verbose)
104 			warnx("%s: unsupported architecture", filename);
105 		elf_close_file(efile);
106 		return (EFTYPE);
107 	}
108 
109 	error = ef_open(efile, verbose);
110 	if (error != 0) {
111 		error = ef_obj_open(efile, verbose);
112 		if (error != 0) {
113 			if (verbose)
114 				warnc(error, "%s: not a valid DSO or object file",
115 				    filename);
116 			elf_close_file(efile);
117 			return (error);
118 		}
119 	}
120 
121 	efile->ef_pointer_size = elf_object_size(efile, ELF_T_ADDR);
122 
123 	return (0);
124 }
125 
126 void
127 elf_close_file(struct elf_file *efile)
128 {
129 	if (efile->ef_ops != NULL) {
130 		EF_CLOSE(efile);
131 	}
132 	if (efile->ef_elf != NULL) {
133 		elf_end(efile->ef_elf);
134 		efile->ef_elf = NULL;
135 	}
136 	if (efile->ef_fd > 0) {
137 		close(efile->ef_fd);
138 		efile->ef_fd = -1;
139 	}
140 }
141 
142 bool
143 elf_compatible(struct elf_file *efile, const GElf_Ehdr *hdr)
144 {
145 	if (efile->ef_hdr.e_ident[EI_CLASS] != hdr->e_ident[EI_CLASS] ||
146 	    efile->ef_hdr.e_ident[EI_DATA] != hdr->e_ident[EI_DATA] ||
147 	    efile->ef_hdr.e_machine != hdr->e_machine)
148 		return (false);
149 	return (true);
150 }
151 
152 size_t
153 elf_object_size(struct elf_file *efile, Elf_Type type)
154 {
155 	return (gelf_fsize(efile->ef_elf, type, 1, efile->ef_hdr.e_version));
156 }
157 
158 /*
159  * The number of objects of 'type' in region of the file of size
160  * 'file_size'.
161  */
162 static size_t
163 elf_object_count(struct elf_file *efile, Elf_Type type, size_t file_size)
164 {
165 	return (file_size / elf_object_size(efile, type));
166 }
167 
168 int
169 elf_read_raw_data(struct elf_file *efile, off_t offset, void *dst, size_t len)
170 {
171 	ssize_t nread;
172 
173 	nread = pread(efile->ef_fd, dst, len, offset);
174 	if (nread == -1)
175 		return (errno);
176 	if (nread != len)
177 		return (EIO);
178 	return (0);
179 }
180 
181 int
182 elf_read_raw_data_alloc(struct elf_file *efile, off_t offset, size_t len,
183     void **out)
184 {
185 	void *buf;
186 	int error;
187 
188 	buf = malloc(len);
189 	if (buf == NULL)
190 		return (ENOMEM);
191 	error = elf_read_raw_data(efile, offset, buf, len);
192 	if (error != 0) {
193 		free(buf);
194 		return (error);
195 	}
196 	*out = buf;
197 	return (0);
198 }
199 
200 int
201 elf_read_data(struct elf_file *efile, Elf_Type type, off_t offset, size_t len,
202     void **out)
203 {
204 	Elf_Data dst, src;
205 	void *buf;
206 	int error;
207 
208 	buf = malloc(len);
209 	if (buf == NULL)
210 		return (ENOMEM);
211 
212 	error = elf_read_raw_data(efile, offset, buf, len);
213 	if (error != 0) {
214 		free(buf);
215 		return (error);
216 	}
217 
218 	memset(&dst, 0, sizeof(dst));
219 	memset(&src, 0, sizeof(src));
220 
221 	src.d_buf = buf;
222 	src.d_size = len;
223 	src.d_type = type;
224 	src.d_version = efile->ef_hdr.e_version;
225 
226 	dst.d_buf = buf;
227 	dst.d_size = len;
228 	dst.d_version = EV_CURRENT;
229 
230 	if (gelf_xlatetom(efile->ef_elf, &dst, &src, elf_encoding(efile)) ==
231 	    NULL) {
232 		free(buf);
233 		return (ENXIO);
234 	}
235 
236 	if (dst.d_size != len)
237 		warnx("elf_read_data: translation of type %u size mismatch",
238 		    type);
239 
240 	*out = buf;
241 	return (0);
242 }
243 
244 int
245 elf_read_relocated_data(struct elf_file *efile, GElf_Addr address, size_t len,
246     void **buf)
247 {
248 	int error;
249 	void *p;
250 
251 	p = malloc(len);
252 	if (p == NULL)
253 		return (ENOMEM);
254 	error = EF_SEG_READ_REL(efile, address, len, p);
255 	if (error != 0) {
256 		free(p);
257 		return (error);
258 	}
259 	*buf = p;
260 	return (0);
261 }
262 
263 int
264 elf_read_phdrs(struct elf_file *efile, size_t *nphdrp, GElf_Phdr **phdrp)
265 {
266 	GElf_Phdr *phdr;
267 	size_t nphdr, i;
268 	int error;
269 
270 	if (elf_getphdrnum(efile->ef_elf, &nphdr) == -1)
271 		return (EFTYPE);
272 
273 	phdr = calloc(nphdr, sizeof(*phdr));
274 	if (phdr == NULL)
275 		return (ENOMEM);
276 
277 	for (i = 0; i < nphdr; i++) {
278 		if (gelf_getphdr(efile->ef_elf, i, &phdr[i]) == NULL) {
279 			error = EFTYPE;
280 			goto out;
281 		}
282 	}
283 
284 	*nphdrp = nphdr;
285 	*phdrp = phdr;
286 	return (0);
287 out:
288 	free(phdr);
289 	return (error);
290 }
291 
292 int
293 elf_read_shdrs(struct elf_file *efile, size_t *nshdrp, GElf_Shdr **shdrp)
294 {
295 	GElf_Shdr *shdr;
296 	Elf_Scn *scn;
297 	size_t nshdr, i;
298 	int error;
299 
300 	if (elf_getshdrnum(efile->ef_elf, &nshdr) == -1)
301 		return (EFTYPE);
302 
303 	shdr = calloc(nshdr, sizeof(*shdr));
304 	if (shdr == NULL)
305 		return (ENOMEM);
306 
307 	for (i = 0; i < nshdr; i++) {
308 		scn = elf_getscn(efile->ef_elf, i);
309 		if (scn == NULL) {
310 			error = EFTYPE;
311 			goto out;
312 		}
313 		if (gelf_getshdr(scn, &shdr[i]) == NULL) {
314 			error = EFTYPE;
315 			goto out;
316 		}
317 	}
318 
319 	*nshdrp = nshdr;
320 	*shdrp = shdr;
321 	return (0);
322 out:
323 	free(shdr);
324 	return (error);
325 }
326 
327 int
328 elf_read_dynamic(struct elf_file *efile, int section_index, size_t *ndynp,
329     GElf_Dyn **dynp)
330 {
331 	GElf_Shdr shdr;
332 	Elf_Scn *scn;
333 	Elf_Data *data;
334 	GElf_Dyn *dyn;
335 	long i, ndyn;
336 
337 	scn = elf_getscn(efile->ef_elf, section_index);
338 	if (scn == NULL)
339 		return (EINVAL);
340 	if (gelf_getshdr(scn, &shdr) == NULL)
341 		return (EINVAL);
342 	data = elf_getdata(scn, NULL);
343 	if (data == NULL)
344 		return (EINVAL);
345 
346 	ndyn = elf_object_count(efile, ELF_T_DYN, shdr.sh_size);
347 	dyn = calloc(ndyn, sizeof(*dyn));
348 	if (dyn == NULL)
349 		return (ENOMEM);
350 
351 	for (i = 0; i < ndyn; i++) {
352 		if (gelf_getdyn(data, i, &dyn[i]) == NULL) {
353 			free(dyn);
354 			return (EINVAL);
355 		}
356 	}
357 
358 	*ndynp = ndyn;
359 	*dynp = dyn;
360 	return (0);
361 }
362 
363 int
364 elf_read_symbols(struct elf_file *efile, int section_index, size_t *nsymp,
365     GElf_Sym **symp)
366 {
367 	GElf_Shdr shdr;
368 	Elf_Scn *scn;
369 	Elf_Data *data;
370 	GElf_Sym *sym;
371 	size_t i, nsym;
372 
373 	scn = elf_getscn(efile->ef_elf, section_index);
374 	if (scn == NULL)
375 		return (EINVAL);
376 	if (gelf_getshdr(scn, &shdr) == NULL)
377 		return (EINVAL);
378 	data = elf_getdata(scn, NULL);
379 	if (data == NULL)
380 		return (EINVAL);
381 
382 	nsym = elf_object_count(efile, ELF_T_SYM, shdr.sh_size);
383 	sym = calloc(nsym, sizeof(*sym));
384 	if (sym == NULL)
385 		return (ENOMEM);
386 
387 	for (i = 0; i < nsym; i++) {
388 		if (gelf_getsym(data, i, &sym[i]) == NULL) {
389 			free(sym);
390 			return (EINVAL);
391 		}
392 	}
393 
394 	*nsymp = nsym;
395 	*symp = sym;
396 	return (0);
397 }
398 
399 int
400 elf_read_string_table(struct elf_file *efile, const GElf_Shdr *shdr,
401     long *strcnt, char **strtab)
402 {
403 	int error;
404 
405 	if (shdr->sh_type != SHT_STRTAB)
406 		return (EINVAL);
407 	error = elf_read_raw_data_alloc(efile, shdr->sh_offset, shdr->sh_size,
408 	    (void **)strtab);
409 	if (error != 0)
410 		return (error);
411 	*strcnt = shdr->sh_size;
412 	return (0);
413 }
414 
415 int
416 elf_read_rel(struct elf_file *efile, int section_index, long *nrelp,
417     GElf_Rel **relp)
418 {
419 	GElf_Shdr shdr;
420 	Elf_Scn *scn;
421 	Elf_Data *data;
422 	GElf_Rel *rel;
423 	long i, nrel;
424 
425 	scn = elf_getscn(efile->ef_elf, section_index);
426 	if (scn == NULL)
427 		return (EINVAL);
428 	if (gelf_getshdr(scn, &shdr) == NULL)
429 		return (EINVAL);
430 	data = elf_getdata(scn, NULL);
431 	if (data == NULL)
432 		return (EINVAL);
433 
434 	nrel = elf_object_count(efile, ELF_T_REL, shdr.sh_size);
435 	rel = calloc(nrel, sizeof(*rel));
436 	if (rel == NULL)
437 		return (ENOMEM);
438 
439 	for (i = 0; i < nrel; i++) {
440 		if (gelf_getrel(data, i, &rel[i]) == NULL) {
441 			free(rel);
442 			return (EINVAL);
443 		}
444 	}
445 
446 	*nrelp = nrel;
447 	*relp = rel;
448 	return (0);
449 }
450 
451 int
452 elf_read_rela(struct elf_file *efile, int section_index, long *nrelap,
453     GElf_Rela **relap)
454 {
455 	GElf_Shdr shdr;
456 	Elf_Scn *scn;
457 	Elf_Data *data;
458 	GElf_Rela *rela;
459 	long i, nrela;
460 
461 	scn = elf_getscn(efile->ef_elf, section_index);
462 	if (scn == NULL)
463 		return (EINVAL);
464 	if (gelf_getshdr(scn, &shdr) == NULL)
465 		return (EINVAL);
466 	data = elf_getdata(scn, NULL);
467 	if (data == NULL)
468 		return (EINVAL);
469 
470 	nrela = elf_object_count(efile, ELF_T_RELA, shdr.sh_size);
471 	rela = calloc(nrela, sizeof(*rela));
472 	if (rela == NULL)
473 		return (ENOMEM);
474 
475 	for (i = 0; i < nrela; i++) {
476 		if (gelf_getrela(data, i, &rela[i]) == NULL) {
477 			free(rela);
478 			return (EINVAL);
479 		}
480 	}
481 
482 	*nrelap = nrela;
483 	*relap = rela;
484 	return (0);
485 }
486 
487 size_t
488 elf_pointer_size(struct elf_file *efile)
489 {
490 	return (efile->ef_pointer_size);
491 }
492 
493 int
494 elf_int(struct elf_file *efile, const void *p)
495 {
496 	if (elf_encoding(efile) == ELFDATA2LSB)
497 		return (le32dec(p));
498 	else
499 		return (be32dec(p));
500 }
501 
502 GElf_Addr
503 elf_address_from_pointer(struct elf_file *efile, const void *p)
504 {
505 	switch (elf_class(efile)) {
506 	case ELFCLASS32:
507 		if (elf_encoding(efile) == ELFDATA2LSB)
508 			return (le32dec(p));
509 		else
510 			return (be32dec(p));
511 	case ELFCLASS64:
512 		if (elf_encoding(efile) == ELFDATA2LSB)
513 			return (le64dec(p));
514 		else
515 			return (be64dec(p));
516 	default:
517 		__builtin_unreachable();
518 	}
519 }
520 
521 int
522 elf_read_string(struct elf_file *efile, GElf_Addr address, void *dst,
523     size_t len)
524 {
525 	return (EF_SEG_READ_STRING(efile, address, len, dst));
526 }
527 
528 int
529 elf_read_linker_set(struct elf_file *efile, const char *name, GElf_Addr **bufp,
530     long *countp)
531 {
532 	GElf_Addr *buf, start, stop;
533 	char *p;
534 	void *raw;
535 	long i, count;
536 	int error;
537 
538 	error = EF_LOOKUP_SET(efile, name, &start, &stop, &count);
539 	if (error != 0)
540 		return (error);
541 
542 	error = elf_read_relocated_data(efile, start,
543 	    count * elf_pointer_size(efile), &raw);
544 	if (error != 0)
545 		return (error);
546 
547 	buf = calloc(count, sizeof(*buf));
548 	if (buf == NULL) {
549 		free(raw);
550 		return (ENOMEM);
551 	}
552 
553 	p = raw;
554 	for (i = 0; i < count; i++) {
555 		buf[i] = elf_address_from_pointer(efile, p);
556 		p += elf_pointer_size(efile);
557 	}
558 	free(raw);
559 
560 	*bufp = buf;
561 	*countp = count;
562 	return (0);
563 }
564 
565 int
566 elf_read_mod_depend(struct elf_file *efile, GElf_Addr addr,
567     struct Gmod_depend *mdp)
568 {
569 	int *p;
570 	int error;
571 
572 	error = elf_read_relocated_data(efile, addr, sizeof(int) * 3,
573 	    (void **)&p);
574 	if (error != 0)
575 		return (error);
576 
577 	memset(mdp, 0, sizeof(*mdp));
578 	mdp->md_ver_minimum = elf_int(efile, p);
579 	mdp->md_ver_preferred = elf_int(efile, p + 1);
580 	mdp->md_ver_maximum = elf_int(efile, p + 2);
581 	free(p);
582 	return (0);
583 }
584 
585 int
586 elf_read_mod_version(struct elf_file *efile, GElf_Addr addr,
587     struct Gmod_version *mdv)
588 {
589 	int error, value;
590 
591 	error = EF_SEG_READ_REL(efile, addr, sizeof(int), &value);
592 	if (error != 0)
593 		return (error);
594 
595 	memset(mdv, 0, sizeof(*mdv));
596 	mdv->mv_version = elf_int(efile, &value);
597 	return (0);
598 }
599 
600 int
601 elf_read_mod_metadata(struct elf_file *efile, GElf_Addr addr,
602     struct Gmod_metadata *md)
603 {
604 	char *p;
605 	size_t len, offset, pointer_size;
606 	int error;
607 
608 	pointer_size = elf_pointer_size(efile);
609 	len = 2 * sizeof(int);
610 	len = roundup(len, pointer_size);
611 	len += 2 * pointer_size;
612 
613 	error = elf_read_relocated_data(efile, addr, len, (void **)&p);
614 	if (error != 0)
615 		return (error);
616 
617 	memset(md, 0, sizeof(*md));
618 	offset = 0;
619 	md->md_version = elf_int(efile, p + offset);
620 	offset += sizeof(int);
621 	md->md_type = elf_int(efile, p + offset);
622 	offset += sizeof(int);
623 	offset = roundup(offset, pointer_size);
624 	md->md_data = elf_address_from_pointer(efile, p + offset);
625 	offset += pointer_size;
626  	md->md_cval = elf_address_from_pointer(efile, p + offset);
627 	free(p);
628 	return (0);
629 }
630 
631 int
632 elf_read_mod_pnp_match_info(struct elf_file *efile, GElf_Addr addr,
633     struct Gmod_pnp_match_info *pnp)
634 {
635 	char *p;
636 	size_t len, offset, pointer_size;
637 	int error;
638 
639 	pointer_size = elf_pointer_size(efile);
640 	len = 3 * pointer_size;
641 	len = roundup(len, pointer_size);
642 	len += 2 * sizeof(int);
643 
644 	error = elf_read_relocated_data(efile, addr, len, (void **)&p);
645 	if (error != 0)
646 		return (error);
647 
648 	memset(pnp, 0, sizeof(*pnp));
649 	offset = 0;
650 	pnp->descr = elf_address_from_pointer(efile, p + offset);
651 	offset += pointer_size;
652 	pnp->bus = elf_address_from_pointer(efile, p + offset);
653 	offset += pointer_size;
654 	pnp->table = elf_address_from_pointer(efile, p + offset);
655 	offset += pointer_size;
656 	offset = roundup(offset, pointer_size);
657 	pnp->entry_len = elf_int(efile, p + offset);
658 	offset += sizeof(int);
659 	pnp->num_entry = elf_int(efile, p + offset);
660 	free(p);
661 	return (0);
662 }
663 
664 int
665 elf_reloc(struct elf_file *efile, const void *reldata, Elf_Type reltype,
666     GElf_Addr relbase, GElf_Addr dataoff, size_t len, void *dest)
667 {
668 	return (efile->ef_reloc(efile, reldata, reltype, relbase, dataoff, len,
669 	    dest));
670 }
671