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