1 /* $OpenBSD: boot.h,v 1.23 2016/09/01 09:33:30 tedu Exp $ */ 2 3 /* 4 * Copyright (c) 1998 Per Fogelstrom, Opsycon AB 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 */ 28 29 /* 30 * IMPORTANT: any functions below are NOT protected by SSP. Please 31 * do not add anything except what is required to reach GOT with 32 * an adjustment. 33 */ 34 35 #define _DYN_LOADER 36 37 #include <sys/types.h> 38 #include <sys/mman.h> 39 #include <sys/exec.h> 40 #include <sys/sysctl.h> 41 #include <nlist.h> 42 #include <link.h> 43 #include <dlfcn.h> 44 45 #include "syscall.h" 46 #include "archdep.h" 47 #include "path.h" 48 #include "resolve.h" 49 #include "sod.h" 50 #include "stdlib.h" 51 52 /* 53 * Use the internal, hidden name for any syscalls we need, to avoid 54 * accidental override by application code 55 */ 56 #define REDIRECT_SYSCALL(x) typeof(x) x asm("_libc_"#x) __dso_hidden 57 REDIRECT_SYSCALL(mprotect); 58 59 #ifdef RCRT0 60 61 #define DT_PROC(n) ((n) - DT_LOPROC) 62 63 #if RELOC_TAG == DT_RELA 64 typedef Elf_RelA RELOC_TYPE; 65 #elif RELOC_TAG == DT_REL 66 typedef Elf_Rel RELOC_TYPE; 67 #else 68 # error "unknown RELOC_TAG" 69 #endif 70 71 /* The set of dynamic tags that we're interested in for bootstrapping */ 72 struct boot_dyn { 73 RELOC_TYPE *dt_reloc; /* DT_RELA or DT_REL */ 74 Elf_Addr dt_relocsz; /* DT_RELASZ or DT_RELSZ */ 75 Elf_Addr *dt_pltgot; 76 Elf_Addr dt_pltrelsz; 77 const Elf_Sym *dt_symtab; 78 RELOC_TYPE *dt_jmprel; 79 #if DT_PROCNUM > 0 80 u_long dt_proc[DT_PROCNUM]; 81 #endif 82 }; 83 84 /* 85 * Local decls. 86 */ 87 void _dl_boot_bind(const long, long *, Elf_Dyn *); 88 89 extern char __got_start[]; 90 extern char __got_end[]; 91 92 void 93 _dl_boot_bind(const long sp, long *dl_data, Elf_Dyn *dynamicp) 94 { 95 struct boot_dyn dynld; /* Resolver data for the loader */ 96 AuxInfo *auxstack; 97 long *stack; 98 Elf_Dyn *dynp; 99 Elf_Addr start; 100 size_t size; 101 int pagesize; 102 int n, argc; 103 char **argv, **envp; 104 long loff; 105 int prot_exec = 0; 106 RELOC_TYPE *rp; 107 Elf_Phdr *phdp; 108 Elf_Addr i; 109 110 /* 111 * Scan argument and environment vectors. Find dynamic 112 * data vector put after them. 113 */ 114 stack = (long *)sp; 115 argc = *stack++; 116 argv = (char **)stack; 117 envp = &argv[argc + 1]; 118 stack = (long *)envp; 119 while (*stack++ != 0L) 120 ; 121 122 /* 123 * Zero out dl_data. 124 */ 125 for (n = 0; n <= AUX_entry; n++) 126 dl_data[n] = 0; 127 128 /* 129 * Dig out auxiliary data set up by exec call. Move all known 130 * tags to an indexed local table for easy access. 131 */ 132 for (auxstack = (AuxInfo *)stack; auxstack->au_id != AUX_null; 133 auxstack++) { 134 if (auxstack->au_id > AUX_entry) 135 continue; 136 dl_data[auxstack->au_id] = auxstack->au_v; 137 } 138 loff = dl_data[AUX_base]; /* XXX assumes ld.so is linked at 0x0 */ 139 140 /* 141 * We need to do 'selfreloc' in case the code weren't 142 * loaded at the address it was linked to. 143 * 144 * Scan the DYNAMIC section for the loader. 145 * Cache the data for easier access. 146 */ 147 dynp = dynamicp; 148 149 _dl_memset(&dynld, 0, sizeof(dynld)); 150 while (dynp->d_tag != DT_NULL) { 151 /* first the tags that are pointers to be relocated */ 152 if (dynp->d_tag == DT_PLTGOT) 153 dynld.dt_pltgot = (void *)(dynp->d_un.d_ptr + loff); 154 else if (dynp->d_tag == DT_SYMTAB) 155 dynld.dt_symtab = (void *)(dynp->d_un.d_ptr + loff); 156 else if (dynp->d_tag == RELOC_TAG) /* DT_{RELA,REL} */ 157 dynld.dt_reloc = (void *)(dynp->d_un.d_ptr + loff); 158 else if (dynp->d_tag == DT_JMPREL) 159 dynld.dt_jmprel = (void *)(dynp->d_un.d_ptr + loff); 160 161 /* Now for the tags that are just sizes or counts */ 162 else if (dynp->d_tag == DT_PLTRELSZ) 163 dynld.dt_pltrelsz = dynp->d_un.d_val; 164 else if (dynp->d_tag == RELOC_TAG+1) /* DT_{RELA,REL}SZ */ 165 dynld.dt_relocsz = dynp->d_un.d_val; 166 #if DT_PROCNUM > 0 167 else if (dynp->d_tag >= DT_LOPROC && 168 dynp->d_tag < DT_LOPROC + DT_PROCNUM) 169 dynld.dt_proc[dynp->d_tag - DT_LOPROC] = 170 dynp->d_un.d_val; 171 #endif /* DT_PROCNUM */ 172 dynp++; 173 } 174 175 rp = dynld.dt_jmprel; 176 for (i = 0; i < dynld.dt_pltrelsz; i += sizeof *rp) { 177 Elf_Addr *ra; 178 const Elf_Sym *sp; 179 180 sp = dynld.dt_symtab + ELF_R_SYM(rp->r_info); 181 if (!ELF_R_SYM(rp->r_info) || sp->st_value != 0) { 182 #ifdef HAVE_JMPREL 183 ra = (Elf_Addr *)(rp->r_offset + loff); 184 RELOC_JMPREL(rp, sp, ra, loff, dynld.dt_pltgot); 185 #else 186 _dl_exit(6); 187 #endif 188 } 189 rp++; 190 } 191 192 rp = dynld.dt_reloc; 193 for (i = 0; i < dynld.dt_relocsz; i += sizeof *rp) { 194 Elf_Addr *ra; 195 const Elf_Sym *sp; 196 197 sp = dynld.dt_symtab + ELF_R_SYM(rp->r_info); 198 if (!ELF_R_SYM(rp->r_info) || sp->st_value != 0) { 199 ra = (Elf_Addr *)(rp->r_offset + loff); 200 RELOC_DYN(rp, sp, ra, loff); 201 } 202 rp++; 203 } 204 205 RELOC_GOT(&dynld, loff); 206 207 /* 208 * we have been fully relocated here, so most things no longer 209 * need the loff adjustment 210 */ 211 212 /* 213 * No further changes to the PLT and/or GOT are needed so make 214 * them read-only. 215 */ 216 217 if (dl_data[AUX_pagesz] != 0) 218 pagesize = dl_data[AUX_pagesz]; 219 else 220 pagesize = 4096; 221 222 /* do any RWX -> RX fixups for executable PLTs and apply GNU_RELRO */ 223 phdp = (Elf_Phdr *)dl_data[AUX_phdr]; 224 for (i = 0; i < dl_data[AUX_phnum]; i++, phdp++) { 225 switch (phdp->p_type) { 226 #if defined(__alpha__) || defined(__hppa__) || defined(__powerpc__) || \ 227 defined(__sparc64__) 228 case PT_LOAD: 229 if ((phdp->p_flags & (PF_X | PF_W)) != (PF_X | PF_W)) 230 break; 231 mprotect((void *)(phdp->p_vaddr + loff), phdp->p_memsz, 232 PROT_READ); 233 break; 234 #endif 235 case PT_GNU_RELRO: 236 mprotect((void *)(phdp->p_vaddr + loff), phdp->p_memsz, 237 PROT_READ); 238 /* 239 * GNU_RELRO (a) covers the GOT, and (b) comes after 240 * all LOAD sections, so if we found it then we're done 241 */ 242 return; 243 } 244 } 245 246 #if defined(__powerpc__) 247 if (dynld.dt_proc[DT_PROC(DT_PPC_GOT)] == 0) 248 prot_exec = PROT_EXEC; 249 #endif 250 251 start = ELF_TRUNC((Elf_Addr)__got_start, pagesize); 252 size = ELF_ROUND((Elf_Addr)__got_end - start, pagesize); 253 mprotect((void *)start, size, GOT_PERMS | prot_exec); 254 } 255 256 #ifdef __alpha__ 257 258 void _reloc_alpha_got(Elf_Dyn *dynp, Elf_Addr relocbase); 259 260 void 261 _reloc_alpha_got(Elf_Dyn *dynp, Elf_Addr relocbase) 262 { 263 const Elf_RelA *rela = 0, *relalim; 264 Elf_Addr relasz = 0; 265 Elf_Addr *where; 266 267 for (; dynp->d_tag != DT_NULL; dynp++) { 268 switch (dynp->d_tag) { 269 case DT_RELA: 270 rela = (const Elf_RelA *)(relocbase + dynp->d_un.d_ptr); 271 break; 272 case DT_RELASZ: 273 relasz = dynp->d_un.d_val; 274 break; 275 } 276 } 277 relalim = (const Elf_RelA *)((caddr_t)rela + relasz); 278 for (; rela < relalim; rela++) { 279 if (ELF64_R_TYPE(rela->r_info) != RELOC_RELATIVE) 280 continue; 281 where = (Elf_Addr *)(relocbase + rela->r_offset); 282 *where += (Elf_Addr)relocbase; 283 } 284 } 285 286 #endif 287 288 #endif /* RCRT0 */ 289