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 *
elf_find_reloc(const GElf_Ehdr * hdr)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
elf_open_file(struct elf_file * efile,const char * filename,int verbose)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
elf_close_file(struct elf_file * efile)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
elf_compatible(struct elf_file * efile,const GElf_Ehdr * hdr)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
elf_object_size(struct elf_file * efile,Elf_Type type)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
elf_object_count(struct elf_file * efile,Elf_Type type,size_t file_size)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
elf_read_raw_data(struct elf_file * efile,off_t offset,void * dst,size_t len)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
elf_read_raw_data_alloc(struct elf_file * efile,off_t offset,size_t len,void ** out)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
elf_read_raw_string(struct elf_file * efile,off_t offset,char * dst,size_t len)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
elf_read_data(struct elf_file * efile,Elf_Type type,off_t offset,size_t len,void ** out)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
elf_read_relocated_data(struct elf_file * efile,GElf_Addr address,size_t len,void ** buf)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
elf_read_phdrs(struct elf_file * efile,size_t * nphdrp,GElf_Phdr ** phdrp)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
elf_read_shdrs(struct elf_file * efile,size_t * nshdrp,GElf_Shdr ** shdrp)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
elf_read_dynamic(struct elf_file * efile,int section_index,size_t * ndynp,GElf_Dyn ** dynp)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
elf_read_symbols(struct elf_file * efile,int section_index,size_t * nsymp,GElf_Sym ** symp)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
elf_read_string_table(struct elf_file * efile,const GElf_Shdr * shdr,long * strcnt,char ** strtab)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
elf_read_rel(struct elf_file * efile,int section_index,long * nrelp,GElf_Rel ** relp)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
elf_read_rela(struct elf_file * efile,int section_index,long * nrelap,GElf_Rela ** relap)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
elf_pointer_size(struct elf_file * efile)506 elf_pointer_size(struct elf_file *efile)
507 {
508 return (efile->ef_pointer_size);
509 }
510
511 int
elf_int(struct elf_file * efile,const void * p)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
elf_address_from_pointer(struct elf_file * efile,const void * p)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
elf_read_string(struct elf_file * efile,GElf_Addr address,void * dst,size_t len)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
elf_read_linker_set(struct elf_file * efile,const char * name,GElf_Addr ** bufp,long * countp)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
elf_read_mod_depend(struct elf_file * efile,GElf_Addr addr,struct Gmod_depend * mdp)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
elf_read_mod_version(struct elf_file * efile,GElf_Addr addr,struct Gmod_version * mdv)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
elf_read_mod_metadata(struct elf_file * efile,GElf_Addr addr,struct Gmod_metadata * md)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
elf_read_mod_pnp_match_info(struct elf_file * efile,GElf_Addr addr,struct Gmod_pnp_match_info * pnp)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
elf_reloc(struct elf_file * efile,const void * reldata,Elf_Type reltype,GElf_Addr relbase,GElf_Addr dataoff,size_t len,void * dest)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
elf_lookup_symbol(struct elf_file * efile,const char * name,GElf_Sym ** sym,bool see_local)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