1 /* $OpenBSD: boot.h,v 1.35 2023/11/18 16:26:15 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 #if RELOC_TAG == DT_RELA
56 typedef Elf_RelA RELOC_TYPE;
57 #elif RELOC_TAG == DT_REL
58 typedef Elf_Rel RELOC_TYPE;
59 #else
60 # error "unknown RELOC_TAG"
61 #endif
62
63 static void *relro_addr;
64 static size_t relro_size;
65 #define RCRT0_RELRO() \
66 do { \
67 if (relro_addr != NULL && relro_size != 0) { \
68 mprotect(relro_addr, relro_size, PROT_READ); \
69 mimmutable(relro_addr, relro_size); \
70 } \
71 } while (0)
72
73 /*
74 * Local decls.
75 */
76 void _dl_boot_bind(const long, long *, Elf_Dyn *);
77
78 void
_dl_boot_bind(const long sp,long * dl_data,Elf_Dyn * dynp)79 _dl_boot_bind(const long sp, long *dl_data, Elf_Dyn *dynp)
80 {
81 AuxInfo *auxstack;
82 long *stack;
83 int n, argc;
84 char **argv, **envp;
85 long loff;
86 RELOC_TYPE *dt_reloc, *rend; /* DT_RELA or DT_REL */
87 Elf_Word dt_relocsz; /* DT_RELASZ or DT_RELSZ */
88 const Elf_Sym *dt_symtab;
89 Elf_Phdr *phdp;
90 Elf_Addr i;
91
92 /*
93 * Scan argument and environment vectors. Find dynamic
94 * data vector put after them.
95 */
96 stack = (long *)sp;
97 argc = *stack++;
98 argv = (char **)stack;
99 envp = &argv[argc + 1];
100 stack = (long *)envp;
101 while (*stack++ != 0L)
102 ;
103
104 /*
105 * Zero out dl_data.
106 */
107 for (n = 0; n <= AUX_entry; n++)
108 dl_data[n] = 0;
109
110 /*
111 * Dig out auxiliary data set up by exec call. Move all known
112 * tags to an indexed local table for easy access.
113 */
114 for (auxstack = (AuxInfo *)stack; auxstack->au_id != AUX_null;
115 auxstack++) {
116 if (auxstack->au_id > AUX_entry)
117 continue;
118 dl_data[auxstack->au_id] = auxstack->au_v;
119 }
120 loff = dl_data[AUX_base]; /* XXX assumes ld.so is linked at 0x0 */
121
122 /*
123 * Scan the DYNAMIC section for the items we need
124 */
125 dt_reloc = NULL;
126 dt_relocsz = 0;
127 while (dynp->d_tag != DT_NULL) {
128 /* first the tags that are pointers to be relocated */
129 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
134 /* Now for the tags that are just sizes or counts */
135 else if (dynp->d_tag == RELOC_TAG+1) /* DT_{RELA,REL}SZ */
136 dt_relocsz = dynp->d_un.d_val;
137 dynp++;
138 }
139
140 rend = (RELOC_TYPE *)((char *)dt_reloc + dt_relocsz);
141 for (; dt_reloc < rend; dt_reloc++) {
142 Elf_Addr *ra;
143 const Elf_Sym *sp;
144
145 sp = dt_symtab + ELF_R_SYM(dt_reloc->r_info);
146 if (!ELF_R_SYM(dt_reloc->r_info) || sp->st_value != 0) {
147 ra = (Elf_Addr *)(dt_reloc->r_offset + loff);
148 RELOC_DYN(dt_reloc, sp, ra, loff);
149 }
150 }
151
152 /* do any RWX -> RX fixups for executable PLTs and apply GNU_RELRO */
153 phdp = (Elf_Phdr *)dl_data[AUX_phdr];
154 for (i = 0; i < dl_data[AUX_phnum]; i++, phdp++) {
155 switch (phdp->p_type) {
156 #if defined(__alpha__) || defined(__powerpc__) || defined(__sparc64__)
157 case PT_LOAD:
158 if ((phdp->p_flags & (PF_X | PF_W)) != (PF_X | PF_W))
159 break;
160 mprotect((void *)(phdp->p_vaddr + loff), phdp->p_memsz,
161 PROT_READ);
162 break;
163 #endif
164 case PT_GNU_RELRO:
165 relro_addr = (void *)(phdp->p_vaddr + loff);
166 relro_size = phdp->p_memsz;
167 /*
168 * GNU_RELRO (a) covers the GOT, and (b) comes after
169 * all LOAD sections, so if we found it then we're done
170 */
171 break;
172 }
173 }
174 }
175