File: | kern/exec_elf.c |
Warning: | line 946, column 8 Although the value stored to 'error' is used in the enclosing expression, the value is never actually read from 'error' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: exec_elf.c,v 1.183 2023/07/12 19:34:14 jasper Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 1996 Per Fogelstrom |
5 | * All rights reserved. |
6 | * |
7 | * Copyright (c) 1994 Christos Zoulas |
8 | * All rights reserved. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * 3. The name of the author may not be used to endorse or promote products |
19 | * derived from this software without specific prior written permission |
20 | * |
21 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
22 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
23 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
24 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
26 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
27 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
28 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
30 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31 | * |
32 | */ |
33 | |
34 | /* |
35 | * Copyright (c) 2001 Wasabi Systems, Inc. |
36 | * All rights reserved. |
37 | * |
38 | * Written by Jason R. Thorpe for Wasabi Systems, Inc. |
39 | * |
40 | * Redistribution and use in source and binary forms, with or without |
41 | * modification, are permitted provided that the following conditions |
42 | * are met: |
43 | * 1. Redistributions of source code must retain the above copyright |
44 | * notice, this list of conditions and the following disclaimer. |
45 | * 2. Redistributions in binary form must reproduce the above copyright |
46 | * notice, this list of conditions and the following disclaimer in the |
47 | * documentation and/or other materials provided with the distribution. |
48 | * 3. All advertising materials mentioning features or use of this software |
49 | * must display the following acknowledgement: |
50 | * This product includes software developed for the NetBSD Project by |
51 | * Wasabi Systems, Inc. |
52 | * 4. The name of Wasabi Systems, Inc. may not be used to endorse |
53 | * or promote products derived from this software without specific prior |
54 | * written permission. |
55 | * |
56 | * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND |
57 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
58 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
59 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC |
60 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
61 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
62 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
63 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
64 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
65 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
66 | * POSSIBILITY OF SUCH DAMAGE. |
67 | */ |
68 | |
69 | #include <sys/param.h> |
70 | #include <sys/systm.h> |
71 | #include <sys/proc.h> |
72 | #include <sys/malloc.h> |
73 | #include <sys/pool.h> |
74 | #include <sys/mount.h> |
75 | #include <sys/namei.h> |
76 | #include <sys/vnode.h> |
77 | #include <sys/core.h> |
78 | #include <sys/exec.h> |
79 | #include <sys/exec_elf.h> |
80 | #include <sys/fcntl.h> |
81 | #include <sys/ptrace.h> |
82 | #include <sys/signalvar.h> |
83 | #include <sys/pledge.h> |
84 | |
85 | #include <sys/mman.h> |
86 | |
87 | #include <uvm/uvm_extern.h> |
88 | |
89 | #include <machine/reg.h> |
90 | #include <machine/exec.h> |
91 | |
92 | int elf_load_file(struct proc *, char *, struct exec_package *, |
93 | struct elf_args *); |
94 | int elf_check_header(Elf_EhdrElf64_Ehdr *); |
95 | int elf_read_from(struct proc *, struct vnode *, u_long, void *, int); |
96 | void elf_load_psection(struct exec_vmcmd_set *, struct vnode *, |
97 | Elf_PhdrElf64_Phdr *, Elf_AddrElf64_Addr *, Elf_AddrElf64_Addr *, int *, int); |
98 | int elf_os_pt_note_name(Elf_NoteElf64_Note *); |
99 | int elf_os_pt_note(struct proc *, struct exec_package *, Elf_EhdrElf64_Ehdr *, int *); |
100 | |
101 | /* round up and down to page boundaries. */ |
102 | #define ELF_ROUND(a, b)(((a) + (b) - 1) & ~((b) - 1)) (((a) + (b) - 1) & ~((b) - 1)) |
103 | #define ELF_TRUNC(a, b)((a) & ~((b) - 1)) ((a) & ~((b) - 1)) |
104 | |
105 | /* |
106 | * We limit the number of program headers to 32, this should |
107 | * be a reasonable limit for ELF, the most we have seen so far is 12 |
108 | */ |
109 | #define ELF_MAX_VALID_PHDR32 32 |
110 | |
111 | #define ELF_NOTE_NAME_OPENBSD0x01 0x01 |
112 | |
113 | struct elf_note_name { |
114 | char *name; |
115 | int id; |
116 | } elf_note_names[] = { |
117 | { "OpenBSD", ELF_NOTE_NAME_OPENBSD0x01 }, |
118 | }; |
119 | |
120 | #define ELFROUNDSIZEsizeof(Elf64_Word) sizeof(Elf_WordElf64_Word) |
121 | #define elfround(x)(((((x))+((sizeof(Elf64_Word))-1))/(sizeof(Elf64_Word)))*(sizeof (Elf64_Word))) roundup((x), ELFROUNDSIZE)(((((x))+((sizeof(Elf64_Word))-1))/(sizeof(Elf64_Word)))*(sizeof (Elf64_Word))) |
122 | |
123 | |
124 | /* |
125 | * Check header for validity; return 0 for ok, ENOEXEC if error |
126 | */ |
127 | int |
128 | elf_check_header(Elf_EhdrElf64_Ehdr *ehdr) |
129 | { |
130 | /* |
131 | * We need to check magic, class size, endianness, and version before |
132 | * we look at the rest of the Elf_Ehdr structure. These few elements |
133 | * are represented in a machine independent fashion. |
134 | */ |
135 | if (!IS_ELF(*ehdr)((*ehdr).e_ident[0] == 0x7f && (*ehdr).e_ident[1] == 'E' && (*ehdr).e_ident[2] == 'L' && (*ehdr).e_ident [3] == 'F') || |
136 | ehdr->e_ident[EI_CLASS4] != ELF_TARG_CLASS2 || |
137 | ehdr->e_ident[EI_DATA5] != ELF_TARG_DATA1 || |
138 | ehdr->e_ident[EI_VERSION6] != ELF_TARG_VER1) |
139 | return (ENOEXEC8); |
140 | |
141 | /* Now check the machine dependent header */ |
142 | if (ehdr->e_machine != ELF_TARG_MACH62 || |
143 | ehdr->e_version != ELF_TARG_VER1) |
144 | return (ENOEXEC8); |
145 | |
146 | /* Don't allow an insane amount of sections. */ |
147 | if (ehdr->e_phnum > ELF_MAX_VALID_PHDR32) |
148 | return (ENOEXEC8); |
149 | |
150 | return (0); |
151 | } |
152 | |
153 | /* |
154 | * Load a psection at the appropriate address |
155 | */ |
156 | void |
157 | elf_load_psection(struct exec_vmcmd_set *vcset, struct vnode *vp, |
158 | Elf_PhdrElf64_Phdr *ph, Elf_AddrElf64_Addr *addr, Elf_AddrElf64_Addr *size, int *prot, int flags) |
159 | { |
160 | u_long msize, lsize, psize, rm, rf; |
161 | long diff, offset, bdiff; |
162 | Elf_AddrElf64_Addr base; |
163 | |
164 | /* |
165 | * If the user specified an address, then we load there. |
166 | */ |
167 | if (*addr != ELF_NO_ADDR((__uint64_t) ~0)) { |
168 | if (ph->p_align > 1) { |
169 | *addr = ELF_TRUNC(*addr, ph->p_align)((*addr) & ~((ph->p_align) - 1)); |
170 | diff = ph->p_vaddr - ELF_TRUNC(ph->p_vaddr, ph->p_align)((ph->p_vaddr) & ~((ph->p_align) - 1)); |
171 | /* page align vaddr */ |
172 | base = *addr + trunc_page(ph->p_vaddr)((ph->p_vaddr) & ~((1 << 12) - 1)) |
173 | - ELF_TRUNC(ph->p_vaddr, ph->p_align)((ph->p_vaddr) & ~((ph->p_align) - 1)); |
174 | } else { |
175 | diff = 0; |
176 | base = *addr + trunc_page(ph->p_vaddr)((ph->p_vaddr) & ~((1 << 12) - 1)) - ph->p_vaddr; |
177 | } |
178 | } else { |
179 | *addr = ph->p_vaddr; |
180 | if (ph->p_align > 1) |
181 | *addr = ELF_TRUNC(*addr, ph->p_align)((*addr) & ~((ph->p_align) - 1)); |
182 | base = trunc_page(ph->p_vaddr)((ph->p_vaddr) & ~((1 << 12) - 1)); |
183 | diff = ph->p_vaddr - *addr; |
184 | } |
185 | bdiff = ph->p_vaddr - trunc_page(ph->p_vaddr)((ph->p_vaddr) & ~((1 << 12) - 1)); |
186 | |
187 | /* |
188 | * Enforce W^X and map W|X segments without X permission |
189 | * initially. The dynamic linker will make these read-only |
190 | * and add back X permission after relocation processing. |
191 | * Static executables with W|X segments will probably crash. |
192 | */ |
193 | *prot |= (ph->p_flags & PF_R0x4) ? PROT_READ0x01 : 0; |
194 | *prot |= (ph->p_flags & PF_W0x2) ? PROT_WRITE0x02 : 0; |
195 | if ((ph->p_flags & PF_W0x2) == 0) |
196 | *prot |= (ph->p_flags & PF_X0x1) ? PROT_EXEC0x04 : 0; |
197 | |
198 | /* |
199 | * Apply immutability as much as possible, but not text/rodata |
200 | * segments of textrel binaries, or RELRO or PT_OPENBSD_MUTABLE |
201 | * sections, or LOADS marked PF_OPENBSD_MUTABLE, or LOADS which |
202 | * violate W^X. |
203 | * Userland (meaning crt0 or ld.so) will repair those regions. |
204 | */ |
205 | if ((ph->p_flags & (PF_X0x1 | PF_W0x2)) != (PF_X0x1 | PF_W0x2) && |
206 | ((ph->p_flags & PF_OPENBSD_MUTABLE0x08000000) == 0)) |
207 | flags |= VMCMD_IMMUTABLE0x0010; |
208 | if ((flags & VMCMD_TEXTREL0x0020) && (ph->p_flags & PF_W0x2) == 0) |
209 | flags &= ~VMCMD_IMMUTABLE0x0010; |
210 | |
211 | msize = ph->p_memsz + diff; |
212 | offset = ph->p_offset - bdiff; |
213 | lsize = ph->p_filesz + bdiff; |
214 | psize = round_page(lsize)(((lsize) + ((1 << 12) - 1)) & ~((1 << 12) - 1 )); |
215 | |
216 | /* |
217 | * Because the pagedvn pager can't handle zero fill of the last |
218 | * data page if it's not page aligned we map the last page readvn. |
219 | */ |
220 | if (ph->p_flags & PF_W0x2) { |
221 | psize = trunc_page(lsize)((lsize) & ~((1 << 12) - 1)); |
222 | if (psize > 0) |
223 | NEW_VMCMD2(vcset, vmcmd_map_pagedvn, psize, base, vp,do { struct exec_vmcmd *__vcp; if ((vcset)->evs_used >= (vcset)->evs_cnt) vmcmdset_extend(vcset); __vcp = &(vcset )->evs_cmds[(vcset)->evs_used++]; __vcp->ev_proc = ( vmcmd_map_pagedvn); __vcp->ev_len = (psize); __vcp->ev_addr = (base); if ((__vcp->ev_vp = (vp)) != ((struct vnode *)( (void *)0))) vref(vp); __vcp->ev_offset = (offset); __vcp-> ev_prot = (*prot); __vcp->ev_flags = (flags); } while (0) |
224 | offset, *prot, flags)do { struct exec_vmcmd *__vcp; if ((vcset)->evs_used >= (vcset)->evs_cnt) vmcmdset_extend(vcset); __vcp = &(vcset )->evs_cmds[(vcset)->evs_used++]; __vcp->ev_proc = ( vmcmd_map_pagedvn); __vcp->ev_len = (psize); __vcp->ev_addr = (base); if ((__vcp->ev_vp = (vp)) != ((struct vnode *)( (void *)0))) vref(vp); __vcp->ev_offset = (offset); __vcp-> ev_prot = (*prot); __vcp->ev_flags = (flags); } while (0); |
225 | if (psize != lsize) { |
226 | NEW_VMCMD2(vcset, vmcmd_map_readvn, lsize - psize,do { struct exec_vmcmd *__vcp; if ((vcset)->evs_used >= (vcset)->evs_cnt) vmcmdset_extend(vcset); __vcp = &(vcset )->evs_cmds[(vcset)->evs_used++]; __vcp->ev_proc = ( vmcmd_map_readvn); __vcp->ev_len = (lsize - psize); __vcp-> ev_addr = (base + psize); if ((__vcp->ev_vp = (vp)) != ((struct vnode *)((void *)0))) vref(vp); __vcp->ev_offset = (offset + psize); __vcp->ev_prot = (*prot); __vcp->ev_flags = ( flags); } while (0) |
227 | base + psize, vp, offset + psize, *prot, flags)do { struct exec_vmcmd *__vcp; if ((vcset)->evs_used >= (vcset)->evs_cnt) vmcmdset_extend(vcset); __vcp = &(vcset )->evs_cmds[(vcset)->evs_used++]; __vcp->ev_proc = ( vmcmd_map_readvn); __vcp->ev_len = (lsize - psize); __vcp-> ev_addr = (base + psize); if ((__vcp->ev_vp = (vp)) != ((struct vnode *)((void *)0))) vref(vp); __vcp->ev_offset = (offset + psize); __vcp->ev_prot = (*prot); __vcp->ev_flags = ( flags); } while (0); |
228 | } |
229 | } else { |
230 | NEW_VMCMD2(vcset, vmcmd_map_pagedvn, psize, base, vp, offset,do { struct exec_vmcmd *__vcp; if ((vcset)->evs_used >= (vcset)->evs_cnt) vmcmdset_extend(vcset); __vcp = &(vcset )->evs_cmds[(vcset)->evs_used++]; __vcp->ev_proc = ( vmcmd_map_pagedvn); __vcp->ev_len = (psize); __vcp->ev_addr = (base); if ((__vcp->ev_vp = (vp)) != ((struct vnode *)( (void *)0))) vref(vp); __vcp->ev_offset = (offset); __vcp-> ev_prot = (*prot); __vcp->ev_flags = (flags); } while (0) |
231 | *prot, flags)do { struct exec_vmcmd *__vcp; if ((vcset)->evs_used >= (vcset)->evs_cnt) vmcmdset_extend(vcset); __vcp = &(vcset )->evs_cmds[(vcset)->evs_used++]; __vcp->ev_proc = ( vmcmd_map_pagedvn); __vcp->ev_len = (psize); __vcp->ev_addr = (base); if ((__vcp->ev_vp = (vp)) != ((struct vnode *)( (void *)0))) vref(vp); __vcp->ev_offset = (offset); __vcp-> ev_prot = (*prot); __vcp->ev_flags = (flags); } while (0); |
232 | } |
233 | |
234 | /* |
235 | * Check if we need to extend the size of the segment |
236 | */ |
237 | rm = round_page(*addr + ph->p_memsz + diff)(((*addr + ph->p_memsz + diff) + ((1 << 12) - 1)) & ~((1 << 12) - 1)); |
238 | rf = round_page(*addr + ph->p_filesz + diff)(((*addr + ph->p_filesz + diff) + ((1 << 12) - 1)) & ~((1 << 12) - 1)); |
239 | |
240 | if (rm != rf) { |
241 | NEW_VMCMD2(vcset, vmcmd_map_zero, rm - rf, rf, NULLVP, 0,do { struct exec_vmcmd *__vcp; if ((vcset)->evs_used >= (vcset)->evs_cnt) vmcmdset_extend(vcset); __vcp = &(vcset )->evs_cmds[(vcset)->evs_used++]; __vcp->ev_proc = ( vmcmd_map_zero); __vcp->ev_len = (rm - rf); __vcp->ev_addr = (rf); if ((__vcp->ev_vp = (((struct vnode *)((void *)0) ))) != ((struct vnode *)((void *)0))) vref(((struct vnode *)( (void *)0))); __vcp->ev_offset = (0); __vcp->ev_prot = ( *prot); __vcp->ev_flags = (flags); } while (0) |
242 | *prot, flags)do { struct exec_vmcmd *__vcp; if ((vcset)->evs_used >= (vcset)->evs_cnt) vmcmdset_extend(vcset); __vcp = &(vcset )->evs_cmds[(vcset)->evs_used++]; __vcp->ev_proc = ( vmcmd_map_zero); __vcp->ev_len = (rm - rf); __vcp->ev_addr = (rf); if ((__vcp->ev_vp = (((struct vnode *)((void *)0) ))) != ((struct vnode *)((void *)0))) vref(((struct vnode *)( (void *)0))); __vcp->ev_offset = (0); __vcp->ev_prot = ( *prot); __vcp->ev_flags = (flags); } while (0); |
243 | } |
244 | *size = msize; |
245 | } |
246 | |
247 | /* |
248 | * Read from vnode into buffer at offset. |
249 | */ |
250 | int |
251 | elf_read_from(struct proc *p, struct vnode *vp, u_long off, void *buf, |
252 | int size) |
253 | { |
254 | int error; |
255 | size_t resid; |
256 | |
257 | if ((error = vn_rdwr(UIO_READ, vp, buf, size, off, UIO_SYSSPACE, |
258 | 0, p->p_ucred, &resid, p)) != 0) |
259 | return error; |
260 | /* |
261 | * See if we got all of it |
262 | */ |
263 | if (resid != 0) |
264 | return (ENOEXEC8); |
265 | return (0); |
266 | } |
267 | |
268 | /* |
269 | * Load a file (interpreter/library) pointed to by path [stolen from |
270 | * coff_load_shlib()]. Made slightly generic so it might be used externally. |
271 | */ |
272 | int |
273 | elf_load_file(struct proc *p, char *path, struct exec_package *epp, |
274 | struct elf_args *ap) |
275 | { |
276 | int error, i; |
277 | struct nameidata nd; |
278 | Elf_EhdrElf64_Ehdr eh; |
279 | Elf_PhdrElf64_Phdr *ph = NULL((void *)0); |
280 | u_long phsize = 0; |
281 | Elf_AddrElf64_Addr addr; |
282 | struct vnode *vp; |
283 | Elf_PhdrElf64_Phdr *base_ph = NULL((void *)0); |
284 | struct interp_ld_sec { |
285 | Elf_AddrElf64_Addr vaddr; |
286 | u_long memsz; |
287 | } loadmap[ELF_MAX_VALID_PHDR32]; |
288 | int nload, idx = 0; |
289 | Elf_AddrElf64_Addr pos; |
290 | int file_align; |
291 | int loop; |
292 | size_t randomizequota = ELF_RANDOMIZE_LIMIT1024*1024; |
293 | |
294 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, path, p)ndinitat(&nd, 0, 0x0040 | 0x0004, UIO_SYSSPACE, -100, path , p); |
295 | nd.ni_pledge = PLEDGE_RPATH0x0000000000000001ULL; |
296 | nd.ni_unveil = UNVEIL_READ0x01; |
297 | if ((error = namei(&nd)) != 0) { |
298 | return (error); |
299 | } |
300 | vp = nd.ni_vp; |
301 | if (vp->v_type != VREG) { |
302 | error = EACCES13; |
303 | goto bad; |
304 | } |
305 | if ((error = VOP_GETATTR(vp, epp->ep_vap, p->p_ucred, p)) != 0) |
306 | goto bad; |
307 | if (vp->v_mount->mnt_flag & MNT_NOEXEC0x00000004) { |
308 | error = EACCES13; |
309 | goto bad; |
310 | } |
311 | if ((error = VOP_ACCESS(vp, VREAD00400, p->p_ucred, p)) != 0) |
312 | goto bad1; |
313 | if ((error = elf_read_from(p, nd.ni_vp, 0, &eh, sizeof(eh))) != 0) |
314 | goto bad1; |
315 | |
316 | if (elf_check_header(&eh) || eh.e_type != ET_DYN3) { |
317 | error = ENOEXEC8; |
318 | goto bad1; |
319 | } |
320 | |
321 | ph = mallocarray(eh.e_phnum, sizeof(Elf_PhdrElf64_Phdr), M_TEMP127, M_WAITOK0x0001); |
322 | phsize = eh.e_phnum * sizeof(Elf_PhdrElf64_Phdr); |
323 | |
324 | if ((error = elf_read_from(p, nd.ni_vp, eh.e_phoff, ph, phsize)) != 0) |
325 | goto bad1; |
326 | |
327 | for (i = 0; i < eh.e_phnum; i++) { |
328 | if ((ph[i].p_align > 1) && !powerof2(ph[i].p_align)((((ph[i].p_align)-1)&(ph[i].p_align))==0)) { |
329 | error = EINVAL22; |
330 | goto bad1; |
331 | } |
332 | |
333 | if (ph[i].p_type == PT_LOAD1) { |
334 | if (ph[i].p_filesz > ph[i].p_memsz || |
335 | ph[i].p_memsz == 0) { |
336 | error = EINVAL22; |
337 | goto bad1; |
338 | } |
339 | loadmap[idx].vaddr = trunc_page(ph[i].p_vaddr)((ph[i].p_vaddr) & ~((1 << 12) - 1)); |
340 | loadmap[idx].memsz = round_page (ph[i].p_vaddr +(((ph[i].p_vaddr + ph[i].p_memsz - loadmap[idx].vaddr) + ((1 << 12) - 1)) & ~((1 << 12) - 1)) |
341 | ph[i].p_memsz - loadmap[idx].vaddr)(((ph[i].p_vaddr + ph[i].p_memsz - loadmap[idx].vaddr) + ((1 << 12) - 1)) & ~((1 << 12) - 1)); |
342 | file_align = ph[i].p_align; |
343 | idx++; |
344 | } |
345 | } |
346 | nload = idx; |
347 | |
348 | /* |
349 | * Load the interpreter where a non-fixed mmap(NULL, ...) |
350 | * would (i.e. something safely out of the way). |
351 | */ |
352 | pos = uvm_map_hint(p->p_vmspace, PROT_EXEC0x04, VM_MIN_ADDRESS(1 << 12), |
353 | VM_MAXUSER_ADDRESS0x00007f7fffffc000); |
354 | pos = ELF_ROUND(pos, file_align)(((pos) + (file_align) - 1) & ~((file_align) - 1)); |
355 | |
356 | loop = 0; |
357 | for (i = 0; i < nload;/**/) { |
358 | vaddr_t addr; |
359 | struct uvm_object *uobj; |
360 | off_t uoff; |
361 | size_t size; |
362 | |
363 | #ifdef this_needs_fixing |
364 | if (i == 0) { |
365 | uobj = &vp->v_uvm.u_obj; |
366 | /* need to fix uoff */ |
367 | } else { |
368 | #endif |
369 | uobj = NULL((void *)0); |
370 | uoff = 0; |
371 | #ifdef this_needs_fixing |
372 | } |
373 | #endif |
374 | |
375 | addr = trunc_page(pos + loadmap[i].vaddr)((pos + loadmap[i].vaddr) & ~((1 << 12) - 1)); |
376 | size = round_page(addr + loadmap[i].memsz)(((addr + loadmap[i].memsz) + ((1 << 12) - 1)) & ~( (1 << 12) - 1)) - addr; |
377 | |
378 | /* CRAP - map_findspace does not avoid daddr+BRKSIZ */ |
379 | if ((addr + size > (vaddr_t)p->p_vmspace->vm_daddr) && |
380 | (addr < (vaddr_t)p->p_vmspace->vm_daddr + BRKSIZ((paddr_t)8*1024*1024*1024))) |
381 | addr = round_page((vaddr_t)p->p_vmspace->vm_daddr +((((vaddr_t)p->p_vmspace->vm_daddr + ((paddr_t)8*1024*1024 *1024)) + ((1 << 12) - 1)) & ~((1 << 12) - 1) ) |
382 | BRKSIZ)((((vaddr_t)p->p_vmspace->vm_daddr + ((paddr_t)8*1024*1024 *1024)) + ((1 << 12) - 1)) & ~((1 << 12) - 1) ); |
383 | |
384 | if (uvm_map_mquery(&p->p_vmspace->vm_map, &addr, size, |
385 | (i == 0 ? uoff : UVM_UNKNOWN_OFFSET((voff_t) -1)), 0) != 0) { |
386 | if (loop == 0) { |
387 | loop = 1; |
388 | i = 0; |
389 | pos = 0; |
390 | continue; |
391 | } |
392 | error = ENOMEM12; |
393 | goto bad1; |
394 | } |
395 | if (addr != pos + loadmap[i].vaddr) { |
396 | /* base changed. */ |
397 | pos = addr - trunc_page(loadmap[i].vaddr)((loadmap[i].vaddr) & ~((1 << 12) - 1)); |
398 | pos = ELF_ROUND(pos,file_align)(((pos) + (file_align) - 1) & ~((file_align) - 1)); |
399 | i = 0; |
400 | continue; |
401 | } |
402 | |
403 | i++; |
404 | } |
405 | |
406 | /* |
407 | * Load all the necessary sections |
408 | */ |
409 | for (i = 0; i < eh.e_phnum; i++) { |
410 | Elf_AddrElf64_Addr size = 0; |
411 | int prot = 0; |
412 | int flags; |
413 | |
414 | switch (ph[i].p_type) { |
415 | case PT_LOAD1: |
416 | if (base_ph == NULL((void *)0)) { |
417 | flags = VMCMD_BASE0x0002; |
418 | addr = pos; |
419 | base_ph = &ph[i]; |
420 | } else { |
421 | flags = VMCMD_RELATIVE0x0001; |
422 | addr = ph[i].p_vaddr - base_ph->p_vaddr; |
423 | } |
424 | elf_load_psection(&epp->ep_vmcmds, nd.ni_vp, |
425 | &ph[i], &addr, &size, &prot, flags | VMCMD_SYSCALL0x0008); |
426 | /* If entry is within this section it must be text */ |
427 | if (eh.e_entry >= ph[i].p_vaddr && |
428 | eh.e_entry < (ph[i].p_vaddr + size)) { |
429 | epp->ep_entry = addr + eh.e_entry - |
430 | ELF_TRUNC(ph[i].p_vaddr,ph[i].p_align)((ph[i].p_vaddr) & ~((ph[i].p_align) - 1)); |
431 | if (flags == VMCMD_RELATIVE0x0001) |
432 | epp->ep_entry += pos; |
433 | ap->arg_interp = pos; |
434 | } |
435 | addr += size; |
436 | break; |
437 | |
438 | case PT_PHDR6: |
439 | case PT_NOTE4: |
440 | break; |
441 | |
442 | case PT_OPENBSD_RANDOMIZE0x65a3dbe6: |
443 | if (ph[i].p_memsz > randomizequota) { |
444 | error = ENOMEM12; |
445 | goto bad1; |
446 | } |
447 | randomizequota -= ph[i].p_memsz; |
448 | NEW_VMCMD(&epp->ep_vmcmds, vmcmd_randomize,do { struct exec_vmcmd *__vcp; if ((&epp->ep_vmcmds)-> evs_used >= (&epp->ep_vmcmds)->evs_cnt) vmcmdset_extend (&epp->ep_vmcmds); __vcp = &(&epp->ep_vmcmds )->evs_cmds[(&epp->ep_vmcmds)->evs_used++]; __vcp ->ev_proc = (vmcmd_randomize); __vcp->ev_len = (ph[i].p_memsz ); __vcp->ev_addr = (ph[i].p_vaddr + pos); if ((__vcp-> ev_vp = (((struct vnode *)((void *)0)))) != ((struct vnode *) ((void *)0))) vref(((struct vnode *)((void *)0))); __vcp-> ev_offset = (0); __vcp->ev_prot = (0); __vcp->ev_flags = (0); } while (0) |
449 | ph[i].p_memsz, ph[i].p_vaddr + pos, NULLVP, 0, 0)do { struct exec_vmcmd *__vcp; if ((&epp->ep_vmcmds)-> evs_used >= (&epp->ep_vmcmds)->evs_cnt) vmcmdset_extend (&epp->ep_vmcmds); __vcp = &(&epp->ep_vmcmds )->evs_cmds[(&epp->ep_vmcmds)->evs_used++]; __vcp ->ev_proc = (vmcmd_randomize); __vcp->ev_len = (ph[i].p_memsz ); __vcp->ev_addr = (ph[i].p_vaddr + pos); if ((__vcp-> ev_vp = (((struct vnode *)((void *)0)))) != ((struct vnode *) ((void *)0))) vref(((struct vnode *)((void *)0))); __vcp-> ev_offset = (0); __vcp->ev_prot = (0); __vcp->ev_flags = (0); } while (0); |
450 | break; |
451 | |
452 | case PT_DYNAMIC2: |
453 | #if defined (__mips__) |
454 | /* DT_DEBUG is not ready on mips */ |
455 | NEW_VMCMD(&epp->ep_vmcmds, vmcmd_mutable,do { struct exec_vmcmd *__vcp; if ((&epp->ep_vmcmds)-> evs_used >= (&epp->ep_vmcmds)->evs_cnt) vmcmdset_extend (&epp->ep_vmcmds); __vcp = &(&epp->ep_vmcmds )->evs_cmds[(&epp->ep_vmcmds)->evs_used++]; __vcp ->ev_proc = (vmcmd_mutable); __vcp->ev_len = (ph[i].p_memsz ); __vcp->ev_addr = (ph[i].p_vaddr + pos); if ((__vcp-> ev_vp = (((struct vnode *)((void *)0)))) != ((struct vnode *) ((void *)0))) vref(((struct vnode *)((void *)0))); __vcp-> ev_offset = (0); __vcp->ev_prot = (0); __vcp->ev_flags = (0); } while (0) |
456 | ph[i].p_memsz, ph[i].p_vaddr + pos, NULLVP, 0, 0)do { struct exec_vmcmd *__vcp; if ((&epp->ep_vmcmds)-> evs_used >= (&epp->ep_vmcmds)->evs_cnt) vmcmdset_extend (&epp->ep_vmcmds); __vcp = &(&epp->ep_vmcmds )->evs_cmds[(&epp->ep_vmcmds)->evs_used++]; __vcp ->ev_proc = (vmcmd_mutable); __vcp->ev_len = (ph[i].p_memsz ); __vcp->ev_addr = (ph[i].p_vaddr + pos); if ((__vcp-> ev_vp = (((struct vnode *)((void *)0)))) != ((struct vnode *) ((void *)0))) vref(((struct vnode *)((void *)0))); __vcp-> ev_offset = (0); __vcp->ev_prot = (0); __vcp->ev_flags = (0); } while (0); |
457 | #endif |
458 | break; |
459 | case PT_GNU_RELRO0x6474e552: |
460 | case PT_OPENBSD_MUTABLE0x65a3dbe5: |
461 | NEW_VMCMD(&epp->ep_vmcmds, vmcmd_mutable,do { struct exec_vmcmd *__vcp; if ((&epp->ep_vmcmds)-> evs_used >= (&epp->ep_vmcmds)->evs_cnt) vmcmdset_extend (&epp->ep_vmcmds); __vcp = &(&epp->ep_vmcmds )->evs_cmds[(&epp->ep_vmcmds)->evs_used++]; __vcp ->ev_proc = (vmcmd_mutable); __vcp->ev_len = (ph[i].p_memsz ); __vcp->ev_addr = (ph[i].p_vaddr + pos); if ((__vcp-> ev_vp = (((struct vnode *)((void *)0)))) != ((struct vnode *) ((void *)0))) vref(((struct vnode *)((void *)0))); __vcp-> ev_offset = (0); __vcp->ev_prot = (0); __vcp->ev_flags = (0); } while (0) |
462 | ph[i].p_memsz, ph[i].p_vaddr + pos, NULLVP, 0, 0)do { struct exec_vmcmd *__vcp; if ((&epp->ep_vmcmds)-> evs_used >= (&epp->ep_vmcmds)->evs_cnt) vmcmdset_extend (&epp->ep_vmcmds); __vcp = &(&epp->ep_vmcmds )->evs_cmds[(&epp->ep_vmcmds)->evs_used++]; __vcp ->ev_proc = (vmcmd_mutable); __vcp->ev_len = (ph[i].p_memsz ); __vcp->ev_addr = (ph[i].p_vaddr + pos); if ((__vcp-> ev_vp = (((struct vnode *)((void *)0)))) != ((struct vnode *) ((void *)0))) vref(((struct vnode *)((void *)0))); __vcp-> ev_offset = (0); __vcp->ev_prot = (0); __vcp->ev_flags = (0); } while (0); |
463 | break; |
464 | |
465 | default: |
466 | break; |
467 | } |
468 | } |
469 | |
470 | vn_marktext(nd.ni_vp); |
471 | |
472 | bad1: |
473 | VOP_CLOSE(nd.ni_vp, FREAD0x0001, p->p_ucred, p); |
474 | bad: |
475 | free(ph, M_TEMP127, phsize); |
476 | |
477 | vput(nd.ni_vp); |
478 | return (error); |
479 | } |
480 | |
481 | /* |
482 | * Prepare an Elf binary's exec package |
483 | * |
484 | * First, set of the various offsets/lengths in the exec package. |
485 | * |
486 | * Then, mark the text image busy (so it can be demand paged) or error out if |
487 | * this is not possible. Finally, set up vmcmds for the text, data, bss, and |
488 | * stack segments. |
489 | */ |
490 | int |
491 | exec_elf_makecmds(struct proc *p, struct exec_package *epp) |
492 | { |
493 | Elf_EhdrElf64_Ehdr *eh = epp->ep_hdr; |
494 | Elf_PhdrElf64_Phdr *ph, *pp, *base_ph = NULL((void *)0); |
495 | Elf_AddrElf64_Addr phdr = 0, exe_base = 0; |
496 | int error, i, has_phdr = 0, names = 0, textrel = 0; |
497 | char *interp = NULL((void *)0); |
498 | u_long phsize; |
499 | size_t randomizequota = ELF_RANDOMIZE_LIMIT1024*1024; |
500 | |
501 | if (epp->ep_hdrvalid < sizeof(Elf_EhdrElf64_Ehdr)) |
502 | return (ENOEXEC8); |
503 | |
504 | if (elf_check_header(eh) || |
505 | (eh->e_type != ET_EXEC2 && eh->e_type != ET_DYN3)) |
506 | return (ENOEXEC8); |
507 | |
508 | /* |
509 | * check if vnode is in open for writing, because we want to demand- |
510 | * page out of it. if it is, don't do it, for various reasons. |
511 | */ |
512 | if (epp->ep_vp->v_writecount != 0) { |
513 | #ifdef DIAGNOSTIC1 |
514 | if (epp->ep_vp->v_flag & VTEXT0x0002) |
515 | panic("exec: a VTEXT vnode has writecount != 0"); |
516 | #endif |
517 | return (ETXTBSY26); |
518 | } |
519 | /* |
520 | * Allocate space to hold all the program headers, and read them |
521 | * from the file |
522 | */ |
523 | ph = mallocarray(eh->e_phnum, sizeof(Elf_PhdrElf64_Phdr), M_TEMP127, M_WAITOK0x0001); |
524 | phsize = eh->e_phnum * sizeof(Elf_PhdrElf64_Phdr); |
525 | |
526 | if ((error = elf_read_from(p, epp->ep_vp, eh->e_phoff, ph, |
527 | phsize)) != 0) |
528 | goto bad; |
529 | |
530 | epp->ep_tsize = ELF_NO_ADDR((__uint64_t) ~0); |
531 | epp->ep_dsize = ELF_NO_ADDR((__uint64_t) ~0); |
532 | |
533 | for (i = 0, pp = ph; i < eh->e_phnum; i++, pp++) { |
534 | if ((pp->p_align > 1) && !powerof2(pp->p_align)((((pp->p_align)-1)&(pp->p_align))==0)) { |
535 | error = EINVAL22; |
536 | goto bad; |
537 | } |
538 | |
539 | if (pp->p_type == PT_INTERP3 && !interp) { |
540 | if (pp->p_filesz < 2 || pp->p_filesz > MAXPATHLEN1024) |
541 | goto bad; |
542 | interp = pool_get(&namei_pool, PR_WAITOK0x0001); |
543 | if ((error = elf_read_from(p, epp->ep_vp, |
544 | pp->p_offset, interp, pp->p_filesz)) != 0) { |
545 | goto bad; |
546 | } |
547 | if (interp[pp->p_filesz - 1] != '\0') |
548 | goto bad; |
549 | } else if (pp->p_type == PT_LOAD1) { |
550 | if (pp->p_filesz > pp->p_memsz || |
551 | pp->p_memsz == 0) { |
552 | error = EINVAL22; |
553 | goto bad; |
554 | } |
555 | if (base_ph == NULL((void *)0)) |
556 | base_ph = pp; |
557 | } else if (pp->p_type == PT_PHDR6) { |
558 | has_phdr = 1; |
559 | } |
560 | } |
561 | |
562 | /* |
563 | * Verify this is an OpenBSD executable. If it's marked that way |
564 | * via a PT_NOTE then also check for a PT_OPENBSD_WXNEEDED segment. |
565 | */ |
566 | if ((error = elf_os_pt_note(p, epp, epp->ep_hdr, &names)) != 0) |
567 | goto bad; |
568 | if (eh->e_ident[EI_OSABI7] == ELFOSABI_OPENBSD12) |
569 | names |= ELF_NOTE_NAME_OPENBSD0x01; |
570 | |
571 | if (eh->e_type == ET_DYN3) { |
572 | /* need phdr and load sections for PIE */ |
573 | if (!has_phdr || base_ph == NULL((void *)0) || base_ph->p_vaddr != 0) { |
574 | error = EINVAL22; |
575 | goto bad; |
576 | } |
577 | /* randomize exe_base for PIE */ |
578 | exe_base = uvm_map_pie(base_ph->p_align); |
579 | |
580 | /* |
581 | * Check if DYNAMIC contains DT_TEXTREL |
582 | */ |
583 | for (i = 0, pp = ph; i < eh->e_phnum; i++, pp++) { |
584 | Elf_DynElf64_Dyn *dt; |
585 | int j; |
586 | |
587 | switch (pp->p_type) { |
588 | case PT_DYNAMIC2: |
589 | if (pp->p_filesz > 64*1024) |
590 | break; |
591 | dt = malloc(pp->p_filesz, M_TEMP127, M_WAITOK0x0001); |
592 | error = vn_rdwr(UIO_READ, epp->ep_vp, |
593 | (caddr_t)dt, pp->p_filesz, pp->p_offset, |
594 | UIO_SYSSPACE, IO_UNIT0x01, p->p_ucred, NULL((void *)0), p); |
595 | if (error) { |
596 | free(dt, M_TEMP127, pp->p_filesz); |
597 | break; |
598 | } |
599 | for (j = 0; j < pp->p_filesz / sizeof(*dt); j++) { |
600 | if (dt[j].d_tag == DT_TEXTREL22) { |
601 | textrel = VMCMD_TEXTREL0x0020; |
602 | break; |
603 | } |
604 | } |
605 | free(dt, M_TEMP127, pp->p_filesz); |
606 | break; |
607 | default: |
608 | break; |
609 | } |
610 | } |
611 | } |
612 | |
613 | /* |
614 | * Load all the necessary sections |
615 | */ |
616 | for (i = 0, pp = ph; i < eh->e_phnum; i++, pp++) { |
617 | Elf_AddrElf64_Addr addr, size = 0; |
618 | int prot = 0, syscall = 0; |
619 | int flags = 0; |
620 | |
621 | switch (pp->p_type) { |
622 | case PT_LOAD1: |
623 | if (exe_base != 0) { |
624 | if (pp == base_ph) { |
625 | flags = VMCMD_BASE0x0002; |
626 | addr = exe_base; |
627 | } else { |
628 | flags = VMCMD_RELATIVE0x0001; |
629 | addr = pp->p_vaddr - base_ph->p_vaddr; |
630 | } |
631 | } else |
632 | addr = ELF_NO_ADDR((__uint64_t) ~0); |
633 | |
634 | /* |
635 | * Permit system calls in main-text static binaries. |
636 | * Also block the ld.so syscall-grant |
637 | */ |
638 | if (interp == NULL((void *)0)) { |
639 | syscall = VMCMD_SYSCALL0x0008; |
640 | p->p_vmspace->vm_map.flags |= VM_MAP_SYSCALL_ONCE0x80; |
641 | } |
642 | |
643 | /* |
644 | * Calculates size of text and data segments |
645 | * by starting at first and going to end of last. |
646 | * 'rwx' sections are treated as data. |
647 | * this is correct for BSS_PLT, but may not be |
648 | * for DATA_PLT, is fine for TEXT_PLT. |
649 | */ |
650 | elf_load_psection(&epp->ep_vmcmds, epp->ep_vp, |
651 | pp, &addr, &size, &prot, flags | textrel | syscall); |
652 | |
653 | /* |
654 | * Update exe_base in case alignment was off. |
655 | * For PIE, addr is relative to exe_base so |
656 | * adjust it (non PIE exe_base is 0 so no change). |
657 | */ |
658 | if (flags == VMCMD_BASE0x0002) |
659 | exe_base = addr; |
660 | else |
661 | addr += exe_base; |
662 | |
663 | /* |
664 | * Decide whether it's text or data by looking |
665 | * at the protection of the section |
666 | */ |
667 | if (prot & PROT_WRITE0x02) { |
668 | /* data section */ |
669 | if (epp->ep_dsize == ELF_NO_ADDR((__uint64_t) ~0)) { |
670 | epp->ep_daddr = addr; |
671 | epp->ep_dsize = size; |
672 | } else { |
673 | if (addr < epp->ep_daddr) { |
674 | epp->ep_dsize = |
675 | epp->ep_dsize + |
676 | epp->ep_daddr - |
677 | addr; |
678 | epp->ep_daddr = addr; |
679 | } else |
680 | epp->ep_dsize = addr+size - |
681 | epp->ep_daddr; |
682 | } |
683 | } else if (prot & PROT_EXEC0x04) { |
684 | /* text section */ |
685 | if (epp->ep_tsize == ELF_NO_ADDR((__uint64_t) ~0)) { |
686 | epp->ep_taddr = addr; |
687 | epp->ep_tsize = size; |
688 | } else { |
689 | if (addr < epp->ep_taddr) { |
690 | epp->ep_tsize = |
691 | epp->ep_tsize + |
692 | epp->ep_taddr - |
693 | addr; |
694 | epp->ep_taddr = addr; |
695 | } else |
696 | epp->ep_tsize = addr+size - |
697 | epp->ep_taddr; |
698 | } |
699 | } |
700 | break; |
701 | |
702 | case PT_SHLIB5: |
703 | error = ENOEXEC8; |
704 | goto bad; |
705 | |
706 | case PT_INTERP3: |
707 | /* Already did this one */ |
708 | case PT_NOTE4: |
709 | break; |
710 | |
711 | case PT_PHDR6: |
712 | /* Note address of program headers (in text segment) */ |
713 | phdr = pp->p_vaddr; |
714 | break; |
715 | |
716 | case PT_OPENBSD_RANDOMIZE0x65a3dbe6: |
717 | if (ph[i].p_memsz > randomizequota) { |
718 | error = ENOMEM12; |
719 | goto bad; |
720 | } |
721 | randomizequota -= ph[i].p_memsz; |
722 | NEW_VMCMD(&epp->ep_vmcmds, vmcmd_randomize,do { struct exec_vmcmd *__vcp; if ((&epp->ep_vmcmds)-> evs_used >= (&epp->ep_vmcmds)->evs_cnt) vmcmdset_extend (&epp->ep_vmcmds); __vcp = &(&epp->ep_vmcmds )->evs_cmds[(&epp->ep_vmcmds)->evs_used++]; __vcp ->ev_proc = (vmcmd_randomize); __vcp->ev_len = (ph[i].p_memsz ); __vcp->ev_addr = (ph[i].p_vaddr + exe_base); if ((__vcp ->ev_vp = (((struct vnode *)((void *)0)))) != ((struct vnode *)((void *)0))) vref(((struct vnode *)((void *)0))); __vcp-> ev_offset = (0); __vcp->ev_prot = (0); __vcp->ev_flags = (0); } while (0) |
723 | ph[i].p_memsz, ph[i].p_vaddr + exe_base, NULLVP, 0, 0)do { struct exec_vmcmd *__vcp; if ((&epp->ep_vmcmds)-> evs_used >= (&epp->ep_vmcmds)->evs_cnt) vmcmdset_extend (&epp->ep_vmcmds); __vcp = &(&epp->ep_vmcmds )->evs_cmds[(&epp->ep_vmcmds)->evs_used++]; __vcp ->ev_proc = (vmcmd_randomize); __vcp->ev_len = (ph[i].p_memsz ); __vcp->ev_addr = (ph[i].p_vaddr + exe_base); if ((__vcp ->ev_vp = (((struct vnode *)((void *)0)))) != ((struct vnode *)((void *)0))) vref(((struct vnode *)((void *)0))); __vcp-> ev_offset = (0); __vcp->ev_prot = (0); __vcp->ev_flags = (0); } while (0); |
724 | break; |
725 | |
726 | case PT_DYNAMIC2: |
727 | #if defined (__mips__) |
728 | /* DT_DEBUG is not ready on mips */ |
729 | NEW_VMCMD(&epp->ep_vmcmds, vmcmd_mutable,do { struct exec_vmcmd *__vcp; if ((&epp->ep_vmcmds)-> evs_used >= (&epp->ep_vmcmds)->evs_cnt) vmcmdset_extend (&epp->ep_vmcmds); __vcp = &(&epp->ep_vmcmds )->evs_cmds[(&epp->ep_vmcmds)->evs_used++]; __vcp ->ev_proc = (vmcmd_mutable); __vcp->ev_len = (ph[i].p_memsz ); __vcp->ev_addr = (ph[i].p_vaddr + exe_base); if ((__vcp ->ev_vp = (((struct vnode *)((void *)0)))) != ((struct vnode *)((void *)0))) vref(((struct vnode *)((void *)0))); __vcp-> ev_offset = (0); __vcp->ev_prot = (0); __vcp->ev_flags = (0); } while (0) |
730 | ph[i].p_memsz, ph[i].p_vaddr + exe_base, NULLVP, 0, 0)do { struct exec_vmcmd *__vcp; if ((&epp->ep_vmcmds)-> evs_used >= (&epp->ep_vmcmds)->evs_cnt) vmcmdset_extend (&epp->ep_vmcmds); __vcp = &(&epp->ep_vmcmds )->evs_cmds[(&epp->ep_vmcmds)->evs_used++]; __vcp ->ev_proc = (vmcmd_mutable); __vcp->ev_len = (ph[i].p_memsz ); __vcp->ev_addr = (ph[i].p_vaddr + exe_base); if ((__vcp ->ev_vp = (((struct vnode *)((void *)0)))) != ((struct vnode *)((void *)0))) vref(((struct vnode *)((void *)0))); __vcp-> ev_offset = (0); __vcp->ev_prot = (0); __vcp->ev_flags = (0); } while (0); |
731 | #endif |
732 | break; |
733 | case PT_GNU_RELRO0x6474e552: |
734 | case PT_OPENBSD_MUTABLE0x65a3dbe5: |
735 | NEW_VMCMD(&epp->ep_vmcmds, vmcmd_mutable,do { struct exec_vmcmd *__vcp; if ((&epp->ep_vmcmds)-> evs_used >= (&epp->ep_vmcmds)->evs_cnt) vmcmdset_extend (&epp->ep_vmcmds); __vcp = &(&epp->ep_vmcmds )->evs_cmds[(&epp->ep_vmcmds)->evs_used++]; __vcp ->ev_proc = (vmcmd_mutable); __vcp->ev_len = (ph[i].p_memsz ); __vcp->ev_addr = (ph[i].p_vaddr + exe_base); if ((__vcp ->ev_vp = (((struct vnode *)((void *)0)))) != ((struct vnode *)((void *)0))) vref(((struct vnode *)((void *)0))); __vcp-> ev_offset = (0); __vcp->ev_prot = (0); __vcp->ev_flags = (0); } while (0) |
736 | ph[i].p_memsz, ph[i].p_vaddr + exe_base, NULLVP, 0, 0)do { struct exec_vmcmd *__vcp; if ((&epp->ep_vmcmds)-> evs_used >= (&epp->ep_vmcmds)->evs_cnt) vmcmdset_extend (&epp->ep_vmcmds); __vcp = &(&epp->ep_vmcmds )->evs_cmds[(&epp->ep_vmcmds)->evs_used++]; __vcp ->ev_proc = (vmcmd_mutable); __vcp->ev_len = (ph[i].p_memsz ); __vcp->ev_addr = (ph[i].p_vaddr + exe_base); if ((__vcp ->ev_vp = (((struct vnode *)((void *)0)))) != ((struct vnode *)((void *)0))) vref(((struct vnode *)((void *)0))); __vcp-> ev_offset = (0); __vcp->ev_prot = (0); __vcp->ev_flags = (0); } while (0); |
737 | break; |
738 | |
739 | default: |
740 | /* |
741 | * Not fatal, we don't need to understand everything |
742 | * :-) |
743 | */ |
744 | break; |
745 | } |
746 | } |
747 | |
748 | phdr += exe_base; |
749 | |
750 | /* |
751 | * Strangely some linux programs may have all load sections marked |
752 | * writeable, in this case, textsize is not -1, but rather 0; |
753 | */ |
754 | if (epp->ep_tsize == ELF_NO_ADDR((__uint64_t) ~0)) |
755 | epp->ep_tsize = 0; |
756 | /* |
757 | * Another possibility is that it has all load sections marked |
758 | * read-only. Fake a zero-sized data segment right after the |
759 | * text segment. |
760 | */ |
761 | if (epp->ep_dsize == ELF_NO_ADDR((__uint64_t) ~0)) { |
762 | epp->ep_daddr = round_page(epp->ep_taddr + epp->ep_tsize)(((epp->ep_taddr + epp->ep_tsize) + ((1 << 12) - 1 )) & ~((1 << 12) - 1)); |
763 | epp->ep_dsize = 0; |
764 | } |
765 | |
766 | epp->ep_interp = interp; |
767 | epp->ep_entry = eh->e_entry + exe_base; |
768 | |
769 | /* |
770 | * Check if we found a dynamically linked binary and arrange to load |
771 | * its interpreter when the exec file is released. |
772 | */ |
773 | if (interp || eh->e_type == ET_DYN3) { |
774 | struct elf_args *ap; |
775 | |
776 | ap = malloc(sizeof(*ap), M_TEMP127, M_WAITOK0x0001); |
777 | |
778 | ap->arg_phaddr = phdr; |
779 | ap->arg_phentsize = eh->e_phentsize; |
780 | ap->arg_phnum = eh->e_phnum; |
781 | ap->arg_entry = eh->e_entry + exe_base; |
782 | ap->arg_interp = exe_base; |
783 | |
784 | epp->ep_args = ap; |
785 | } |
786 | |
787 | free(ph, M_TEMP127, phsize); |
788 | vn_marktext(epp->ep_vp); |
789 | return (exec_setup_stack(p, epp)); |
790 | |
791 | bad: |
792 | if (interp) |
793 | pool_put(&namei_pool, interp); |
794 | free(ph, M_TEMP127, phsize); |
795 | kill_vmcmds(&epp->ep_vmcmds); |
796 | if (error == 0) |
797 | return (ENOEXEC8); |
798 | return (error); |
799 | } |
800 | |
801 | /* |
802 | * Phase II of load. It is now safe to load the interpreter. Info collected |
803 | * when loading the program is available for setup of the interpreter. |
804 | */ |
805 | int |
806 | exec_elf_fixup(struct proc *p, struct exec_package *epp) |
807 | { |
808 | char *interp; |
809 | int error = 0; |
810 | struct elf_args *ap; |
811 | AuxInfoAux64Info ai[ELF_AUX_ENTRIES9], *a; |
812 | |
813 | ap = epp->ep_args; |
814 | if (ap == NULL((void *)0)) { |
815 | return (0); |
816 | } |
817 | |
818 | interp = epp->ep_interp; |
819 | |
820 | /* disable kbind in programs that don't use ld.so */ |
821 | if (interp == NULL((void *)0)) |
822 | p->p_p->ps_kbind_addr = BOGO_PC(u_long)-1; |
823 | |
824 | if (interp && |
825 | (error = elf_load_file(p, interp, epp, ap)) != 0) { |
826 | uprintf("execve: cannot load %s\n", interp); |
827 | free(ap, M_TEMP127, sizeof *ap); |
828 | pool_put(&namei_pool, interp); |
829 | kill_vmcmds(&epp->ep_vmcmds); |
830 | return (error); |
831 | } |
832 | /* |
833 | * We have to do this ourselves... |
834 | */ |
835 | error = exec_process_vmcmds(p, epp); |
836 | |
837 | /* |
838 | * Push extra arguments on the stack needed by dynamically |
839 | * linked binaries |
840 | */ |
841 | if (error == 0) { |
842 | memset(&ai, 0, sizeof ai)__builtin_memset((&ai), (0), (sizeof ai)); |
843 | a = ai; |
844 | |
845 | a->au_id = AUX_phdr; |
846 | a->au_v = ap->arg_phaddr; |
847 | a++; |
848 | |
849 | a->au_id = AUX_phent; |
850 | a->au_v = ap->arg_phentsize; |
851 | a++; |
852 | |
853 | a->au_id = AUX_phnum; |
854 | a->au_v = ap->arg_phnum; |
855 | a++; |
856 | |
857 | a->au_id = AUX_pagesz; |
858 | a->au_v = PAGE_SIZE(1 << 12); |
859 | a++; |
860 | |
861 | a->au_id = AUX_base; |
862 | a->au_v = ap->arg_interp; |
863 | a++; |
864 | |
865 | a->au_id = AUX_flags; |
866 | a->au_v = 0; |
867 | a++; |
868 | |
869 | a->au_id = AUX_entry; |
870 | a->au_v = ap->arg_entry; |
871 | a++; |
872 | |
873 | a->au_id = AUX_openbsd_timekeep; |
874 | a->au_v = p->p_p->ps_timekeep; |
875 | a++; |
876 | |
877 | a->au_id = AUX_null; |
878 | a->au_v = 0; |
879 | a++; |
880 | |
881 | error = copyout(ai, epp->ep_auxinfo, sizeof ai); |
882 | } |
883 | free(ap, M_TEMP127, sizeof *ap); |
884 | if (interp) |
885 | pool_put(&namei_pool, interp); |
886 | return (error); |
887 | } |
888 | |
889 | int |
890 | elf_os_pt_note_name(Elf_NoteElf64_Note *np) |
891 | { |
892 | int i, j; |
893 | |
894 | for (i = 0; i < nitems(elf_note_names)(sizeof((elf_note_names)) / sizeof((elf_note_names)[0])); i++) { |
895 | size_t namlen = strlen(elf_note_names[i].name); |
896 | if (np->namesz < namlen) |
897 | continue; |
898 | /* verify name padding (after the NUL) is NUL */ |
899 | for (j = namlen + 1; j < elfround(np->namesz)(((((np->namesz))+((sizeof(Elf64_Word))-1))/(sizeof(Elf64_Word )))*(sizeof(Elf64_Word))); j++) |
900 | if (((char *)(np + 1))[j] != '\0') |
901 | continue; |
902 | /* verify desc padding is NUL */ |
903 | for (j = np->descsz; j < elfround(np->descsz)(((((np->descsz))+((sizeof(Elf64_Word))-1))/(sizeof(Elf64_Word )))*(sizeof(Elf64_Word))); j++) |
904 | if (((char *)(np + 1))[j] != '\0') |
905 | continue; |
906 | if (strcmp((char *)(np + 1), elf_note_names[i].name) == 0) |
907 | return elf_note_names[i].id; |
908 | } |
909 | return (0); |
910 | } |
911 | |
912 | int |
913 | elf_os_pt_note(struct proc *p, struct exec_package *epp, Elf_EhdrElf64_Ehdr *eh, int *namesp) |
914 | { |
915 | Elf_PhdrElf64_Phdr *hph, *ph; |
916 | Elf_NoteElf64_Note *np = NULL((void *)0); |
917 | size_t phsize, offset, pfilesz = 0, total; |
918 | int error, names = 0; |
919 | |
920 | hph = mallocarray(eh->e_phnum, sizeof(Elf_PhdrElf64_Phdr), M_TEMP127, M_WAITOK0x0001); |
921 | phsize = eh->e_phnum * sizeof(Elf_PhdrElf64_Phdr); |
922 | if ((error = elf_read_from(p, epp->ep_vp, eh->e_phoff, |
923 | hph, phsize)) != 0) |
924 | goto out1; |
925 | |
926 | for (ph = hph; ph < &hph[eh->e_phnum]; ph++) { |
927 | if (ph->p_type == PT_OPENBSD_WXNEEDED0x65a3dbe7) { |
928 | epp->ep_flags |= EXEC_WXNEEDED0x0020; |
929 | continue; |
930 | } |
931 | if (ph->p_type == PT_OPENBSD_NOBTCFI0x65a3dbe8) { |
932 | epp->ep_flags |= EXEC_NOBTCFI0x0040; |
933 | continue; |
934 | } |
935 | |
936 | if (ph->p_type != PT_NOTE4 || ph->p_filesz > 1024) |
937 | continue; |
938 | |
939 | if (np && ph->p_filesz != pfilesz) { |
940 | free(np, M_TEMP127, pfilesz); |
941 | np = NULL((void *)0); |
942 | } |
943 | if (!np) |
944 | np = malloc(ph->p_filesz, M_TEMP127, M_WAITOK0x0001); |
945 | pfilesz = ph->p_filesz; |
946 | if ((error = elf_read_from(p, epp->ep_vp, ph->p_offset, |
Although the value stored to 'error' is used in the enclosing expression, the value is never actually read from 'error' | |
947 | np, ph->p_filesz)) != 0) |
948 | goto out2; |
949 | |
950 | for (offset = 0; offset < ph->p_filesz; offset += total) { |
951 | Elf_NoteElf64_Note *np2 = (Elf_NoteElf64_Note *)((char *)np + offset); |
952 | |
953 | if (offset + sizeof(Elf_NoteElf64_Note) > ph->p_filesz) |
954 | break; |
955 | total = sizeof(Elf_NoteElf64_Note) + elfround(np2->namesz)(((((np2->namesz))+((sizeof(Elf64_Word))-1))/(sizeof(Elf64_Word )))*(sizeof(Elf64_Word))) + |
956 | elfround(np2->descsz)(((((np2->descsz))+((sizeof(Elf64_Word))-1))/(sizeof(Elf64_Word )))*(sizeof(Elf64_Word))); |
957 | if (offset + total > ph->p_filesz) |
958 | break; |
959 | names |= elf_os_pt_note_name(np2); |
960 | } |
961 | } |
962 | |
963 | out2: |
964 | free(np, M_TEMP127, pfilesz); |
965 | out1: |
966 | free(hph, M_TEMP127, phsize); |
967 | *namesp = names; |
968 | return ((names & ELF_NOTE_NAME_OPENBSD0x01) ? 0 : ENOEXEC8); |
969 | } |
970 | |
971 | /* |
972 | * Start of routines related to dumping core |
973 | */ |
974 | |
975 | #ifdef SMALL_KERNEL |
976 | int |
977 | coredump_elf(struct proc *p, void *cookie) |
978 | { |
979 | return EPERM1; |
980 | } |
981 | #else /* !SMALL_KERNEL */ |
982 | |
983 | struct writesegs_state { |
984 | off_t notestart; |
985 | off_t secstart; |
986 | off_t secoff; |
987 | struct proc *p; |
988 | void *iocookie; |
989 | Elf_PhdrElf64_Phdr *psections; |
990 | size_t psectionslen; |
991 | size_t notesize; |
992 | int npsections; |
993 | }; |
994 | |
995 | uvm_coredump_setup_cb coredump_setup_elf; |
996 | uvm_coredump_walk_cb coredump_walk_elf; |
997 | |
998 | int coredump_notes_elf(struct proc *, void *, size_t *); |
999 | int coredump_note_elf(struct proc *, void *, size_t *); |
1000 | int coredump_writenote_elf(struct proc *, void *, Elf_NoteElf64_Note *, |
1001 | const char *, void *); |
1002 | |
1003 | extern vaddr_t sigcode_va; |
1004 | extern vsize_t sigcode_sz; |
1005 | |
1006 | int |
1007 | coredump_elf(struct proc *p, void *cookie) |
1008 | { |
1009 | #ifdef DIAGNOSTIC1 |
1010 | off_t offset; |
1011 | #endif |
1012 | struct writesegs_state ws; |
1013 | size_t notesize; |
1014 | int error, i; |
1015 | |
1016 | ws.p = p; |
1017 | ws.iocookie = cookie; |
1018 | ws.psections = NULL((void *)0); |
1019 | |
1020 | /* |
1021 | * Walk the map to get all the segment offsets and lengths, |
1022 | * write out the ELF header. |
1023 | */ |
1024 | error = uvm_coredump_walkmap(p, coredump_setup_elf, |
1025 | coredump_walk_elf, &ws); |
1026 | if (error) |
1027 | goto out; |
1028 | |
1029 | error = coredump_write(cookie, UIO_SYSSPACE, ws.psections, |
1030 | ws.psectionslen); |
1031 | if (error) |
1032 | goto out; |
1033 | |
1034 | /* Write out the notes. */ |
1035 | error = coredump_notes_elf(p, cookie, ¬esize); |
1036 | if (error) |
1037 | goto out; |
1038 | |
1039 | #ifdef DIAGNOSTIC1 |
1040 | if (notesize != ws.notesize) |
1041 | panic("coredump: notesize changed: %zu != %zu", |
1042 | ws.notesize, notesize); |
1043 | offset = ws.notestart + notesize; |
1044 | if (offset != ws.secstart) |
1045 | panic("coredump: offset %lld != secstart %lld", |
1046 | (long long) offset, (long long) ws.secstart); |
1047 | #endif |
1048 | |
1049 | /* Pass 3: finally, write the sections themselves. */ |
1050 | for (i = 0; i < ws.npsections - 1; i++) { |
1051 | Elf_PhdrElf64_Phdr *pent = &ws.psections[i]; |
1052 | if (pent->p_filesz == 0) |
1053 | continue; |
1054 | |
1055 | #ifdef DIAGNOSTIC1 |
1056 | if (offset != pent->p_offset) |
1057 | panic("coredump: offset %lld != p_offset[%d] %lld", |
1058 | (long long) offset, i, |
1059 | (long long) pent->p_filesz); |
1060 | #endif |
1061 | |
1062 | /* |
1063 | * Since the sigcode is mapped execute-only, we can't |
1064 | * read it. So use the kernel mapping for it instead. |
1065 | */ |
1066 | if (pent->p_vaddr == p->p_p->ps_sigcode && |
1067 | pent->p_filesz == sigcode_sz) { |
1068 | error = coredump_write(cookie, UIO_SYSSPACE, |
1069 | (void *)sigcode_va, sigcode_sz); |
1070 | } else { |
1071 | error = coredump_write(cookie, UIO_USERSPACE, |
1072 | (void *)(vaddr_t)pent->p_vaddr, pent->p_filesz); |
1073 | } |
1074 | if (error) |
1075 | goto out; |
1076 | |
1077 | coredump_unmap(cookie, (vaddr_t)pent->p_vaddr, |
1078 | (vaddr_t)pent->p_vaddr + pent->p_filesz); |
1079 | |
1080 | #ifdef DIAGNOSTIC1 |
1081 | offset += ws.psections[i].p_filesz; |
1082 | #endif |
1083 | } |
1084 | |
1085 | out: |
1086 | free(ws.psections, M_TEMP127, ws.psectionslen); |
1087 | return (error); |
1088 | } |
1089 | |
1090 | |
1091 | /* |
1092 | * Normally we lay out core files like this: |
1093 | * [ELF Header] [Program headers] [Notes] [data for PT_LOAD segments] |
1094 | * |
1095 | * However, if there's >= 65535 segments then it overflows the field |
1096 | * in the ELF header, so the standard specifies putting a magic |
1097 | * number there and saving the real count in the .sh_info field of |
1098 | * the first *section* header...which requires generating a section |
1099 | * header. To avoid confusing tools, we include an .shstrtab section |
1100 | * as well so all the indexes look valid. So in this case we lay |
1101 | * out the core file like this: |
1102 | * [ELF Header] [Section Headers] [.shstrtab] [Program headers] \ |
1103 | * [Notes] [data for PT_LOAD segments] |
1104 | * |
1105 | * The 'shstrtab' structure below is data for the second of the two |
1106 | * section headers, plus the .shstrtab itself, in one const buffer. |
1107 | */ |
1108 | static const struct { |
1109 | Elf_ShdrElf64_Shdr shdr; |
1110 | char shstrtab[sizeof(ELF_SHSTRTAB".shstrtab") + 1]; |
1111 | } shstrtab = { |
1112 | .shdr = { |
1113 | .sh_name = 1, /* offset in .shstrtab below */ |
1114 | .sh_type = SHT_STRTAB3, |
1115 | .sh_offset = sizeof(Elf_EhdrElf64_Ehdr) + 2*sizeof(Elf_ShdrElf64_Shdr), |
1116 | .sh_size = sizeof(ELF_SHSTRTAB".shstrtab") + 1, |
1117 | .sh_addralign = 1, |
1118 | }, |
1119 | .shstrtab = "\0" ELF_SHSTRTAB".shstrtab", |
1120 | }; |
1121 | |
1122 | int |
1123 | coredump_setup_elf(int segment_count, void *cookie) |
1124 | { |
1125 | Elf_EhdrElf64_Ehdr ehdr; |
1126 | struct writesegs_state *ws = cookie; |
1127 | Elf_PhdrElf64_Phdr *note; |
1128 | int error; |
1129 | |
1130 | /* Get the count of segments, plus one for the PT_NOTE */ |
1131 | ws->npsections = segment_count + 1; |
1132 | |
1133 | /* Get the size of the notes. */ |
1134 | error = coredump_notes_elf(ws->p, NULL((void *)0), &ws->notesize); |
1135 | if (error) |
1136 | return error; |
1137 | |
1138 | /* Setup the ELF header */ |
1139 | memset(&ehdr, 0, sizeof(ehdr))__builtin_memset((&ehdr), (0), (sizeof(ehdr))); |
1140 | memcpy(ehdr.e_ident, ELFMAG, SELFMAG)__builtin_memcpy((ehdr.e_ident), ("\177ELF"), (4)); |
1141 | ehdr.e_ident[EI_CLASS4] = ELF_TARG_CLASS2; |
1142 | ehdr.e_ident[EI_DATA5] = ELF_TARG_DATA1; |
1143 | ehdr.e_ident[EI_VERSION6] = EV_CURRENT1; |
1144 | /* XXX Should be the OSABI/ABI version of the executable. */ |
1145 | ehdr.e_ident[EI_OSABI7] = ELFOSABI_SYSV0; |
1146 | ehdr.e_ident[EI_ABIVERSION8] = 0; |
1147 | ehdr.e_type = ET_CORE4; |
1148 | /* XXX This should be the e_machine of the executable. */ |
1149 | ehdr.e_machine = ELF_TARG_MACH62; |
1150 | ehdr.e_version = EV_CURRENT1; |
1151 | ehdr.e_entry = 0; |
1152 | ehdr.e_flags = 0; |
1153 | ehdr.e_ehsize = sizeof(ehdr); |
1154 | ehdr.e_phentsize = sizeof(Elf_PhdrElf64_Phdr); |
1155 | |
1156 | if (ws->npsections < PN_XNUM0xffff) { |
1157 | ehdr.e_phoff = sizeof(ehdr); |
1158 | ehdr.e_shoff = 0; |
1159 | ehdr.e_phnum = ws->npsections; |
1160 | ehdr.e_shentsize = 0; |
1161 | ehdr.e_shnum = 0; |
1162 | ehdr.e_shstrndx = 0; |
1163 | } else { |
1164 | /* too many segments, use extension setup */ |
1165 | ehdr.e_shoff = sizeof(ehdr); |
1166 | ehdr.e_phnum = PN_XNUM0xffff; |
1167 | ehdr.e_shentsize = sizeof(Elf_ShdrElf64_Shdr); |
1168 | ehdr.e_shnum = 2; |
1169 | ehdr.e_shstrndx = 1; |
1170 | ehdr.e_phoff = shstrtab.shdr.sh_offset + shstrtab.shdr.sh_size; |
1171 | } |
1172 | |
1173 | /* Write out the ELF header. */ |
1174 | error = coredump_write(ws->iocookie, UIO_SYSSPACE, &ehdr, sizeof(ehdr)); |
1175 | if (error) |
1176 | return error; |
1177 | |
1178 | /* |
1179 | * If an section header is needed to store extension info, write |
1180 | * it out after the ELF header and before the program header. |
1181 | */ |
1182 | if (ehdr.e_shnum != 0) { |
1183 | Elf_ShdrElf64_Shdr shdr = { .sh_info = ws->npsections }; |
1184 | error = coredump_write(ws->iocookie, UIO_SYSSPACE, &shdr, |
1185 | sizeof shdr); |
1186 | if (error) |
1187 | return error; |
1188 | error = coredump_write(ws->iocookie, UIO_SYSSPACE, &shstrtab, |
1189 | sizeof(shstrtab.shdr) + sizeof(shstrtab.shstrtab)); |
1190 | if (error) |
1191 | return error; |
1192 | } |
1193 | |
1194 | /* |
1195 | * Allocate the segment header array and setup to collect |
1196 | * the section sizes and offsets |
1197 | */ |
1198 | ws->psections = mallocarray(ws->npsections, sizeof(Elf_PhdrElf64_Phdr), |
1199 | M_TEMP127, M_WAITOK0x0001|M_CANFAIL0x0004|M_ZERO0x0008); |
1200 | if (ws->psections == NULL((void *)0)) |
1201 | return ENOMEM12; |
1202 | ws->psectionslen = ws->npsections * sizeof(Elf_PhdrElf64_Phdr); |
1203 | |
1204 | ws->notestart = ehdr.e_phoff + ws->psectionslen; |
1205 | ws->secstart = ws->notestart + ws->notesize; |
1206 | ws->secoff = ws->secstart; |
1207 | |
1208 | /* Fill in the PT_NOTE segment header in the last slot */ |
1209 | note = &ws->psections[ws->npsections - 1]; |
1210 | note->p_type = PT_NOTE4; |
1211 | note->p_offset = ws->notestart; |
1212 | note->p_vaddr = 0; |
1213 | note->p_paddr = 0; |
1214 | note->p_filesz = ws->notesize; |
1215 | note->p_memsz = 0; |
1216 | note->p_flags = PF_R0x4; |
1217 | note->p_align = ELFROUNDSIZEsizeof(Elf64_Word); |
1218 | |
1219 | return (0); |
1220 | } |
1221 | |
1222 | int |
1223 | coredump_walk_elf(vaddr_t start, vaddr_t realend, vaddr_t end, vm_prot_t prot, |
1224 | int nsegment, void *cookie) |
1225 | { |
1226 | struct writesegs_state *ws = cookie; |
1227 | Elf_PhdrElf64_Phdr phdr; |
1228 | vsize_t size, realsize; |
1229 | |
1230 | size = end - start; |
1231 | realsize = realend - start; |
1232 | |
1233 | phdr.p_type = PT_LOAD1; |
1234 | phdr.p_offset = ws->secoff; |
1235 | phdr.p_vaddr = start; |
1236 | phdr.p_paddr = 0; |
1237 | phdr.p_filesz = realsize; |
1238 | phdr.p_memsz = size; |
1239 | phdr.p_flags = 0; |
1240 | if (prot & PROT_READ0x01) |
1241 | phdr.p_flags |= PF_R0x4; |
1242 | if (prot & PROT_WRITE0x02) |
1243 | phdr.p_flags |= PF_W0x2; |
1244 | if (prot & PROT_EXEC0x04) |
1245 | phdr.p_flags |= PF_X0x1; |
1246 | phdr.p_align = PAGE_SIZE(1 << 12); |
1247 | |
1248 | ws->secoff += phdr.p_filesz; |
1249 | ws->psections[nsegment] = phdr; |
1250 | |
1251 | return (0); |
1252 | } |
1253 | |
1254 | int |
1255 | coredump_notes_elf(struct proc *p, void *iocookie, size_t *sizep) |
1256 | { |
1257 | struct elfcore_procinfo cpi; |
1258 | Elf_NoteElf64_Note nhdr; |
1259 | struct process *pr = p->p_p; |
1260 | struct proc *q; |
1261 | size_t size, notesize; |
1262 | int error; |
1263 | |
1264 | KASSERT(!P_HASSIBLING(p) || pr->ps_single != NULL)((!((p)->p_p->ps_threadcnt > 1) || pr->ps_single != ((void *)0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/kern/exec_elf.c" , 1264, "!P_HASSIBLING(p) || pr->ps_single != NULL")); |
1265 | size = 0; |
1266 | |
1267 | /* First, write an elfcore_procinfo. */ |
1268 | notesize = sizeof(nhdr) + elfround(sizeof("OpenBSD"))(((((sizeof("OpenBSD")))+((sizeof(Elf64_Word))-1))/(sizeof(Elf64_Word )))*(sizeof(Elf64_Word))) + |
1269 | elfround(sizeof(cpi))(((((sizeof(cpi)))+((sizeof(Elf64_Word))-1))/(sizeof(Elf64_Word )))*(sizeof(Elf64_Word))); |
1270 | if (iocookie) { |
1271 | memset(&cpi, 0, sizeof(cpi))__builtin_memset((&cpi), (0), (sizeof(cpi))); |
1272 | |
1273 | cpi.cpi_version = ELFCORE_PROCINFO_VERSION1; |
1274 | cpi.cpi_cpisize = sizeof(cpi); |
1275 | cpi.cpi_signo = p->p_sisig; |
1276 | cpi.cpi_sigcode = p->p_sicode; |
1277 | |
1278 | cpi.cpi_sigpend = p->p_siglist | pr->ps_siglist; |
1279 | cpi.cpi_sigmask = p->p_sigmask; |
1280 | cpi.cpi_sigignore = pr->ps_sigacts->ps_sigignore; |
1281 | cpi.cpi_sigcatch = pr->ps_sigacts->ps_sigcatch; |
1282 | |
1283 | cpi.cpi_pid = pr->ps_pid; |
1284 | cpi.cpi_ppid = pr->ps_ppid; |
1285 | cpi.cpi_pgrp = pr->ps_pgidps_pgrp->pg_id; |
1286 | if (pr->ps_sessionps_pgrp->pg_session->s_leader) |
1287 | cpi.cpi_sid = pr->ps_sessionps_pgrp->pg_session->s_leader->ps_pid; |
1288 | else |
1289 | cpi.cpi_sid = 0; |
1290 | |
1291 | cpi.cpi_ruid = p->p_ucred->cr_ruid; |
1292 | cpi.cpi_euid = p->p_ucred->cr_uid; |
1293 | cpi.cpi_svuid = p->p_ucred->cr_svuid; |
1294 | |
1295 | cpi.cpi_rgid = p->p_ucred->cr_rgid; |
1296 | cpi.cpi_egid = p->p_ucred->cr_gid; |
1297 | cpi.cpi_svgid = p->p_ucred->cr_svgid; |
1298 | |
1299 | (void)strlcpy(cpi.cpi_name, pr->ps_comm, sizeof(cpi.cpi_name)); |
1300 | |
1301 | nhdr.namesz = sizeof("OpenBSD"); |
1302 | nhdr.descsz = sizeof(cpi); |
1303 | nhdr.type = NT_OPENBSD_PROCINFO10; |
1304 | |
1305 | error = coredump_writenote_elf(p, iocookie, &nhdr, |
1306 | "OpenBSD", &cpi); |
1307 | if (error) |
1308 | return (error); |
1309 | } |
1310 | size += notesize; |
1311 | |
1312 | /* Second, write an NT_OPENBSD_AUXV note. */ |
1313 | notesize = sizeof(nhdr) + elfround(sizeof("OpenBSD"))(((((sizeof("OpenBSD")))+((sizeof(Elf64_Word))-1))/(sizeof(Elf64_Word )))*(sizeof(Elf64_Word))) + |
1314 | elfround(ELF_AUX_WORDS * sizeof(char *))((((((sizeof(Aux64Info) * 9 / sizeof(char *)) * sizeof(char * )))+((sizeof(Elf64_Word))-1))/(sizeof(Elf64_Word)))*(sizeof(Elf64_Word ))); |
1315 | if (iocookie && pr->ps_auxinfo) { |
1316 | |
1317 | nhdr.namesz = sizeof("OpenBSD"); |
1318 | nhdr.descsz = ELF_AUX_WORDS(sizeof(Aux64Info) * 9 / sizeof(char *)) * sizeof(char *); |
1319 | nhdr.type = NT_OPENBSD_AUXV11; |
1320 | |
1321 | error = coredump_write(iocookie, UIO_SYSSPACE, |
1322 | &nhdr, sizeof(nhdr)); |
1323 | if (error) |
1324 | return (error); |
1325 | |
1326 | error = coredump_write(iocookie, UIO_SYSSPACE, |
1327 | "OpenBSD", elfround(nhdr.namesz)(((((nhdr.namesz))+((sizeof(Elf64_Word))-1))/(sizeof(Elf64_Word )))*(sizeof(Elf64_Word)))); |
1328 | if (error) |
1329 | return (error); |
1330 | |
1331 | error = coredump_write(iocookie, UIO_USERSPACE, |
1332 | (caddr_t)pr->ps_auxinfo, nhdr.descsz); |
1333 | if (error) |
1334 | return (error); |
1335 | } |
1336 | size += notesize; |
1337 | |
1338 | #ifdef PT_WCOOKIE |
1339 | notesize = sizeof(nhdr) + elfround(sizeof("OpenBSD"))(((((sizeof("OpenBSD")))+((sizeof(Elf64_Word))-1))/(sizeof(Elf64_Word )))*(sizeof(Elf64_Word))) + |
1340 | elfround(sizeof(register_t))(((((sizeof(register_t)))+((sizeof(Elf64_Word))-1))/(sizeof(Elf64_Word )))*(sizeof(Elf64_Word))); |
1341 | if (iocookie) { |
1342 | register_t wcookie; |
1343 | |
1344 | nhdr.namesz = sizeof("OpenBSD"); |
1345 | nhdr.descsz = sizeof(register_t); |
1346 | nhdr.type = NT_OPENBSD_WCOOKIE23; |
1347 | |
1348 | wcookie = process_get_wcookie(p); |
1349 | error = coredump_writenote_elf(p, iocookie, &nhdr, |
1350 | "OpenBSD", &wcookie); |
1351 | if (error) |
1352 | return (error); |
1353 | } |
1354 | size += notesize; |
1355 | #endif |
1356 | |
1357 | /* |
1358 | * Now write the register info for the thread that caused the |
1359 | * coredump. |
1360 | */ |
1361 | error = coredump_note_elf(p, iocookie, ¬esize); |
1362 | if (error) |
1363 | return (error); |
1364 | size += notesize; |
1365 | |
1366 | /* |
1367 | * Now, for each thread, write the register info and any other |
1368 | * per-thread notes. Since we're dumping core, all the other |
1369 | * threads in the process have been stopped and the list can't |
1370 | * change. |
1371 | */ |
1372 | TAILQ_FOREACH(q, &pr->ps_threads, p_thr_link)for((q) = ((&pr->ps_threads)->tqh_first); (q) != (( void *)0); (q) = ((q)->p_thr_link.tqe_next)) { |
1373 | if (q == p) /* we've taken care of this thread */ |
1374 | continue; |
1375 | error = coredump_note_elf(q, iocookie, ¬esize); |
1376 | if (error) |
1377 | return (error); |
1378 | size += notesize; |
1379 | } |
1380 | |
1381 | *sizep = size; |
1382 | return (0); |
1383 | } |
1384 | |
1385 | int |
1386 | coredump_note_elf(struct proc *p, void *iocookie, size_t *sizep) |
1387 | { |
1388 | Elf_NoteElf64_Note nhdr; |
1389 | int size, notesize, error; |
1390 | int namesize; |
1391 | char name[64+ELFROUNDSIZEsizeof(Elf64_Word)]; |
1392 | struct reg intreg; |
1393 | #ifdef PT_GETFPREGS(32 + 3) |
1394 | struct fpreg freg; |
1395 | #endif |
1396 | #ifdef PT_PACMASK |
1397 | register_t pacmask[2]; |
1398 | #endif |
1399 | |
1400 | size = 0; |
1401 | |
1402 | snprintf(name, sizeof(name)-ELFROUNDSIZEsizeof(Elf64_Word), "%s@%d", |
1403 | "OpenBSD", p->p_tid + THREAD_PID_OFFSET100000); |
1404 | namesize = strlen(name) + 1; |
1405 | memset(name + namesize, 0, elfround(namesize) - namesize)__builtin_memset((name + namesize), (0), ((((((namesize))+((sizeof (Elf64_Word))-1))/(sizeof(Elf64_Word)))*(sizeof(Elf64_Word))) - namesize)); |
1406 | |
1407 | notesize = sizeof(nhdr) + elfround(namesize)(((((namesize))+((sizeof(Elf64_Word))-1))/(sizeof(Elf64_Word) ))*(sizeof(Elf64_Word))) + elfround(sizeof(intreg))(((((sizeof(intreg)))+((sizeof(Elf64_Word))-1))/(sizeof(Elf64_Word )))*(sizeof(Elf64_Word))); |
1408 | if (iocookie) { |
1409 | error = process_read_regs(p, &intreg); |
1410 | if (error) |
1411 | return (error); |
1412 | |
1413 | nhdr.namesz = namesize; |
1414 | nhdr.descsz = sizeof(intreg); |
1415 | nhdr.type = NT_OPENBSD_REGS20; |
1416 | |
1417 | error = coredump_writenote_elf(p, iocookie, &nhdr, |
1418 | name, &intreg); |
1419 | if (error) |
1420 | return (error); |
1421 | |
1422 | } |
1423 | size += notesize; |
1424 | |
1425 | #ifdef PT_GETFPREGS(32 + 3) |
1426 | notesize = sizeof(nhdr) + elfround(namesize)(((((namesize))+((sizeof(Elf64_Word))-1))/(sizeof(Elf64_Word) ))*(sizeof(Elf64_Word))) + elfround(sizeof(freg))(((((sizeof(freg)))+((sizeof(Elf64_Word))-1))/(sizeof(Elf64_Word )))*(sizeof(Elf64_Word))); |
1427 | if (iocookie) { |
1428 | error = process_read_fpregs(p, &freg); |
1429 | if (error) |
1430 | return (error); |
1431 | |
1432 | nhdr.namesz = namesize; |
1433 | nhdr.descsz = sizeof(freg); |
1434 | nhdr.type = NT_OPENBSD_FPREGS21; |
1435 | |
1436 | error = coredump_writenote_elf(p, iocookie, &nhdr, name, &freg); |
1437 | if (error) |
1438 | return (error); |
1439 | } |
1440 | size += notesize; |
1441 | #endif |
1442 | |
1443 | #ifdef PT_PACMASK |
1444 | notesize = sizeof(nhdr) + elfround(namesize)(((((namesize))+((sizeof(Elf64_Word))-1))/(sizeof(Elf64_Word) ))*(sizeof(Elf64_Word))) + |
1445 | elfround(sizeof(pacmask))(((((sizeof(pacmask)))+((sizeof(Elf64_Word))-1))/(sizeof(Elf64_Word )))*(sizeof(Elf64_Word))); |
1446 | if (iocookie) { |
1447 | pacmask[0] = pacmask[1] = process_get_pacmask(p); |
1448 | |
1449 | nhdr.namesz = namesize; |
1450 | nhdr.descsz = sizeof(pacmask); |
1451 | nhdr.type = NT_OPENBSD_PACMASK24; |
1452 | |
1453 | error = coredump_writenote_elf(p, iocookie, &nhdr, |
1454 | name, &pacmask); |
1455 | if (error) |
1456 | return (error); |
1457 | } |
1458 | size += notesize; |
1459 | #endif |
1460 | |
1461 | *sizep = size; |
1462 | /* XXX Add hook for machdep per-LWP notes. */ |
1463 | return (0); |
1464 | } |
1465 | |
1466 | int |
1467 | coredump_writenote_elf(struct proc *p, void *cookie, Elf_NoteElf64_Note *nhdr, |
1468 | const char *name, void *data) |
1469 | { |
1470 | int error; |
1471 | |
1472 | error = coredump_write(cookie, UIO_SYSSPACE, nhdr, sizeof(*nhdr)); |
1473 | if (error) |
1474 | return error; |
1475 | |
1476 | error = coredump_write(cookie, UIO_SYSSPACE, name, |
1477 | elfround(nhdr->namesz)(((((nhdr->namesz))+((sizeof(Elf64_Word))-1))/(sizeof(Elf64_Word )))*(sizeof(Elf64_Word)))); |
1478 | if (error) |
1479 | return error; |
1480 | |
1481 | return coredump_write(cookie, UIO_SYSSPACE, data, nhdr->descsz); |
1482 | } |
1483 | #endif /* !SMALL_KERNEL */ |