diff --git a/libexec/rtld-elf/map_object.c b/libexec/rtld-elf/map_object.c index b725fe93b8f6..2da323c115cc 100644 --- a/libexec/rtld-elf/map_object.c +++ b/libexec/rtld-elf/map_object.c @@ -1,505 +1,513 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright 1996-1998 John D. Polstra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include "debug.h" #include "rtld.h" static Elf_Ehdr *get_elf_header(int, const char *, const struct stat *, Elf_Phdr **phdr); static int convert_flags(int); /* Elf flags -> mmap flags */ int __getosreldate(void); static bool phdr_in_zero_page(const Elf_Ehdr *hdr) { return (hdr->e_phoff + hdr->e_phnum * sizeof(Elf_Phdr) <= (size_t)PAGE_SIZE); } /* * Map a shared object into memory. The "fd" argument is a file descriptor, * which must be open on the object and positioned at its beginning. * The "path" argument is a pathname that is used only for error messages. * * The return value is a pointer to a newly-allocated Obj_Entry structure * for the shared object. Returns NULL on failure. */ Obj_Entry * map_object(int fd, const char *path, const struct stat *sb) { Obj_Entry *obj; Elf_Ehdr *hdr; int i; Elf_Phdr *phdr; Elf_Phdr *phlimit; Elf_Phdr **segs; int nsegs; Elf_Phdr *phdyn; Elf_Phdr *phinterp; Elf_Phdr *phtls; caddr_t mapbase; size_t mapsize; Elf_Addr base_vaddr; Elf_Addr base_vlimit; caddr_t base_addr; int base_flags; Elf_Off data_offset; Elf_Addr data_vaddr; Elf_Addr data_vlimit; caddr_t data_addr; int data_prot; int data_flags; Elf_Addr clear_vaddr; caddr_t clear_addr; caddr_t clear_page; Elf_Addr phdr_vaddr; size_t nclear, phsize; Elf_Addr bss_vaddr; Elf_Addr bss_vlimit; caddr_t bss_addr; Elf_Word stack_flags; Elf_Addr relro_page; size_t relro_size; Elf_Addr note_start; Elf_Addr note_end; char *note_map; size_t note_map_len; Elf_Addr text_end; hdr = get_elf_header(fd, path, sb, &phdr); if (hdr == NULL) return (NULL); /* * Scan the program header entries, and save key information. * We expect that the loadable segments are ordered by load address. */ phsize = hdr->e_phnum * sizeof(phdr[0]); phlimit = phdr + hdr->e_phnum; nsegs = -1; phdyn = phinterp = phtls = NULL; phdr_vaddr = 0; relro_page = 0; relro_size = 0; note_start = 0; note_end = 0; note_map = NULL; note_map_len = 0; segs = alloca(sizeof(segs[0]) * hdr->e_phnum); stack_flags = RTLD_DEFAULT_STACK_PF_EXEC | PF_R | PF_W; text_end = 0; while (phdr < phlimit) { switch (phdr->p_type) { case PT_INTERP: phinterp = phdr; break; case PT_LOAD: segs[++nsegs] = phdr; if ((segs[nsegs]->p_align & (PAGE_SIZE - 1)) != 0) { _rtld_error("%s: PT_LOAD segment %d not page-aligned", path, nsegs); goto error; } if ((segs[nsegs]->p_flags & PF_X) == PF_X) { text_end = MAX(text_end, round_page(segs[nsegs]->p_vaddr + segs[nsegs]->p_memsz)); } break; case PT_PHDR: phdr_vaddr = phdr->p_vaddr; phsize = phdr->p_memsz; break; case PT_DYNAMIC: phdyn = phdr; break; case PT_TLS: phtls = phdr; break; case PT_GNU_STACK: stack_flags = phdr->p_flags; break; case PT_GNU_RELRO: relro_page = phdr->p_vaddr; relro_size = phdr->p_memsz; break; case PT_NOTE: if (phdr->p_offset > PAGE_SIZE || phdr->p_offset + phdr->p_filesz > PAGE_SIZE) { note_map_len = round_page(phdr->p_offset + phdr->p_filesz) - trunc_page(phdr->p_offset); note_map = mmap(NULL, note_map_len, PROT_READ, MAP_PRIVATE, fd, trunc_page(phdr->p_offset)); if (note_map == MAP_FAILED) { _rtld_error("%s: error mapping PT_NOTE (%d)", path, errno); goto error; } note_start = (Elf_Addr)(note_map + phdr->p_offset - trunc_page(phdr->p_offset)); } else { note_start = (Elf_Addr)(char *)hdr + phdr->p_offset; } note_end = note_start + phdr->p_filesz; break; } ++phdr; } if (phdyn == NULL) { _rtld_error("%s: object is not dynamically-linked", path); goto error; } if (nsegs < 0) { _rtld_error("%s: too few PT_LOAD segments", path); goto error; } /* * Map the entire address space of the object, to stake out our * contiguous region, and to establish the base address for relocation. */ base_vaddr = trunc_page(segs[0]->p_vaddr); base_vlimit = round_page(segs[nsegs]->p_vaddr + segs[nsegs]->p_memsz); mapsize = base_vlimit - base_vaddr; base_addr = (caddr_t) base_vaddr; base_flags = __getosreldate() >= P_OSREL_MAP_GUARD ? MAP_GUARD : MAP_PRIVATE | MAP_ANON | MAP_NOCORE; if (npagesizes > 1 && round_page(segs[0]->p_filesz) >= pagesizes[1]) base_flags |= MAP_ALIGNED_SUPER; if (base_vaddr != 0) base_flags |= MAP_FIXED | MAP_EXCL; mapbase = mmap(base_addr, mapsize, PROT_NONE, base_flags, -1, 0); if (mapbase == MAP_FAILED) { _rtld_error("%s: mmap of entire address space failed: %s", path, rtld_strerror(errno)); goto error; } if (base_addr != NULL && mapbase != base_addr) { _rtld_error("%s: mmap returned wrong address: wanted %p, got %p", path, base_addr, mapbase); goto error1; } for (i = 0; i <= nsegs; i++) { /* Overlay the segment onto the proper region. */ data_offset = trunc_page(segs[i]->p_offset); data_vaddr = trunc_page(segs[i]->p_vaddr); data_vlimit = round_page(segs[i]->p_vaddr + segs[i]->p_filesz); data_addr = mapbase + (data_vaddr - base_vaddr); data_prot = convert_prot(segs[i]->p_flags); data_flags = convert_flags(segs[i]->p_flags) | MAP_FIXED; if (data_vlimit != data_vaddr && mmap(data_addr, data_vlimit - data_vaddr, data_prot, data_flags | MAP_PREFAULT_READ, fd, data_offset) == MAP_FAILED) { _rtld_error("%s: mmap of data failed: %s", path, rtld_strerror(errno)); goto error1; } /* Do BSS setup */ if (segs[i]->p_filesz != segs[i]->p_memsz) { /* Clear any BSS in the last page of the segment. */ clear_vaddr = segs[i]->p_vaddr + segs[i]->p_filesz; clear_addr = mapbase + (clear_vaddr - base_vaddr); clear_page = mapbase + (trunc_page(clear_vaddr) - base_vaddr); if ((nclear = data_vlimit - clear_vaddr) > 0) { /* Make sure the end of the segment is writable */ if ((data_prot & PROT_WRITE) == 0 && -1 == mprotect(clear_page, PAGE_SIZE, data_prot|PROT_WRITE)) { _rtld_error("%s: mprotect failed: %s", path, rtld_strerror(errno)); goto error1; } memset(clear_addr, 0, nclear); /* Reset the data protection back */ if ((data_prot & PROT_WRITE) == 0) mprotect(clear_page, PAGE_SIZE, data_prot); } /* Overlay the BSS segment onto the proper region. */ bss_vaddr = data_vlimit; bss_vlimit = round_page(segs[i]->p_vaddr + segs[i]->p_memsz); bss_addr = mapbase + (bss_vaddr - base_vaddr); if (bss_vlimit > bss_vaddr) { /* There is something to do */ if (mmap(bss_addr, bss_vlimit - bss_vaddr, data_prot, data_flags | MAP_ANON, -1, 0) == MAP_FAILED) { _rtld_error("%s: mmap of bss failed: %s", path, rtld_strerror(errno)); goto error1; } } } if (phdr_vaddr == 0 && data_offset <= hdr->e_phoff && (data_vlimit - data_vaddr + data_offset) >= (hdr->e_phoff + hdr->e_phnum * sizeof (Elf_Phdr))) { phdr_vaddr = data_vaddr + hdr->e_phoff - data_offset; } } obj = obj_new(); if (sb != NULL) { obj->dev = sb->st_dev; obj->ino = sb->st_ino; } obj->mapbase = mapbase; obj->mapsize = mapsize; obj->vaddrbase = base_vaddr; obj->relocbase = mapbase - base_vaddr; obj->dynamic = (const Elf_Dyn *)(obj->relocbase + phdyn->p_vaddr); if (hdr->e_entry != 0) obj->entry = (caddr_t)(obj->relocbase + hdr->e_entry); if (phdr_vaddr != 0) { obj->phdr = (const Elf_Phdr *)(obj->relocbase + phdr_vaddr); } else { obj->phdr = malloc(phsize); if (obj->phdr == NULL) { obj_free(obj); _rtld_error("%s: cannot allocate program header", path); goto error1; } memcpy(__DECONST(char *, obj->phdr), (char *)hdr + hdr->e_phoff, phsize); obj->phdr_alloc = true; } obj->phsize = phsize; if (phinterp != NULL) obj->interp = (const char *)(obj->relocbase + phinterp->p_vaddr); if (phtls != NULL) { tls_dtv_generation++; obj->tlsindex = ++tls_max_index; obj->tlssize = phtls->p_memsz; obj->tlsalign = phtls->p_align; obj->tlspoffset = phtls->p_offset; obj->tlsinitsize = phtls->p_filesz; obj->tlsinit = mapbase + phtls->p_vaddr; } obj->stack_flags = stack_flags; obj->relro_page = obj->relocbase + trunc_page(relro_page); obj->relro_size = trunc_page(relro_page + relro_size) - trunc_page(relro_page); if (note_start < note_end) digest_notes(obj, note_start, note_end); if (note_map != NULL) munmap(note_map, note_map_len); munmap(hdr, PAGE_SIZE); return (obj); error1: munmap(mapbase, mapsize); error: if (note_map != NULL && note_map != MAP_FAILED) munmap(note_map, note_map_len); if (!phdr_in_zero_page(hdr)) munmap(phdr, hdr->e_phnum * sizeof(phdr[0])); munmap(hdr, PAGE_SIZE); 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 * get_elf_header(int fd, const char *path, const struct stat *sbp, Elf_Phdr **phdr_p) { Elf_Ehdr *hdr; Elf_Phdr *phdr; /* Make sure file has enough data for the ELF header */ if (sbp != NULL && sbp->st_size < (off_t)sizeof(Elf_Ehdr)) { _rtld_error("%s: invalid file format", path); return (NULL); } hdr = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE | MAP_PREFAULT_READ, fd, 0); if (hdr == MAP_FAILED) { _rtld_error("%s: read error: %s", path, rtld_strerror(errno)); return (NULL); } /* Make sure the file is valid */ - if (!IS_ELF(*hdr)) { - _rtld_error("%s: invalid file format", path); + if (!check_elf_headers(hdr, path)) 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 * not strictly required by the ABI specification, but it seems to * 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)) { phdr = (Elf_Phdr *)((char *)hdr + hdr->e_phoff); } else { phdr = mmap(NULL, hdr->e_phnum * sizeof(phdr[0]), PROT_READ, MAP_PRIVATE | MAP_PREFAULT_READ, fd, hdr->e_phoff); if (phdr == MAP_FAILED) { _rtld_error("%s: error mapping phdr: %s", path, rtld_strerror(errno)); goto error; } } *phdr_p = phdr; return (hdr); error: munmap(hdr, PAGE_SIZE); return (NULL); } void obj_free(Obj_Entry *obj) { Objlist_Entry *elm; if (obj->tls_done) free_tls_offset(obj); while (obj->needed != NULL) { Needed_Entry *needed = obj->needed; obj->needed = needed->next; free(needed); } while (!STAILQ_EMPTY(&obj->names)) { Name_Entry *entry = STAILQ_FIRST(&obj->names); STAILQ_REMOVE_HEAD(&obj->names, link); free(entry); } while (!STAILQ_EMPTY(&obj->dldags)) { elm = STAILQ_FIRST(&obj->dldags); STAILQ_REMOVE_HEAD(&obj->dldags, link); free(elm); } while (!STAILQ_EMPTY(&obj->dagmembers)) { elm = STAILQ_FIRST(&obj->dagmembers); STAILQ_REMOVE_HEAD(&obj->dagmembers, link); free(elm); } if (obj->vertab) free(obj->vertab); if (obj->origin_path) free(obj->origin_path); if (obj->z_origin) free(__DECONST(void*, obj->rpath)); if (obj->priv) free(obj->priv); if (obj->path) free(obj->path); if (obj->phdr_alloc) free(__DECONST(void *, obj->phdr)); free(obj); } Obj_Entry * obj_new(void) { Obj_Entry *obj; obj = CNEW(Obj_Entry); STAILQ_INIT(&obj->dldags); STAILQ_INIT(&obj->dagmembers); STAILQ_INIT(&obj->names); return obj; } /* * Given a set of ELF protection flags, return the corresponding protection * flags for MMAP. */ int convert_prot(int elfflags) { int prot = 0; if (elfflags & PF_R) prot |= PROT_READ; if (elfflags & PF_W) prot |= PROT_WRITE; if (elfflags & PF_X) prot |= PROT_EXEC; return prot; } static int convert_flags(int elfflags) { int flags = MAP_PRIVATE; /* All mappings are private */ /* * Readonly mappings are marked "MAP_NOCORE", because they can be * reconstructed by a debugger. */ if (!(elfflags & PF_W)) flags |= MAP_NOCORE; return flags; } diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h index b216e80115bc..48b3ad526828 100644 --- a/libexec/rtld-elf/rtld.h +++ b/libexec/rtld-elf/rtld.h @@ -1,429 +1,430 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright 1996, 1997, 1998, 1999, 2000 John D. Polstra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef RTLD_H /* { */ #define RTLD_H 1 #include #include #include #include #include #include #include #include #include #include "rtld_lock.h" #include "rtld_machdep.h" #define NEW(type) ((type *) xmalloc(sizeof(type))) #define CNEW(type) ((type *) xcalloc(1, sizeof(type))) extern size_t tls_last_offset; extern size_t tls_last_size; extern size_t tls_static_space; extern Elf_Addr tls_dtv_generation; extern int tls_max_index; extern int npagesizes; extern size_t *pagesizes; extern int main_argc; extern char **main_argv; extern char **environ; struct stat; struct Struct_Obj_Entry; /* Lists of shared objects */ typedef struct Struct_Objlist_Entry { STAILQ_ENTRY(Struct_Objlist_Entry) link; struct Struct_Obj_Entry *obj; } Objlist_Entry; typedef STAILQ_HEAD(Struct_Objlist, Struct_Objlist_Entry) Objlist; /* Types of init and fini functions */ typedef void (*InitFunc)(void); typedef void (*InitArrFunc)(int, char **, char **); /* Lists of shared object dependencies */ typedef struct Struct_Needed_Entry { struct Struct_Needed_Entry *next; struct Struct_Obj_Entry *obj; unsigned long name; /* Offset of name in string table */ } Needed_Entry; typedef struct Struct_Name_Entry { STAILQ_ENTRY(Struct_Name_Entry) link; char name[1]; } Name_Entry; /* Lock object */ typedef struct Struct_LockInfo { void *context; /* Client context for creating locks */ void *thelock; /* The one big lock */ /* Debugging aids. */ volatile int rcount; /* Number of readers holding lock */ volatile int wcount; /* Number of writers holding lock */ /* Methods */ void *(*lock_create)(void *context); void (*rlock_acquire)(void *lock); void (*wlock_acquire)(void *lock); void (*rlock_release)(void *lock); void (*wlock_release)(void *lock); void (*lock_destroy)(void *lock); void (*context_destroy)(void *context); } LockInfo; typedef struct Struct_Ver_Entry { Elf_Word hash; unsigned int flags; const char *name; const char *file; } Ver_Entry; typedef struct Struct_Sym_Match_Result { const Elf_Sym *sym_out; const Elf_Sym *vsymp; int vcount; } Sym_Match_Result; #define VER_INFO_HIDDEN 0x01 /* * Shared object descriptor. * * Items marked with "(%)" are dynamically allocated, and must be freed * when the structure is destroyed. * * CAUTION: It appears that the JDK port peeks into these structures. * It looks at "next" and "mapbase" at least. Don't add new members * near the front, until this can be straightened out. */ typedef struct Struct_Obj_Entry { /* * These two items have to be set right for compatibility with the * original ElfKit crt1.o. */ Elf_Size magic; /* Magic number (sanity check) */ Elf_Size version; /* Version number of struct format */ TAILQ_ENTRY(Struct_Obj_Entry) next; char *path; /* Pathname of underlying file (%) */ char *origin_path; /* Directory path of origin file */ int refcount; /* DAG references */ int holdcount; /* Count of transient references */ int dl_refcount; /* Number of times loaded by dlopen */ /* These items are computed by map_object() or by digest_phdr(). */ caddr_t mapbase; /* Base address of mapped region */ size_t mapsize; /* Size of mapped region in bytes */ Elf_Addr vaddrbase; /* Base address in shared object file */ caddr_t relocbase; /* Relocation constant = mapbase - vaddrbase */ const Elf_Dyn *dynamic; /* Dynamic section */ caddr_t entry; /* Entry point */ const Elf_Phdr *phdr; /* Program header if it is mapped, else NULL */ size_t phsize; /* Size of program header in bytes */ const char *interp; /* Pathname of the interpreter, if any */ Elf_Word stack_flags; /* TLS information */ int tlsindex; /* Index in DTV for this module */ void *tlsinit; /* Base address of TLS init block */ size_t tlsinitsize; /* Size of TLS init block for this module */ size_t tlssize; /* Size of TLS block for this module */ size_t tlsoffset; /* Offset of static TLS block for this module */ size_t tlsalign; /* Alignment of static TLS block */ size_t tlspoffset; /* p_offset of the static TLS block */ caddr_t relro_page; size_t relro_size; /* Items from the dynamic section. */ Elf_Addr *pltgot; /* PLT or GOT, depending on architecture */ const Elf_Rel *rel; /* Relocation entries */ unsigned long relsize; /* Size in bytes of relocation info */ const Elf_Rela *rela; /* Relocation entries with addend */ unsigned long relasize; /* Size in bytes of addend relocation info */ const Elf_Relr *relr; /* RELR relocation entries */ unsigned long relrsize; /* Size in bytes of RELR relocations */ const Elf_Rel *pltrel; /* PLT relocation entries */ unsigned long pltrelsize; /* Size in bytes of PLT relocation info */ const Elf_Rela *pltrela; /* PLT relocation entries with addend */ unsigned long pltrelasize; /* Size in bytes of PLT addend reloc info */ const Elf_Sym *symtab; /* Symbol table */ const char *strtab; /* String table */ unsigned long strsize; /* Size in bytes of string table */ #ifdef __mips__ Elf_Word local_gotno; /* Number of local GOT entries */ Elf_Word symtabno; /* Number of dynamic symbols */ Elf_Word gotsym; /* First dynamic symbol in GOT */ Elf_Addr *mips_pltgot; /* Second PLT GOT */ #endif #ifdef __powerpc__ #ifdef __powerpc64__ Elf_Addr glink; /* GLINK PLT call stub section */ #else Elf_Addr *gotptr; /* GOT pointer (secure-plt only) */ #endif #endif const Elf_Verneed *verneed; /* Required versions. */ Elf_Word verneednum; /* Number of entries in verneed table */ const Elf_Verdef *verdef; /* Provided versions. */ Elf_Word verdefnum; /* Number of entries in verdef table */ const Elf_Versym *versyms; /* Symbol versions table */ const Elf_Hashelt *buckets; /* Hash table buckets array */ unsigned long nbuckets; /* Number of buckets */ const Elf_Hashelt *chains; /* Hash table chain array */ unsigned long nchains; /* Number of entries in chain array */ Elf32_Word nbuckets_gnu; /* Number of GNU hash buckets*/ Elf32_Word symndx_gnu; /* 1st accessible symbol on dynsym table */ Elf32_Word maskwords_bm_gnu; /* Bloom filter words - 1 (bitmask) */ Elf32_Word shift2_gnu; /* Bloom filter shift count */ Elf32_Word dynsymcount; /* Total entries in dynsym table */ const Elf_Addr *bloom_gnu; /* Bloom filter used by GNU hash func */ const Elf_Hashelt *buckets_gnu; /* GNU hash table bucket array */ const Elf_Hashelt *chain_zero_gnu; /* GNU hash table value array (Zeroed) */ const char *rpath; /* Search path specified in object */ const char *runpath; /* Search path with different priority */ Needed_Entry *needed; /* Shared objects needed by this one (%) */ Needed_Entry *needed_filtees; Needed_Entry *needed_aux_filtees; STAILQ_HEAD(, Struct_Name_Entry) names; /* List of names for this object we know about. */ Ver_Entry *vertab; /* Versions required /defined by this object */ int vernum; /* Number of entries in vertab */ Elf_Addr init; /* Initialization function to call */ Elf_Addr fini; /* Termination function to call */ Elf_Addr preinit_array; /* Pre-initialization array of functions */ Elf_Addr init_array; /* Initialization array of functions */ Elf_Addr fini_array; /* Termination array of functions */ int preinit_array_num; /* Number of entries in preinit_array */ int init_array_num; /* Number of entries in init_array */ int fini_array_num; /* Number of entries in fini_array */ int32_t osrel; /* OSREL note value */ uint32_t fctl0; /* FEATURE_CONTROL note desc[0] value */ bool mainprog : 1; /* True if this is the main program */ bool rtld : 1; /* True if this is the dynamic linker */ bool relocated : 1; /* True if processed by relocate_objects() */ bool ver_checked : 1; /* True if processed by rtld_verify_object_versions */ bool textrel : 1; /* True if there are relocations to text seg */ bool symbolic : 1; /* True if generated with "-Bsymbolic" */ bool bind_now : 1; /* True if all relocations should be made first */ bool traced : 1; /* Already printed in ldd trace output */ bool jmpslots_done : 1; /* Already have relocated the jump slots */ bool init_done : 1; /* Already have added object to init list */ bool tls_done : 1; /* Already allocated offset for static TLS */ bool phdr_alloc : 1; /* Phdr is allocated and needs to be freed. */ bool z_origin : 1; /* Process rpath and soname tokens */ bool z_nodelete : 1; /* Do not unload the object and dependencies */ bool z_noopen : 1; /* Do not load on dlopen */ bool z_loadfltr : 1; /* Immediately load filtees */ bool z_interpose : 1; /* Interpose all objects but main */ bool z_nodeflib : 1; /* Don't search default library path */ bool z_global : 1; /* Make the object global */ bool z_pie : 1; /* Object proclaimed itself PIE executable */ bool static_tls : 1; /* Needs static TLS allocation */ bool static_tls_copied : 1; /* Needs static TLS copying */ bool ref_nodel : 1; /* Refcount increased to prevent dlclose */ bool init_scanned: 1; /* Object is already on init list. */ bool on_fini_list: 1; /* Object is already on fini list. */ bool dag_inited : 1; /* Object has its DAG initialized. */ bool filtees_loaded : 1; /* Filtees loaded */ bool irelative : 1; /* Object has R_MACHDEP_IRELATIVE relocs */ bool irelative_nonplt : 1; /* Object has R_MACHDEP_IRELATIVE non-plt relocs */ bool gnu_ifunc : 1; /* Object has references to STT_GNU_IFUNC */ bool non_plt_gnu_ifunc : 1; /* Object has non-plt IFUNC references */ bool ifuncs_resolved : 1; /* Object ifuncs were already resolved */ bool crt_no_init : 1; /* Object' crt does not call _init/_fini */ bool valid_hash_sysv : 1; /* A valid System V hash hash tag is available */ bool valid_hash_gnu : 1; /* A valid GNU hash tag is available */ bool dlopened : 1; /* dlopen()-ed (vs. load statically) */ bool marker : 1; /* marker on the global obj list */ bool unholdfree : 1; /* unmap upon last unhold */ bool doomed : 1; /* Object cannot be referenced */ struct link_map linkmap; /* For GDB and dlinfo() */ Objlist dldags; /* Object belongs to these dlopened DAGs (%) */ Objlist dagmembers; /* DAG has these members (%) */ dev_t dev; /* Object's filesystem's device */ ino_t ino; /* Object's inode number */ void *priv; /* Platform-dependent */ } Obj_Entry; #define RTLD_MAGIC 0xd550b87a #define RTLD_VERSION 1 TAILQ_HEAD(obj_entry_q, Struct_Obj_Entry); #define RTLD_STATIC_TLS_EXTRA 128 /* Flags to be passed into symlook_ family of functions. */ #define SYMLOOK_IN_PLT 0x01 /* Lookup for PLT symbol */ #define SYMLOOK_DLSYM 0x02 /* Return newest versioned symbol. Used by dlsym. */ #define SYMLOOK_EARLY 0x04 /* Symlook is done during initialization. */ #define SYMLOOK_IFUNC 0x08 /* Allow IFUNC processing in reloc_non_plt(). */ /* Flags for load_object(). */ #define RTLD_LO_NOLOAD 0x01 /* dlopen() specified RTLD_NOLOAD. */ #define RTLD_LO_DLOPEN 0x02 /* Load_object() called from dlopen(). */ #define RTLD_LO_TRACE 0x04 /* Only tracing. */ #define RTLD_LO_NODELETE 0x08 /* Loaded object cannot be closed. */ #define RTLD_LO_FILTEES 0x10 /* Loading filtee. */ #define RTLD_LO_EARLY 0x20 /* Do not call ctors, postpone it to the initialization during the image start. */ #define RTLD_LO_IGNSTLS 0x40 /* Do not allocate static TLS */ #define RTLD_LO_DEEPBIND 0x80 /* Force symbolic for this object */ /* * Symbol cache entry used during relocation to avoid multiple lookups * of the same symbol. */ typedef struct Struct_SymCache { const Elf_Sym *sym; /* Symbol table entry */ const Obj_Entry *obj; /* Shared object which defines it */ } SymCache; /* * This structure provides a reentrant way to keep a list of objects and * check which ones have already been processed in some way. */ typedef struct Struct_DoneList { const Obj_Entry **objs; /* Array of object pointers */ unsigned int num_alloc; /* Allocated size of the array */ unsigned int num_used; /* Number of array slots used */ } DoneList; struct Struct_RtldLockState { int lockstate; sigjmp_buf env; }; struct fill_search_info_args { int request; unsigned int flags; struct dl_serinfo *serinfo; struct dl_serpath *serpath; char *strspace; }; /* * The pack of arguments and results for the symbol lookup functions. */ typedef struct Struct_SymLook { const char *name; unsigned long hash; uint32_t hash_gnu; const Ver_Entry *ventry; int flags; const Obj_Entry *defobj_out; const Elf_Sym *sym_out; struct Struct_RtldLockState *lockstate; } SymLook; void _rtld_error(const char *, ...) __printflike(1, 2) __exported; void rtld_die(void) __dead2; const char *rtld_strerror(int); Obj_Entry *map_object(int, const char *, const struct stat *); void *xcalloc(size_t, size_t); void *xmalloc(size_t); char *xstrdup(const char *); void *malloc_aligned(size_t size, size_t align, size_t offset); void free_aligned(void *ptr); extern Elf_Addr _GLOBAL_OFFSET_TABLE_[]; extern Elf_Sym sym_zero; /* For resolving undefined weak refs. */ extern bool ld_bind_not; extern bool ld_fast_sigblock; void dump_relocations(Obj_Entry *); void dump_obj_relocations(Obj_Entry *); void dump_Elf_Rel(Obj_Entry *, const Elf_Rel *, u_long); void dump_Elf_Rela(Obj_Entry *, const Elf_Rela *, u_long); /* * Function declarations. */ unsigned long elf_hash(const char *); const Elf_Sym *find_symdef(unsigned long, const Obj_Entry *, const Obj_Entry **, int, SymCache *, struct Struct_RtldLockState *); void lockdflt_init(void); void digest_notes(Obj_Entry *, Elf_Addr, Elf_Addr); Obj_Entry *globallist_curr(const Obj_Entry *obj); Obj_Entry *globallist_next(const Obj_Entry *obj); void obj_free(Obj_Entry *); Obj_Entry *obj_new(void); Obj_Entry *obj_from_addr(const void *); void _rtld_bind_start(void); void *rtld_resolve_ifunc(const Obj_Entry *obj, const Elf_Sym *def); void symlook_init(SymLook *, const char *); int symlook_obj(SymLook *, const Obj_Entry *); void *tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset); void *allocate_tls(Obj_Entry *, void *, size_t, size_t); void free_tls(void *, size_t, size_t); void *allocate_module_tls(int index); bool allocate_tls_offset(Obj_Entry *obj); void free_tls_offset(Obj_Entry *obj); const Ver_Entry *fetch_ventry(const Obj_Entry *obj, unsigned long); int convert_prot(int elfflags); void *_get_tp(void); /* libc implementation */ +bool check_elf_headers(const Elf_Ehdr *hdr, const char *path); /* * MD function declarations. */ int do_copy_relocations(Obj_Entry *); int reloc_non_plt(Obj_Entry *, Obj_Entry *, int flags, struct Struct_RtldLockState *); int reloc_plt(Obj_Entry *, int flags, struct Struct_RtldLockState *); int reloc_jmpslots(Obj_Entry *, int flags, struct Struct_RtldLockState *); int reloc_iresolve(Obj_Entry *, struct Struct_RtldLockState *); int reloc_iresolve_nonplt(Obj_Entry *, struct Struct_RtldLockState *); int reloc_gnu_ifunc(Obj_Entry *, int flags, struct Struct_RtldLockState *); void ifunc_init(Elf_Auxinfo[__min_size(AT_COUNT)]); void init_pltgot(Obj_Entry *); void allocate_initial_tls(Obj_Entry *); void *__crt_calloc(size_t num, size_t size); void __crt_free(void *cp); void *__crt_malloc(size_t nbytes); void *__crt_realloc(void *cp, size_t nbytes); #endif /* } */