1 /* $OpenBSD: rtld_machine.c,v 1.59 2016/06/21 15:25:36 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 1999 Dale Rahn 5 * Copyright (c) 2001 Niklas Hallqvist 6 * Copyright (c) 2001 Artur Grabowski 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 */ 30 31 #define _DYN_LOADER 32 33 #include <sys/types.h> 34 #include <sys/mman.h> 35 #include <sys/exec.h> 36 #include <sys/syscall.h> 37 #include <sys/unistd.h> 38 #include <machine/pal.h> 39 40 #include <nlist.h> 41 #include <link.h> 42 43 #include "syscall.h" 44 #include "archdep.h" 45 #include "resolve.h" 46 47 #define DT_PROC(n) ((n) - DT_LOPROC + DT_NUM) 48 49 int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden; 50 51 int 52 _dl_md_reloc(elf_object_t *object, int rel, int relasz) 53 { 54 long i; 55 long numrela; 56 long relrel; 57 int fails = 0; 58 Elf64_Addr loff; 59 Elf64_Addr prev_value = 0; 60 const Elf_Sym *prev_sym = NULL; 61 Elf64_Rela *relas; 62 struct load_list *llist; 63 64 loff = object->obj_base; 65 numrela = object->Dyn.info[relasz] / sizeof(Elf64_Rela); 66 relrel = rel == DT_RELA ? object->relacount : 0; 67 relas = (Elf64_Rela *)(object->Dyn.info[rel]); 68 69 if (relas == NULL) 70 return(0); 71 72 if (relrel > numrela) { 73 _dl_printf("relacount > numrel: %ld > %ld\n", relrel, numrela); 74 _dl_exit(20); 75 } 76 77 /* 78 * unprotect some segments if we need it. 79 * XXX - we unprotect way to much. only the text can have cow 80 * relocations. 81 */ 82 if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) { 83 for (llist = object->load_list; llist != NULL; llist = llist->next) { 84 if (!(llist->prot & PROT_WRITE)) { 85 _dl_mprotect(llist->start, llist->size, 86 PROT_READ | PROT_WRITE); 87 } 88 } 89 } 90 91 /* tight loop for leading RELATIVE relocs */ 92 for (i = 0; i < relrel; i++, relas++) { 93 Elf_Addr *r_addr; 94 95 #ifdef DEBUG 96 if (ELF64_R_TYPE(relas->r_info) != R_TYPE(RELATIVE)) { 97 _dl_printf("RELACOUNT wrong\n"); 98 _dl_exit(20); 99 } 100 #endif 101 102 r_addr = (Elf64_Addr *)(relas->r_offset + loff); 103 104 /* Handle unaligned RELATIVE relocs */ 105 if ((((Elf_Addr)r_addr) & 0x7) != 0) { 106 Elf_Addr tmp; 107 _dl_bcopy(r_addr, &tmp, sizeof(Elf_Addr)); 108 tmp += loff; 109 _dl_bcopy(&tmp, r_addr, sizeof(Elf_Addr)); 110 } else 111 *r_addr += loff; 112 } 113 for (; i < numrela; i++, relas++) { 114 Elf64_Addr *r_addr; 115 Elf64_Addr ooff; 116 const Elf64_Sym *sym, *this; 117 const char *symn; 118 119 r_addr = (Elf64_Addr *)(relas->r_offset + loff); 120 121 if (ELF64_R_SYM(relas->r_info) == 0xffffffff) 122 continue; 123 124 125 sym = object->dyn.symtab; 126 sym += ELF64_R_SYM(relas->r_info); 127 symn = object->dyn.strtab + sym->st_name; 128 129 this = NULL; 130 switch (ELF64_R_TYPE(relas->r_info)) { 131 case R_TYPE(REFQUAD): 132 ooff = _dl_find_symbol_bysym(object, 133 ELF64_R_SYM(relas->r_info), &this, 134 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT, 135 sym, NULL); 136 if (this == NULL) 137 goto resolve_failed; 138 *r_addr += ooff + this->st_value + relas->r_addend; 139 break; 140 case R_TYPE(RELATIVE): 141 /* 142 * There is a lot of unaligned RELATIVE 143 * relocs generated by gcc in the exception handlers. 144 */ 145 if ((((Elf_Addr) r_addr) & 0x7) != 0) { 146 Elf_Addr tmp; 147 #if 0 148 _dl_printf("unaligned RELATIVE: %p type: %d %s 0x%lx -> 0x%lx\n", r_addr, 149 ELF_R_TYPE(relas->r_info), object->load_name, *r_addr, *r_addr+loff); 150 #endif 151 _dl_bcopy(r_addr, &tmp, sizeof(Elf_Addr)); 152 tmp += loff; 153 _dl_bcopy(&tmp, r_addr, sizeof(Elf_Addr)); 154 } else 155 *r_addr += loff; 156 break; 157 case R_TYPE(JMP_SLOT): 158 ooff = _dl_find_symbol(symn, &this, 159 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, 160 sym, object, NULL); 161 if (this == NULL) 162 goto resolve_failed; 163 *r_addr = ooff + this->st_value + relas->r_addend; 164 break; 165 case R_TYPE(GLOB_DAT): 166 if (sym == prev_sym) { 167 *r_addr = prev_value + relas->r_addend; 168 break; 169 } 170 ooff = _dl_find_symbol_bysym(object, 171 ELF64_R_SYM(relas->r_info), &this, 172 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT, 173 sym, NULL); 174 if (this == NULL) 175 goto resolve_failed; 176 prev_sym = sym; 177 prev_value = ooff + this->st_value; 178 *r_addr = prev_value + relas->r_addend; 179 break; 180 case R_TYPE(NONE): 181 break; 182 default: 183 _dl_printf("%s:" 184 " %s: unsupported relocation '%s' %d at %lx\n", 185 __progname, object->load_name, symn, 186 ELF64_R_TYPE(relas->r_info), r_addr ); 187 _dl_exit(1); 188 } 189 continue; 190 resolve_failed: 191 if (ELF_ST_BIND(sym->st_info) != STB_WEAK) 192 fails++; 193 } 194 __asm volatile("imb" : : : "memory"); 195 196 /* reprotect the unprotected segments */ 197 if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) { 198 for (llist = object->load_list; llist != NULL; llist = llist->next) { 199 if (!(llist->prot & PROT_WRITE)) 200 _dl_mprotect(llist->start, llist->size, 201 llist->prot); 202 } 203 } 204 return (fails); 205 } 206 207 /* 208 * Resolve a symbol at run-time. 209 */ 210 Elf_Addr 211 _dl_bind(elf_object_t *object, int reloff) 212 { 213 Elf_RelA *rela; 214 Elf_Addr ooff; 215 const Elf_Sym *sym, *this; 216 const char *symn; 217 const elf_object_t *sobj; 218 uint64_t cookie = pcookie; 219 struct { 220 struct __kbind param; 221 Elf_Addr newval; 222 } buf; 223 224 rela = (Elf_RelA *)(object->Dyn.info[DT_JMPREL] + reloff); 225 226 sym = object->dyn.symtab; 227 sym += ELF64_R_SYM(rela->r_info); 228 symn = object->dyn.strtab + sym->st_name; 229 230 this = NULL; 231 ooff = _dl_find_symbol(symn, &this, 232 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, sym, object, &sobj); 233 if (this == NULL) { 234 _dl_printf("lazy binding failed!\n"); 235 *(volatile int *)0 = 0; /* XXX */ 236 } 237 238 buf.newval = ooff + this->st_value + rela->r_addend; 239 240 if (__predict_false(sobj->traced) && _dl_trace_plt(sobj, symn)) 241 return (buf.newval); 242 243 buf.param.kb_addr = (Elf_Addr *)(object->obj_base + rela->r_offset); 244 buf.param.kb_size = sizeof(Elf_Addr); 245 246 /* directly code the syscall, so that it's actually inline here */ 247 { 248 register long syscall_num __asm("$0") /* v0 */ = SYS_kbind; 249 register void *arg1 __asm("$16") /* a0 */ = &buf; 250 register long arg2 __asm("$17") /* a1 */ = sizeof(buf); 251 register long arg3 __asm("$18") /* a2 */ = cookie; 252 253 __asm volatile( "call_pal %1" : "+r" (syscall_num) 254 : "i" (PAL_OSF1_callsys), "r" (arg1), "r" (arg2), 255 "r" (arg3) : "$19", "$20", "memory"); 256 } 257 258 return (buf.newval); 259 } 260 261 /* 262 * Relocate the Global Offset Table (GOT). 263 */ 264 int 265 _dl_md_reloc_got(elf_object_t *object, int lazy) 266 { 267 int fails = 0; 268 Elf_Addr *pltgot; 269 extern void _dl_bind_start(void); /* XXX */ 270 extern void _dl_bind_secureplt(void); /* XXX */ 271 Elf_Addr seg_start; 272 u_long pltro; 273 274 if (object->Dyn.info[DT_PLTREL] != DT_RELA) 275 return (0); 276 277 pltro = object->Dyn.info[DT_PROC(DT_ALPHA_PLTRO)]; 278 pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT]; 279 280 if (object->traced) 281 lazy = 1; 282 283 if (object->obj_type == OBJTYPE_LDR || !lazy || pltgot == NULL) { 284 fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); 285 } else { 286 if (object->obj_base != 0) { 287 int i, size; 288 Elf_Addr *addr; 289 Elf_RelA *rela; 290 291 size = object->Dyn.info[DT_PLTRELSZ] / 292 sizeof(Elf_RelA); 293 rela = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]); 294 295 for (i = 0; i < size; i++) { 296 addr = (Elf_Addr *)(object->obj_base + 297 rela[i].r_offset); 298 *addr += object->obj_base; 299 } 300 } 301 if (pltro == 0) { 302 pltgot[2] = (Elf_Addr)_dl_bind_start; 303 pltgot[3] = (Elf_Addr)object; 304 } else { 305 pltgot[0] = (Elf_Addr)_dl_bind_secureplt; 306 pltgot[1] = (Elf_Addr)object; 307 } 308 } 309 310 /* mprotect the GOT */ 311 seg_start = 0; 312 if (pltro != 0) 313 seg_start = (Elf_Addr)pltgot; 314 _dl_protect_segment(object, seg_start, "__got_start", "__got_end", 315 PROT_READ); 316 317 /* mprotect the PLT, if it isn't already read-only */ 318 if (pltro == 0) 319 _dl_protect_segment(object, (Elf_Addr)pltgot, "__plt_start", 320 "__plt_end", PROT_READ|PROT_EXEC); 321 322 return (fails); 323 } 324 325 /* relocate the GOT early */ 326 327 void _reloc_alpha_got(Elf_Dyn *dynp, Elf_Addr relocbase); 328 329 void 330 _reloc_alpha_got(Elf_Dyn *dynp, Elf_Addr relocbase) 331 { 332 const Elf_RelA *rela = NULL, *relalim; 333 Elf_Addr relasz = 0; 334 Elf_Addr *where; 335 336 for (; dynp->d_tag != DT_NULL; dynp++) { 337 switch (dynp->d_tag) { 338 case DT_RELA: 339 rela = (const Elf_RelA *)(relocbase + dynp->d_un.d_ptr); 340 break; 341 case DT_RELASZ: 342 relasz = dynp->d_un.d_val; 343 break; 344 } 345 } 346 relalim = (const Elf_RelA *)((caddr_t)rela + relasz); 347 for (; rela < relalim; rela++) { 348 if (ELF64_R_TYPE(rela->r_info) != RELOC_RELATIVE) 349 continue; 350 where = (Elf_Addr *)(relocbase + rela->r_offset); 351 *where += (Elf_Addr)relocbase; 352 } 353 } 354