Changeset View
Changeset View
Standalone View
Standalone View
libexec/rtld-elf/map_object.c
Show First 20 Lines • Show All 339 Lines • ▼ Show 20 Lines | error: | ||||
if (note_map != NULL && note_map != MAP_FAILED) | if (note_map != NULL && note_map != MAP_FAILED) | ||||
munmap(note_map, note_map_len); | munmap(note_map, note_map_len); | ||||
if (!phdr_in_zero_page(hdr)) | if (!phdr_in_zero_page(hdr)) | ||||
munmap(phdr, hdr->e_phnum * sizeof(phdr[0])); | munmap(phdr, hdr->e_phnum * sizeof(phdr[0])); | ||||
munmap(hdr, PAGE_SIZE); | munmap(hdr, PAGE_SIZE); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
bool | |||||
check_elf_headers(const Elf_Ehdr *hdr, const char *path) | |||||
{ | |||||
if (!IS_ELF(*hdr)) { | |||||
_rtld_error("%s: invalid file format", path); | |||||
return (false); | |||||
} | |||||
if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || | |||||
hdr->e_ident[EI_DATA] != ELF_TARG_DATA) { | |||||
_rtld_error("%s: unsupported file layout", path); | |||||
return (false); | |||||
} | |||||
if (hdr->e_ident[EI_VERSION] != EV_CURRENT || | |||||
hdr->e_version != EV_CURRENT) { | |||||
_rtld_error("%s: unsupported file version", path); | |||||
return (false); | |||||
} | |||||
if (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN) { | |||||
_rtld_error("%s: unsupported file type", path); | |||||
return (false); | |||||
} | |||||
if (hdr->e_machine != ELF_TARG_MACH) { | |||||
_rtld_error("%s: unsupported machine", path); | |||||
return (false); | |||||
} | |||||
if (hdr->e_phentsize != sizeof(Elf_Phdr)) { | |||||
_rtld_error( | |||||
"%s: invalid shared object: e_phentsize != sizeof(Elf_Phdr)", path); | |||||
return (false); | |||||
} | |||||
return (true); | |||||
} | |||||
static Elf_Ehdr * | static Elf_Ehdr * | ||||
get_elf_header(int fd, const char *path, const struct stat *sbp, | get_elf_header(int fd, const char *path, const struct stat *sbp, | ||||
Elf_Phdr **phdr_p) | Elf_Phdr **phdr_p) | ||||
{ | { | ||||
Elf_Ehdr *hdr; | Elf_Ehdr *hdr; | ||||
Elf_Phdr *phdr; | Elf_Phdr *phdr; | ||||
/* Make sure file has enough data for the ELF header */ | /* Make sure file has enough data for the ELF header */ | ||||
if (sbp != NULL && sbp->st_size < (off_t)sizeof(Elf_Ehdr)) { | if (sbp != NULL && sbp->st_size < (off_t)sizeof(Elf_Ehdr)) { | ||||
_rtld_error("%s: invalid file format", path); | _rtld_error("%s: invalid file format", path); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
hdr = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE | MAP_PREFAULT_READ, | hdr = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE | MAP_PREFAULT_READ, | ||||
fd, 0); | fd, 0); | ||||
if (hdr == MAP_FAILED) { | if (hdr == MAP_FAILED) { | ||||
_rtld_error("%s: read error: %s", path, rtld_strerror(errno)); | _rtld_error("%s: read error: %s", path, rtld_strerror(errno)); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
/* Make sure the file is valid */ | /* Make sure the file is valid */ | ||||
if (!IS_ELF(*hdr)) { | if (!check_elf_headers(hdr, path)) | ||||
_rtld_error("%s: invalid file format", path); | |||||
goto error; | goto error; | ||||
} | |||||
if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || | |||||
hdr->e_ident[EI_DATA] != ELF_TARG_DATA) { | |||||
_rtld_error("%s: unsupported file layout", path); | |||||
goto error; | |||||
} | |||||
if (hdr->e_ident[EI_VERSION] != EV_CURRENT || | |||||
hdr->e_version != EV_CURRENT) { | |||||
_rtld_error("%s: unsupported file version", path); | |||||
goto error; | |||||
} | |||||
if (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN) { | |||||
_rtld_error("%s: unsupported file type", path); | |||||
goto error; | |||||
} | |||||
if (hdr->e_machine != ELF_TARG_MACH) { | |||||
_rtld_error("%s: unsupported machine", path); | |||||
goto error; | |||||
} | |||||
/* | /* | ||||
* We rely on the program header being in the first page. This is | * We rely on the program header being in the first page. This is | ||||
* not strictly required by the ABI specification, but it seems to | * not strictly required by the ABI specification, but it seems to | ||||
* always true in practice. And, it simplifies things considerably. | * always true in practice. And, it simplifies things considerably. | ||||
*/ | */ | ||||
if (hdr->e_phentsize != sizeof(Elf_Phdr)) { | |||||
_rtld_error( | |||||
"%s: invalid shared object: e_phentsize != sizeof(Elf_Phdr)", path); | |||||
goto error; | |||||
} | |||||
if (phdr_in_zero_page(hdr)) { | if (phdr_in_zero_page(hdr)) { | ||||
phdr = (Elf_Phdr *)((char *)hdr + hdr->e_phoff); | phdr = (Elf_Phdr *)((char *)hdr + hdr->e_phoff); | ||||
} else { | } else { | ||||
phdr = mmap(NULL, hdr->e_phnum * sizeof(phdr[0]), | phdr = mmap(NULL, hdr->e_phnum * sizeof(phdr[0]), | ||||
PROT_READ, MAP_PRIVATE | MAP_PREFAULT_READ, fd, | PROT_READ, MAP_PRIVATE | MAP_PREFAULT_READ, fd, | ||||
hdr->e_phoff); | hdr->e_phoff); | ||||
if (phdr == MAP_FAILED) { | if (phdr == MAP_FAILED) { | ||||
_rtld_error("%s: error mapping phdr: %s", path, | _rtld_error("%s: error mapping phdr: %s", path, | ||||
▲ Show 20 Lines • Show All 96 Lines • Show Last 20 Lines |