1 |
|
|
/* $OpenBSD: boot.h,v 1.28 2017/01/29 22:31:09 chl 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 |
|
|
void |
90 |
|
|
_dl_boot_bind(const long sp, long *dl_data, Elf_Dyn *dynamicp) |
91 |
|
|
{ |
92 |
|
30 |
struct boot_dyn dynld; /* Resolver data for the loader */ |
93 |
|
|
AuxInfo *auxstack; |
94 |
|
|
long *stack; |
95 |
|
|
Elf_Dyn *dynp; |
96 |
|
|
int n, argc; |
97 |
|
|
char **argv, **envp; |
98 |
|
|
long loff; |
99 |
|
|
RELOC_TYPE *rp; |
100 |
|
|
Elf_Phdr *phdp; |
101 |
|
|
Elf_Addr i; |
102 |
|
|
|
103 |
|
|
/* |
104 |
|
|
* Scan argument and environment vectors. Find dynamic |
105 |
|
|
* data vector put after them. |
106 |
|
|
*/ |
107 |
|
15 |
stack = (long *)sp; |
108 |
|
15 |
argc = *stack++; |
109 |
|
15 |
argv = (char **)stack; |
110 |
|
15 |
envp = &argv[argc + 1]; |
111 |
|
15 |
stack = (long *)envp; |
112 |
✓✓ |
750 |
while (*stack++ != 0L) |
113 |
|
|
; |
114 |
|
|
|
115 |
|
|
/* |
116 |
|
|
* Zero out dl_data. |
117 |
|
|
*/ |
118 |
✓✓ |
330 |
for (n = 0; n <= AUX_entry; n++) |
119 |
|
150 |
dl_data[n] = 0; |
120 |
|
|
|
121 |
|
|
/* |
122 |
|
|
* Dig out auxiliary data set up by exec call. Move all known |
123 |
|
|
* tags to an indexed local table for easy access. |
124 |
|
|
*/ |
125 |
✓✓ |
240 |
for (auxstack = (AuxInfo *)stack; auxstack->au_id != AUX_null; |
126 |
|
105 |
auxstack++) { |
127 |
✓✗ |
105 |
if (auxstack->au_id > AUX_entry) |
128 |
|
|
continue; |
129 |
|
105 |
dl_data[auxstack->au_id] = auxstack->au_v; |
130 |
|
105 |
} |
131 |
|
15 |
loff = dl_data[AUX_base]; /* XXX assumes ld.so is linked at 0x0 */ |
132 |
|
|
|
133 |
|
|
/* |
134 |
|
|
* We need to do 'selfreloc' in case the code weren't |
135 |
|
|
* loaded at the address it was linked to. |
136 |
|
|
* |
137 |
|
|
* Scan the DYNAMIC section for the loader. |
138 |
|
|
* Cache the data for easier access. |
139 |
|
|
*/ |
140 |
|
|
dynp = dynamicp; |
141 |
|
|
|
142 |
|
15 |
_dl_memset(&dynld, 0, sizeof(dynld)); |
143 |
✓✓ |
450 |
while (dynp->d_tag != DT_NULL) { |
144 |
|
|
/* first the tags that are pointers to be relocated */ |
145 |
✓✓ |
210 |
if (dynp->d_tag == DT_PLTGOT) |
146 |
|
15 |
dynld.dt_pltgot = (void *)(dynp->d_un.d_ptr + loff); |
147 |
✓✓ |
195 |
else if (dynp->d_tag == DT_SYMTAB) |
148 |
|
15 |
dynld.dt_symtab = (void *)(dynp->d_un.d_ptr + loff); |
149 |
✓✓ |
180 |
else if (dynp->d_tag == RELOC_TAG) /* DT_{RELA,REL} */ |
150 |
|
15 |
dynld.dt_reloc = (void *)(dynp->d_un.d_ptr + loff); |
151 |
✓✓ |
165 |
else if (dynp->d_tag == DT_JMPREL) |
152 |
|
15 |
dynld.dt_jmprel = (void *)(dynp->d_un.d_ptr + loff); |
153 |
|
|
|
154 |
|
|
/* Now for the tags that are just sizes or counts */ |
155 |
✓✓ |
150 |
else if (dynp->d_tag == DT_PLTRELSZ) |
156 |
|
15 |
dynld.dt_pltrelsz = dynp->d_un.d_val; |
157 |
✓✓ |
135 |
else if (dynp->d_tag == RELOC_TAG+1) /* DT_{RELA,REL}SZ */ |
158 |
|
15 |
dynld.dt_relocsz = dynp->d_un.d_val; |
159 |
|
|
#if DT_PROCNUM > 0 |
160 |
|
|
else if (dynp->d_tag >= DT_LOPROC && |
161 |
|
|
dynp->d_tag < DT_LOPROC + DT_PROCNUM) |
162 |
|
|
dynld.dt_proc[dynp->d_tag - DT_LOPROC] = |
163 |
|
|
dynp->d_un.d_val; |
164 |
|
|
#endif /* DT_PROCNUM */ |
165 |
|
210 |
dynp++; |
166 |
|
|
} |
167 |
|
|
|
168 |
|
15 |
rp = dynld.dt_jmprel; |
169 |
✓✓ |
60 |
for (i = 0; i < dynld.dt_pltrelsz; i += sizeof *rp) { |
170 |
|
|
const Elf_Sym *sp; |
171 |
|
|
|
172 |
|
15 |
sp = dynld.dt_symtab + ELF_R_SYM(rp->r_info); |
173 |
✓✗✗✓
|
30 |
if (!ELF_R_SYM(rp->r_info) || sp->st_value != 0) { |
174 |
|
|
#ifdef HAVE_JMPREL |
175 |
|
|
Elf_Addr *ra = (Elf_Addr *)(rp->r_offset + loff); |
176 |
|
|
RELOC_JMPREL(rp, sp, ra, loff, dynld.dt_pltgot); |
177 |
|
|
#else |
178 |
|
|
_dl_exit(6); |
179 |
|
|
#endif |
180 |
|
|
} |
181 |
|
15 |
rp++; |
182 |
|
|
} |
183 |
|
|
|
184 |
|
15 |
rp = dynld.dt_reloc; |
185 |
✓✓ |
40530 |
for (i = 0; i < dynld.dt_relocsz; i += sizeof *rp) { |
186 |
|
|
Elf_Addr *ra; |
187 |
|
|
const Elf_Sym *sp; |
188 |
|
|
|
189 |
|
20250 |
sp = dynld.dt_symtab + ELF_R_SYM(rp->r_info); |
190 |
✓✓✓✓
|
20352 |
if (!ELF_R_SYM(rp->r_info) || sp->st_value != 0) { |
191 |
|
20235 |
ra = (Elf_Addr *)(rp->r_offset + loff); |
192 |
|
20235 |
RELOC_DYN(rp, sp, ra, loff); |
193 |
|
20235 |
} |
194 |
|
20250 |
rp++; |
195 |
|
|
} |
196 |
|
|
|
197 |
|
|
RELOC_GOT(&dynld, loff); |
198 |
|
|
|
199 |
|
|
/* |
200 |
|
|
* we have been fully relocated here, so most things no longer |
201 |
|
|
* need the loff adjustment |
202 |
|
|
*/ |
203 |
|
|
|
204 |
|
|
/* |
205 |
|
|
* No further changes to the PLT and/or GOT are needed so make |
206 |
|
|
* them read-only. |
207 |
|
|
*/ |
208 |
|
|
|
209 |
|
|
/* do any RWX -> RX fixups for executable PLTs and apply GNU_RELRO */ |
210 |
|
15 |
phdp = (Elf_Phdr *)dl_data[AUX_phdr]; |
211 |
✓✓ |
300 |
for (i = 0; i < dl_data[AUX_phnum]; i++, phdp++) { |
212 |
✓✓ |
135 |
switch (phdp->p_type) { |
213 |
|
|
#if defined(__alpha__) || defined(__hppa__) || defined(__powerpc__) || \ |
214 |
|
|
defined(__sparc64__) |
215 |
|
|
case PT_LOAD: |
216 |
|
|
if ((phdp->p_flags & (PF_X | PF_W)) != (PF_X | PF_W)) |
217 |
|
|
break; |
218 |
|
|
mprotect((void *)(phdp->p_vaddr + loff), phdp->p_memsz, |
219 |
|
|
PROT_READ); |
220 |
|
|
break; |
221 |
|
|
#endif |
222 |
|
|
case PT_GNU_RELRO: |
223 |
|
15 |
mprotect((void *)(phdp->p_vaddr + loff), phdp->p_memsz, |
224 |
|
|
PROT_READ); |
225 |
|
|
/* |
226 |
|
|
* GNU_RELRO (a) covers the GOT, and (b) comes after |
227 |
|
|
* all LOAD sections, so if we found it then we're done |
228 |
|
|
*/ |
229 |
|
15 |
break; |
230 |
|
|
} |
231 |
|
|
} |
232 |
|
15 |
} |
233 |
|
|
|
234 |
|
|
#ifdef __alpha__ |
235 |
|
|
|
236 |
|
|
void _reloc_alpha_got(Elf_Dyn *dynp, Elf_Addr relocbase); |
237 |
|
|
|
238 |
|
|
void |
239 |
|
|
_reloc_alpha_got(Elf_Dyn *dynp, Elf_Addr relocbase) |
240 |
|
|
{ |
241 |
|
|
const Elf_RelA *rela = 0, *relalim; |
242 |
|
|
Elf_Addr relasz = 0; |
243 |
|
|
Elf_Addr *where; |
244 |
|
|
|
245 |
|
|
for (; dynp->d_tag != DT_NULL; dynp++) { |
246 |
|
|
switch (dynp->d_tag) { |
247 |
|
|
case DT_RELA: |
248 |
|
|
rela = (const Elf_RelA *)(relocbase + dynp->d_un.d_ptr); |
249 |
|
|
break; |
250 |
|
|
case DT_RELASZ: |
251 |
|
|
relasz = dynp->d_un.d_val; |
252 |
|
|
break; |
253 |
|
|
} |
254 |
|
|
} |
255 |
|
|
relalim = (const Elf_RelA *)((caddr_t)rela + relasz); |
256 |
|
|
for (; rela < relalim; rela++) { |
257 |
|
|
if (ELF64_R_TYPE(rela->r_info) != RELOC_RELATIVE) |
258 |
|
|
continue; |
259 |
|
|
where = (Elf_Addr *)(relocbase + rela->r_offset); |
260 |
|
|
*where += (Elf_Addr)relocbase; |
261 |
|
|
} |
262 |
|
|
} |
263 |
|
|
|
264 |
|
|
#endif |
265 |
|
|
|
266 |
|
|
#endif /* RCRT0 */ |