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
_dl_md_reloc(elf_object_t * object,int rel,int relasz)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
_dl_md_reloc_got(elf_object_t * object,int lazy)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
_dl_bind(elf_object_t * object,int reloff)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