1 /* $NetBSD: mdreloc.c,v 1.18 2023/06/04 01:24:56 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.18 2023/06/04 01:24:56 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_static) { 161 /* Variable is in initially 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(IRELATIVE): 252 /* IFUNC relocations are handled in _rtld_call_ifunc */ 253 if (obj->ifunc_remaining_nonplt == 0) 254 obj->ifunc_remaining_nonplt = obj->relalim - rela; 255 rdbg(("IRELATIVE in %s, %zx", obj->path, 256 obj->ifunc_remaining_nonplt)); 257 /* FALLTHROUGH */ 258 259 case R_TYPE(RELATIVE): /* word B + A */ 260 *where = (Elf_Addr)(obj->relocbase + rela->r_addend); 261 rdbg(("RELATIVE in %s --> %p", obj->path, 262 (void *)*where)); 263 break; 264 265 case R_TYPE(COPY): 266 /* 267 * These are deferred until all other relocations have 268 * been done. All we do here is make sure that the 269 * COPY relocation is not in a shared library. They 270 * are allowed only in executable files. 271 */ 272 if (obj->isdynamic) { 273 _rtld_error( 274 "%s: Unexpected R_COPY relocation in shared library", 275 obj->path); 276 return -1; 277 } 278 rdbg(("COPY (avoid in main)")); 279 break; 280 281 case R_TYPE(TLSDESC): 282 _rtld_tlsdesc_fill(obj, rela, where, 0); 283 break; 284 285 case R_TLS_TYPE(TLS_DTPREL): 286 *where = (Elf_Addr)(def->st_value + rela->r_addend); 287 288 rdbg(("TLS_DTPREL %s in %s --> %p", 289 obj->strtab + obj->symtab[symnum].st_name, 290 obj->path, (void *)*where)); 291 break; 292 293 case R_TLS_TYPE(TLS_DTPMOD): 294 *where = (Elf_Addr)(defobj->tlsindex); 295 296 rdbg(("TLS_DTPMOD %s in %s --> %p", 297 obj->strtab + obj->symtab[symnum].st_name, 298 obj->path, (void *)*where)); 299 break; 300 301 case R_TLS_TYPE(TLS_TPREL): 302 if (!defobj->tls_static && 303 _rtld_tls_offset_allocate(__UNCONST(defobj))) 304 return -1; 305 306 *where = (Elf_Addr)(def->st_value + defobj->tlsoffset + 307 rela->r_addend + sizeof(struct tls_tcb)); 308 309 rdbg(("TLS_TPREL %s in %s --> %p in %s", 310 obj->strtab + obj->symtab[symnum].st_name, 311 obj->path, (void *)*where, defobj->path)); 312 break; 313 314 default: 315 rdbg(("sym = %lu, type = %lu, offset = %p, " 316 "addend = %p, contents = %p", 317 (u_long)ELF_R_SYM(rela->r_info), 318 (u_long)ELF_R_TYPE(rela->r_info), 319 (void *)rela->r_offset, (void *)rela->r_addend, 320 (void *)*where)); 321 _rtld_error("%s: Unsupported relocation type %ld " 322 "in non-PLT relocations", 323 obj->path, (u_long) ELF_R_TYPE(rela->r_info)); 324 return -1; 325 } 326 } 327 return 0; 328 } 329 330 int 331 _rtld_relocate_plt_lazy(Obj_Entry *obj) 332 { 333 334 if (!obj->relocbase) 335 return 0; 336 337 for (const Elf_Rela *rela = obj->pltrela; rela < obj->pltrelalim; rela++) { 338 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 339 340 assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JUMP_SLOT) || 341 ELF_R_TYPE(rela->r_info) == R_TYPE(TLSDESC) || 342 ELF_R_TYPE(rela->r_info) == R_TYPE(IRELATIVE)); 343 344 switch (ELF_R_TYPE(rela->r_info)) { 345 case R_TYPE(JUMP_SLOT): 346 /* Just relocate the GOT slots pointing into the PLT */ 347 *where += (Elf_Addr)obj->relocbase; 348 rdbg(("fixup !main in %s --> %p", obj->path, (void *)*where)); 349 break; 350 case R_TYPE(TLSDESC): 351 _rtld_tlsdesc_fill(obj, rela, where, SYMLOOK_IN_PLT); 352 break; 353 case R_TYPE(IRELATIVE): 354 obj->ifunc_remaining = obj->pltrelalim - rela; 355 break; 356 } 357 } 358 359 return 0; 360 } 361 362 void 363 _rtld_call_ifunc(Obj_Entry *obj, sigset_t *mask, u_int cur_objgen) 364 { 365 const Elf_Rela *rela; 366 Elf_Addr *where, target; 367 368 while (obj->ifunc_remaining > 0 && _rtld_objgen == cur_objgen) { 369 rela = obj->pltrelalim - obj->ifunc_remaining; 370 --obj->ifunc_remaining; 371 if (ELF_R_TYPE(rela->r_info) == R_TYPE(IRELATIVE)) { 372 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 373 target = (Elf_Addr)(obj->relocbase + rela->r_addend); 374 _rtld_exclusive_exit(mask); 375 target = _rtld_resolve_ifunc2(obj, target); 376 _rtld_exclusive_enter(mask); 377 if (*where != target) 378 *where = target; 379 } 380 } 381 } 382 383 static int 384 _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, 385 Elf_Addr *tp) 386 { 387 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 388 Elf_Addr new_value; 389 const Elf_Sym *def; 390 const Obj_Entry *defobj; 391 392 switch (ELF_R_TYPE(rela->r_info)) { 393 case R_TYPE(JUMP_SLOT): 394 def = _rtld_find_plt_symdef(ELF_R_SYM(rela->r_info), obj, 395 &defobj, tp != NULL); 396 if (__predict_false(def == NULL)) 397 return -1; 398 if (__predict_false(def == &_rtld_sym_zero)) 399 return 0; 400 401 if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 402 if (tp == NULL) 403 return 0; 404 new_value = _rtld_resolve_ifunc(defobj, def); 405 } else { 406 new_value = (Elf_Addr)(defobj->relocbase + 407 def->st_value); 408 } 409 rdbg(("bind now/fixup in %s --> old=%p new=%p", 410 defobj->strtab + def->st_name, (void *)*where, 411 (void *)new_value)); 412 if (*where != new_value) 413 *where = new_value; 414 if (tp) 415 *tp = new_value; 416 break; 417 case R_TYPE(TLSDESC): 418 _rtld_tlsdesc_fill(obj, rela, where, SYMLOOK_IN_PLT); 419 break; 420 } 421 422 return 0; 423 } 424 425 Elf_Addr 426 _rtld_bind(const Obj_Entry *obj, Elf_Word relaidx) 427 { 428 const Elf_Rela *rela = obj->pltrela + relaidx; 429 Elf_Addr new_value = 0; 430 431 _rtld_shared_enter(); 432 int err = _rtld_relocate_plt_object(obj, rela, &new_value); 433 if (err) 434 _rtld_die(); 435 _rtld_shared_exit(); 436 437 return new_value; 438 } 439 int 440 _rtld_relocate_plt_objects(const Obj_Entry *obj) 441 { 442 const Elf_Rela *rela; 443 int err = 0; 444 445 for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) { 446 err = _rtld_relocate_plt_object(obj, rela, NULL); 447 if (err) 448 break; 449 } 450 451 return err; 452 } 453