xref: /openbsd-src/libexec/ld.so/boot.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: boot.c,v 1.14 2016/08/13 20:57:04 guenther 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 "stdlib.h"
48 
49 #include "../../lib/csu/os-note-elf.h"
50 
51 #if RELOC_TAG == DT_RELA
52 typedef	Elf_RelA	RELOC_TYPE;
53 #elif RELOC_TAG == DT_REL
54 typedef	Elf_Rel		RELOC_TYPE;
55 #else
56 # error "unknown RELOC_TAG"
57 #endif
58 
59 /* The set of dynamic tags that we're interested in for bootstrapping */
60 struct boot_dyn {
61 	RELOC_TYPE	*dt_reloc;	/* DT_RELA   or DT_REL */
62 	Elf_Addr	dt_relocsz;	/* DT_RELASZ or DT_RELSZ */
63 	Elf_Addr	*dt_pltgot;
64 	Elf_Addr	dt_pltrelsz;
65 	const Elf_Sym	*dt_symtab;
66 #ifdef HAVE_JMPREL
67 	RELOC_TYPE	*dt_jmprel;
68 #endif
69 #if DT_PROCNUM > 0
70 	u_long		dt_proc[DT_PROCNUM];
71 #endif
72 };
73 
74 /*
75  * Local decls.
76  */
77 void _dl_boot_bind(const long, long *, Elf_Dyn *);
78 
79 void
80 _dl_boot_bind(const long sp, long *dl_data, Elf_Dyn *dynp)
81 {
82 	struct boot_dyn	dynld;		/* Resolver data for the loader */
83 	AuxInfo		*auxstack;
84 	long		*stack;
85 	int		n, argc;
86 	char		**argv, **envp;
87 	long		loff;
88 	Elf_Addr	i;
89 	RELOC_TYPE	*rp;
90 
91 	/*
92 	 * Scan argument and environment vectors. Find dynamic
93 	 * data vector put after them.
94 	 */
95 	stack = (long *)sp;
96 	argc = *stack++;
97 	argv = (char **)stack;
98 	envp = &argv[argc + 1];
99 	stack = (long *)envp;
100 	while (*stack++ != 0L)
101 		;
102 
103 	/*
104 	 * Zero out dl_data.
105 	 */
106 	for (n = 0; n <= AUX_entry; n++)
107 		dl_data[n] = 0;
108 
109 	/*
110 	 * Dig out auxiliary data set up by exec call. Move all known
111 	 * tags to an indexed local table for easy access.
112 	 */
113 	for (auxstack = (AuxInfo *)stack; auxstack->au_id != AUX_null;
114 	    auxstack++) {
115 		if (auxstack->au_id > AUX_entry)
116 			continue;
117 		dl_data[auxstack->au_id] = auxstack->au_v;
118 	}
119 	loff = dl_data[AUX_base];	/* XXX assumes ld.so is linked at 0x0 */
120 
121 	/*
122 	 * We need to do 'selfreloc' in case the code weren't
123 	 * loaded at the address it was linked to.
124 	 *
125 	 * Scan the DYNAMIC section for the loader.
126 	 * Cache the data for easier access.
127 	 */
128 	_dl_memset(&dynld, 0, sizeof(dynld));
129 	while (dynp->d_tag != DT_NULL) {
130 		/* first the tags that are pointers to be relocated */
131 		if (dynp->d_tag == DT_PLTGOT)
132 			dynld.dt_pltgot = (void *)(dynp->d_un.d_ptr + loff);
133 		else if (dynp->d_tag == DT_SYMTAB)
134 			dynld.dt_symtab = (void *)(dynp->d_un.d_ptr + loff);
135 		else if (dynp->d_tag == RELOC_TAG)	/* DT_{RELA,REL} */
136 			dynld.dt_reloc = (void *)(dynp->d_un.d_ptr + loff);
137 #ifdef HAVE_JMPREL
138 		else if (dynp->d_tag == DT_JMPREL)
139 			dynld.dt_jmprel = (void *)(dynp->d_un.d_ptr + loff);
140 #endif
141 
142 		/* Now for the tags that are just sizes or counts */
143 		else if (dynp->d_tag == DT_PLTRELSZ)
144 			dynld.dt_pltrelsz = dynp->d_un.d_val;
145 		else if (dynp->d_tag == RELOC_TAG+1)	/* DT_{RELA,REL}SZ */
146 			dynld.dt_relocsz = dynp->d_un.d_val;
147 #if DT_PROCNUM > 0
148 		else if (dynp->d_tag >= DT_LOPROC &&
149 		    dynp->d_tag < DT_LOPROC + DT_PROCNUM)
150 			dynld.dt_proc[dynp->d_tag - DT_LOPROC] =
151 			    dynp->d_un.d_val;
152 #endif /* DT_PROCNUM */
153 		dynp++;
154 	}
155 
156 #ifdef HAVE_JMPREL
157 	rp = dynld.dt_jmprel;
158 	for (i = 0; i < dynld.dt_pltrelsz; i += sizeof *rp) {
159 		Elf_Addr *ra;
160 		const Elf_Sym *sp;
161 
162 		sp = dynld.dt_symtab + ELF_R_SYM(rp->r_info);
163 		if (ELF_R_SYM(rp->r_info) && sp->st_value == 0)
164 			_dl_exit(5);
165 
166 		ra = (Elf_Addr *)(rp->r_offset + loff);
167 		RELOC_JMPREL(rp, sp, ra, loff, dynld.dt_pltgot);
168 		rp++;
169 	}
170 #endif /* HAVE_JMPREL */
171 
172 	rp = dynld.dt_reloc;
173 	for (i = 0; i < dynld.dt_relocsz; i += sizeof *rp) {
174 		Elf_Addr *ra;
175 		const Elf_Sym *sp;
176 
177 		sp = dynld.dt_symtab + ELF_R_SYM(rp->r_info);
178 		if (ELF_R_SYM(rp->r_info) && sp->st_value == 0)
179 			_dl_exit(6);
180 
181 		ra = (Elf_Addr *)(rp->r_offset + loff);
182 		RELOC_DYN(rp, sp, ra, loff);
183 		rp++;
184 	}
185 
186 	RELOC_GOT(&dynld, loff);
187 
188 	/*
189 	 * we have been fully relocated here, so most things no longer
190 	 * need the loff adjustment
191 	 */
192 }
193