1/* $OpenBSD: boot_md.h,v 1.5 2023/11/18 18:02:47 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 43void _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 52REDIRECT_SYSCALL(mprotect); 53REDIRECT_SYSCALL(mimmutable); 54 55#define DT_PROC(n) ((n) - DT_LOPROC) 56 57#if RELOC_TAG == DT_RELA 58typedef Elf_RelA RELOC_TYPE; 59#elif RELOC_TAG == DT_REL 60typedef Elf_Rel RELOC_TYPE; 61#else 62# error "unknown RELOC_TAG" 63#endif 64 65/* The set of dynamic tags that we're interested in for bootstrapping */ 66struct boot_dyn { 67 RELOC_TYPE *dt_reloc; /* DT_RELA or DT_REL */ 68 Elf_Addr dt_relocsz; /* DT_RELASZ or DT_RELSZ */ 69 Elf_Addr *dt_pltgot; 70 const Elf_Sym *dt_symtab; 71 u_long dt_proc[DT_PROCNUM]; 72}; 73 74static void *relro_addr; 75static size_t relro_size; 76#define RCRT0_RELRO() \ 77 do { \ 78 if (relro_addr != NULL && relro_size != 0) \ 79 mprotect(relro_addr, relro_size, PROT_READ); \ 80 mimmutable(relro_addr, relro_size); \ 81 } while (0) 82 83/* 84 * Local decls. 85 */ 86void _dl_boot_bind(const long, long *, Elf_Dyn *); 87 88void 89_dl_boot_bind(const long sp, long *dl_data, Elf_Dyn *dynp) 90{ 91 struct boot_dyn dynld; /* Resolver data for the loader */ 92 AuxInfo *auxstack; 93 long *stack; 94 int n, argc; 95 char **argv, **envp; 96 long loff; 97 RELOC_TYPE *rp; 98 Elf_Phdr *phdp; 99 Elf_Addr i; 100 101 /* 102 * Scan argument and environment vectors. Find dynamic 103 * data vector put after them. 104 */ 105 stack = (long *)sp; 106 argc = *stack++; 107 argv = (char **)stack; 108 envp = &argv[argc + 1]; 109 stack = (long *)envp; 110 while (*stack++ != 0L) 111 ; 112 113 /* 114 * Zero out dl_data. 115 */ 116 for (n = 0; n <= AUX_entry; n++) 117 dl_data[n] = 0; 118 119 /* 120 * Dig out auxiliary data set up by exec call. Move all known 121 * tags to an indexed local table for easy access. 122 */ 123 for (auxstack = (AuxInfo *)stack; auxstack->au_id != AUX_null; 124 auxstack++) { 125 if (auxstack->au_id > AUX_entry) 126 continue; 127 dl_data[auxstack->au_id] = auxstack->au_v; 128 } 129 loff = dl_data[AUX_base]; /* XXX assumes ld.so is linked at 0x0 */ 130 131 /* 132 * We need to do 'selfreloc' in case the code weren't 133 * loaded at the address it was linked to. 134 * 135 * Scan the DYNAMIC section for the loader. 136 * Cache the data for easier access. 137 */ 138 _dl_memset(&dynld, 0, sizeof(dynld)); 139 while (dynp->d_tag != DT_NULL) { 140 /* first the tags that are pointers to be relocated */ 141 if (dynp->d_tag == DT_PLTGOT) 142 dynld.dt_pltgot = (void *)(dynp->d_un.d_ptr + loff); 143 else if (dynp->d_tag == DT_SYMTAB) 144 dynld.dt_symtab = (void *)(dynp->d_un.d_ptr + loff); 145 else if (dynp->d_tag == RELOC_TAG) /* DT_{RELA,REL} */ 146 dynld.dt_reloc = (void *)(dynp->d_un.d_ptr + loff); 147 148 /* Now for the tags that are just sizes or counts */ 149 else if (dynp->d_tag == RELOC_TAG+1) /* DT_{RELA,REL}SZ */ 150 dynld.dt_relocsz = dynp->d_un.d_val; 151 else if (dynp->d_tag >= DT_LOPROC && 152 dynp->d_tag < DT_LOPROC + DT_PROCNUM) 153 dynld.dt_proc[dynp->d_tag - DT_LOPROC] = 154 dynp->d_un.d_val; 155 dynp++; 156 } 157 158 rp = dynld.dt_reloc; 159 for (i = 0; i < dynld.dt_relocsz; i += sizeof *rp) { 160 Elf_Addr *ra; 161 const Elf_Sym *sp; 162 163 sp = dynld.dt_symtab + ELF_R_SYM(rp->r_info); 164 if (!ELF_R_SYM(rp->r_info) || sp->st_value != 0) { 165 ra = (Elf_Addr *)(rp->r_offset + loff); 166 RELOC_DYN(rp, sp, ra, loff); 167 } 168 rp++; 169 } 170 171 RELOC_GOT(&dynld, loff); 172 173 /* apply GNU_RELRO */ 174 phdp = (Elf_Phdr *)dl_data[AUX_phdr]; 175 for (i = 0; i < dl_data[AUX_phnum]; i++, phdp++) { 176 switch (phdp->p_type) { 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