rtld_machine.c revision 1.3
1/* $OpenBSD: rtld_machine.c,v 1.3 2017/01/24 07:48:37 guenther Exp $ */ 2 3/* 4 * Copyright (c) 2004 Dale Rahn 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#define _DYN_LOADER 30 31#include <sys/types.h> 32#include <sys/mman.h> 33#include <sys/syscall.h> 34#include <sys/unistd.h> 35 36#include <nlist.h> 37#include <link.h> 38 39#include "syscall.h" 40#include "archdep.h" 41#include "resolve.h" 42 43int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden; 44 45void _dl_bind_start(void); /* XXX */ 46Elf_Addr _dl_bind(elf_object_t *object, int index); 47#define _RF_S 0x80000000 /* Resolve symbol */ 48#define _RF_A 0x40000000 /* Use addend */ 49#define _RF_P 0x20000000 /* Location relative */ 50#define _RF_G 0x10000000 /* GOT offset */ 51#define _RF_B 0x08000000 /* Load address relative */ 52#define _RF_U 0x04000000 /* Unaligned */ 53#define _RF_V 0x02000000 /* ERROR */ 54#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */ 55#define _RF_RS(s) ((s) & 0xff) /* right shift */ 56static int reloc_target_flags[] = { 57 0, /* 0 NONE */ 58 [ R_AARCH64_ABS64 ] = 59 _RF_V|_RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* ABS64 */ 60 [ R_AARCH64_GLOB_DAT ] = 61 _RF_V|_RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* GLOB_DAT */ 62 [ R_AARCH64_JUMP_SLOT ] = 63 _RF_V|_RF_S| _RF_SZ(64) | _RF_RS(0), /* JUMP_SLOT */ 64 [ R_AARCH64_RELATIVE ] = 65 _RF_V|_RF_B|_RF_A| _RF_SZ(64) | _RF_RS(0), /* REL64 */ 66 [ R_AARCH64_TLSDESC ] = 67 _RF_V|_RF_S, 68 [ R_AARCH64_TLS_TPREL64 ] = 69 _RF_V|_RF_S, 70 [ R_AARCH64_COPY ] = 71 _RF_V|_RF_S| _RF_SZ(32) | _RF_RS(0), /* 20 COPY */ 72 73}; 74 75#define RELOC_RESOLVE_SYMBOL(t) ((reloc_target_flags[t] & _RF_S) != 0) 76#define RELOC_PC_RELATIVE(t) ((reloc_target_flags[t] & _RF_P) != 0) 77#define RELOC_BASE_RELATIVE(t) ((reloc_target_flags[t] & _RF_B) != 0) 78#define RELOC_UNALIGNED(t) ((reloc_target_flags[t] & _RF_U) != 0) 79#define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0) 80#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff) 81#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff) 82static Elf_Addr reloc_target_bitmask[] = { 83#define _BM(x) (~(Elf_Addr)0 >> ((8*sizeof(reloc_target_bitmask[0])) - (x))) 84 0, /* 0 NONE */ 85 [ R_AARCH64_ABS64 ] = _BM(64), 86 [ R_AARCH64_GLOB_DAT ] = _BM(64), 87 [ R_AARCH64_JUMP_SLOT ] = _BM(64), 88 [ R_AARCH64_RELATIVE ] = _BM(64), 89 [ R_AARCH64_TLSDESC ] = _BM(64), 90 [ R_AARCH64_TLS_TPREL64 ] = _BM(64), 91 [ R_AARCH64_COPY ] = _BM(64), 92#undef _BM 93}; 94#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t]) 95 96#define R_TYPE(x) R_AARCH64_ ## x 97 98void _dl_reloc_plt(Elf_Word *where, Elf_Addr value, Elf_RelA *rel); 99 100#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) 101 102int 103_dl_md_reloc(elf_object_t *object, int rel, int relsz) 104{ 105 long i; 106 long numrel; 107 long relrel; 108 int fails = 0; 109 Elf_Addr loff; 110 Elf_Addr prev_value = 0; 111 const Elf_Sym *prev_sym = NULL; 112 Elf_RelA *rels; 113 struct load_list *llist; 114 115 loff = object->obj_base; 116 numrel = object->Dyn.info[relsz] / sizeof(Elf_RelA); 117 relrel = rel == DT_RELA ? object->relcount : 0; 118 rels = (Elf_RelA *)(object->Dyn.info[rel]); 119 120 if (rels == NULL) 121 return(0); 122 123 if (relrel > numrel) 124 _dl_die("relcount > numrel: %ld > %ld", relrel, numrel); 125 126 /* 127 * unprotect some segments if we need it. 128 */ 129 if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) { 130 for (llist = object->load_list; 131 llist != NULL; 132 llist = llist->next) { 133 if (!(llist->prot & PROT_WRITE)) 134 _dl_mprotect(llist->start, llist->size, 135 llist->prot|PROT_WRITE); 136 } 137 } 138 139 /* tight loop for leading RELATIVE relocs */ 140 for (i = 0; i < relrel; i++, rels++) { 141 Elf_Addr *where; 142 143#ifdef DEBUG 144 if (ELF_R_TYPE(rels->r_info) != R_TYPE(RELATIVE)) 145 _dl_die("RELCOUNT wrong"); 146#endif 147 where = (Elf_Addr *)(rels->r_offset + loff); 148 *where += loff; 149 } 150 for (; i < numrel; i++, rels++) { 151 Elf_Addr *where, value, ooff, mask; 152 Elf_Word type; 153 const Elf_Sym *sym, *this; 154 const char *symn; 155 156 type = ELF_R_TYPE(rels->r_info); 157 158 if (type >= nitems(reloc_target_flags) || 159 (reloc_target_flags[type] & _RF_V) == 0) 160 _dl_die("bad relocation %ld %d", i, type); 161 162 if (type == R_TYPE(NONE)) 163 continue; 164 165 if (type == R_TYPE(JUMP_SLOT) && rel != DT_JMPREL) 166 continue; 167 168 where = (Elf_Addr *)(rels->r_offset + loff); 169 170 if (RELOC_USE_ADDEND(type)) 171 value = rels->r_addend; 172 else 173 value = 0; 174 175 sym = NULL; 176 symn = NULL; 177 if (RELOC_RESOLVE_SYMBOL(type)) { 178 sym = object->dyn.symtab; 179 sym += ELF_R_SYM(rels->r_info); 180 symn = object->dyn.strtab + sym->st_name; 181 182 if (sym->st_shndx != SHN_UNDEF && 183 ELF_ST_BIND(sym->st_info) == STB_LOCAL) { 184 value += loff; 185 } else if (sym == prev_sym) { 186 value += prev_value; 187 } else { 188 this = NULL; 189 ooff = _dl_find_symbol_bysym(object, 190 ELF_R_SYM(rels->r_info), &this, 191 SYM_SEARCH_ALL|SYM_WARNNOTFOUND| 192 ((type == R_TYPE(JUMP_SLOT)) ? 193 SYM_PLT : SYM_NOTPLT), 194 sym, NULL); 195 if (this == NULL) { 196resolve_failed: 197 if (ELF_ST_BIND(sym->st_info) != 198 STB_WEAK) 199 fails++; 200 continue; 201 } 202 prev_sym = sym; 203 prev_value = (Elf_Addr)(ooff + this->st_value); 204 value += prev_value; 205 } 206 } 207 208 if (type == R_TYPE(JUMP_SLOT)) { 209 /* 210 _dl_reloc_plt((Elf_Word *)where, value, rels); 211 */ 212 *where = value; 213 continue; 214 } 215 216 if (type == R_TYPE(COPY)) { 217 void *dstaddr = where; 218 const void *srcaddr; 219 const Elf_Sym *dstsym = sym, *srcsym = NULL; 220 Elf_Addr soff; 221 222 soff = _dl_find_symbol(symn, &srcsym, 223 SYM_SEARCH_OTHER|SYM_WARNNOTFOUND|SYM_NOTPLT, 224 dstsym, object, NULL); 225 if (srcsym == NULL) 226 goto resolve_failed; 227 228 srcaddr = (void *)(soff + srcsym->st_value); 229 _dl_bcopy(srcaddr, dstaddr, dstsym->st_size); 230 continue; 231 } 232 233 if (RELOC_PC_RELATIVE(type)) 234 value -= (Elf_Addr)where; 235 if (RELOC_BASE_RELATIVE(type)) 236 value += loff; 237 238 mask = RELOC_VALUE_BITMASK(type); 239 value >>= RELOC_VALUE_RIGHTSHIFT(type); 240 value &= mask; 241 242 if (RELOC_UNALIGNED(type)) { 243 /* Handle unaligned relocations. */ 244 Elf_Addr tmp = 0; 245 char *ptr = (char *)where; 246 int i, size = RELOC_TARGET_SIZE(type)/8; 247 248 /* Read it in one byte at a time. */ 249 for (i=0; i<size; i++) 250 tmp = (tmp << 8) | ptr[i]; 251 252 tmp &= ~mask; 253 tmp |= value; 254 255 /* Write it back out. */ 256 for (i=0; i<size; i++) 257 ptr[i] = ((tmp >> (8*i)) & 0xff); 258 } else { 259 *where &= ~mask; 260 *where |= value; 261 } 262 } 263 264 /* reprotect the unprotected segments */ 265 if ((object->dyn.textrel == 1) && (rel == DT_REL || rel == DT_RELA)) { 266 for (llist = object->load_list; 267 llist != NULL; 268 llist = llist->next) { 269 if (!(llist->prot & PROT_WRITE)) 270 _dl_mprotect(llist->start, llist->size, 271 llist->prot); 272 } 273 } 274 275 return (fails); 276} 277 278/* 279 * Relocate the Global Offset Table (GOT). 280 * This is done by calling _dl_md_reloc on DT_JMPREL for DL_BIND_NOW, 281 * otherwise the lazy binding plt initialization is performed. 282 */ 283int 284_dl_md_reloc_got(elf_object_t *object, int lazy) 285{ 286 int fails = 0; 287 Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT]; 288 int i, num; 289 Elf_RelA *rel; 290 291 if (object->Dyn.info[DT_PLTREL] != DT_RELA) 292 return (0); 293 294 if (object->traced) 295 lazy = 1; 296 297 lazy = 0; // until support is written. 298 299 if (!lazy) { 300 fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); 301 } else { 302 rel = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]); 303 num = (object->Dyn.info[DT_PLTRELSZ]); 304 305 for (i = 0; i < num/sizeof(Elf_RelA); i++, rel++) { 306 Elf_Addr *where; 307 where = (Elf_Addr *)(rel->r_offset + object->obj_base); 308 *where += object->obj_base; 309 } 310 311 pltgot[1] = (Elf_Addr)object; 312 pltgot[2] = (Elf_Addr)_dl_bind_start; 313 } 314 315 /* mprotect the GOT */ 316 _dl_protect_segment(object, 0, "__got_start", "__got_end", PROT_READ); 317 318 return (fails); 319} 320 321Elf_Addr 322_dl_bind(elf_object_t *object, int relidx) 323{ 324 Elf_RelA *rel; 325 const Elf_Sym *sym, *this; 326 const char *symn; 327 const elf_object_t *sobj; 328 Elf_Addr ooff; 329 int64_t cookie = pcookie; 330 struct { 331 struct __kbind param; 332 Elf_Addr newval; 333 } buf; 334 335 rel = ((Elf_RelA *)object->Dyn.info[DT_JMPREL]) + (relidx); 336 337 sym = object->dyn.symtab; 338 sym += ELF_R_SYM(rel->r_info); 339 symn = object->dyn.strtab + sym->st_name; 340 341 this = NULL; 342 ooff = _dl_find_symbol(symn, &this, 343 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, sym, object, &sobj); 344 if (this == NULL) 345 _dl_die("lazy binding failed!"); 346 347 buf.newval = ooff + this->st_value; 348 349 if (sobj->traced && _dl_trace_plt(sobj, symn)) 350 return buf.newval; 351 352 buf.param.kb_addr = (Elf_Word *)(object->obj_base + rel->r_offset); 353 buf.param.kb_size = sizeof(Elf_Addr); 354 355 /* directly code the syscall, so that it's actually inline here */ 356 { 357 register long syscall_num __asm("x8") = SYS_kbind; 358 register void *arg1 __asm("x0") = &buf; 359 register long arg2 __asm("x1") = sizeof(buf); 360 register long arg3 __asm("x2") = cookie; 361 362 __asm volatile("svc 0" : "+r" (arg1), "+r" (arg2) 363 : "r" (syscall_num), "r" (arg3) 364 : "cc", "memory"); 365 } 366 367 return buf.newval; 368} 369