134192Sjdp/*- 234192Sjdp * Copyright 1996-1998 John D. Polstra. 334192Sjdp * All rights reserved. 434192Sjdp * 534192Sjdp * Redistribution and use in source and binary forms, with or without 634192Sjdp * modification, are permitted provided that the following conditions 734192Sjdp * are met: 834192Sjdp * 1. Redistributions of source code must retain the above copyright 934192Sjdp * notice, this list of conditions and the following disclaimer. 1034192Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1134192Sjdp * notice, this list of conditions and the following disclaimer in the 1234192Sjdp * documentation and/or other materials provided with the distribution. 1334192Sjdp * 1434192Sjdp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1534192Sjdp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1634192Sjdp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1734192Sjdp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1834192Sjdp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1934192Sjdp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2034192Sjdp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2134192Sjdp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2234192Sjdp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2334192Sjdp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2434192Sjdp * 2550476Speter * $FreeBSD$ 2634192Sjdp */ 2734192Sjdp 2834192Sjdp#include <sys/param.h> 2934192Sjdp#include <sys/mman.h> 3050609Sjdp#include <sys/stat.h> 3134192Sjdp 3234192Sjdp#include <errno.h> 3334192Sjdp#include <stddef.h> 3450608Sjdp#include <stdlib.h> 3534192Sjdp#include <string.h> 3634192Sjdp#include <unistd.h> 3734192Sjdp 3885004Sdfr#include "debug.h" 3934192Sjdp#include "rtld.h" 4034192Sjdp 41237058Skibstatic Elf_Ehdr *get_elf_header(int, const char *); 42107948Sdillonstatic int convert_prot(int); /* Elf flags -> mmap protection */ 43107948Sdillonstatic int convert_flags(int); /* Elf flags -> mmap flags */ 4434192Sjdp 4534192Sjdp/* 4648871Sjdp * Map a shared object into memory. The "fd" argument is a file descriptor, 4734192Sjdp * which must be open on the object and positioned at its beginning. 4848871Sjdp * The "path" argument is a pathname that is used only for error messages. 4934192Sjdp * 5034192Sjdp * The return value is a pointer to a newly-allocated Obj_Entry structure 5134192Sjdp * for the shared object. Returns NULL on failure. 5234192Sjdp */ 5334192SjdpObj_Entry * 5450609Sjdpmap_object(int fd, const char *path, const struct stat *sb) 5534192Sjdp{ 5634192Sjdp Obj_Entry *obj; 57115446Smdodd Elf_Ehdr *hdr; 58114625Sobrien int i; 5938816Sdfr Elf_Phdr *phdr; 6038816Sdfr Elf_Phdr *phlimit; 61105753Skan Elf_Phdr **segs; 6234192Sjdp int nsegs; 6338816Sdfr Elf_Phdr *phdyn; 6450610Sjdp Elf_Phdr *phinterp; 65133063Sdfr Elf_Phdr *phtls; 6634192Sjdp caddr_t mapbase; 6734192Sjdp size_t mapsize; 6838816Sdfr Elf_Addr base_vaddr; 6938816Sdfr Elf_Addr base_vlimit; 7034192Sjdp caddr_t base_addr; 7138816Sdfr Elf_Off data_offset; 7238816Sdfr Elf_Addr data_vaddr; 7338816Sdfr Elf_Addr data_vlimit; 7434192Sjdp caddr_t data_addr; 75105753Skan int data_prot; 76107948Sdillon int data_flags; 7738816Sdfr Elf_Addr clear_vaddr; 7834192Sjdp caddr_t clear_addr; 79105753Skan caddr_t clear_page; 80168312Skan Elf_Addr phdr_vaddr; 81168312Skan size_t nclear, phsize; 8238816Sdfr Elf_Addr bss_vaddr; 8338816Sdfr Elf_Addr bss_vlimit; 8434192Sjdp caddr_t bss_addr; 85217153Skib Elf_Word stack_flags; 86230784Skib Elf_Addr relro_page; 87230784Skib size_t relro_size; 88232831Skib Elf_Addr note_start; 89232831Skib Elf_Addr note_end; 9034192Sjdp 91115446Smdodd hdr = get_elf_header(fd, path); 92115446Smdodd if (hdr == NULL) 93115446Smdodd return (NULL); 9434192Sjdp 9534192Sjdp /* 9634192Sjdp * Scan the program header entries, and save key information. 9734192Sjdp * 98190883Skib * We expect that the loadable segments are ordered by load address. 9934192Sjdp */ 100115446Smdodd phdr = (Elf_Phdr *) ((char *)hdr + hdr->e_phoff); 101168312Skan phsize = hdr->e_phnum * sizeof (phdr[0]); 102115446Smdodd phlimit = phdr + hdr->e_phnum; 103105753Skan nsegs = -1; 104168312Skan phdyn = phinterp = phtls = NULL; 105168312Skan phdr_vaddr = 0; 106230784Skib relro_page = 0; 107230784Skib relro_size = 0; 108232831Skib note_start = 0; 109232831Skib note_end = 0; 110115446Smdodd segs = alloca(sizeof(segs[0]) * hdr->e_phnum); 111217851Skib stack_flags = RTLD_DEFAULT_STACK_PF_EXEC | PF_R | PF_W; 11234192Sjdp while (phdr < phlimit) { 11334192Sjdp switch (phdr->p_type) { 11434192Sjdp 11550610Sjdp case PT_INTERP: 11650610Sjdp phinterp = phdr; 11750610Sjdp break; 11850610Sjdp 11934192Sjdp case PT_LOAD: 120105753Skan segs[++nsegs] = phdr; 121168312Skan if ((segs[nsegs]->p_align & (PAGE_SIZE - 1)) != 0) { 122105753Skan _rtld_error("%s: PT_LOAD segment %d not page-aligned", 123105753Skan path, nsegs); 124237058Skib goto error; 12548871Sjdp } 12634192Sjdp break; 12734192Sjdp 12834192Sjdp case PT_PHDR: 129168312Skan phdr_vaddr = phdr->p_vaddr; 130168312Skan phsize = phdr->p_memsz; 13134192Sjdp break; 13234192Sjdp 13334192Sjdp case PT_DYNAMIC: 13434192Sjdp phdyn = phdr; 13534192Sjdp break; 136133063Sdfr 137133063Sdfr case PT_TLS: 138133063Sdfr phtls = phdr; 139133063Sdfr break; 140217153Skib 141217153Skib case PT_GNU_STACK: 142217153Skib stack_flags = phdr->p_flags; 143217153Skib break; 144230784Skib 145230784Skib case PT_GNU_RELRO: 146230784Skib relro_page = phdr->p_vaddr; 147230784Skib relro_size = phdr->p_memsz; 148230784Skib break; 149232831Skib 150232831Skib case PT_NOTE: 151232856Skib if (phdr->p_offset > PAGE_SIZE || 152232856Skib phdr->p_offset + phdr->p_filesz > PAGE_SIZE) 153232856Skib break; 154232856Skib note_start = (Elf_Addr)(char *)hdr + phdr->p_offset; 155232831Skib note_end = note_start + phdr->p_filesz; 156232831Skib break; 15734192Sjdp } 15834192Sjdp 15934192Sjdp ++phdr; 16034192Sjdp } 16134192Sjdp if (phdyn == NULL) { 16248871Sjdp _rtld_error("%s: object is not dynamically-linked", path); 163237058Skib goto error; 16434192Sjdp } 16534192Sjdp 166105753Skan if (nsegs < 0) { 16748871Sjdp _rtld_error("%s: too few PT_LOAD segments", path); 168237058Skib goto error; 16948871Sjdp } 17034192Sjdp 17134192Sjdp /* 17234192Sjdp * Map the entire address space of the object, to stake out our 17334192Sjdp * contiguous region, and to establish the base address for relocation. 17434192Sjdp */ 17534192Sjdp base_vaddr = trunc_page(segs[0]->p_vaddr); 176105753Skan base_vlimit = round_page(segs[nsegs]->p_vaddr + segs[nsegs]->p_memsz); 17734192Sjdp mapsize = base_vlimit - base_vaddr; 178247396Stijl base_addr = (caddr_t) base_vaddr; 17934192Sjdp 180190885Skib mapbase = mmap(base_addr, mapsize, PROT_NONE, MAP_ANON | MAP_PRIVATE | 181190885Skib MAP_NOCORE, -1, 0); 18234192Sjdp if (mapbase == (caddr_t) -1) { 18348871Sjdp _rtld_error("%s: mmap of entire address space failed: %s", 184232974Skib path, rtld_strerror(errno)); 185237058Skib goto error; 18634192Sjdp } 18734192Sjdp if (base_addr != NULL && mapbase != base_addr) { 18848871Sjdp _rtld_error("%s: mmap returned wrong address: wanted %p, got %p", 18948871Sjdp path, base_addr, mapbase); 190237058Skib goto error1; 19134192Sjdp } 19234192Sjdp 193190883Skib for (i = 0; i <= nsegs; i++) { 194105753Skan /* Overlay the segment onto the proper region. */ 195105753Skan data_offset = trunc_page(segs[i]->p_offset); 196105753Skan data_vaddr = trunc_page(segs[i]->p_vaddr); 197105753Skan data_vlimit = round_page(segs[i]->p_vaddr + segs[i]->p_filesz); 198105753Skan data_addr = mapbase + (data_vaddr - base_vaddr); 199107948Sdillon data_prot = convert_prot(segs[i]->p_flags); 200107948Sdillon data_flags = convert_flags(segs[i]->p_flags) | MAP_FIXED; 201190885Skib if (mmap(data_addr, data_vlimit - data_vaddr, data_prot, 202237058Skib data_flags | MAP_PREFAULT_READ, fd, data_offset) == (caddr_t) -1) { 203232974Skib _rtld_error("%s: mmap of data failed: %s", path, 204232974Skib rtld_strerror(errno)); 205237058Skib goto error1; 206105753Skan } 20734192Sjdp 208195743Skib /* Do BSS setup */ 209195743Skib if (segs[i]->p_filesz != segs[i]->p_memsz) { 210195743Skib 211195743Skib /* Clear any BSS in the last page of the segment. */ 212195743Skib clear_vaddr = segs[i]->p_vaddr + segs[i]->p_filesz; 213195743Skib clear_addr = mapbase + (clear_vaddr - base_vaddr); 214195743Skib clear_page = mapbase + (trunc_page(clear_vaddr) - base_vaddr); 215195743Skib 216195743Skib if ((nclear = data_vlimit - clear_vaddr) > 0) { 217195743Skib /* Make sure the end of the segment is writable */ 218195743Skib if ((data_prot & PROT_WRITE) == 0 && -1 == 219195743Skib mprotect(clear_page, PAGE_SIZE, data_prot|PROT_WRITE)) { 220105753Skan _rtld_error("%s: mprotect failed: %s", path, 221232974Skib rtld_strerror(errno)); 222237058Skib goto error1; 223195743Skib } 22434192Sjdp 225195743Skib memset(clear_addr, 0, nclear); 226105753Skan 227195743Skib /* Reset the data protection back */ 228195743Skib if ((data_prot & PROT_WRITE) == 0) 229195743Skib mprotect(clear_page, PAGE_SIZE, data_prot); 230195743Skib } 231105753Skan 232195743Skib /* Overlay the BSS segment onto the proper region. */ 233195743Skib bss_vaddr = data_vlimit; 234195743Skib bss_vlimit = round_page(segs[i]->p_vaddr + segs[i]->p_memsz); 235195743Skib bss_addr = mapbase + (bss_vaddr - base_vaddr); 236195743Skib if (bss_vlimit > bss_vaddr) { /* There is something to do */ 237225699Skib if (mmap(bss_addr, bss_vlimit - bss_vaddr, data_prot, 238225699Skib data_flags | MAP_ANON, -1, 0) == (caddr_t)-1) { 239225699Skib _rtld_error("%s: mmap of bss failed: %s", path, 240232974Skib rtld_strerror(errno)); 241237058Skib goto error1; 242195743Skib } 243105753Skan } 244105753Skan } 245195743Skib 246168312Skan if (phdr_vaddr == 0 && data_offset <= hdr->e_phoff && 247168312Skan (data_vlimit - data_vaddr + data_offset) >= 248168312Skan (hdr->e_phoff + hdr->e_phnum * sizeof (Elf_Phdr))) { 249168312Skan phdr_vaddr = data_vaddr + hdr->e_phoff - data_offset; 250168312Skan } 25134192Sjdp } 25234192Sjdp 25350608Sjdp obj = obj_new(); 25450609Sjdp if (sb != NULL) { 25550609Sjdp obj->dev = sb->st_dev; 25650609Sjdp obj->ino = sb->st_ino; 25750609Sjdp } 25834192Sjdp obj->mapbase = mapbase; 25934192Sjdp obj->mapsize = mapsize; 26034192Sjdp obj->textsize = round_page(segs[0]->p_vaddr + segs[0]->p_memsz) - 26134192Sjdp base_vaddr; 26234192Sjdp obj->vaddrbase = base_vaddr; 26334192Sjdp obj->relocbase = mapbase - base_vaddr; 26450610Sjdp obj->dynamic = (const Elf_Dyn *) (obj->relocbase + phdyn->p_vaddr); 265115446Smdodd if (hdr->e_entry != 0) 266115446Smdodd obj->entry = (caddr_t) (obj->relocbase + hdr->e_entry); 267168312Skan if (phdr_vaddr != 0) { 268168312Skan obj->phdr = (const Elf_Phdr *) (obj->relocbase + phdr_vaddr); 269168312Skan } else { 270168312Skan obj->phdr = malloc(phsize); 271168312Skan if (obj->phdr == NULL) { 272168312Skan obj_free(obj); 273168312Skan _rtld_error("%s: cannot allocate program header", path); 274237058Skib goto error1; 275168312Skan } 276168312Skan memcpy((char *)obj->phdr, (char *)hdr + hdr->e_phoff, phsize); 277168312Skan obj->phdr_alloc = true; 27834192Sjdp } 279168312Skan obj->phsize = phsize; 28050610Sjdp if (phinterp != NULL) 28150610Sjdp obj->interp = (const char *) (obj->relocbase + phinterp->p_vaddr); 282133063Sdfr if (phtls != NULL) { 283133063Sdfr tls_dtv_generation++; 284133063Sdfr obj->tlsindex = ++tls_max_index; 285133063Sdfr obj->tlssize = phtls->p_memsz; 286133063Sdfr obj->tlsalign = phtls->p_align; 287133063Sdfr obj->tlsinitsize = phtls->p_filesz; 288133063Sdfr obj->tlsinit = mapbase + phtls->p_vaddr; 289133063Sdfr } 290217153Skib obj->stack_flags = stack_flags; 291230784Skib obj->relro_page = obj->relocbase + trunc_page(relro_page); 292230784Skib obj->relro_size = round_page(relro_size); 293239019Skan if (note_start < note_end) 294239019Skan digest_notes(obj, note_start, note_end); 295237058Skib munmap(hdr, PAGE_SIZE); 296237058Skib return (obj); 297237058Skib 298237058Skiberror1: 299237058Skib munmap(mapbase, mapsize); 300237058Skiberror: 301237058Skib munmap(hdr, PAGE_SIZE); 302237058Skib return (NULL); 30334192Sjdp} 30434192Sjdp 305115446Smdoddstatic Elf_Ehdr * 306237058Skibget_elf_header(int fd, const char *path) 307115446Smdodd{ 308237058Skib Elf_Ehdr *hdr; 309115446Smdodd 310237058Skib hdr = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE | MAP_PREFAULT_READ, 311237058Skib fd, 0); 312237058Skib if (hdr == (Elf_Ehdr *)MAP_FAILED) { 313237058Skib _rtld_error("%s: read error: %s", path, rtld_strerror(errno)); 314237058Skib return (NULL); 315237058Skib } 316115446Smdodd 317237058Skib /* Make sure the file is valid */ 318237058Skib if (!IS_ELF(*hdr)) { 319237058Skib _rtld_error("%s: invalid file format", path); 320237058Skib goto error; 321237058Skib } 322237058Skib if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || 323237058Skib hdr->e_ident[EI_DATA] != ELF_TARG_DATA) { 324237058Skib _rtld_error("%s: unsupported file layout", path); 325237058Skib goto error; 326237058Skib } 327237058Skib if (hdr->e_ident[EI_VERSION] != EV_CURRENT || 328237058Skib hdr->e_version != EV_CURRENT) { 329237058Skib _rtld_error("%s: unsupported file version", path); 330237058Skib goto error; 331237058Skib } 332237058Skib if (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN) { 333237058Skib _rtld_error("%s: unsupported file type", path); 334237058Skib goto error; 335237058Skib } 336237058Skib if (hdr->e_machine != ELF_TARG_MACH) { 337237058Skib _rtld_error("%s: unsupported machine", path); 338237058Skib goto error; 339237058Skib } 340115446Smdodd 341237058Skib /* 342237058Skib * We rely on the program header being in the first page. This is 343237058Skib * not strictly required by the ABI specification, but it seems to 344237058Skib * always true in practice. And, it simplifies things considerably. 345237058Skib */ 346237058Skib if (hdr->e_phentsize != sizeof(Elf_Phdr)) { 347237058Skib _rtld_error( 348237058Skib "%s: invalid shared object: e_phentsize != sizeof(Elf_Phdr)", path); 349237058Skib goto error; 350237058Skib } 351237058Skib if (hdr->e_phoff + hdr->e_phnum * sizeof(Elf_Phdr) > 352237058Skib (size_t)PAGE_SIZE) { 353237058Skib _rtld_error("%s: program header too large", path); 354237058Skib goto error; 355237058Skib } 356237058Skib return (hdr); 357115446Smdodd 358237058Skiberror: 359237058Skib munmap(hdr, PAGE_SIZE); 360237058Skib return (NULL); 361115446Smdodd} 362115446Smdodd 36350608Sjdpvoid 36450608Sjdpobj_free(Obj_Entry *obj) 36550608Sjdp{ 36650608Sjdp Objlist_Entry *elm; 36750608Sjdp 368153515Skan if (obj->tls_done) 369142645Sdfr free_tls_offset(obj); 37050608Sjdp while (obj->needed != NULL) { 37150608Sjdp Needed_Entry *needed = obj->needed; 37250608Sjdp obj->needed = needed->next; 37350608Sjdp free(needed); 37450608Sjdp } 375153515Skan while (!STAILQ_EMPTY(&obj->names)) { 376153515Skan Name_Entry *entry = STAILQ_FIRST(&obj->names); 377153515Skan STAILQ_REMOVE_HEAD(&obj->names, link); 378153515Skan free(entry); 379153515Skan } 38050608Sjdp while (!STAILQ_EMPTY(&obj->dldags)) { 38150608Sjdp elm = STAILQ_FIRST(&obj->dldags); 38250608Sjdp STAILQ_REMOVE_HEAD(&obj->dldags, link); 38350608Sjdp free(elm); 38450608Sjdp } 38550608Sjdp while (!STAILQ_EMPTY(&obj->dagmembers)) { 38650608Sjdp elm = STAILQ_FIRST(&obj->dagmembers); 38750608Sjdp STAILQ_REMOVE_HEAD(&obj->dagmembers, link); 38850608Sjdp free(elm); 38950608Sjdp } 390168312Skan if (obj->vertab) 391168312Skan free(obj->vertab); 392168312Skan if (obj->origin_path) 393168312Skan free(obj->origin_path); 394189959Skib if (obj->z_origin) 395189959Skib free(obj->rpath); 396168312Skan if (obj->priv) 397168312Skan free(obj->priv); 398168312Skan if (obj->path) 399168312Skan free(obj->path); 400168312Skan if (obj->phdr_alloc) 401168312Skan free((void *)obj->phdr); 40250608Sjdp free(obj); 40350608Sjdp} 40450608Sjdp 40550608SjdpObj_Entry * 40650608Sjdpobj_new(void) 40750608Sjdp{ 40850608Sjdp Obj_Entry *obj; 40950608Sjdp 41050608Sjdp obj = CNEW(Obj_Entry); 41150608Sjdp STAILQ_INIT(&obj->dldags); 41250608Sjdp STAILQ_INIT(&obj->dagmembers); 413153515Skan STAILQ_INIT(&obj->names); 41450608Sjdp return obj; 41550608Sjdp} 41650608Sjdp 41734192Sjdp/* 41834192Sjdp * Given a set of ELF protection flags, return the corresponding protection 41934192Sjdp * flags for MMAP. 42034192Sjdp */ 42134192Sjdpstatic int 422107948Sdillonconvert_prot(int elfflags) 42334192Sjdp{ 42434192Sjdp int prot = 0; 42534192Sjdp if (elfflags & PF_R) 42634192Sjdp prot |= PROT_READ; 42734192Sjdp if (elfflags & PF_W) 42834192Sjdp prot |= PROT_WRITE; 42934192Sjdp if (elfflags & PF_X) 43034192Sjdp prot |= PROT_EXEC; 43134192Sjdp return prot; 43234192Sjdp} 433107948Sdillon 434107948Sdillonstatic int 435107948Sdillonconvert_flags(int elfflags) 436107948Sdillon{ 437107948Sdillon int flags = MAP_PRIVATE; /* All mappings are private */ 438107948Sdillon 439107948Sdillon /* 440107948Sdillon * Readonly mappings are marked "MAP_NOCORE", because they can be 441107948Sdillon * reconstructed by a debugger. 442107948Sdillon */ 443107948Sdillon if (!(elfflags & PF_W)) 444107948Sdillon flags |= MAP_NOCORE; 445107948Sdillon return flags; 446107948Sdillon} 447