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