mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-27 06:48:31 +00:00
skip ELF image validation
This commit is contained in:
parent
a9cb14668e
commit
850a7dab74
1 changed files with 0 additions and 165 deletions
|
@ -199,170 +199,6 @@ static void GetOpts(int argc, char *argv[]) {
|
|||
exepath = argv[optind];
|
||||
}
|
||||
|
||||
static void ValidateElfImage(Elf64_Ehdr *e, Elf64_Off esize, //
|
||||
const char *epath) {
|
||||
|
||||
// validate elf header
|
||||
if (e->e_type != ET_EXEC && e->e_type != ET_DYN)
|
||||
Die(epath, "elf binary isn't an executable");
|
||||
if (!e->e_phnum)
|
||||
Die(epath, "elf executable needs at least one program header");
|
||||
if (e->e_phnum > 65534)
|
||||
Die(epath, "elf with more than 65534 phdrs not supported");
|
||||
if (e->e_phentsize != sizeof(Elf64_Phdr))
|
||||
Die(epath, "elf e_phentsize isn't sizeof(Elf64_Phdr)");
|
||||
if (e->e_phoff > esize)
|
||||
Die(epath, "elf program header offset points past image eof");
|
||||
if (e->e_phoff & 7)
|
||||
Die(epath, "elf e_phoff must be aligned on an 8-byte boundary");
|
||||
if (e->e_phoff + e->e_phoff + e->e_phnum * sizeof(Elf64_Phdr) > esize)
|
||||
Die(epath, "elf program header array overlaps image eof");
|
||||
|
||||
// determine microprocessor page size requirement
|
||||
//
|
||||
// even though operating systems (windows) and c libraries (cosmo)
|
||||
// sometimes impose a larger page size requirement than the actual
|
||||
// microprocessor itself, the cpu page size is still the only page
|
||||
// size that actually matters when it comes to executable loading.
|
||||
unsigned long pagesz;
|
||||
if (e->e_machine == EM_AARCH64) {
|
||||
pagesz = 16384; // apple m1 (xnu, linux)
|
||||
} else { //
|
||||
pagesz = 4096; // x86-64, raspberry pi
|
||||
}
|
||||
|
||||
// remove empty segment loads
|
||||
// empty loads should be inconsequential; linux ignores them
|
||||
// however they tend to trip up many systems such as openbsd
|
||||
int i, j;
|
||||
Elf64_Phdr *p = (Elf64_Phdr *)((char *)e + e->e_phoff);
|
||||
|
||||
for (i = 0; i < e->e_phnum;) {
|
||||
if (p[i].p_type == PT_LOAD && !p[i].p_memsz) {
|
||||
if (i + 1 < e->e_phnum) {
|
||||
memmove(p + i, p + i + 1, (e->e_phnum - (i + 1)) * sizeof(*p));
|
||||
}
|
||||
--e->e_phnum;
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// oracle says loadable segment entries in the program header table
|
||||
// appear in ascending order, sorted on the p_vaddr member.
|
||||
int found_load = 0;
|
||||
Elf64_Addr last_vaddr = 0;
|
||||
for (i = 0; i < e->e_phnum; ++i) {
|
||||
if (p[i].p_type != PT_LOAD)
|
||||
continue;
|
||||
if (found_load && p[i].p_vaddr <= last_vaddr) {
|
||||
Die(epath, "ELF PT_LOAD segments must be ordered by p_vaddr");
|
||||
}
|
||||
last_vaddr = p[i].p_vaddr;
|
||||
found_load = 1;
|
||||
}
|
||||
if (!found_load) {
|
||||
Die(epath, "ELF must have at least one PT_LOAD segment");
|
||||
}
|
||||
|
||||
// merge adjacent loads that are contiguous with equal protection
|
||||
for (i = 0; i + 1 < e->e_phnum;) {
|
||||
if (p[i].p_type == PT_LOAD && p[i + 1].p_type == PT_LOAD &&
|
||||
((p[i].p_flags & (PF_R | PF_W | PF_X)) ==
|
||||
(p[i + 1].p_flags & (PF_R | PF_W | PF_X))) &&
|
||||
((p[i].p_offset + p[i].p_filesz + (pagesz - 1)) & -pagesz) -
|
||||
(p[i + 1].p_offset & -pagesz) <=
|
||||
pagesz &&
|
||||
((p[i].p_vaddr + p[i].p_memsz + (pagesz - 1)) & -pagesz) -
|
||||
(p[i + 1].p_vaddr & -pagesz) <=
|
||||
pagesz) {
|
||||
p[i].p_memsz = (p[i + 1].p_vaddr + p[i + 1].p_memsz) - p[i].p_vaddr;
|
||||
p[i].p_filesz = (p[i + 1].p_offset + p[i + 1].p_filesz) - p[i].p_offset;
|
||||
if (i + 2 < e->e_phnum) {
|
||||
memmove(p + i + 1, p + i + 2, (e->e_phnum - (i + 2)) * sizeof(*p));
|
||||
}
|
||||
--e->e_phnum;
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// validate program headers
|
||||
bool found_entry = false;
|
||||
for (i = 0; i < e->e_phnum; ++i) {
|
||||
if (p[i].p_type == PT_INTERP) {
|
||||
Die(epath, "ELF has PT_INTERP which isn't supported");
|
||||
}
|
||||
if (p[i].p_type == PT_DYNAMIC) {
|
||||
Die(epath, "ELF has PT_DYNAMIC which isn't supported");
|
||||
}
|
||||
if (p[i].p_type != PT_LOAD) {
|
||||
continue;
|
||||
}
|
||||
if (!p[i].p_memsz) {
|
||||
Die(epath, "ELF PT_LOAD p_memsz was zero");
|
||||
}
|
||||
if (p[i].p_offset > esize) {
|
||||
Die(epath, "ELF PT_LOAD p_offset points past EOF");
|
||||
}
|
||||
if (p[i].p_filesz > p[i].p_memsz) {
|
||||
Die(epath, "ELF PT_LOAD p_filesz exceeds p_memsz");
|
||||
}
|
||||
if (p[i].p_align > 1 && (p[i].p_align & (p[i].p_align - 1))) {
|
||||
Die(epath, "ELF PT_LOAD p_align must be two power");
|
||||
}
|
||||
if (p[i].p_vaddr + p[i].p_memsz < p[i].p_vaddr ||
|
||||
p[i].p_vaddr + p[i].p_memsz + (pagesz - 1) < p[i].p_vaddr) {
|
||||
Die(epath, "ELF PT_LOAD p_vaddr + p_memsz overflow");
|
||||
}
|
||||
if (p[i].p_offset + p[i].p_filesz < p[i].p_offset ||
|
||||
p[i].p_offset + p[i].p_filesz + (pagesz - 1) < p[i].p_offset) {
|
||||
Die(epath, "ELF PT_LOAD p_offset + p_filesz overflow");
|
||||
}
|
||||
if (p[i].p_align > 1 && ((p[i].p_vaddr & (p[i].p_align - 1)) !=
|
||||
(p[i].p_offset & (p[i].p_align - 1)))) {
|
||||
Die(epath, "ELF p_vaddr incongruent w/ p_offset modulo p_align");
|
||||
}
|
||||
if ((p[i].p_vaddr & (pagesz - 1)) != (p[i].p_offset & (pagesz - 1))) {
|
||||
Die(epath, "ELF p_vaddr incongruent w/ p_offset modulo AT_PAGESZ");
|
||||
}
|
||||
if (p[i].p_offset + p[i].p_filesz > esize) {
|
||||
Die(epath, "ELF PT_LOAD p_offset and p_filesz overlaps image EOF");
|
||||
}
|
||||
Elf64_Off a = p[i].p_vaddr & -pagesz;
|
||||
Elf64_Off b = (p[i].p_vaddr + p[i].p_memsz + (pagesz - 1)) & -pagesz;
|
||||
for (j = i + 1; j < e->e_phnum; ++j) {
|
||||
if (p[j].p_type != PT_LOAD)
|
||||
continue;
|
||||
Elf64_Off c = p[j].p_vaddr & -pagesz;
|
||||
Elf64_Off d = (p[j].p_vaddr + p[j].p_memsz + (pagesz - 1)) & -pagesz;
|
||||
if (MAX(a, c) < MIN(b, d)) {
|
||||
Die(epath,
|
||||
"ELF PT_LOAD phdrs %d and %d overlap each others virtual memory");
|
||||
}
|
||||
}
|
||||
if (e->e_machine == EM_AARCH64 &&
|
||||
p[i].p_vaddr + p[i].p_memsz > 0x0001000000000000) {
|
||||
Die(epath, "this is an ARM ELF program but it loads to virtual"
|
||||
" memory addresses outside the legal range [0,2^48)");
|
||||
}
|
||||
if (e->e_machine == EM_NEXGEN32E &&
|
||||
!(-140737488355328 <= (Elf64_Sxword)p[i].p_vaddr &&
|
||||
(Elf64_Sxword)(p[i].p_vaddr + p[i].p_memsz) <= 140737488355328)) {
|
||||
Die(epath, "this is an x86-64 ELF program, but it loads to virtual"
|
||||
" memory addresses outside the legal range [-2^47,2^47)");
|
||||
}
|
||||
if ((p[i].p_flags & PF_X) && //
|
||||
p[i].p_vaddr <= e->e_entry &&
|
||||
e->e_entry < p[i].p_vaddr + p[i].p_memsz) {
|
||||
found_entry = 1;
|
||||
}
|
||||
}
|
||||
if (!found_entry) {
|
||||
Die(epath, "ELF entrypoint not found in PT_LOAD with PF_X");
|
||||
}
|
||||
}
|
||||
|
||||
struct Input {
|
||||
union {
|
||||
char *map;
|
||||
|
@ -417,7 +253,6 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
GetOpts(argc, argv);
|
||||
OpenInput(exepath);
|
||||
ValidateElfImage(input.elf, input.size, input.path);
|
||||
rodata = FindElfSectionByName(
|
||||
input.elf, input.size,
|
||||
GetElfSectionNameStringTable(input.elf, input.size), ".rodata");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue