1 /* $OpenBSD: rtld_machine.c,v 1.68 2019/10/05 00:08:50 guenther 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 63 loff = object->obj_base; 64 numrela = object->Dyn.info[relasz] / sizeof(Elf64_Rela); 65 relrel = rel == DT_RELA ? object->relacount : 0; 66 relas = (Elf64_Rela *)(object->Dyn.info[rel]); 67 68 if (relas == NULL) 69 return(0); 70 71 if (relrel > numrela) 72 _dl_die("relacount > numrel: %ld > %ld", relrel, numrela); 73 74 if (! object->Dyn.info[DT_PROC(DT_ALPHA_PLTRO)]) 75 _dl_die("unsupported insecure PLT object"); 76 77 /* tight loop for leading RELATIVE relocs */ 78 for (i = 0; i < relrel; i++, relas++) { 79 Elf_Addr *r_addr; 80 81 r_addr = (Elf64_Addr *)(relas->r_offset + loff); 82 83 /* Handle unaligned RELATIVE relocs */ 84 if ((((Elf_Addr)r_addr) & 0x7) != 0) { 85 Elf_Addr tmp; 86 _dl_bcopy(r_addr, &tmp, sizeof(Elf_Addr)); 87 tmp += loff; 88 _dl_bcopy(&tmp, r_addr, sizeof(Elf_Addr)); 89 } else 90 *r_addr += loff; 91 } 92 for (; i < numrela; i++, relas++) { 93 Elf64_Addr *r_addr; 94 struct sym_res sr; 95 const Elf64_Sym *sym; 96 const char *symn; 97 98 r_addr = (Elf64_Addr *)(relas->r_offset + loff); 99 100 if (ELF64_R_SYM(relas->r_info) == 0xffffffff) 101 continue; 102 103 104 sym = object->dyn.symtab; 105 sym += ELF64_R_SYM(relas->r_info); 106 symn = object->dyn.strtab + sym->st_name; 107 108 switch (ELF64_R_TYPE(relas->r_info)) { 109 case R_TYPE(REFQUAD): 110 sr = _dl_find_symbol(symn, 111 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT, 112 sym, object); 113 if (sr.sym == NULL) 114 goto resolve_failed; 115 *r_addr += sr.obj->obj_base + sr.sym->st_value + 116 relas->r_addend; 117 break; 118 case R_TYPE(RELATIVE): 119 /* 120 * There is a lot of unaligned RELATIVE 121 * relocs generated by gcc in the exception handlers. 122 */ 123 if ((((Elf_Addr) r_addr) & 0x7) != 0) { 124 Elf_Addr tmp; 125 #if 0 126 _dl_printf("unaligned RELATIVE: %p type: %d %s 0x%lx -> 0x%lx\n", r_addr, 127 ELF_R_TYPE(relas->r_info), object->load_name, *r_addr, *r_addr+loff); 128 #endif 129 _dl_bcopy(r_addr, &tmp, sizeof(Elf_Addr)); 130 tmp += loff; 131 _dl_bcopy(&tmp, r_addr, sizeof(Elf_Addr)); 132 } else 133 *r_addr += loff; 134 break; 135 case R_TYPE(JMP_SLOT): 136 sr = _dl_find_symbol(symn, 137 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, 138 sym, object); 139 if (sr.sym == NULL) 140 goto resolve_failed; 141 *r_addr = sr.obj->obj_base + sr.sym->st_value + 142 relas->r_addend; 143 break; 144 case R_TYPE(GLOB_DAT): 145 if (sym == prev_sym) { 146 *r_addr = prev_value + relas->r_addend; 147 break; 148 } 149 sr = _dl_find_symbol(symn, 150 SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_NOTPLT, 151 sym, object); 152 if (sr.sym == NULL) 153 goto resolve_failed; 154 prev_sym = sym; 155 prev_value = sr.obj->obj_base + sr.sym->st_value; 156 *r_addr = prev_value + relas->r_addend; 157 break; 158 case R_TYPE(NONE): 159 break; 160 default: 161 _dl_die("%s: unsupported relocation '%s' %lld at %p", 162 object->load_name, symn, 163 ELF64_R_TYPE(relas->r_info), (void *)r_addr); 164 } 165 continue; 166 resolve_failed: 167 if (ELF_ST_BIND(sym->st_info) != STB_WEAK) 168 fails++; 169 } 170 __asm volatile("imb" : : : "memory"); 171 172 return (fails); 173 } 174 175 /* 176 * Resolve a symbol at run-time. 177 */ 178 Elf_Addr 179 _dl_bind(elf_object_t *object, int reloff) 180 { 181 Elf_RelA *rela; 182 struct sym_res sr; 183 const Elf_Sym *sym; 184 const char *symn; 185 uint64_t cookie = pcookie; 186 struct { 187 struct __kbind param; 188 Elf_Addr newval; 189 } buf; 190 191 rela = (Elf_RelA *)(object->Dyn.info[DT_JMPREL] + reloff); 192 193 sym = object->dyn.symtab; 194 sym += ELF64_R_SYM(rela->r_info); 195 symn = object->dyn.strtab + sym->st_name; 196 197 sr = _dl_find_symbol(symn, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, 198 sym, object); 199 if (sr.sym == NULL) 200 _dl_die("lazy binding failed!"); 201 202 buf.newval = sr.obj->obj_base + sr.sym->st_value + rela->r_addend; 203 204 if (__predict_false(sr.obj->traced) && _dl_trace_plt(sr.obj, symn)) 205 return (buf.newval); 206 207 buf.param.kb_addr = (Elf_Addr *)(object->obj_base + rela->r_offset); 208 buf.param.kb_size = sizeof(Elf_Addr); 209 210 /* directly code the syscall, so that it's actually inline here */ 211 { 212 register long syscall_num __asm("$0") /* v0 */ = SYS_kbind; 213 register void *arg1 __asm("$16") /* a0 */ = &buf; 214 register long arg2 __asm("$17") /* a1 */ = sizeof(buf); 215 register long arg3 __asm("$18") /* a2 */ = cookie; 216 217 __asm volatile( "call_pal %1" : "+r" (syscall_num) 218 : "i" (PAL_OSF1_callsys), "r" (arg1), "r" (arg2), 219 "r" (arg3) : "$19", "$20", "memory"); 220 } 221 222 return (buf.newval); 223 } 224 225 void _dl_bind_start(void) __dso_hidden; /* XXX */ 226 227 /* 228 * Relocate the Global Offset Table (GOT). 229 */ 230 int 231 _dl_md_reloc_got(elf_object_t *object, int lazy) 232 { 233 int fails = 0; 234 Elf_Addr *pltgot; 235 236 if (object->Dyn.info[DT_PLTREL] != DT_RELA) 237 return (0); 238 239 pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT]; 240 241 if (object->traced) 242 lazy = 1; 243 244 if (!lazy || pltgot == NULL) { 245 fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); 246 } else { 247 if (object->obj_base != 0) { 248 int i, size; 249 Elf_Addr *addr; 250 Elf_RelA *rela; 251 252 size = object->Dyn.info[DT_PLTRELSZ] / 253 sizeof(Elf_RelA); 254 rela = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]); 255 256 for (i = 0; i < size; i++) { 257 addr = (Elf_Addr *)(object->obj_base + 258 rela[i].r_offset); 259 *addr += object->obj_base; 260 } 261 } 262 pltgot[0] = (Elf_Addr)_dl_bind_start; 263 pltgot[1] = (Elf_Addr)object; 264 } 265 266 return (fails); 267 } 268