xref: /freebsd/lib/libkldelf/elf.c (revision 5036d9652a5701d00e9e40ea942c278e9f77d33d)
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 "kldelf.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_raw_string(struct elf_file *efile, off_t offset, char *dst, size_t len)
202 {
203 	ssize_t nread;
204 
205 	nread = pread(efile->ef_fd, dst, len, offset);
206 	if (nread == -1)
207 		return (errno);
208 	if (nread == 0)
209 		return (EIO);
210 
211 	/* A short read is ok so long as the data contains a terminator. */
212 	if (strnlen(dst, nread) == nread)
213 		return (EFAULT);
214 
215 	return (0);
216 }
217 
218 int
219 elf_read_data(struct elf_file *efile, Elf_Type type, off_t offset, size_t len,
220     void **out)
221 {
222 	Elf_Data dst, src;
223 	void *buf;
224 	int error;
225 
226 	buf = malloc(len);
227 	if (buf == NULL)
228 		return (ENOMEM);
229 
230 	error = elf_read_raw_data(efile, offset, buf, len);
231 	if (error != 0) {
232 		free(buf);
233 		return (error);
234 	}
235 
236 	memset(&dst, 0, sizeof(dst));
237 	memset(&src, 0, sizeof(src));
238 
239 	src.d_buf = buf;
240 	src.d_size = len;
241 	src.d_type = type;
242 	src.d_version = efile->ef_hdr.e_version;
243 
244 	dst.d_buf = buf;
245 	dst.d_size = len;
246 	dst.d_version = EV_CURRENT;
247 
248 	if (gelf_xlatetom(efile->ef_elf, &dst, &src, elf_encoding(efile)) ==
249 	    NULL) {
250 		free(buf);
251 		return (ENXIO);
252 	}
253 
254 	if (dst.d_size != len)
255 		warnx("elf_read_data: translation of type %u size mismatch",
256 		    type);
257 
258 	*out = buf;
259 	return (0);
260 }
261 
262 int
263 elf_read_relocated_data(struct elf_file *efile, GElf_Addr address, size_t len,
264     void **buf)
265 {
266 	int error;
267 	void *p;
268 
269 	p = malloc(len);
270 	if (p == NULL)
271 		return (ENOMEM);
272 	error = EF_SEG_READ_REL(efile, address, len, p);
273 	if (error != 0) {
274 		free(p);
275 		return (error);
276 	}
277 	*buf = p;
278 	return (0);
279 }
280 
281 int
282 elf_read_phdrs(struct elf_file *efile, size_t *nphdrp, GElf_Phdr **phdrp)
283 {
284 	GElf_Phdr *phdr;
285 	size_t nphdr, i;
286 	int error;
287 
288 	if (elf_getphdrnum(efile->ef_elf, &nphdr) == -1)
289 		return (EFTYPE);
290 
291 	phdr = calloc(nphdr, sizeof(*phdr));
292 	if (phdr == NULL)
293 		return (ENOMEM);
294 
295 	for (i = 0; i < nphdr; i++) {
296 		if (gelf_getphdr(efile->ef_elf, i, &phdr[i]) == NULL) {
297 			error = EFTYPE;
298 			goto out;
299 		}
300 	}
301 
302 	*nphdrp = nphdr;
303 	*phdrp = phdr;
304 	return (0);
305 out:
306 	free(phdr);
307 	return (error);
308 }
309 
310 int
311 elf_read_shdrs(struct elf_file *efile, size_t *nshdrp, GElf_Shdr **shdrp)
312 {
313 	GElf_Shdr *shdr;
314 	Elf_Scn *scn;
315 	size_t nshdr, i;
316 	int error;
317 
318 	if (elf_getshdrnum(efile->ef_elf, &nshdr) == -1)
319 		return (EFTYPE);
320 
321 	shdr = calloc(nshdr, sizeof(*shdr));
322 	if (shdr == NULL)
323 		return (ENOMEM);
324 
325 	for (i = 0; i < nshdr; i++) {
326 		scn = elf_getscn(efile->ef_elf, i);
327 		if (scn == NULL) {
328 			error = EFTYPE;
329 			goto out;
330 		}
331 		if (gelf_getshdr(scn, &shdr[i]) == NULL) {
332 			error = EFTYPE;
333 			goto out;
334 		}
335 	}
336 
337 	*nshdrp = nshdr;
338 	*shdrp = shdr;
339 	return (0);
340 out:
341 	free(shdr);
342 	return (error);
343 }
344 
345 int
346 elf_read_dynamic(struct elf_file *efile, int section_index, size_t *ndynp,
347     GElf_Dyn **dynp)
348 {
349 	GElf_Shdr shdr;
350 	Elf_Scn *scn;
351 	Elf_Data *data;
352 	GElf_Dyn *dyn;
353 	long i, ndyn;
354 
355 	scn = elf_getscn(efile->ef_elf, section_index);
356 	if (scn == NULL)
357 		return (EINVAL);
358 	if (gelf_getshdr(scn, &shdr) == NULL)
359 		return (EINVAL);
360 	data = elf_getdata(scn, NULL);
361 	if (data == NULL)
362 		return (EINVAL);
363 
364 	ndyn = elf_object_count(efile, ELF_T_DYN, shdr.sh_size);
365 	dyn = calloc(ndyn, sizeof(*dyn));
366 	if (dyn == NULL)
367 		return (ENOMEM);
368 
369 	for (i = 0; i < ndyn; i++) {
370 		if (gelf_getdyn(data, i, &dyn[i]) == NULL) {
371 			free(dyn);
372 			return (EINVAL);
373 		}
374 	}
375 
376 	*ndynp = ndyn;
377 	*dynp = dyn;
378 	return (0);
379 }
380 
381 int
382 elf_read_symbols(struct elf_file *efile, int section_index, size_t *nsymp,
383     GElf_Sym **symp)
384 {
385 	GElf_Shdr shdr;
386 	Elf_Scn *scn;
387 	Elf_Data *data;
388 	GElf_Sym *sym;
389 	size_t i, nsym;
390 
391 	scn = elf_getscn(efile->ef_elf, section_index);
392 	if (scn == NULL)
393 		return (EINVAL);
394 	if (gelf_getshdr(scn, &shdr) == NULL)
395 		return (EINVAL);
396 	data = elf_getdata(scn, NULL);
397 	if (data == NULL)
398 		return (EINVAL);
399 
400 	nsym = elf_object_count(efile, ELF_T_SYM, shdr.sh_size);
401 	sym = calloc(nsym, sizeof(*sym));
402 	if (sym == NULL)
403 		return (ENOMEM);
404 
405 	for (i = 0; i < nsym; i++) {
406 		if (gelf_getsym(data, i, &sym[i]) == NULL) {
407 			free(sym);
408 			return (EINVAL);
409 		}
410 	}
411 
412 	*nsymp = nsym;
413 	*symp = sym;
414 	return (0);
415 }
416 
417 int
418 elf_read_string_table(struct elf_file *efile, const GElf_Shdr *shdr,
419     long *strcnt, char **strtab)
420 {
421 	int error;
422 
423 	if (shdr->sh_type != SHT_STRTAB)
424 		return (EINVAL);
425 	error = elf_read_raw_data_alloc(efile, shdr->sh_offset, shdr->sh_size,
426 	    (void **)strtab);
427 	if (error != 0)
428 		return (error);
429 	*strcnt = shdr->sh_size;
430 	return (0);
431 }
432 
433 int
434 elf_read_rel(struct elf_file *efile, int section_index, long *nrelp,
435     GElf_Rel **relp)
436 {
437 	GElf_Shdr shdr;
438 	Elf_Scn *scn;
439 	Elf_Data *data;
440 	GElf_Rel *rel;
441 	long i, nrel;
442 
443 	scn = elf_getscn(efile->ef_elf, section_index);
444 	if (scn == NULL)
445 		return (EINVAL);
446 	if (gelf_getshdr(scn, &shdr) == NULL)
447 		return (EINVAL);
448 	data = elf_getdata(scn, NULL);
449 	if (data == NULL)
450 		return (EINVAL);
451 
452 	nrel = elf_object_count(efile, ELF_T_REL, shdr.sh_size);
453 	rel = calloc(nrel, sizeof(*rel));
454 	if (rel == NULL)
455 		return (ENOMEM);
456 
457 	for (i = 0; i < nrel; i++) {
458 		if (gelf_getrel(data, i, &rel[i]) == NULL) {
459 			free(rel);
460 			return (EINVAL);
461 		}
462 	}
463 
464 	*nrelp = nrel;
465 	*relp = rel;
466 	return (0);
467 }
468 
469 int
470 elf_read_rela(struct elf_file *efile, int section_index, long *nrelap,
471     GElf_Rela **relap)
472 {
473 	GElf_Shdr shdr;
474 	Elf_Scn *scn;
475 	Elf_Data *data;
476 	GElf_Rela *rela;
477 	long i, nrela;
478 
479 	scn = elf_getscn(efile->ef_elf, section_index);
480 	if (scn == NULL)
481 		return (EINVAL);
482 	if (gelf_getshdr(scn, &shdr) == NULL)
483 		return (EINVAL);
484 	data = elf_getdata(scn, NULL);
485 	if (data == NULL)
486 		return (EINVAL);
487 
488 	nrela = elf_object_count(efile, ELF_T_RELA, shdr.sh_size);
489 	rela = calloc(nrela, sizeof(*rela));
490 	if (rela == NULL)
491 		return (ENOMEM);
492 
493 	for (i = 0; i < nrela; i++) {
494 		if (gelf_getrela(data, i, &rela[i]) == NULL) {
495 			free(rela);
496 			return (EINVAL);
497 		}
498 	}
499 
500 	*nrelap = nrela;
501 	*relap = rela;
502 	return (0);
503 }
504 
505 size_t
506 elf_pointer_size(struct elf_file *efile)
507 {
508 	return (efile->ef_pointer_size);
509 }
510 
511 int
512 elf_int(struct elf_file *efile, const void *p)
513 {
514 	if (elf_encoding(efile) == ELFDATA2LSB)
515 		return (le32dec(p));
516 	else
517 		return (be32dec(p));
518 }
519 
520 GElf_Addr
521 elf_address_from_pointer(struct elf_file *efile, const void *p)
522 {
523 	switch (elf_class(efile)) {
524 	case ELFCLASS32:
525 		if (elf_encoding(efile) == ELFDATA2LSB)
526 			return (le32dec(p));
527 		else
528 			return (be32dec(p));
529 	case ELFCLASS64:
530 		if (elf_encoding(efile) == ELFDATA2LSB)
531 			return (le64dec(p));
532 		else
533 			return (be64dec(p));
534 	default:
535 		__unreachable();
536 	}
537 }
538 
539 int
540 elf_read_string(struct elf_file *efile, GElf_Addr address, void *dst,
541     size_t len)
542 {
543 	return (EF_SEG_READ_STRING(efile, address, len, dst));
544 }
545 
546 int
547 elf_read_linker_set(struct elf_file *efile, const char *name, GElf_Addr **bufp,
548     long *countp)
549 {
550 	GElf_Addr *buf, start, stop;
551 	char *p;
552 	void *raw;
553 	long i, count;
554 	int error;
555 
556 	error = EF_LOOKUP_SET(efile, name, &start, &stop, &count);
557 	if (error != 0)
558 		return (error);
559 
560 	error = elf_read_relocated_data(efile, start,
561 	    count * elf_pointer_size(efile), &raw);
562 	if (error != 0)
563 		return (error);
564 
565 	buf = calloc(count, sizeof(*buf));
566 	if (buf == NULL) {
567 		free(raw);
568 		return (ENOMEM);
569 	}
570 
571 	p = raw;
572 	for (i = 0; i < count; i++) {
573 		buf[i] = elf_address_from_pointer(efile, p);
574 		p += elf_pointer_size(efile);
575 	}
576 	free(raw);
577 
578 	*bufp = buf;
579 	*countp = count;
580 	return (0);
581 }
582 
583 int
584 elf_read_mod_depend(struct elf_file *efile, GElf_Addr addr,
585     struct Gmod_depend *mdp)
586 {
587 	int *p;
588 	int error;
589 
590 	error = elf_read_relocated_data(efile, addr, sizeof(int) * 3,
591 	    (void **)&p);
592 	if (error != 0)
593 		return (error);
594 
595 	memset(mdp, 0, sizeof(*mdp));
596 	mdp->md_ver_minimum = elf_int(efile, p);
597 	mdp->md_ver_preferred = elf_int(efile, p + 1);
598 	mdp->md_ver_maximum = elf_int(efile, p + 2);
599 	free(p);
600 	return (0);
601 }
602 
603 int
604 elf_read_mod_version(struct elf_file *efile, GElf_Addr addr,
605     struct Gmod_version *mdv)
606 {
607 	int error, value;
608 
609 	error = EF_SEG_READ_REL(efile, addr, sizeof(int), &value);
610 	if (error != 0)
611 		return (error);
612 
613 	memset(mdv, 0, sizeof(*mdv));
614 	mdv->mv_version = elf_int(efile, &value);
615 	return (0);
616 }
617 
618 int
619 elf_read_mod_metadata(struct elf_file *efile, GElf_Addr addr,
620     struct Gmod_metadata *md)
621 {
622 	char *p;
623 	size_t len, offset, pointer_size;
624 	int error;
625 
626 	pointer_size = elf_pointer_size(efile);
627 	len = 2 * sizeof(int);
628 	len = roundup(len, pointer_size);
629 	len += 2 * pointer_size;
630 
631 	error = elf_read_relocated_data(efile, addr, len, (void **)&p);
632 	if (error != 0)
633 		return (error);
634 
635 	memset(md, 0, sizeof(*md));
636 	offset = 0;
637 	md->md_version = elf_int(efile, p + offset);
638 	offset += sizeof(int);
639 	md->md_type = elf_int(efile, p + offset);
640 	offset += sizeof(int);
641 	offset = roundup(offset, pointer_size);
642 	md->md_data = elf_address_from_pointer(efile, p + offset);
643 	offset += pointer_size;
644  	md->md_cval = elf_address_from_pointer(efile, p + offset);
645 	free(p);
646 	return (0);
647 }
648 
649 int
650 elf_read_mod_pnp_match_info(struct elf_file *efile, GElf_Addr addr,
651     struct Gmod_pnp_match_info *pnp)
652 {
653 	char *p;
654 	size_t len, offset, pointer_size;
655 	int error;
656 
657 	pointer_size = elf_pointer_size(efile);
658 	len = 3 * pointer_size;
659 	len = roundup(len, pointer_size);
660 	len += 2 * sizeof(int);
661 
662 	error = elf_read_relocated_data(efile, addr, len, (void **)&p);
663 	if (error != 0)
664 		return (error);
665 
666 	memset(pnp, 0, sizeof(*pnp));
667 	offset = 0;
668 	pnp->descr = elf_address_from_pointer(efile, p + offset);
669 	offset += pointer_size;
670 	pnp->bus = elf_address_from_pointer(efile, p + offset);
671 	offset += pointer_size;
672 	pnp->table = elf_address_from_pointer(efile, p + offset);
673 	offset += pointer_size;
674 	offset = roundup(offset, pointer_size);
675 	pnp->entry_len = elf_int(efile, p + offset);
676 	offset += sizeof(int);
677 	pnp->num_entry = elf_int(efile, p + offset);
678 	free(p);
679 	return (0);
680 }
681 
682 int
683 elf_reloc(struct elf_file *efile, const void *reldata, Elf_Type reltype,
684     GElf_Addr relbase, GElf_Addr dataoff, size_t len, void *dest)
685 {
686 	return (efile->ef_reloc(efile, reldata, reltype, relbase, dataoff, len,
687 	    dest));
688 }
689 
690 int
691 elf_lookup_symbol(struct elf_file *efile, const char *name, GElf_Sym **sym,
692     bool see_local)
693 {
694 	return (EF_LOOKUP_SYMBOL(efile, name, sym, see_local));
695 }
696