1 /* $NetBSD: mdreloc.c,v 1.14 2020/06/16 21:01:30 joerg 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.14 2020/06/16 21:01:30 joerg 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 rela->r_addend + sizeof(struct tls_tcb)); 301 302 rdbg(("TLS_TPREL %s in %s --> %p in %s", 303 obj->strtab + obj->symtab[symnum].st_name, 304 obj->path, (void *)*where, defobj->path)); 305 break; 306 307 default: 308 rdbg(("sym = %lu, type = %lu, offset = %p, " 309 "addend = %p, contents = %p", 310 (u_long)ELF_R_SYM(rela->r_info), 311 (u_long)ELF_R_TYPE(rela->r_info), 312 (void *)rela->r_offset, (void *)rela->r_addend, 313 (void *)*where)); 314 _rtld_error("%s: Unsupported relocation type %ld " 315 "in non-PLT relocations", 316 obj->path, (u_long) ELF_R_TYPE(rela->r_info)); 317 return -1; 318 } 319 } 320 return 0; 321 } 322 323 int 324 _rtld_relocate_plt_lazy(Obj_Entry *obj) 325 { 326 327 if (!obj->relocbase) 328 return 0; 329 330 for (const Elf_Rela *rela = obj->pltrela; rela < obj->pltrelalim; rela++) { 331 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 332 333 assert((ELF_R_TYPE(rela->r_info) == R_TYPE(JUMP_SLOT)) || 334 (ELF_R_TYPE(rela->r_info) == R_TYPE(TLSDESC))); 335 336 switch (ELF_R_TYPE(rela->r_info)) { 337 case R_TYPE(JUMP_SLOT): 338 /* Just relocate the GOT slots pointing into the PLT */ 339 *where += (Elf_Addr)obj->relocbase; 340 rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where)); 341 break; 342 case R_TYPE(TLSDESC): 343 _rtld_tlsdesc_fill(obj, rela, where, SYMLOOK_IN_PLT); 344 break; 345 } 346 } 347 348 return 0; 349 } 350 351 void 352 _rtld_call_ifunc(Obj_Entry *obj, sigset_t *mask, u_int cur_objgen) 353 { 354 const Elf_Rela *rela; 355 Elf_Addr *where, target; 356 357 while (obj->ifunc_remaining > 0 && _rtld_objgen == cur_objgen) { 358 rela = obj->pltrelalim - obj->ifunc_remaining; 359 --obj->ifunc_remaining; 360 if (ELF_R_TYPE(rela->r_info) == R_TYPE(IRELATIVE)) { 361 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 362 target = (Elf_Addr)(obj->relocbase + rela->r_addend); 363 _rtld_exclusive_exit(mask); 364 target = _rtld_resolve_ifunc2(obj, target); 365 _rtld_exclusive_enter(mask); 366 if (*where != target) 367 *where = target; 368 } 369 } 370 } 371 372 static int 373 _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, 374 Elf_Addr *tp) 375 { 376 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 377 Elf_Addr new_value; 378 const Elf_Sym *def; 379 const Obj_Entry *defobj; 380 381 switch (ELF_R_TYPE(rela->r_info)) { 382 case R_TYPE(JUMP_SLOT): 383 def = _rtld_find_plt_symdef(ELF_R_SYM(rela->r_info), obj, 384 &defobj, tp != NULL); 385 if (__predict_false(def == NULL)) 386 return -1; 387 if (__predict_false(def == &_rtld_sym_zero)) 388 return 0; 389 390 if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 391 if (tp == NULL) 392 return 0; 393 new_value = _rtld_resolve_ifunc(defobj, def); 394 } else { 395 new_value = (Elf_Addr)(defobj->relocbase + 396 def->st_value); 397 } 398 rdbg(("bind now/fixup in %s --> old=%p new=%p", 399 defobj->strtab + def->st_name, (void *)*where, 400 (void *)new_value)); 401 if (*where != new_value) 402 *where = new_value; 403 if (tp) 404 *tp = new_value; 405 break; 406 case R_TYPE(TLSDESC): 407 _rtld_tlsdesc_fill(obj, rela, where, SYMLOOK_IN_PLT); 408 break; 409 } 410 411 return 0; 412 } 413 414 Elf_Addr 415 _rtld_bind(const Obj_Entry *obj, Elf_Word relaidx) 416 { 417 const Elf_Rela *rela = obj->pltrela + relaidx; 418 Elf_Addr new_value = 0; 419 420 _rtld_shared_enter(); 421 int err = _rtld_relocate_plt_object(obj, rela, &new_value); 422 if (err) 423 _rtld_die(); 424 _rtld_shared_exit(); 425 426 return new_value; 427 } 428 int 429 _rtld_relocate_plt_objects(const Obj_Entry *obj) 430 { 431 const Elf_Rela *rela; 432 int err = 0; 433 434 for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) { 435 err = _rtld_relocate_plt_object(obj, rela, NULL); 436 if (err) 437 break; 438 } 439 440 return err; 441 } 442