xref: /openbsd-src/sys/lib/libsa/loadfile_elf.c (revision 174697beef01c2f6add49ad98dbc1dc953740c31)
1 /* $NetBSD: loadfile.c,v 1.10 2000/12/03 02:53:04 tsutsui Exp $ */
2 /* $OpenBSD: loadfile_elf.c,v 1.17 2020/10/26 04:04:31 visa Exp $ */
3 
4 /*-
5  * Copyright (c) 1997 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10  * NASA Ames Research Center and by Christos Zoulas.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*
35  * Copyright (c) 1992, 1993
36  *	The Regents of the University of California.  All rights reserved.
37  *
38  * This code is derived from software contributed to Berkeley by
39  * Ralph Campbell.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. Neither the name of the University nor the names of its contributors
50  *    may be used to endorse or promote products derived from this software
51  *    without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63  * SUCH DAMAGE.
64  *
65  *	@(#)boot.c	8.1 (Berkeley) 6/10/93
66  */
67 
68 #include <lib/libsa/arc4.h>
69 
70 int ELFNAME(exec)(int, Elf_Ehdr *, uint64_t *, int);
71 
72 int
ELFNAME(exec)73 ELFNAME(exec)(int fd, Elf_Ehdr *elf, uint64_t *marks, int flags)
74 {
75 	Elf_Shdr *shp;
76 	Elf_Phdr *phdr;
77 	Elf_Off off;
78 	int i;
79 	size_t sz;
80 	int first;
81 	int havesyms;
82 	paddr_t minp = ~0, maxp = 0, pos = 0;
83 	paddr_t offset = marks[MARK_START], shpp, elfp;
84 
85 	sz = elf->e_phnum * sizeof(Elf_Phdr);
86 	phdr = ALLOC(sz);
87 
88 	if (lseek(fd, (off_t)elf->e_phoff, SEEK_SET) == -1)  {
89 		WARN(("lseek phdr"));
90 		FREE(phdr, sz);
91 		return 1;
92 	}
93 	if (read(fd, phdr, sz) != sz) {
94 		WARN(("read program headers"));
95 		FREE(phdr, sz);
96 		return 1;
97 	}
98 
99 	for (first = 1, i = 0; i < elf->e_phnum; i++) {
100 		if (phdr[i].p_type == PT_OPENBSD_RANDOMIZE) {
101 
102 			/* Fill segment if asked for. */
103 			if (flags & LOAD_RANDOM) {
104 				extern struct rc4_ctx randomctx;
105 
106 				rc4_getbytes(&randomctx,
107 				    (void *)LOADADDR(phdr[i].p_paddr),
108 				    phdr[i].p_filesz);
109 			}
110 			if (flags & (LOAD_RANDOM | COUNT_RANDOM)) {
111 				marks[MARK_RANDOM] = LOADADDR(phdr[i].p_paddr);
112 				marks[MARK_ERANDOM] =
113 				    marks[MARK_RANDOM] + phdr[i].p_filesz;
114 			}
115 			continue;
116 		}
117 
118 		if (phdr[i].p_type != PT_LOAD ||
119 		    (phdr[i].p_flags & (PF_W|PF_R|PF_X)) == 0)
120 			continue;
121 
122 #ifdef CHECK_PHDR
123 		if (CHECK_PHDR(ELFSIZE, &phdr[i])) {
124 			FREE(phdr, sz);
125 			return 1;
126 		}
127 #endif
128 
129 #define IS_TEXT(p)	(p.p_flags & PF_X)
130 #define IS_DATA(p)	((p.p_flags & PF_X) == 0)
131 #define IS_BSS(p)	(p.p_filesz < p.p_memsz)
132 		/*
133 		 * XXX: Assume first address is lowest
134 		 */
135 		if ((IS_TEXT(phdr[i]) && (flags & LOAD_TEXT)) ||
136 		    (IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
137 
138 			/* Read in segment. */
139 			PROGRESS(("%s%lu", first ? "" : "+",
140 			    (u_long)phdr[i].p_filesz));
141 
142 			if (lseek(fd, (off_t)phdr[i].p_offset, SEEK_SET) == -1) {
143 				WARN(("lseek text"));
144 				FREE(phdr, sz);
145 				return 1;
146 			}
147 			if (READ(fd, phdr[i].p_paddr, phdr[i].p_filesz) !=
148 			    phdr[i].p_filesz) {
149 				WARN(("read text"));
150 				FREE(phdr, sz);
151 				return 1;
152 			}
153 
154 			first = 0;
155 		}
156 
157 		if ((IS_TEXT(phdr[i]) && (flags & (LOAD_TEXT | COUNT_TEXT))) ||
158 		    (IS_DATA(phdr[i]) && (flags & (LOAD_DATA | COUNT_TEXT)))) {
159 			pos = phdr[i].p_paddr;
160 			if (minp > pos)
161 				minp = pos;
162 			pos += phdr[i].p_filesz;
163 			if (maxp < pos)
164 				maxp = pos;
165 		}
166 
167 		/* Zero out BSS. */
168 		if (IS_BSS(phdr[i]) && (flags & LOAD_BSS)) {
169 			PROGRESS(("+%lu",
170 			    (u_long)(phdr[i].p_memsz - phdr[i].p_filesz)));
171 			BZERO((phdr[i].p_paddr + phdr[i].p_filesz),
172 			    phdr[i].p_memsz - phdr[i].p_filesz);
173 		}
174 		if (IS_BSS(phdr[i]) && (flags & (LOAD_BSS|COUNT_BSS))) {
175 			pos += phdr[i].p_memsz - phdr[i].p_filesz;
176 			if (maxp < pos)
177 				maxp = pos;
178 		}
179 	}
180 	FREE(phdr, sz);
181 
182 	/*
183 	 * Copy the ELF and section headers.
184 	 */
185 	elfp = maxp = roundup(maxp, sizeof(Elf_Addr));
186 	if (flags & (LOAD_HDR | COUNT_HDR))
187 		maxp += sizeof(Elf_Ehdr);
188 
189 	if (flags & (LOAD_SYM | COUNT_SYM)) {
190 		if (lseek(fd, (off_t)elf->e_shoff, SEEK_SET) == -1)  {
191 			WARN(("lseek section headers"));
192 			return 1;
193 		}
194 		sz = elf->e_shnum * sizeof(Elf_Shdr);
195 		shp = ALLOC(sz);
196 
197 		if (read(fd, shp, sz) != sz) {
198 			WARN(("read section headers"));
199 			FREE(shp, sz);
200 			return 1;
201 		}
202 
203 		shpp = maxp;
204 		maxp += roundup(sz, sizeof(Elf_Addr));
205 
206 		size_t shstrsz = shp[elf->e_shstrndx].sh_size;
207 		char *shstr = ALLOC(shstrsz);
208 		if (lseek(fd, (off_t)shp[elf->e_shstrndx].sh_offset, SEEK_SET) == -1) {
209 			WARN(("lseek section header string table"));
210 			FREE(shstr, shstrsz);
211 			FREE(shp, sz);
212 			return 1;
213 		}
214 		if (read(fd, shstr, shstrsz) != shstrsz) {
215 			WARN(("read section header string table"));
216 			FREE(shstr, shstrsz);
217 			FREE(shp, sz);
218 			return 1;
219 		}
220 
221 		/*
222 		 * Now load the symbol sections themselves. Make sure the
223 		 * sections are aligned. Don't bother with string tables if
224 		 * there are no symbol sections.
225 		 */
226 		off = roundup((sizeof(Elf_Ehdr) + sz), sizeof(Elf_Addr));
227 
228 		for (havesyms = i = 0; i < elf->e_shnum; i++)
229 			if (shp[i].sh_type == SHT_SYMTAB)
230 				havesyms = 1;
231 
232 		for (first = 1, i = 0; i < elf->e_shnum; i++) {
233 			if (shp[i].sh_type == SHT_SYMTAB ||
234 			    shp[i].sh_type == SHT_STRTAB ||
235 			    !strcmp(shstr + shp[i].sh_name, ".debug_line") ||
236 			    !strcmp(shstr + shp[i].sh_name, ELF_CTF)) {
237 				if (havesyms && (flags & LOAD_SYM)) {
238 					PROGRESS(("%s%ld", first ? " [" : "+",
239 					    (u_long)shp[i].sh_size));
240 					if (lseek(fd, (off_t)shp[i].sh_offset,
241 					    SEEK_SET) == -1) {
242 						WARN(("lseek symbols"));
243 						FREE(shstr, shstrsz);
244 						FREE(shp, sz);
245 						return 1;
246 					}
247 					if (READ(fd, maxp, shp[i].sh_size) !=
248 					    shp[i].sh_size) {
249 						WARN(("read symbols"));
250 						FREE(shstr, shstrsz);
251 						FREE(shp, sz);
252 						return 1;
253 					}
254 				}
255 				maxp += roundup(shp[i].sh_size,
256 				    sizeof(Elf_Addr));
257 				shp[i].sh_offset = off;
258 				shp[i].sh_flags |= SHF_ALLOC;
259 				off += roundup(shp[i].sh_size, sizeof(Elf_Addr));
260 				first = 0;
261 			}
262 		}
263 		if (flags & LOAD_SYM) {
264 			BCOPY(shp, shpp, sz);
265 
266 			if (havesyms && first == 0)
267 				PROGRESS(("]"));
268 		}
269 		FREE(shstr, shstrsz);
270 		FREE(shp, sz);
271 	}
272 
273 	/*
274 	 * Frob the copied ELF header to give information relative
275 	 * to elfp.
276 	 */
277 	if (flags & LOAD_HDR) {
278 		elf->e_phoff = 0;
279 		elf->e_shoff = sizeof(Elf_Ehdr);
280 		elf->e_phentsize = 0;
281 		elf->e_phnum = 0;
282 		BCOPY(elf, elfp, sizeof(*elf));
283 	}
284 
285 	marks[MARK_START] = LOADADDR(minp);
286 	marks[MARK_ENTRY] = LOADADDR(elf->e_entry);
287 	marks[MARK_VENTRY] = elf->e_entry;
288 	marks[MARK_NSYM] = 1;	/* XXX: Kernel needs >= 0 */
289 	marks[MARK_SYM] = LOADADDR(elfp);
290 	marks[MARK_END] = LOADADDR(maxp);
291 
292 	return 0;
293 }
294