1 /* $OpenBSD: rtld_machine.c,v 1.70 2019/12/07 22:57:48 guenther Exp $ */ 2 3 /* 4 * Copyright (c) 1999 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 43 #define DT_PROC(n) ((n) - DT_LOPROC + DT_NUM) 44 45 int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden; 46 47 /* relocation bits */ 48 #define B24_VALID_RANGE(x) \ 49 ((((x) & 0xfe000000) == 0x00000000) || (((x) & 0xfe000000) == 0xfe000000)) 50 51 void _dl_bind_start(void); /* XXX */ 52 Elf_Addr _dl_bind(elf_object_t *object, int reloff); 53 54 int 55 _dl_md_reloc(elf_object_t *object, int rel, int relasz) 56 { 57 int i; 58 int numrela; 59 long relrel; 60 int fails = 0; 61 Elf_Addr loff; 62 Elf_RelA *relas; 63 /* for jmp table relocations */ 64 Elf_Addr prev_value = 0, prev_ooff = 0; 65 const Elf_Sym *prev_sym = NULL; 66 67 loff = object->obj_base; 68 numrela = object->Dyn.info[relasz] / sizeof(Elf_RelA); 69 relrel = rel == DT_RELA ? object->relacount : 0; 70 relas = (Elf_RelA *)(object->Dyn.info[rel]); 71 72 if (relas == NULL) 73 return 0; 74 75 if (relrel > numrela) 76 _dl_die("relcount > numrel: %ld > %d", relrel, numrela); 77 78 if (object->Dyn.info[DT_PROC(DT_PPC_GOT)] == 0) 79 _dl_die("unsupported insecure BSS PLT object"); 80 81 /* tight loop for leading RELATIVE relocs */ 82 for (i = 0; i < relrel; i++, relas++) { 83 Elf_Addr *r_addr; 84 85 r_addr = (Elf_Addr *)(relas->r_offset + loff); 86 *r_addr = loff + relas->r_addend; 87 } 88 for (; i < numrela; i++, relas++) { 89 Elf_Addr *r_addr = (Elf_Addr *)(relas->r_offset + loff); 90 const Elf_Sym *sym; 91 const char *symn; 92 int type; 93 94 if (ELF_R_SYM(relas->r_info) == 0xffffff) 95 continue; 96 97 type = ELF_R_TYPE(relas->r_info); 98 99 if (type == RELOC_JMP_SLOT && rel != DT_JMPREL) 100 continue; 101 102 sym = object->dyn.symtab; 103 sym += ELF_R_SYM(relas->r_info); 104 symn = object->dyn.strtab + sym->st_name; 105 106 if (ELF_R_SYM(relas->r_info) && 107 !(ELF_ST_BIND(sym->st_info) == STB_LOCAL && 108 ELF_ST_TYPE (sym->st_info) == STT_NOTYPE) && 109 sym != prev_sym) { 110 struct sym_res sr; 111 112 sr = _dl_find_symbol(symn, 113 SYM_SEARCH_ALL|SYM_WARNNOTFOUND| 114 ((type == RELOC_JMP_SLOT) ? 115 SYM_PLT:SYM_NOTPLT), sym, object); 116 117 if (sr.sym == NULL) { 118 if (ELF_ST_BIND(sym->st_info) != STB_WEAK) 119 fails++; 120 continue; 121 } 122 prev_sym = sym; 123 prev_value = sr.sym->st_value; 124 prev_ooff = sr.obj->obj_base; 125 } 126 127 switch (type) { 128 case RELOC_32: 129 if (ELF_ST_BIND(sym->st_info) == STB_LOCAL && 130 (ELF_ST_TYPE(sym->st_info) == STT_SECTION || 131 ELF_ST_TYPE(sym->st_info) == STT_NOTYPE) ) { 132 *r_addr = prev_ooff + relas->r_addend; 133 } else { 134 *r_addr = prev_ooff + prev_value + 135 relas->r_addend; 136 } 137 break; 138 case RELOC_RELATIVE: 139 if (ELF_ST_BIND(sym->st_info) == STB_LOCAL && 140 (ELF_ST_TYPE(sym->st_info) == STT_SECTION || 141 ELF_ST_TYPE(sym->st_info) == STT_NOTYPE) ) { 142 *r_addr = loff + relas->r_addend; 143 } else { 144 *r_addr = loff + prev_value + 145 relas->r_addend; 146 } 147 break; 148 /* 149 * For Secure-PLT, RELOC_JMP_SLOT simply sets PLT 150 * slots similarly to how RELOC_GLOB_DAT updates GOT 151 * slots. 152 */ 153 case RELOC_JMP_SLOT: 154 case RELOC_GLOB_DAT: 155 *r_addr = prev_ooff + prev_value + relas->r_addend; 156 break; 157 #if 1 158 /* should not be supported ??? */ 159 case RELOC_REL24: 160 { 161 Elf_Addr val = prev_ooff + prev_value + 162 relas->r_addend - (Elf_Addr)r_addr; 163 if (!B24_VALID_RANGE(val)) { 164 /* invalid offset */ 165 _dl_die("%s: invalid %s offset %x at %p", 166 object->load_name, "REL24", val, 167 (void *)r_addr); 168 } 169 val &= ~0xfc000003; 170 val |= (*r_addr & 0xfc000003); 171 *r_addr = val; 172 173 _dl_dcbf(r_addr); 174 } 175 break; 176 #endif 177 #if 1 178 case RELOC_16_LO: 179 { 180 Elf_Addr val; 181 182 val = loff + relas->r_addend; 183 *(Elf_Half *)r_addr = val; 184 185 _dl_dcbf(r_addr); 186 } 187 break; 188 #endif 189 #if 1 190 case RELOC_16_HI: 191 { 192 Elf_Addr val; 193 194 val = loff + relas->r_addend; 195 *(Elf_Half *)r_addr = (val >> 16); 196 197 _dl_dcbf(r_addr); 198 } 199 break; 200 #endif 201 #if 1 202 case RELOC_16_HA: 203 { 204 Elf_Addr val; 205 206 val = loff + relas->r_addend; 207 *(Elf_Half *)r_addr = ((val + 0x8000) >> 16); 208 209 _dl_dcbf(r_addr); 210 } 211 break; 212 #endif 213 case RELOC_REL14_TAKEN: 214 /* val |= 1 << (31-10) XXX? */ 215 case RELOC_REL14: 216 case RELOC_REL14_NTAKEN: 217 { 218 Elf_Addr val = prev_ooff + prev_value + 219 relas->r_addend - (Elf_Addr)r_addr; 220 if (((val & 0xffff8000) != 0) && 221 ((val & 0xffff8000) != 0xffff8000)) { 222 /* invalid offset */ 223 _dl_die("%s: invalid %s offset %x at %p", 224 object->load_name, "REL14", val, 225 (void *)r_addr); 226 } 227 val &= ~0xffff0003; 228 val |= (*r_addr & 0xffff0003); 229 *r_addr = val; 230 _dl_dcbf(r_addr); 231 } 232 break; 233 case RELOC_COPY: 234 { 235 struct sym_res sr; 236 /* 237 * we need to find a symbol, that is not in the current 238 * object, start looking at the beginning of the list, 239 * searching all objects but _not_ the current object, 240 * first one found wins. 241 */ 242 sr = _dl_find_symbol(symn, 243 SYM_SEARCH_OTHER|SYM_WARNNOTFOUND| SYM_NOTPLT, 244 sym, object); 245 if (sr.sym != NULL) { 246 _dl_bcopy((void *)(sr.obj->obj_base + sr.sym->st_value), 247 r_addr, sym->st_size); 248 } else 249 fails++; 250 } 251 break; 252 case RELOC_NONE: 253 break; 254 255 default: 256 _dl_die("%s: unsupported relocation '%s' %d at %p\n", 257 object->load_name, symn, 258 ELF_R_TYPE(relas->r_info), (void *)r_addr ); 259 } 260 } 261 262 return fails; 263 } 264 265 /* 266 * Relocate the Global Offset Table (GOT). 267 * This is done by calling _dl_md_reloc on DT_JMPREL for DL_BIND_NOW, 268 * otherwise the lazy binding plt initialization is performed. 269 */ 270 int 271 _dl_md_reloc_got(elf_object_t *object, int lazy) 272 { 273 int fails = 0; 274 275 if (object->Dyn.info[DT_PLTREL] != DT_RELA) 276 return 0; 277 278 if (!lazy) { 279 fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); 280 } else { 281 Elf_Addr *got; 282 Elf_Addr *plt; 283 int numplt, i; 284 285 /* Relocate processor-specific tags. */ 286 object->Dyn.info[DT_PROC(DT_PPC_GOT)] += object->obj_base; 287 288 got = (Elf_Addr *) 289 (Elf_RelA *)(object->Dyn.info[DT_PROC(DT_PPC_GOT)]); 290 got[1] = (Elf_Addr)_dl_bind_start; 291 got[2] = (Elf_Addr)object; 292 293 plt = (Elf_Addr *) 294 (Elf_RelA *)(object->Dyn.info[DT_PLTGOT]); 295 numplt = object->Dyn.info[DT_PLTRELSZ] / sizeof(Elf_RelA); 296 for (i = 0; i < numplt; i++) 297 plt[i] += object->obj_base; 298 } 299 300 return fails; 301 } 302 303 Elf_Addr 304 _dl_bind(elf_object_t *object, int reloff) 305 { 306 const Elf_Sym *sym; 307 struct sym_res sr; 308 const char *symn; 309 Elf_RelA *relas; 310 Elf_Addr *plttable; 311 int64_t cookie = pcookie; 312 struct { 313 struct __kbind param; 314 Elf_Addr newval; 315 } buf; 316 317 relas = (Elf_RelA *)(object->Dyn.info[DT_JMPREL] + reloff); 318 319 sym = object->dyn.symtab; 320 sym += ELF_R_SYM(relas->r_info); 321 symn = object->dyn.strtab + sym->st_name; 322 323 sr = _dl_find_symbol(symn, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, 324 sym, object); 325 if (sr.sym == NULL) 326 _dl_die("lazy binding failed!"); 327 328 buf.newval = sr.obj->obj_base + sr.sym->st_value; 329 330 if (__predict_false(sr.obj->traced) && _dl_trace_plt(sr.obj, symn)) 331 return buf.newval; 332 333 plttable = (Elf_Addr *)(Elf_RelA *)(object->Dyn.info[DT_PLTGOT]); 334 buf.param.kb_addr = &plttable[ reloff / sizeof(Elf_RelA) ]; 335 buf.param.kb_size = sizeof(Elf_Addr); 336 337 { 338 register long syscall_num __asm("r0") = SYS_kbind; 339 register void *arg1 __asm("r3") = &buf.param; 340 register long arg2 __asm("r4") = sizeof(struct __kbind) + 341 sizeof(Elf_Addr); 342 register long arg3 __asm("r5") = 0xffffffff & (cookie >> 32); 343 register long arg4 __asm("r6") = 0xffffffff & cookie; 344 345 __asm volatile("sc" : "+r" (syscall_num), "+r" (arg1), 346 "+r" (arg2) : "r" (arg3), "r" (arg4) : "cc", "memory"); 347 } 348 349 return buf.newval; 350 } 351