1 /* $OpenBSD: boot_md.h,v 1.5 2023/11/18 16:26:16 deraadt 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/exec_elf.h>
38 #include <sys/mman.h>
39
40 #include <machine/reloc.h>
41
42 __dead
43 void _csu_abort(void);
44
45 #include "archdep.h"
46
47 /*
48 * Use the internal, hidden name for any syscalls we need, to avoid
49 * accidental override by application code
50 */
51 #define REDIRECT_SYSCALL(x) typeof(x) x asm("_libc_"#x) __dso_hidden
52 REDIRECT_SYSCALL(mprotect);
53 REDIRECT_SYSCALL(mimmutable);
54
55 typedef Elf_RelA RELOC_TYPE;
56
57 static void *relro_addr;
58 static size_t relro_size;
59 #define RCRT0_RELRO() \
60 do { \
61 if (relro_addr != NULL && relro_size != 0) \
62 mprotect(relro_addr, relro_size, PROT_READ); \
63 mimmutable(relro_addr, relro_size); \
64 } while (0)
65
66 /*
67 * Local decls.
68 */
69 void _dl_boot_bind(const long, long *, Elf_Dyn *);
70
71 void
_dl_boot_bind(const long sp,long * dl_data,Elf_Dyn * dynp)72 _dl_boot_bind(const long sp, long *dl_data, Elf_Dyn *dynp)
73 {
74 AuxInfo *auxstack;
75 long *stack;
76 int n, argc;
77 char **argv, **envp;
78 long loff;
79 Elf_Phdr *phdp;
80 const RELOC_TYPE *rend;
81 const RELOC_TYPE *dt_reloc; /* DT_RELA */
82 Elf_Addr dt_relocsz; /* DT_RELASZ */
83 Elf_Addr dt_pltgot;
84 Elf_Addr dt_pltrelsz;
85 const Elf_Sym *dt_symtab;
86 const RELOC_TYPE *dt_jmprel;
87 Elf_Addr i;
88
89 /*
90 * Scan argument and environment vectors. Find dynamic
91 * data vector put after them.
92 */
93 stack = (long *)sp;
94 argc = *stack++;
95 argv = (char **)stack;
96 envp = &argv[argc + 1];
97 stack = (long *)envp;
98 while (*stack++ != 0L)
99 ;
100
101 /*
102 * Zero out dl_data.
103 */
104 for (n = 0; n <= AUX_entry; n++)
105 dl_data[n] = 0;
106
107 /*
108 * Dig out auxiliary data set up by exec call. Move all known
109 * tags to an indexed local table for easy access.
110 */
111 for (auxstack = (AuxInfo *)stack; auxstack->au_id != AUX_null;
112 auxstack++) {
113 if (auxstack->au_id > AUX_entry)
114 continue;
115 dl_data[auxstack->au_id] = auxstack->au_v;
116 }
117 loff = dl_data[AUX_base]; /* XXX assumes ld.so is linked at 0x0 */
118
119 /*
120 * Scan the DYNAMIC section for the items we need
121 */
122 dt_pltrelsz = dt_relocsz = dt_pltgot = 0;
123 dt_jmprel = dt_reloc = NULL;
124 dt_symtab = NULL;
125 while (dynp->d_tag != DT_NULL) {
126 /* first the tags that are pointers to be relocated */
127 if (dynp->d_tag == DT_PLTGOT)
128 dt_pltgot = dynp->d_un.d_ptr + loff;
129 else if (dynp->d_tag == DT_SYMTAB)
130 dt_symtab = (void *)(dynp->d_un.d_ptr + loff);
131 else if (dynp->d_tag == RELOC_TAG) /* DT_{RELA,REL} */
132 dt_reloc = (void *)(dynp->d_un.d_ptr + loff);
133 else if (dynp->d_tag == DT_JMPREL)
134 dt_jmprel = (void *)(dynp->d_un.d_ptr + loff);
135
136 /* Now for the tags that are just sizes or counts */
137 else if (dynp->d_tag == DT_PLTRELSZ)
138 dt_pltrelsz = dynp->d_un.d_val;
139 else if (dynp->d_tag == RELOC_TAG+1) /* DT_{RELA,REL}SZ */
140 dt_relocsz = dynp->d_un.d_val;
141 dynp++;
142 }
143
144 rend = (RELOC_TYPE *)((char *)dt_jmprel + dt_pltrelsz);
145 for (; dt_jmprel < rend; dt_jmprel++) {
146 const Elf_Sym *sp;
147
148 sp = dt_symtab + ELF_R_SYM(dt_jmprel->r_info);
149 if (!ELF_R_SYM(dt_jmprel->r_info) || sp->st_value != 0) {
150 Elf_Addr *ra = (Elf_Addr *)(dt_jmprel->r_offset + loff);
151 RELOC_JMPREL(dt_jmprel, sp, ra, loff, dt_pltgot);
152 }
153 }
154
155 rend = (RELOC_TYPE *)((char *)dt_reloc + dt_relocsz);
156 for (; dt_reloc < rend; dt_reloc++) {
157 Elf_Addr *ra;
158 const Elf_Sym *sp;
159
160 sp = dt_symtab + ELF_R_SYM(dt_reloc->r_info);
161 if (!ELF_R_SYM(dt_reloc->r_info) || sp->st_value != 0) {
162 ra = (Elf_Addr *)(dt_reloc->r_offset + loff);
163 RELOC_DYN(dt_reloc, sp, ra, loff);
164 }
165 }
166
167 /* do any RWX -> RX fixups for executable PLTs and apply GNU_RELRO */
168 phdp = (Elf_Phdr *)dl_data[AUX_phdr];
169 for (i = 0; i < dl_data[AUX_phnum]; i++, phdp++) {
170 switch (phdp->p_type) {
171 case PT_LOAD:
172 if ((phdp->p_flags & (PF_X | PF_W)) != (PF_X | PF_W))
173 break;
174 mprotect((void *)(phdp->p_vaddr + loff), phdp->p_memsz,
175 PROT_READ);
176 break;
177 case PT_GNU_RELRO:
178 relro_addr = (void *)(phdp->p_vaddr + loff);
179 relro_size = phdp->p_memsz;
180 /*
181 * GNU_RELRO (a) covers the GOT, and (b) comes after
182 * all LOAD sections, so if we found it then we're done
183 */
184 break;
185 }
186 }
187 }
188