Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/stand/common/load_elf_obj.c
34677 views
1
/*-
2
* Copyright (c) 2004 Ian Dowse <[email protected]>
3
* Copyright (c) 1998 Michael Smith <[email protected]>
4
* Copyright (c) 1998 Peter Wemm <[email protected]>
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*/
28
29
#include <sys/param.h>
30
#include <sys/exec.h>
31
#include <sys/linker.h>
32
#include <sys/module.h>
33
#include <machine/elf.h>
34
#include <stand.h>
35
36
#include "bootstrap.h"
37
#include "modinfo.h"
38
39
#define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l)
40
41
#if defined(__i386__) && __ELF_WORD_SIZE == 64
42
#undef ELF_TARG_CLASS
43
#undef ELF_TARG_MACH
44
#define ELF_TARG_CLASS ELFCLASS64
45
#define ELF_TARG_MACH EM_X86_64
46
#endif
47
48
typedef struct elf_file {
49
Elf_Ehdr hdr;
50
Elf_Shdr *e_shdr;
51
52
int symtabindex; /* Index of symbol table */
53
int shstrindex; /* Index of section name string table */
54
55
int fd;
56
vm_offset_t off;
57
#ifdef LOADER_VERIEXEC_VECTX
58
struct vectx *vctx;
59
#endif
60
} *elf_file_t;
61
62
#ifdef LOADER_VERIEXEC_VECTX
63
#define VECTX_HANDLE(ef) (ef)->vctx
64
#else
65
#define VECTX_HANDLE(ef) (ef)->fd
66
#endif
67
68
static int __elfN(obj_loadimage)(struct preloaded_file *mp, elf_file_t ef,
69
uint64_t loadaddr);
70
static int __elfN(obj_lookup_set)(struct preloaded_file *mp, elf_file_t ef,
71
const char *name, Elf_Addr *startp, Elf_Addr *stopp, int *countp);
72
static int __elfN(obj_reloc_ptr)(struct preloaded_file *mp, elf_file_t ef,
73
Elf_Addr p, void *val, size_t len);
74
static int __elfN(obj_parse_modmetadata)(struct preloaded_file *mp,
75
elf_file_t ef);
76
static Elf_Addr __elfN(obj_symaddr)(struct elf_file *ef, Elf_Size symidx);
77
78
/*
79
* Attempt to load the file (file) as an ELF module. It will be stored at
80
* (dest), and a pointer to a module structure describing the loaded object
81
* will be saved in (result).
82
*/
83
int
84
__elfN(obj_loadfile)(char *filename, uint64_t dest,
85
struct preloaded_file **result)
86
{
87
struct preloaded_file *fp, *kfp;
88
struct elf_file ef;
89
Elf_Ehdr *hdr;
90
int err;
91
ssize_t bytes_read;
92
93
fp = NULL;
94
bzero(&ef, sizeof(struct elf_file));
95
96
/*
97
* Open the image, read and validate the ELF header
98
*/
99
if (filename == NULL) /* can't handle nameless */
100
return(EFTYPE);
101
if ((ef.fd = open(filename, O_RDONLY)) == -1)
102
return(errno);
103
#ifdef LOADER_VERIEXEC_VECTX
104
{
105
int verror;
106
107
ef.vctx = vectx_open(ef.fd, filename, 0L, NULL, &verror, __func__);
108
if (verror) {
109
printf("Unverified %s: %s\n", filename, ve_error_get());
110
close(ef.fd);
111
free(ef.vctx);
112
return (EAUTH);
113
}
114
}
115
#endif
116
117
hdr = &ef.hdr;
118
bytes_read = VECTX_READ(VECTX_HANDLE(&ef), hdr, sizeof(*hdr));
119
if (bytes_read != sizeof(*hdr)) {
120
err = EFTYPE; /* could be EIO, but may be small file */
121
goto oerr;
122
}
123
124
/* Is it ELF? */
125
if (!IS_ELF(*hdr)) {
126
err = EFTYPE;
127
goto oerr;
128
}
129
if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */
130
hdr->e_ident[EI_DATA] != ELF_TARG_DATA ||
131
hdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */
132
hdr->e_version != EV_CURRENT ||
133
hdr->e_machine != ELF_TARG_MACH || /* Machine ? */
134
hdr->e_type != ET_REL) {
135
err = EFTYPE;
136
goto oerr;
137
}
138
139
if (hdr->e_shnum * hdr->e_shentsize == 0 || hdr->e_shoff == 0 ||
140
hdr->e_shentsize != sizeof(Elf_Shdr)) {
141
err = EFTYPE;
142
goto oerr;
143
}
144
145
#if defined(LOADER_VERIEXEC) && !defined(LOADER_VERIEXEC_VECTX)
146
if (verify_file(ef.fd, filename, bytes_read, VE_MUST, __func__) < 0) {
147
err = EAUTH;
148
goto oerr;
149
}
150
#endif
151
152
kfp = file_findfile(NULL, md_kerntype);
153
if (kfp == NULL) {
154
printf("elf" __XSTRING(__ELF_WORD_SIZE)
155
"_obj_loadfile: can't load module before kernel\n");
156
err = EPERM;
157
goto oerr;
158
}
159
160
dest = md_align(dest);
161
162
/*
163
* Ok, we think we should handle this.
164
*/
165
fp = file_alloc();
166
if (fp == NULL) {
167
printf("elf" __XSTRING(__ELF_WORD_SIZE)
168
"_obj_loadfile: cannot allocate module info\n");
169
err = EPERM;
170
goto out;
171
}
172
fp->f_name = strdup(filename);
173
fp->f_type = strdup(md_modtype_obj);
174
175
if (module_verbose > MODULE_VERBOSE_SILENT)
176
printf("%s ", filename);
177
178
fp->f_size = __elfN(obj_loadimage)(fp, &ef, dest);
179
if (fp->f_size == 0 || fp->f_addr == 0)
180
goto ioerr;
181
182
/* save exec header as metadata */
183
file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*hdr), hdr);
184
185
/* Load OK, return module pointer */
186
*result = (struct preloaded_file *)fp;
187
err = 0;
188
goto out;
189
190
ioerr:
191
err = EIO;
192
oerr:
193
file_discard(fp);
194
out:
195
#ifdef LOADER_VERIEXEC_VECTX
196
if (!err && ef.vctx) {
197
int verror;
198
199
verror = vectx_close(ef.vctx, VE_MUST, __func__);
200
if (verror) {
201
err = EAUTH;
202
file_discard(fp);
203
}
204
}
205
#endif
206
close(ef.fd);
207
if (ef.e_shdr != NULL)
208
free(ef.e_shdr);
209
210
return(err);
211
}
212
213
/*
214
* With the file (fd) open on the image, and (ehdr) containing
215
* the Elf header, load the image at (off)
216
*/
217
static int
218
__elfN(obj_loadimage)(struct preloaded_file *fp, elf_file_t ef, uint64_t off)
219
{
220
Elf_Ehdr *hdr;
221
Elf_Shdr *shdr, *cshdr, *lshdr;
222
vm_offset_t firstaddr, lastaddr;
223
int i, nsym, res, ret, shdrbytes, symstrindex;
224
225
ret = 0;
226
firstaddr = lastaddr = (vm_offset_t)off;
227
hdr = &ef->hdr;
228
ef->off = (vm_offset_t)off;
229
230
/* Read in the section headers. */
231
shdrbytes = hdr->e_shnum * hdr->e_shentsize;
232
shdr = alloc_pread(VECTX_HANDLE(ef), (off_t)hdr->e_shoff, shdrbytes);
233
if (shdr == NULL) {
234
printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
235
"_obj_loadimage: read section headers failed\n");
236
goto out;
237
}
238
ef->e_shdr = shdr;
239
240
/*
241
* Decide where to load everything, but don't read it yet.
242
* We store the load address as a non-zero sh_addr value.
243
* Start with the code/data and bss.
244
*/
245
for (i = 0; i < hdr->e_shnum; i++)
246
shdr[i].sh_addr = 0;
247
for (i = 0; i < hdr->e_shnum; i++) {
248
if (shdr[i].sh_size == 0)
249
continue;
250
switch (shdr[i].sh_type) {
251
case SHT_PROGBITS:
252
case SHT_NOBITS:
253
#if defined(__i386__) || defined(__amd64__)
254
case SHT_X86_64_UNWIND:
255
#endif
256
case SHT_INIT_ARRAY:
257
case SHT_FINI_ARRAY:
258
if ((shdr[i].sh_flags & SHF_ALLOC) == 0)
259
break;
260
lastaddr = roundup(lastaddr, shdr[i].sh_addralign);
261
shdr[i].sh_addr = (Elf_Addr)lastaddr;
262
lastaddr += shdr[i].sh_size;
263
break;
264
}
265
}
266
267
/* Symbols. */
268
nsym = 0;
269
for (i = 0; i < hdr->e_shnum; i++) {
270
switch (shdr[i].sh_type) {
271
case SHT_SYMTAB:
272
nsym++;
273
ef->symtabindex = i;
274
break;
275
}
276
}
277
if (nsym != 1) {
278
printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
279
"_obj_loadimage: file has no valid symbol table\n");
280
goto out;
281
}
282
lastaddr = roundup(lastaddr, shdr[ef->symtabindex].sh_addralign);
283
shdr[ef->symtabindex].sh_addr = (Elf_Addr)lastaddr;
284
lastaddr += shdr[ef->symtabindex].sh_size;
285
286
symstrindex = shdr[ef->symtabindex].sh_link;
287
if (symstrindex < 0 || symstrindex >= hdr->e_shnum ||
288
shdr[symstrindex].sh_type != SHT_STRTAB) {
289
printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
290
"_obj_loadimage: file has invalid symbol strings\n");
291
goto out;
292
}
293
lastaddr = roundup(lastaddr, shdr[symstrindex].sh_addralign);
294
shdr[symstrindex].sh_addr = (Elf_Addr)lastaddr;
295
lastaddr += shdr[symstrindex].sh_size;
296
297
/* Section names. */
298
if (hdr->e_shstrndx == 0 || hdr->e_shstrndx >= hdr->e_shnum ||
299
shdr[hdr->e_shstrndx].sh_type != SHT_STRTAB) {
300
printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
301
"_obj_loadimage: file has no section names\n");
302
goto out;
303
}
304
ef->shstrindex = hdr->e_shstrndx;
305
lastaddr = roundup(lastaddr, shdr[ef->shstrindex].sh_addralign);
306
shdr[ef->shstrindex].sh_addr = (Elf_Addr)lastaddr;
307
lastaddr += shdr[ef->shstrindex].sh_size;
308
309
/* Relocation tables. */
310
for (i = 0; i < hdr->e_shnum; i++) {
311
switch (shdr[i].sh_type) {
312
case SHT_REL:
313
case SHT_RELA:
314
if ((shdr[shdr[i].sh_info].sh_flags & SHF_ALLOC) == 0)
315
break;
316
lastaddr = roundup(lastaddr, shdr[i].sh_addralign);
317
shdr[i].sh_addr = (Elf_Addr)lastaddr;
318
lastaddr += shdr[i].sh_size;
319
break;
320
}
321
}
322
323
/* Clear the whole area, including bss regions. */
324
kern_bzero(firstaddr, lastaddr - firstaddr);
325
326
/* Figure section with the lowest file offset we haven't loaded yet. */
327
for (cshdr = NULL; /* none */; /* none */)
328
{
329
/*
330
* Find next section to load. The complexity of this loop is
331
* O(n^2), but with the number of sections being typically
332
* small, we do not care.
333
*/
334
lshdr = cshdr;
335
336
for (i = 0; i < hdr->e_shnum; i++) {
337
if (shdr[i].sh_addr == 0 ||
338
shdr[i].sh_type == SHT_NOBITS)
339
continue;
340
/* Skip sections that were loaded already. */
341
if (lshdr != NULL &&
342
lshdr->sh_offset >= shdr[i].sh_offset)
343
continue;
344
/* Find section with smallest offset. */
345
if (cshdr == lshdr ||
346
cshdr->sh_offset > shdr[i].sh_offset)
347
cshdr = &shdr[i];
348
}
349
350
if (cshdr == lshdr)
351
break;
352
353
if (kern_pread(VECTX_HANDLE(ef), (vm_offset_t)cshdr->sh_addr,
354
cshdr->sh_size, (off_t)cshdr->sh_offset) != 0) {
355
printf("\nelf" __XSTRING(__ELF_WORD_SIZE)
356
"_obj_loadimage: read failed\n");
357
goto out;
358
}
359
}
360
361
file_addmetadata(fp, MODINFOMD_SHDR, shdrbytes, shdr);
362
363
res = __elfN(obj_parse_modmetadata)(fp, ef);
364
if (res != 0)
365
goto out;
366
367
ret = lastaddr - firstaddr;
368
fp->f_addr = firstaddr;
369
370
if (module_verbose > MODULE_VERBOSE_SILENT)
371
printf("size 0x%lx at 0x%lx", (u_long)ret, (u_long)firstaddr);
372
373
out:
374
if (module_verbose > MODULE_VERBOSE_SILENT)
375
printf("\n");
376
return ret;
377
}
378
379
#if defined(__i386__) && __ELF_WORD_SIZE == 64
380
struct mod_metadata64 {
381
int md_version; /* structure version MDTV_* */
382
int md_type; /* type of entry MDT_* */
383
uint64_t md_data; /* specific data */
384
uint64_t md_cval; /* common string label */
385
};
386
#endif
387
388
int
389
__elfN(obj_parse_modmetadata)(struct preloaded_file *fp, elf_file_t ef)
390
{
391
struct mod_metadata md;
392
#if defined(__i386__) && __ELF_WORD_SIZE == 64
393
struct mod_metadata64 md64;
394
#endif
395
struct mod_depend *mdepend;
396
struct mod_version mver;
397
char *s;
398
int error, modcnt, minfolen;
399
Elf_Addr v, p, p_stop;
400
401
if (__elfN(obj_lookup_set)(fp, ef, "modmetadata_set", &p, &p_stop,
402
&modcnt) != 0)
403
return 0;
404
405
modcnt = 0;
406
while (p < p_stop) {
407
COPYOUT(p, &v, sizeof(v));
408
error = __elfN(obj_reloc_ptr)(fp, ef, p, &v, sizeof(v));
409
if (error != 0)
410
return (error);
411
#if defined(__i386__) && __ELF_WORD_SIZE == 64
412
COPYOUT(v, &md64, sizeof(md64));
413
error = __elfN(obj_reloc_ptr)(fp, ef, v, &md64, sizeof(md64));
414
if (error != 0)
415
return (error);
416
md.md_version = md64.md_version;
417
md.md_type = md64.md_type;
418
md.md_cval = (const char *)(uintptr_t)md64.md_cval;
419
md.md_data = (void *)(uintptr_t)md64.md_data;
420
#else
421
COPYOUT(v, &md, sizeof(md));
422
error = __elfN(obj_reloc_ptr)(fp, ef, v, &md, sizeof(md));
423
if (error != 0)
424
return (error);
425
#endif
426
p += sizeof(Elf_Addr);
427
switch(md.md_type) {
428
case MDT_DEPEND:
429
s = strdupout((vm_offset_t)md.md_cval);
430
minfolen = sizeof(*mdepend) + strlen(s) + 1;
431
mdepend = malloc(minfolen);
432
if (mdepend == NULL)
433
return ENOMEM;
434
COPYOUT((vm_offset_t)md.md_data, mdepend,
435
sizeof(*mdepend));
436
strcpy((char*)(mdepend + 1), s);
437
free(s);
438
file_addmetadata(fp, MODINFOMD_DEPLIST, minfolen,
439
mdepend);
440
free(mdepend);
441
break;
442
case MDT_VERSION:
443
s = strdupout((vm_offset_t)md.md_cval);
444
COPYOUT((vm_offset_t)md.md_data, &mver, sizeof(mver));
445
file_addmodule(fp, s, mver.mv_version, NULL);
446
free(s);
447
modcnt++;
448
break;
449
case MDT_MODULE:
450
case MDT_PNP_INFO:
451
break;
452
default:
453
printf("unknown type %d\n", md.md_type);
454
break;
455
}
456
}
457
return 0;
458
}
459
460
static int
461
__elfN(obj_lookup_set)(struct preloaded_file *fp, elf_file_t ef,
462
const char* name, Elf_Addr *startp, Elf_Addr *stopp, int *countp)
463
{
464
Elf_Ehdr *hdr;
465
Elf_Shdr *shdr;
466
char *p;
467
vm_offset_t shstrtab;
468
int i;
469
470
hdr = &ef->hdr;
471
shdr = ef->e_shdr;
472
shstrtab = shdr[ef->shstrindex].sh_addr;
473
474
for (i = 0; i < hdr->e_shnum; i++) {
475
if (shdr[i].sh_type != SHT_PROGBITS)
476
continue;
477
if (shdr[i].sh_name == 0)
478
continue;
479
p = strdupout(shstrtab + shdr[i].sh_name);
480
if (strncmp(p, "set_", 4) == 0 && strcmp(p + 4, name) == 0) {
481
*startp = shdr[i].sh_addr;
482
*stopp = shdr[i].sh_addr + shdr[i].sh_size;
483
*countp = (*stopp - *startp) / sizeof(Elf_Addr);
484
free(p);
485
return (0);
486
}
487
free(p);
488
}
489
490
return (ESRCH);
491
}
492
493
/*
494
* Apply any intra-module relocations to the value. p is the load address
495
* of the value and val/len is the value to be modified. This does NOT modify
496
* the image in-place, because this is done by kern_linker later on.
497
*/
498
static int
499
__elfN(obj_reloc_ptr)(struct preloaded_file *mp, elf_file_t ef, Elf_Addr p,
500
void *val, size_t len)
501
{
502
Elf_Ehdr *hdr;
503
Elf_Shdr *shdr;
504
Elf_Addr off = p;
505
Elf_Addr base;
506
Elf_Rela a, *abase;
507
Elf_Rel r, *rbase;
508
int error, i, j, nrel, nrela;
509
510
hdr = &ef->hdr;
511
shdr = ef->e_shdr;
512
513
for (i = 0; i < hdr->e_shnum; i++) {
514
if (shdr[i].sh_type != SHT_RELA && shdr[i].sh_type != SHT_REL)
515
continue;
516
base = shdr[shdr[i].sh_info].sh_addr;
517
if (base == 0 || shdr[i].sh_addr == 0)
518
continue;
519
if (off < base || off + len > base +
520
shdr[shdr[i].sh_info].sh_size)
521
continue;
522
523
switch (shdr[i].sh_type) {
524
case SHT_RELA:
525
abase = (Elf_Rela *)(intptr_t)shdr[i].sh_addr;
526
527
nrela = shdr[i].sh_size / sizeof(Elf_Rela);
528
for (j = 0; j < nrela; j++) {
529
COPYOUT(abase + j, &a, sizeof(a));
530
531
error = __elfN(reloc)(ef, __elfN(obj_symaddr),
532
&a, ELF_RELOC_RELA, base, off, val, len);
533
if (error != 0)
534
return (error);
535
}
536
break;
537
case SHT_REL:
538
rbase = (Elf_Rel *)(intptr_t)shdr[i].sh_addr;
539
540
nrel = shdr[i].sh_size / sizeof(Elf_Rel);
541
for (j = 0; j < nrel; j++) {
542
COPYOUT(rbase + j, &r, sizeof(r));
543
544
error = __elfN(reloc)(ef, __elfN(obj_symaddr),
545
&r, ELF_RELOC_REL, base, off, val, len);
546
if (error != 0)
547
return (error);
548
}
549
break;
550
}
551
}
552
return (0);
553
}
554
555
/* Look up the address of a specified symbol. */
556
static Elf_Addr
557
__elfN(obj_symaddr)(struct elf_file *ef, Elf_Size symidx)
558
{
559
Elf_Sym sym;
560
Elf_Addr base;
561
562
if (symidx >= ef->e_shdr[ef->symtabindex].sh_size / sizeof(Elf_Sym))
563
return (0);
564
COPYOUT(ef->e_shdr[ef->symtabindex].sh_addr + symidx * sizeof(Elf_Sym),
565
&sym, sizeof(sym));
566
if (sym.st_shndx == SHN_UNDEF || sym.st_shndx >= ef->hdr.e_shnum)
567
return (0);
568
base = ef->e_shdr[sym.st_shndx].sh_addr;
569
if (base == 0)
570
return (0);
571
return (base + sym.st_value);
572
}
573
574