1 /* $NetBSD: mdreloc.c,v 1.13 2019/01/18 11:59:03 skrll Exp $ */ 2 3 /*- 4 * Copyright (c) 2014 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Matt Thomas of 3am Software Foundry. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /*- 33 * Copyright (c) 2014-2015 The FreeBSD Foundation 34 * All rights reserved. 35 * 36 * Portions of this software were developed by Andrew Turner 37 * under sponsorship from the FreeBSD Foundation. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 */ 60 61 #include <sys/cdefs.h> 62 #ifndef lint 63 __RCSID("$NetBSD: mdreloc.c,v 1.13 2019/01/18 11:59:03 skrll Exp $"); 64 #endif /* not lint */ 65 66 #include <sys/types.h> 67 #include <string.h> 68 69 #include "debug.h" 70 #include "rtld.h" 71 72 struct tls_data { 73 size_t td_tlsindex; 74 Elf_Addr td_tlsoffs; 75 }; 76 77 void _rtld_bind_start(void); 78 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr); 79 Elf_Addr _rtld_bind(const Obj_Entry *, Elf_Word); 80 void *_rtld_tlsdesc_static(void *); 81 void *_rtld_tlsdesc_undef(void *); 82 void *_rtld_tlsdesc_dynamic(void *); 83 84 /* 85 * AARCH64 PLT looks like this; 86 * 87 * PLT HEADER <8 instructions> 88 * PLT ENTRY #0 <4 instructions> 89 * PLT ENTRY #1 <4 instructions> 90 * . 91 * . 92 * PLT ENTRY #n <4 instructions> 93 * 94 * PLT HEADER 95 * stp x16, x30, [sp, #-16]! 96 * adrp x16, (GOT+16) 97 * ldr x17, [x16, #PLT_GOT+0x10] 98 * add x16, x16, #PLT_GOT+0x10 99 * br x17 100 * nop 101 * nop 102 * nop 103 * 104 * PLT ENTRY #n 105 * adrp x16, PLTGOT + n * 8 106 * ldr x17, [x16, PLTGOT + n * 8] 107 * add x16, x16, :lo12:PLTGOT + n * 8 108 * br x17 109 */ 110 void 111 _rtld_setup_pltgot(const Obj_Entry *obj) 112 { 113 114 obj->pltgot[1] = (Elf_Addr) obj; 115 obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start; 116 } 117 118 static struct tls_data * 119 _rtld_tlsdesc_alloc(size_t tlsindex, Elf_Addr offs) 120 { 121 struct tls_data *tlsdesc; 122 123 tlsdesc = xmalloc(sizeof(*tlsdesc)); 124 tlsdesc->td_tlsindex = tlsindex; 125 tlsdesc->td_tlsoffs = offs; 126 127 return tlsdesc; 128 } 129 130 static void 131 _rtld_tlsdesc_fill(const Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *where, u_int flags) 132 { 133 const Elf_Sym *def; 134 const Obj_Entry *defobj; 135 Elf_Addr offs = 0; 136 unsigned long symnum = ELF_R_SYM(rela->r_info); 137 138 if (symnum != 0) { 139 def = _rtld_find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 140 flags); 141 if (def == NULL) 142 _rtld_die(); 143 if (def == &_rtld_sym_zero) { 144 /* Weak undefined thread variable */ 145 where[0] = (Elf_Addr)_rtld_tlsdesc_undef; 146 where[1] = rela->r_addend; 147 148 rdbg(("TLSDESC %s (weak) in %s --> %p", 149 obj->strtab + obj->symtab[symnum].st_name, 150 obj->path, (void *)where[1])); 151 152 return; 153 } 154 offs = def->st_value; 155 } else { 156 defobj = obj; 157 } 158 offs += rela->r_addend; 159 160 if (defobj->tls_done) { 161 /* Variable is in initialy allocated TLS segment */ 162 where[0] = (Elf_Addr)_rtld_tlsdesc_static; 163 where[1] = defobj->tlsoffset + offs + 164 sizeof(struct tls_tcb); 165 166 rdbg(("TLSDESC %s --> %p static", 167 obj->path, (void *)where[1])); 168 } else { 169 /* TLS offset is unknown at load time, use dynamic resolving */ 170 where[0] = (Elf_Addr)_rtld_tlsdesc_dynamic; 171 where[1] = (Elf_Addr)_rtld_tlsdesc_alloc(defobj->tlsindex, offs); 172 173 rdbg(("TLSDESC %s in %s --> %p dynamic (%zu, %p)", 174 obj->strtab + obj->symtab[symnum].st_name, 175 obj->path, (void *)where[1], defobj->tlsindex, (void *)offs)); 176 } 177 } 178 179 void 180 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 181 { 182 const Elf_Rela *rela = 0, *relalim; 183 Elf_Addr relasz = 0; 184 Elf_Addr *where; 185 186 for (; dynp->d_tag != DT_NULL; dynp++) { 187 switch (dynp->d_tag) { 188 case DT_RELA: 189 rela = (const Elf_Rela *)(relocbase + dynp->d_un.d_ptr); 190 break; 191 case DT_RELASZ: 192 relasz = dynp->d_un.d_val; 193 break; 194 } 195 } 196 relalim = (const Elf_Rela *)((const uint8_t *)rela + relasz); 197 for (; rela < relalim; rela++) { 198 where = (Elf_Addr *)(relocbase + rela->r_offset); 199 *where += (Elf_Addr)relocbase; 200 } 201 } 202 203 int 204 _rtld_relocate_nonplt_objects(Obj_Entry *obj) 205 { 206 const Elf_Sym *def = NULL; 207 const Obj_Entry *defobj = NULL; 208 unsigned long last_symnum = ULONG_MAX; 209 210 for (const Elf_Rela *rela = obj->rela; rela < obj->relalim; rela++) { 211 Elf_Addr *where; 212 Elf_Addr tmp; 213 unsigned long symnum = ULONG_MAX; 214 215 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 216 217 switch (ELF_R_TYPE(rela->r_info)) { 218 case R_TYPE(ABS64): /* word S + A */ 219 case R_TYPE(GLOB_DAT): /* word S + A */ 220 case R_TLS_TYPE(TLS_DTPREL): 221 case R_TLS_TYPE(TLS_DTPMOD): 222 case R_TLS_TYPE(TLS_TPREL): 223 symnum = ELF_R_SYM(rela->r_info); 224 if (last_symnum != symnum) { 225 last_symnum = symnum; 226 def = _rtld_find_symdef(symnum, obj, &defobj, 227 false); 228 if (def == NULL) 229 return -1; 230 } 231 232 default: 233 break; 234 } 235 236 switch (ELF_R_TYPE(rela->r_info)) { 237 case R_TYPE(NONE): 238 break; 239 240 case R_TYPE(ABS64): /* word S + A */ 241 case R_TYPE(GLOB_DAT): /* word S + A */ 242 tmp = (Elf_Addr)defobj->relocbase + def->st_value + 243 rela->r_addend; 244 if (*where != tmp) 245 *where = tmp; 246 rdbg(("ABS64/GLOB_DAT %s in %s --> %p @ %p in %s", 247 obj->strtab + obj->symtab[symnum].st_name, 248 obj->path, (void *)tmp, where, defobj->path)); 249 break; 250 251 case R_TYPE(RELATIVE): /* word B + A */ 252 *where = (Elf_Addr)(obj->relocbase + rela->r_addend); 253 rdbg(("RELATIVE in %s --> %p", obj->path, 254 (void *)*where)); 255 break; 256 257 case R_TYPE(COPY): 258 /* 259 * These are deferred until all other relocations have 260 * been done. All we do here is make sure that the 261 * COPY relocation is not in a shared library. They 262 * are allowed only in executable files. 263 */ 264 if (obj->isdynamic) { 265 _rtld_error( 266 "%s: Unexpected R_COPY relocation in shared library", 267 obj->path); 268 return -1; 269 } 270 rdbg(("COPY (avoid in main)")); 271 break; 272 273 case R_TYPE(TLSDESC): 274 _rtld_tlsdesc_fill(obj, rela, where, 0); 275 break; 276 277 case R_TLS_TYPE(TLS_DTPREL): 278 *where = (Elf_Addr)(def->st_value + rela->r_addend); 279 280 rdbg(("TLS_DTPREL %s in %s --> %p", 281 obj->strtab + obj->symtab[symnum].st_name, 282 obj->path, (void *)*where)); 283 284 break; 285 case R_TLS_TYPE(TLS_DTPMOD): 286 *where = (Elf_Addr)(defobj->tlsindex); 287 288 rdbg(("TLS_DTPMOD %s in %s --> %p", 289 obj->strtab + obj->symtab[symnum].st_name, 290 obj->path, (void *)*where)); 291 292 break; 293 294 case R_TLS_TYPE(TLS_TPREL): 295 if (!defobj->tls_done && 296 _rtld_tls_offset_allocate(obj)) 297 return -1; 298 299 *where = (Elf_Addr)def->st_value + defobj->tlsoffset + 300 sizeof(struct tls_tcb); 301 rdbg(("TLS_TPREL %s in %s --> %p in %s", 302 obj->strtab + obj->symtab[symnum].st_name, 303 obj->path, (void *)*where, defobj->path)); 304 break; 305 306 default: 307 rdbg(("sym = %lu, type = %lu, offset = %p, " 308 "addend = %p, contents = %p", 309 (u_long)ELF_R_SYM(rela->r_info), 310 (u_long)ELF_R_TYPE(rela->r_info), 311 (void *)rela->r_offset, (void *)rela->r_addend, 312 (void *)*where)); 313 _rtld_error("%s: Unsupported relocation type %ld " 314 "in non-PLT relocations", 315 obj->path, (u_long) ELF_R_TYPE(rela->r_info)); 316 return -1; 317 } 318 } 319 return 0; 320 } 321 322 int 323 _rtld_relocate_plt_lazy(Obj_Entry *obj) 324 { 325 326 if (!obj->relocbase) 327 return 0; 328 329 for (const Elf_Rela *rela = obj->pltrela; rela < obj->pltrelalim; rela++) { 330 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 331 332 assert((ELF_R_TYPE(rela->r_info) == R_TYPE(JUMP_SLOT)) || 333 (ELF_R_TYPE(rela->r_info) == R_TYPE(TLSDESC))); 334 335 switch (ELF_R_TYPE(rela->r_info)) { 336 case R_TYPE(JUMP_SLOT): 337 /* Just relocate the GOT slots pointing into the PLT */ 338 *where += (Elf_Addr)obj->relocbase; 339 rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where)); 340 break; 341 case R_TYPE(TLSDESC): 342 _rtld_tlsdesc_fill(obj, rela, where, SYMLOOK_IN_PLT); 343 break; 344 } 345 } 346 347 return 0; 348 } 349 350 void 351 _rtld_call_ifunc(Obj_Entry *obj, sigset_t *mask, u_int cur_objgen) 352 { 353 const Elf_Rela *rela; 354 Elf_Addr *where, target; 355 356 while (obj->ifunc_remaining > 0 && _rtld_objgen == cur_objgen) { 357 rela = obj->pltrelalim - obj->ifunc_remaining; 358 --obj->ifunc_remaining; 359 if (ELF_R_TYPE(rela->r_info) == R_TYPE(IRELATIVE)) { 360 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 361 target = (Elf_Addr)(obj->relocbase + rela->r_addend); 362 _rtld_exclusive_exit(mask); 363 target = _rtld_resolve_ifunc2(obj, target); 364 _rtld_exclusive_enter(mask); 365 if (*where != target) 366 *where = target; 367 } 368 } 369 } 370 371 static int 372 _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, 373 Elf_Addr *tp) 374 { 375 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 376 Elf_Addr new_value; 377 const Elf_Sym *def; 378 const Obj_Entry *defobj; 379 380 switch (ELF_R_TYPE(rela->r_info)) { 381 case R_TYPE(JUMP_SLOT): 382 def = _rtld_find_plt_symdef(ELF_R_SYM(rela->r_info), obj, 383 &defobj, tp != NULL); 384 if (__predict_false(def == NULL)) 385 return -1; 386 if (__predict_false(def == &_rtld_sym_zero)) 387 return 0; 388 389 if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 390 if (tp == NULL) 391 return 0; 392 new_value = _rtld_resolve_ifunc(defobj, def); 393 } else { 394 new_value = (Elf_Addr)(defobj->relocbase + 395 def->st_value); 396 } 397 rdbg(("bind now/fixup in %s --> old=%p new=%p", 398 defobj->strtab + def->st_name, (void *)*where, 399 (void *)new_value)); 400 if (*where != new_value) 401 *where = new_value; 402 if (tp) 403 *tp = new_value; 404 break; 405 case R_TYPE(TLSDESC): 406 _rtld_tlsdesc_fill(obj, rela, where, SYMLOOK_IN_PLT); 407 break; 408 } 409 410 return 0; 411 } 412 413 Elf_Addr 414 _rtld_bind(const Obj_Entry *obj, Elf_Word relaidx) 415 { 416 const Elf_Rela *rela = obj->pltrela + relaidx; 417 Elf_Addr new_value = 0; 418 419 _rtld_shared_enter(); 420 int err = _rtld_relocate_plt_object(obj, rela, &new_value); 421 if (err) 422 _rtld_die(); 423 _rtld_shared_exit(); 424 425 return new_value; 426 } 427 int 428 _rtld_relocate_plt_objects(const Obj_Entry *obj) 429 { 430 const Elf_Rela *rela; 431 int err = 0; 432 433 for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) { 434 err = _rtld_relocate_plt_object(obj, rela, NULL); 435 if (err) 436 break; 437 } 438 439 return err; 440 } 441