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