xref: /openbsd-src/lib/csu/boot.h (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: boot.h,v 1.23 2016/09/01 09:33:30 tedu Exp $ */
2 
3 /*
4  * Copyright (c) 1998 Per Fogelstrom, Opsycon AB
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 /*
30  * IMPORTANT: any functions below are NOT protected by SSP.  Please
31  * do not add anything except what is required to reach GOT with
32  * an adjustment.
33  */
34 
35 #define	_DYN_LOADER
36 
37 #include <sys/types.h>
38 #include <sys/mman.h>
39 #include <sys/exec.h>
40 #include <sys/sysctl.h>
41 #include <nlist.h>
42 #include <link.h>
43 #include <dlfcn.h>
44 
45 #include "syscall.h"
46 #include "archdep.h"
47 #include "path.h"
48 #include "resolve.h"
49 #include "sod.h"
50 #include "stdlib.h"
51 
52 /*
53  * Use the internal, hidden name for any syscalls we need, to avoid
54  * accidental override by application code
55  */
56 #define REDIRECT_SYSCALL(x)	typeof(x) x asm("_libc_"#x) __dso_hidden
57 REDIRECT_SYSCALL(mprotect);
58 
59 #ifdef RCRT0
60 
61 #define	DT_PROC(n)	((n) - DT_LOPROC)
62 
63 #if RELOC_TAG == DT_RELA
64 typedef	Elf_RelA	RELOC_TYPE;
65 #elif RELOC_TAG == DT_REL
66 typedef	Elf_Rel		RELOC_TYPE;
67 #else
68 # error "unknown RELOC_TAG"
69 #endif
70 
71 /* The set of dynamic tags that we're interested in for bootstrapping */
72 struct boot_dyn {
73 	RELOC_TYPE	*dt_reloc;	/* DT_RELA   or DT_REL */
74 	Elf_Addr	dt_relocsz;	/* DT_RELASZ or DT_RELSZ */
75 	Elf_Addr	*dt_pltgot;
76 	Elf_Addr	dt_pltrelsz;
77 	const Elf_Sym	*dt_symtab;
78 	RELOC_TYPE	*dt_jmprel;
79 #if DT_PROCNUM > 0
80 	u_long		dt_proc[DT_PROCNUM];
81 #endif
82 };
83 
84 /*
85  * Local decls.
86  */
87 void _dl_boot_bind(const long, long *, Elf_Dyn *);
88 
89 extern char __got_start[];
90 extern char __got_end[];
91 
92 void
93 _dl_boot_bind(const long sp, long *dl_data, Elf_Dyn *dynamicp)
94 {
95 	struct boot_dyn	dynld;		/* Resolver data for the loader */
96 	AuxInfo		*auxstack;
97 	long		*stack;
98 	Elf_Dyn		*dynp;
99 	Elf_Addr	start;
100 	size_t		size;
101 	int		pagesize;
102 	int		n, argc;
103 	char		**argv, **envp;
104 	long		loff;
105 	int		prot_exec = 0;
106 	RELOC_TYPE	*rp;
107 	Elf_Phdr	*phdp;
108 	Elf_Addr	i;
109 
110 	/*
111 	 * Scan argument and environment vectors. Find dynamic
112 	 * data vector put after them.
113 	 */
114 	stack = (long *)sp;
115 	argc = *stack++;
116 	argv = (char **)stack;
117 	envp = &argv[argc + 1];
118 	stack = (long *)envp;
119 	while (*stack++ != 0L)
120 		;
121 
122 	/*
123 	 * Zero out dl_data.
124 	 */
125 	for (n = 0; n <= AUX_entry; n++)
126 		dl_data[n] = 0;
127 
128 	/*
129 	 * Dig out auxiliary data set up by exec call. Move all known
130 	 * tags to an indexed local table for easy access.
131 	 */
132 	for (auxstack = (AuxInfo *)stack; auxstack->au_id != AUX_null;
133 	    auxstack++) {
134 		if (auxstack->au_id > AUX_entry)
135 			continue;
136 		dl_data[auxstack->au_id] = auxstack->au_v;
137 	}
138 	loff = dl_data[AUX_base];	/* XXX assumes ld.so is linked at 0x0 */
139 
140 	/*
141 	 * We need to do 'selfreloc' in case the code weren't
142 	 * loaded at the address it was linked to.
143 	 *
144 	 * Scan the DYNAMIC section for the loader.
145 	 * Cache the data for easier access.
146 	 */
147 	dynp = dynamicp;
148 
149 	_dl_memset(&dynld, 0, sizeof(dynld));
150 	while (dynp->d_tag != DT_NULL) {
151 		/* first the tags that are pointers to be relocated */
152 		if (dynp->d_tag == DT_PLTGOT)
153 			dynld.dt_pltgot = (void *)(dynp->d_un.d_ptr + loff);
154 		else if (dynp->d_tag == DT_SYMTAB)
155 			dynld.dt_symtab = (void *)(dynp->d_un.d_ptr + loff);
156 		else if (dynp->d_tag == RELOC_TAG)	/* DT_{RELA,REL} */
157 			dynld.dt_reloc = (void *)(dynp->d_un.d_ptr + loff);
158 		else if (dynp->d_tag == DT_JMPREL)
159 			dynld.dt_jmprel = (void *)(dynp->d_un.d_ptr + loff);
160 
161 		/* Now for the tags that are just sizes or counts */
162 		else if (dynp->d_tag == DT_PLTRELSZ)
163 			dynld.dt_pltrelsz = dynp->d_un.d_val;
164 		else if (dynp->d_tag == RELOC_TAG+1)	/* DT_{RELA,REL}SZ */
165 			dynld.dt_relocsz = dynp->d_un.d_val;
166 #if DT_PROCNUM > 0
167 		else if (dynp->d_tag >= DT_LOPROC &&
168 		    dynp->d_tag < DT_LOPROC + DT_PROCNUM)
169 			dynld.dt_proc[dynp->d_tag - DT_LOPROC] =
170 			    dynp->d_un.d_val;
171 #endif /* DT_PROCNUM */
172 		dynp++;
173 	}
174 
175 	rp = dynld.dt_jmprel;
176 	for (i = 0; i < dynld.dt_pltrelsz; i += sizeof *rp) {
177 		Elf_Addr *ra;
178 		const Elf_Sym *sp;
179 
180 		sp = dynld.dt_symtab + ELF_R_SYM(rp->r_info);
181 		if (!ELF_R_SYM(rp->r_info) || sp->st_value != 0) {
182 #ifdef HAVE_JMPREL
183 			ra = (Elf_Addr *)(rp->r_offset + loff);
184 			RELOC_JMPREL(rp, sp, ra, loff, dynld.dt_pltgot);
185 #else
186 			_dl_exit(6);
187 #endif
188 		}
189 		rp++;
190 	}
191 
192 	rp = dynld.dt_reloc;
193 	for (i = 0; i < dynld.dt_relocsz; i += sizeof *rp) {
194 		Elf_Addr *ra;
195 		const Elf_Sym *sp;
196 
197 		sp = dynld.dt_symtab + ELF_R_SYM(rp->r_info);
198 		if (!ELF_R_SYM(rp->r_info) || sp->st_value != 0) {
199 			ra = (Elf_Addr *)(rp->r_offset + loff);
200 			RELOC_DYN(rp, sp, ra, loff);
201 		}
202 		rp++;
203 	}
204 
205 	RELOC_GOT(&dynld, loff);
206 
207 	/*
208 	 * we have been fully relocated here, so most things no longer
209 	 * need the loff adjustment
210 	 */
211 
212 	/*
213 	 * No further changes to the PLT and/or GOT are needed so make
214 	 * them read-only.
215 	 */
216 
217 	if (dl_data[AUX_pagesz] != 0)
218 		pagesize = dl_data[AUX_pagesz];
219 	else
220 		pagesize = 4096;
221 
222 	/* do any RWX -> RX fixups for executable PLTs and apply GNU_RELRO */
223 	phdp = (Elf_Phdr *)dl_data[AUX_phdr];
224 	for (i = 0; i < dl_data[AUX_phnum]; i++, phdp++) {
225 		switch (phdp->p_type) {
226 #if defined(__alpha__) || defined(__hppa__) || defined(__powerpc__) || \
227     defined(__sparc64__)
228 		case PT_LOAD:
229 			if ((phdp->p_flags & (PF_X | PF_W)) != (PF_X | PF_W))
230 				break;
231 			mprotect((void *)(phdp->p_vaddr + loff), phdp->p_memsz,
232 			    PROT_READ);
233 			break;
234 #endif
235 		case PT_GNU_RELRO:
236 			mprotect((void *)(phdp->p_vaddr + loff), phdp->p_memsz,
237 			    PROT_READ);
238 			/*
239 			 * GNU_RELRO (a) covers the GOT, and (b) comes after
240 			 * all LOAD sections, so if we found it then we're done
241 			 */
242 			return;
243 		}
244 	}
245 
246 #if defined(__powerpc__)
247 	if (dynld.dt_proc[DT_PROC(DT_PPC_GOT)] == 0)
248 		prot_exec = PROT_EXEC;
249 #endif
250 
251 	start = ELF_TRUNC((Elf_Addr)__got_start, pagesize);
252 	size = ELF_ROUND((Elf_Addr)__got_end - start, pagesize);
253 	mprotect((void *)start, size, GOT_PERMS | prot_exec);
254 }
255 
256 #ifdef __alpha__
257 
258 void	_reloc_alpha_got(Elf_Dyn *dynp, Elf_Addr relocbase);
259 
260 void
261 _reloc_alpha_got(Elf_Dyn *dynp, Elf_Addr relocbase)
262 {
263 	const Elf_RelA *rela = 0, *relalim;
264 	Elf_Addr relasz = 0;
265 	Elf_Addr *where;
266 
267 	for (; dynp->d_tag != DT_NULL; dynp++) {
268 		switch (dynp->d_tag) {
269 		case DT_RELA:
270 			rela = (const Elf_RelA *)(relocbase + dynp->d_un.d_ptr);
271 			break;
272 		case DT_RELASZ:
273 			relasz = dynp->d_un.d_val;
274 			break;
275 		}
276 	}
277 	relalim = (const Elf_RelA *)((caddr_t)rela + relasz);
278 	for (; rela < relalim; rela++) {
279 		if (ELF64_R_TYPE(rela->r_info) != RELOC_RELATIVE)
280 			continue;
281 		where = (Elf_Addr *)(relocbase + rela->r_offset);
282 		*where += (Elf_Addr)relocbase;
283 	}
284 }
285 
286 #endif
287 
288 #endif /* RCRT0 */
289