xref: /freebsd/sys/compat/linux/linux_elf.c (revision 3460fab5fced39c7ea597cc7de0ebc3e4c88989a)
1447636e4SEdward Tomasz Napierala /*-
2447636e4SEdward Tomasz Napierala  * SPDX-License-Identifier: BSD-3-Clause
3447636e4SEdward Tomasz Napierala  *
4447636e4SEdward Tomasz Napierala  * Copyright (c) 2021 Edward Tomasz Napierala <trasz@FreeBSD.org>
5447636e4SEdward Tomasz Napierala  * Copyright (c) 2018 Chuck Tuffli
6447636e4SEdward Tomasz Napierala  * Copyright (c) 2017 Dell EMC
7447636e4SEdward Tomasz Napierala  * Copyright (c) 2000 David O'Brien
8447636e4SEdward Tomasz Napierala  * Copyright (c) 1995-1996 Søren Schmidt
9447636e4SEdward Tomasz Napierala  * Copyright (c) 1996 Peter Wemm
10447636e4SEdward Tomasz Napierala  * All rights reserved.
11447636e4SEdward Tomasz Napierala  *
12447636e4SEdward Tomasz Napierala  * This software was developed by the University of Cambridge Computer
13447636e4SEdward Tomasz Napierala  * Laboratory as part of the CHERI for Hypervisors and Operating Systems
14447636e4SEdward Tomasz Napierala  * (CHaOS) project, funded by EPSRC grant EP/V000292/1.
15447636e4SEdward Tomasz Napierala  *
16447636e4SEdward Tomasz Napierala  * Redistribution and use in source and binary forms, with or without
17447636e4SEdward Tomasz Napierala  * modification, are permitted provided that the following conditions
18447636e4SEdward Tomasz Napierala  * are met:
19447636e4SEdward Tomasz Napierala  * 1. Redistributions of source code must retain the above copyright
20447636e4SEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer
21447636e4SEdward Tomasz Napierala  *    in this position and unchanged.
22447636e4SEdward Tomasz Napierala  * 2. Redistributions in binary form must reproduce the above copyright
23447636e4SEdward Tomasz Napierala  *    notice, this list of conditions and the following disclaimer in the
24447636e4SEdward Tomasz Napierala  *    documentation and/or other materials provided with the distribution.
25447636e4SEdward Tomasz Napierala  * 3. The name of the author may not be used to endorse or promote products
26447636e4SEdward Tomasz Napierala  *    derived from this software without specific prior written permission
27447636e4SEdward Tomasz Napierala  *
28447636e4SEdward Tomasz Napierala  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
29447636e4SEdward Tomasz Napierala  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
30447636e4SEdward Tomasz Napierala  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
31447636e4SEdward Tomasz Napierala  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
32447636e4SEdward Tomasz Napierala  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
33447636e4SEdward Tomasz Napierala  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34447636e4SEdward Tomasz Napierala  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35447636e4SEdward Tomasz Napierala  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36447636e4SEdward Tomasz Napierala  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
37447636e4SEdward Tomasz Napierala  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38447636e4SEdward Tomasz Napierala  */
39447636e4SEdward Tomasz Napierala 
40447636e4SEdward Tomasz Napierala #include <sys/param.h>
416039e966SDmitry Chagin #include <sys/exec.h>
42447636e4SEdward Tomasz Napierala #include <sys/imgact.h>
43447636e4SEdward Tomasz Napierala #include <sys/imgact_elf.h>
4406d5ef0aSEdward Tomasz Napierala #include <sys/lock.h>
4506d5ef0aSEdward Tomasz Napierala #include <sys/malloc.h>
4606d5ef0aSEdward Tomasz Napierala #include <sys/mutex.h>
47447636e4SEdward Tomasz Napierala #include <sys/proc.h>
48447636e4SEdward Tomasz Napierala #include <sys/procfs.h>
49b7924341SAndrew Turner #include <sys/reg.h>
50447636e4SEdward Tomasz Napierala #include <sys/sbuf.h>
516039e966SDmitry Chagin #include <sys/sysent.h>
526039e966SDmitry Chagin 
536039e966SDmitry Chagin #include <vm/vm.h>
546039e966SDmitry Chagin #include <vm/pmap.h>
556039e966SDmitry Chagin #include <vm/vm_map.h>
56447636e4SEdward Tomasz Napierala 
57447636e4SEdward Tomasz Napierala #include <machine/elf.h>
58447636e4SEdward Tomasz Napierala 
596f8439dbSDmitry Chagin #ifdef COMPAT_LINUX32
60447636e4SEdward Tomasz Napierala #define linux_pt_regset linux_pt_regset32
61447636e4SEdward Tomasz Napierala #define bsd_to_linux_regset bsd_to_linux_regset32
62447636e4SEdward Tomasz Napierala #include <machine/../linux32/linux.h>
63447636e4SEdward Tomasz Napierala #else
64447636e4SEdward Tomasz Napierala #include <machine/../linux/linux.h>
65447636e4SEdward Tomasz Napierala #endif
66447636e4SEdward Tomasz Napierala #include <compat/linux/linux_elf.h>
6795b86034SDmitry Chagin #include <compat/linux/linux_mib.h>
686039e966SDmitry Chagin #include <compat/linux/linux_misc.h>
69447636e4SEdward Tomasz Napierala 
7074465145SDmitry Chagin struct l_elf_siginfo {
7174465145SDmitry Chagin 	l_int		si_signo;
7274465145SDmitry Chagin 	l_int		si_code;
7374465145SDmitry Chagin 	l_int		si_errno;
7474465145SDmitry Chagin };
7574465145SDmitry Chagin 
7674465145SDmitry Chagin typedef struct linux_pt_regset l_elf_gregset_t;
7774465145SDmitry Chagin 
7874465145SDmitry Chagin struct linux_elf_prstatus {
7974465145SDmitry Chagin 	struct l_elf_siginfo pr_info;
8074465145SDmitry Chagin 	l_short		pr_cursig;
8174465145SDmitry Chagin 	l_ulong		pr_sigpend;
8274465145SDmitry Chagin 	l_ulong		pr_sighold;
8374465145SDmitry Chagin 	l_pid_t		pr_pid;
8474465145SDmitry Chagin 	l_pid_t		pr_ppid;
8574465145SDmitry Chagin 	l_pid_t		pr_pgrp;
8674465145SDmitry Chagin 	l_pid_t		pr_sid;
8774465145SDmitry Chagin 	l_timeval	pr_utime;
8874465145SDmitry Chagin 	l_timeval	pr_stime;
8974465145SDmitry Chagin 	l_timeval	pr_cutime;
9074465145SDmitry Chagin 	l_timeval	pr_cstime;
9174465145SDmitry Chagin 	l_elf_gregset_t	pr_reg;
9274465145SDmitry Chagin 	l_int		pr_fpvalid;
9374465145SDmitry Chagin };
94447636e4SEdward Tomasz Napierala 
95447636e4SEdward Tomasz Napierala #define	LINUX_NT_AUXV	6
96447636e4SEdward Tomasz Napierala 
97447636e4SEdward Tomasz Napierala static void __linuxN(note_fpregset)(void *, struct sbuf *, size_t *);
98447636e4SEdward Tomasz Napierala static void __linuxN(note_prpsinfo)(void *, struct sbuf *, size_t *);
99447636e4SEdward Tomasz Napierala static void __linuxN(note_prstatus)(void *, struct sbuf *, size_t *);
100447636e4SEdward Tomasz Napierala static void __linuxN(note_threadmd)(void *, struct sbuf *, size_t *);
101447636e4SEdward Tomasz Napierala static void __linuxN(note_nt_auxv)(void *, struct sbuf *, size_t *);
102447636e4SEdward Tomasz Napierala 
103447636e4SEdward Tomasz Napierala void
__linuxN(prepare_notes)104447636e4SEdward Tomasz Napierala __linuxN(prepare_notes)(struct thread *td, struct note_info_list *list,
105447636e4SEdward Tomasz Napierala     size_t *sizep)
106447636e4SEdward Tomasz Napierala {
107447636e4SEdward Tomasz Napierala 	struct proc *p;
108447636e4SEdward Tomasz Napierala 	struct thread *thr;
109447636e4SEdward Tomasz Napierala 	size_t size;
110447636e4SEdward Tomasz Napierala 
111447636e4SEdward Tomasz Napierala 	p = td->td_proc;
112447636e4SEdward Tomasz Napierala 	size = 0;
113447636e4SEdward Tomasz Napierala 
114447636e4SEdward Tomasz Napierala 	/*
115447636e4SEdward Tomasz Napierala 	 * To have the debugger select the right thread (LWP) as the initial
116447636e4SEdward Tomasz Napierala 	 * thread, we dump the state of the thread passed to us in td first.
117447636e4SEdward Tomasz Napierala 	 * This is the thread that causes the core dump and thus likely to
118447636e4SEdward Tomasz Napierala 	 * be the right thread one wants to have selected in the debugger.
119447636e4SEdward Tomasz Napierala 	 */
120447636e4SEdward Tomasz Napierala 	thr = td;
121447636e4SEdward Tomasz Napierala 	while (thr != NULL) {
122447636e4SEdward Tomasz Napierala 		size += __elfN(register_note)(td, list,
123447636e4SEdward Tomasz Napierala 		    NT_PRSTATUS, __linuxN(note_prstatus), thr);
124447636e4SEdward Tomasz Napierala 		size += __elfN(register_note)(td, list,
125447636e4SEdward Tomasz Napierala 		    NT_PRPSINFO, __linuxN(note_prpsinfo), p);
126447636e4SEdward Tomasz Napierala 		size += __elfN(register_note)(td, list,
127447636e4SEdward Tomasz Napierala 		    LINUX_NT_AUXV, __linuxN(note_nt_auxv), p);
128447636e4SEdward Tomasz Napierala 		size += __elfN(register_note)(td, list,
129447636e4SEdward Tomasz Napierala 		    NT_FPREGSET, __linuxN(note_fpregset), thr);
130447636e4SEdward Tomasz Napierala 		size += __elfN(register_note)(td, list,
131447636e4SEdward Tomasz Napierala 		    -1, __linuxN(note_threadmd), thr);
132447636e4SEdward Tomasz Napierala 
133447636e4SEdward Tomasz Napierala 		thr = thr == td ? TAILQ_FIRST(&p->p_threads) :
134447636e4SEdward Tomasz Napierala 		    TAILQ_NEXT(thr, td_plist);
135447636e4SEdward Tomasz Napierala 		if (thr == td)
136447636e4SEdward Tomasz Napierala 			thr = TAILQ_NEXT(thr, td_plist);
137447636e4SEdward Tomasz Napierala 	}
138447636e4SEdward Tomasz Napierala 
139447636e4SEdward Tomasz Napierala 	*sizep = size;
140447636e4SEdward Tomasz Napierala }
141447636e4SEdward Tomasz Napierala 
142447636e4SEdward Tomasz Napierala typedef struct linux_elf_prstatus linux_elf_prstatus_t;
1436f8439dbSDmitry Chagin #ifdef COMPAT_LINUX32
144447636e4SEdward Tomasz Napierala typedef struct prpsinfo32 linux_elf_prpsinfo_t;
145447636e4SEdward Tomasz Napierala typedef struct fpreg32 linux_elf_prfpregset_t;
146447636e4SEdward Tomasz Napierala #else
147447636e4SEdward Tomasz Napierala typedef prpsinfo_t linux_elf_prpsinfo_t;
148447636e4SEdward Tomasz Napierala typedef prfpregset_t linux_elf_prfpregset_t;
149447636e4SEdward Tomasz Napierala #endif
150447636e4SEdward Tomasz Napierala 
151447636e4SEdward Tomasz Napierala static void
__linuxN(note_prpsinfo)152447636e4SEdward Tomasz Napierala __linuxN(note_prpsinfo)(void *arg, struct sbuf *sb, size_t *sizep)
153447636e4SEdward Tomasz Napierala {
154447636e4SEdward Tomasz Napierala 	struct sbuf sbarg;
155447636e4SEdward Tomasz Napierala 	size_t len;
156447636e4SEdward Tomasz Napierala 	char *cp, *end;
157447636e4SEdward Tomasz Napierala 	struct proc *p;
158447636e4SEdward Tomasz Napierala 	linux_elf_prpsinfo_t *psinfo;
159447636e4SEdward Tomasz Napierala 	int error;
160447636e4SEdward Tomasz Napierala 
161447636e4SEdward Tomasz Napierala 	p = arg;
162447636e4SEdward Tomasz Napierala 	if (sb != NULL) {
163447636e4SEdward Tomasz Napierala 		KASSERT(*sizep == sizeof(*psinfo), ("invalid size"));
164447636e4SEdward Tomasz Napierala 		psinfo = malloc(sizeof(*psinfo), M_TEMP, M_ZERO | M_WAITOK);
165447636e4SEdward Tomasz Napierala 		psinfo->pr_version = PRPSINFO_VERSION;
166447636e4SEdward Tomasz Napierala 		psinfo->pr_psinfosz = sizeof(linux_elf_prpsinfo_t);
167447636e4SEdward Tomasz Napierala 		strlcpy(psinfo->pr_fname, p->p_comm, sizeof(psinfo->pr_fname));
168447636e4SEdward Tomasz Napierala 		PROC_LOCK(p);
169447636e4SEdward Tomasz Napierala 		if (p->p_args != NULL) {
170447636e4SEdward Tomasz Napierala 			len = sizeof(psinfo->pr_psargs) - 1;
171447636e4SEdward Tomasz Napierala 			if (len > p->p_args->ar_length)
172447636e4SEdward Tomasz Napierala 				len = p->p_args->ar_length;
173447636e4SEdward Tomasz Napierala 			memcpy(psinfo->pr_psargs, p->p_args->ar_args, len);
174447636e4SEdward Tomasz Napierala 			PROC_UNLOCK(p);
175447636e4SEdward Tomasz Napierala 			error = 0;
176447636e4SEdward Tomasz Napierala 		} else {
177447636e4SEdward Tomasz Napierala 			_PHOLD(p);
178447636e4SEdward Tomasz Napierala 			PROC_UNLOCK(p);
179447636e4SEdward Tomasz Napierala 			sbuf_new(&sbarg, psinfo->pr_psargs,
180447636e4SEdward Tomasz Napierala 			    sizeof(psinfo->pr_psargs), SBUF_FIXEDLEN);
181447636e4SEdward Tomasz Napierala 			error = proc_getargv(curthread, p, &sbarg);
182447636e4SEdward Tomasz Napierala 			PRELE(p);
18300d17cf3SKonstantin Belousov 			if (sbuf_finish(&sbarg) == 0) {
184447636e4SEdward Tomasz Napierala 				len = sbuf_len(&sbarg) - 1;
18500d17cf3SKonstantin Belousov 				if (len > 0)
18600d17cf3SKonstantin Belousov 					len--;
18700d17cf3SKonstantin Belousov 			} else {
188447636e4SEdward Tomasz Napierala 				len = sizeof(psinfo->pr_psargs) - 1;
18900d17cf3SKonstantin Belousov 			}
190447636e4SEdward Tomasz Napierala 			sbuf_delete(&sbarg);
191447636e4SEdward Tomasz Napierala 		}
19200d17cf3SKonstantin Belousov 		if (error != 0 || len == 0 || (ssize_t)len == -1)
193447636e4SEdward Tomasz Napierala 			strlcpy(psinfo->pr_psargs, p->p_comm,
194447636e4SEdward Tomasz Napierala 			    sizeof(psinfo->pr_psargs));
195447636e4SEdward Tomasz Napierala 		else {
196447636e4SEdward Tomasz Napierala 			KASSERT(len < sizeof(psinfo->pr_psargs),
197447636e4SEdward Tomasz Napierala 			    ("len is too long: %zu vs %zu", len,
198447636e4SEdward Tomasz Napierala 			    sizeof(psinfo->pr_psargs)));
199447636e4SEdward Tomasz Napierala 			cp = psinfo->pr_psargs;
200447636e4SEdward Tomasz Napierala 			end = cp + len - 1;
201447636e4SEdward Tomasz Napierala 			for (;;) {
202447636e4SEdward Tomasz Napierala 				cp = memchr(cp, '\0', end - cp);
203447636e4SEdward Tomasz Napierala 				if (cp == NULL)
204447636e4SEdward Tomasz Napierala 					break;
205447636e4SEdward Tomasz Napierala 				*cp = ' ';
206447636e4SEdward Tomasz Napierala 			}
207447636e4SEdward Tomasz Napierala 		}
208447636e4SEdward Tomasz Napierala 		psinfo->pr_pid = p->p_pid;
209447636e4SEdward Tomasz Napierala 		sbuf_bcat(sb, psinfo, sizeof(*psinfo));
210447636e4SEdward Tomasz Napierala 		free(psinfo, M_TEMP);
211447636e4SEdward Tomasz Napierala 	}
212447636e4SEdward Tomasz Napierala 	*sizep = sizeof(*psinfo);
213447636e4SEdward Tomasz Napierala }
214447636e4SEdward Tomasz Napierala 
215447636e4SEdward Tomasz Napierala static void
__linuxN(note_prstatus)216447636e4SEdward Tomasz Napierala __linuxN(note_prstatus)(void *arg, struct sbuf *sb, size_t *sizep)
217447636e4SEdward Tomasz Napierala {
218447636e4SEdward Tomasz Napierala 	struct thread *td;
219447636e4SEdward Tomasz Napierala 	linux_elf_prstatus_t *status;
2206f8439dbSDmitry Chagin #ifdef COMPAT_LINUX32
221447636e4SEdward Tomasz Napierala 	struct reg32 pr_reg;
222447636e4SEdward Tomasz Napierala #else
223447636e4SEdward Tomasz Napierala 	struct reg pr_reg;
224447636e4SEdward Tomasz Napierala #endif
225447636e4SEdward Tomasz Napierala 
226447636e4SEdward Tomasz Napierala 	td = arg;
227447636e4SEdward Tomasz Napierala 	if (sb != NULL) {
228447636e4SEdward Tomasz Napierala 		KASSERT(*sizep == sizeof(*status), ("invalid size"));
229447636e4SEdward Tomasz Napierala 		status = malloc(sizeof(*status), M_TEMP, M_ZERO | M_WAITOK);
230447636e4SEdward Tomasz Napierala 
231447636e4SEdward Tomasz Napierala 		/*
232447636e4SEdward Tomasz Napierala 		 * XXX: Some fields missing.
233447636e4SEdward Tomasz Napierala 		 */
234447636e4SEdward Tomasz Napierala 		status->pr_cursig = td->td_proc->p_sig;
235447636e4SEdward Tomasz Napierala 		status->pr_pid = td->td_tid;
236447636e4SEdward Tomasz Napierala 
2376f8439dbSDmitry Chagin #ifdef COMPAT_LINUX32
238447636e4SEdward Tomasz Napierala 		fill_regs32(td, &pr_reg);
239447636e4SEdward Tomasz Napierala #else
240447636e4SEdward Tomasz Napierala 		fill_regs(td, &pr_reg);
241447636e4SEdward Tomasz Napierala #endif
242447636e4SEdward Tomasz Napierala 		bsd_to_linux_regset(&pr_reg, &status->pr_reg);
243447636e4SEdward Tomasz Napierala 		sbuf_bcat(sb, status, sizeof(*status));
244447636e4SEdward Tomasz Napierala 		free(status, M_TEMP);
245447636e4SEdward Tomasz Napierala 	}
246447636e4SEdward Tomasz Napierala 	*sizep = sizeof(*status);
247447636e4SEdward Tomasz Napierala }
248447636e4SEdward Tomasz Napierala 
249447636e4SEdward Tomasz Napierala static void
__linuxN(note_fpregset)250447636e4SEdward Tomasz Napierala __linuxN(note_fpregset)(void *arg, struct sbuf *sb, size_t *sizep)
251447636e4SEdward Tomasz Napierala {
252447636e4SEdward Tomasz Napierala 	struct thread *td;
253447636e4SEdward Tomasz Napierala 	linux_elf_prfpregset_t *fpregset;
254447636e4SEdward Tomasz Napierala 
255447636e4SEdward Tomasz Napierala 	td = arg;
256447636e4SEdward Tomasz Napierala 	if (sb != NULL) {
257447636e4SEdward Tomasz Napierala 		KASSERT(*sizep == sizeof(*fpregset), ("invalid size"));
258447636e4SEdward Tomasz Napierala 		fpregset = malloc(sizeof(*fpregset), M_TEMP, M_ZERO | M_WAITOK);
2596f8439dbSDmitry Chagin #ifdef COMPAT_LINUX32
260447636e4SEdward Tomasz Napierala 		fill_fpregs32(td, fpregset);
261447636e4SEdward Tomasz Napierala #else
262447636e4SEdward Tomasz Napierala 		fill_fpregs(td, fpregset);
263447636e4SEdward Tomasz Napierala #endif
264447636e4SEdward Tomasz Napierala 		sbuf_bcat(sb, fpregset, sizeof(*fpregset));
265447636e4SEdward Tomasz Napierala 		free(fpregset, M_TEMP);
266447636e4SEdward Tomasz Napierala 	}
267447636e4SEdward Tomasz Napierala 	*sizep = sizeof(*fpregset);
268447636e4SEdward Tomasz Napierala }
269447636e4SEdward Tomasz Napierala 
270447636e4SEdward Tomasz Napierala /*
271447636e4SEdward Tomasz Napierala  * Allow for MD specific notes, as well as any MD
272447636e4SEdward Tomasz Napierala  * specific preparations for writing MI notes.
273447636e4SEdward Tomasz Napierala  */
274447636e4SEdward Tomasz Napierala static void
__linuxN(note_threadmd)275447636e4SEdward Tomasz Napierala __linuxN(note_threadmd)(void *arg, struct sbuf *sb, size_t *sizep)
276447636e4SEdward Tomasz Napierala {
277447636e4SEdward Tomasz Napierala 	struct thread *td;
278447636e4SEdward Tomasz Napierala 	void *buf;
279447636e4SEdward Tomasz Napierala 	size_t size;
280447636e4SEdward Tomasz Napierala 
281447636e4SEdward Tomasz Napierala 	td = arg;
282447636e4SEdward Tomasz Napierala 	size = *sizep;
283447636e4SEdward Tomasz Napierala 	if (size != 0 && sb != NULL)
284447636e4SEdward Tomasz Napierala 		buf = malloc(size, M_TEMP, M_ZERO | M_WAITOK);
285447636e4SEdward Tomasz Napierala 	else
286447636e4SEdward Tomasz Napierala 		buf = NULL;
287447636e4SEdward Tomasz Napierala 	size = 0;
288447636e4SEdward Tomasz Napierala 	__elfN(dump_thread)(td, buf, &size);
289447636e4SEdward Tomasz Napierala 	KASSERT(sb == NULL || *sizep == size, ("invalid size"));
290447636e4SEdward Tomasz Napierala 	if (size != 0 && sb != NULL)
291447636e4SEdward Tomasz Napierala 		sbuf_bcat(sb, buf, size);
292447636e4SEdward Tomasz Napierala 	free(buf, M_TEMP);
293447636e4SEdward Tomasz Napierala 	*sizep = size;
294447636e4SEdward Tomasz Napierala }
295447636e4SEdward Tomasz Napierala 
296447636e4SEdward Tomasz Napierala static void
__linuxN(note_nt_auxv)297447636e4SEdward Tomasz Napierala __linuxN(note_nt_auxv)(void *arg, struct sbuf *sb, size_t *sizep)
298447636e4SEdward Tomasz Napierala {
299447636e4SEdward Tomasz Napierala 	struct proc *p;
300447636e4SEdward Tomasz Napierala 	size_t size;
301447636e4SEdward Tomasz Napierala 
302447636e4SEdward Tomasz Napierala 	p = arg;
303447636e4SEdward Tomasz Napierala 	if (sb == NULL) {
304447636e4SEdward Tomasz Napierala 		size = 0;
305447636e4SEdward Tomasz Napierala 		sb = sbuf_new(NULL, NULL, LINUX_AT_COUNT * sizeof(Elf_Auxinfo),
306447636e4SEdward Tomasz Napierala 		    SBUF_FIXEDLEN);
307447636e4SEdward Tomasz Napierala 		sbuf_set_drain(sb, sbuf_count_drain, &size);
308447636e4SEdward Tomasz Napierala 		PHOLD(p);
309447636e4SEdward Tomasz Napierala 		proc_getauxv(curthread, p, sb);
310447636e4SEdward Tomasz Napierala 		PRELE(p);
311447636e4SEdward Tomasz Napierala 		sbuf_finish(sb);
312447636e4SEdward Tomasz Napierala 		sbuf_delete(sb);
313447636e4SEdward Tomasz Napierala 		*sizep = size;
314447636e4SEdward Tomasz Napierala 	} else {
315447636e4SEdward Tomasz Napierala 		PHOLD(p);
316447636e4SEdward Tomasz Napierala 		proc_getauxv(curthread, p, sb);
317447636e4SEdward Tomasz Napierala 		PRELE(p);
318447636e4SEdward Tomasz Napierala 	}
319447636e4SEdward Tomasz Napierala }
3206039e966SDmitry Chagin 
3216039e966SDmitry Chagin /*
3226039e966SDmitry Chagin  * Copy strings out to the new process address space, constructing new arg
3236039e966SDmitry Chagin  * and env vector tables. Return a pointer to the base so that it can be used
3246039e966SDmitry Chagin  * as the initial stack pointer.
3256039e966SDmitry Chagin  */
3266039e966SDmitry Chagin int
__linuxN(copyout_strings)3276039e966SDmitry Chagin __linuxN(copyout_strings)(struct image_params *imgp, uintptr_t *stack_base)
3286039e966SDmitry Chagin {
3296039e966SDmitry Chagin 	char canary[LINUX_AT_RANDOM_LEN];
3306039e966SDmitry Chagin 	char **vectp;
3316039e966SDmitry Chagin 	char *stringp;
3326039e966SDmitry Chagin 	uintptr_t destp, ustringp;
3336039e966SDmitry Chagin 	struct ps_strings *arginfo;
3346039e966SDmitry Chagin 	struct proc *p;
3356039e966SDmitry Chagin 	size_t execpath_len;
3366039e966SDmitry Chagin 	int argc, envc;
3376039e966SDmitry Chagin 	int error;
3386039e966SDmitry Chagin 
3396039e966SDmitry Chagin 	p = imgp->proc;
3406039e966SDmitry Chagin 	destp =	PROC_PS_STRINGS(p);
3416039e966SDmitry Chagin 	arginfo = imgp->ps_strings = (void *)destp;
3426039e966SDmitry Chagin 
3436039e966SDmitry Chagin 	/*
3446039e966SDmitry Chagin 	 * Copy the image path for the rtld.
3456039e966SDmitry Chagin 	 */
3466039e966SDmitry Chagin 	if (imgp->execpath != NULL && imgp->auxargs != NULL) {
3476039e966SDmitry Chagin 		execpath_len = strlen(imgp->execpath) + 1;
3486039e966SDmitry Chagin 		destp -= execpath_len;
3496039e966SDmitry Chagin 		destp = rounddown2(destp, sizeof(void *));
3506039e966SDmitry Chagin 		imgp->execpathp = (void *)destp;
3516039e966SDmitry Chagin 		error = copyout(imgp->execpath, imgp->execpathp, execpath_len);
3526039e966SDmitry Chagin 		if (error != 0)
3536039e966SDmitry Chagin 			return (error);
3546039e966SDmitry Chagin 	}
3556039e966SDmitry Chagin 
3566039e966SDmitry Chagin 	/*
3576039e966SDmitry Chagin 	 * Prepare the canary for SSP.
3586039e966SDmitry Chagin 	 */
3596039e966SDmitry Chagin 	arc4rand(canary, sizeof(canary), 0);
3606039e966SDmitry Chagin 	destp -= sizeof(canary);
3616039e966SDmitry Chagin 	imgp->canary = (void *)destp;
3626039e966SDmitry Chagin 	error = copyout(canary, imgp->canary, sizeof(canary));
3636039e966SDmitry Chagin 	if (error != 0)
3646039e966SDmitry Chagin 		return (error);
3656039e966SDmitry Chagin 	imgp->canarylen = sizeof(canary);
3666039e966SDmitry Chagin 
3676039e966SDmitry Chagin 	/*
3686039e966SDmitry Chagin 	 * Allocate room for the argument and environment strings.
3696039e966SDmitry Chagin 	 */
3706039e966SDmitry Chagin 	destp -= ARG_MAX - imgp->args->stringspace;
3716039e966SDmitry Chagin 	destp = rounddown2(destp, sizeof(void *));
3726039e966SDmitry Chagin 	ustringp = destp;
3736039e966SDmitry Chagin 
3746039e966SDmitry Chagin 	if (imgp->auxargs) {
3756039e966SDmitry Chagin 		/*
3766039e966SDmitry Chagin 		 * Allocate room on the stack for the ELF auxargs
3776039e966SDmitry Chagin 		 * array.  It has up to LINUX_AT_COUNT entries.
3786039e966SDmitry Chagin 		 */
3796039e966SDmitry Chagin 		destp -= LINUX_AT_COUNT * sizeof(Elf_Auxinfo);
3806039e966SDmitry Chagin 		destp = rounddown2(destp, sizeof(void *));
3816039e966SDmitry Chagin 	}
3826039e966SDmitry Chagin 
3836039e966SDmitry Chagin 	vectp = (char **)destp;
3846039e966SDmitry Chagin 
3856039e966SDmitry Chagin 	/*
3866039e966SDmitry Chagin 	 * Allocate room for the argv[] and env vectors including the
3876039e966SDmitry Chagin 	 * terminating NULL pointers.
3886039e966SDmitry Chagin 	 */
3896039e966SDmitry Chagin 	vectp -= imgp->args->argc + 1 + imgp->args->envc + 1;
3906039e966SDmitry Chagin 
3916039e966SDmitry Chagin 	/*
3926039e966SDmitry Chagin 	 * Starting with 2.24, glibc depends on a 16-byte stack alignment.
3936039e966SDmitry Chagin 	 */
3946039e966SDmitry Chagin 	vectp = (char **)((((uintptr_t)vectp + 8) & ~0xF) - 8);
3956039e966SDmitry Chagin 
3966039e966SDmitry Chagin 	/*
3976039e966SDmitry Chagin 	 * vectp also becomes our initial stack base
3986039e966SDmitry Chagin 	 */
3996039e966SDmitry Chagin 	*stack_base = (uintptr_t)vectp;
4006039e966SDmitry Chagin 
4016039e966SDmitry Chagin 	stringp = imgp->args->begin_argv;
4026039e966SDmitry Chagin 	argc = imgp->args->argc;
4036039e966SDmitry Chagin 	envc = imgp->args->envc;
4046039e966SDmitry Chagin 
4056039e966SDmitry Chagin 	/*
4066039e966SDmitry Chagin 	 * Copy out strings - arguments and environment.
4076039e966SDmitry Chagin 	 */
4086039e966SDmitry Chagin 	error = copyout(stringp, (void *)ustringp,
4096039e966SDmitry Chagin 	    ARG_MAX - imgp->args->stringspace);
4106039e966SDmitry Chagin 	if (error != 0)
4116039e966SDmitry Chagin 		return (error);
4126039e966SDmitry Chagin 
4136039e966SDmitry Chagin 	/*
4146039e966SDmitry Chagin 	 * Fill in "ps_strings" struct for ps, w, etc.
4156039e966SDmitry Chagin 	 */
4166039e966SDmitry Chagin 	imgp->argv = vectp;
4176039e966SDmitry Chagin 	if (suword(&arginfo->ps_argvstr, (long)(intptr_t)vectp) != 0 ||
4186039e966SDmitry Chagin 	    suword32(&arginfo->ps_nargvstr, argc) != 0)
4196039e966SDmitry Chagin 		return (EFAULT);
4206039e966SDmitry Chagin 
4216039e966SDmitry Chagin 	/*
4226039e966SDmitry Chagin 	 * Fill in argument portion of vector table.
4236039e966SDmitry Chagin 	 */
4246039e966SDmitry Chagin 	for (; argc > 0; --argc) {
4256039e966SDmitry Chagin 		if (suword(vectp++, ustringp) != 0)
4266039e966SDmitry Chagin 			return (EFAULT);
4276039e966SDmitry Chagin 		while (*stringp++ != 0)
4286039e966SDmitry Chagin 			ustringp++;
4296039e966SDmitry Chagin 		ustringp++;
4306039e966SDmitry Chagin 	}
4316039e966SDmitry Chagin 
4326039e966SDmitry Chagin 	/* a null vector table pointer separates the argp's from the envp's */
4336039e966SDmitry Chagin 	if (suword(vectp++, 0) != 0)
4346039e966SDmitry Chagin 		return (EFAULT);
4356039e966SDmitry Chagin 
4366039e966SDmitry Chagin 	imgp->envv = vectp;
4376039e966SDmitry Chagin 	if (suword(&arginfo->ps_envstr, (long)(intptr_t)vectp) != 0 ||
4386039e966SDmitry Chagin 	    suword32(&arginfo->ps_nenvstr, envc) != 0)
4396039e966SDmitry Chagin 		return (EFAULT);
4406039e966SDmitry Chagin 
4416039e966SDmitry Chagin 	/*
4426039e966SDmitry Chagin 	 * Fill in environment portion of vector table.
4436039e966SDmitry Chagin 	 */
4446039e966SDmitry Chagin 	for (; envc > 0; --envc) {
4456039e966SDmitry Chagin 		if (suword(vectp++, ustringp) != 0)
4466039e966SDmitry Chagin 			return (EFAULT);
4476039e966SDmitry Chagin 		while (*stringp++ != 0)
4486039e966SDmitry Chagin 			ustringp++;
4496039e966SDmitry Chagin 		ustringp++;
4506039e966SDmitry Chagin 	}
4516039e966SDmitry Chagin 
4526039e966SDmitry Chagin 	/* end of vector table is a null pointer */
4536039e966SDmitry Chagin 	if (suword(vectp, 0) != 0)
4546039e966SDmitry Chagin 		return (EFAULT);
4556039e966SDmitry Chagin 
4566039e966SDmitry Chagin 	if (imgp->auxargs) {
4576039e966SDmitry Chagin 		vectp++;
4586039e966SDmitry Chagin 		error = imgp->sysent->sv_copyout_auxargs(imgp,
4596039e966SDmitry Chagin 		    (uintptr_t)vectp);
4606039e966SDmitry Chagin 		if (error != 0)
4616039e966SDmitry Chagin 			return (error);
4626039e966SDmitry Chagin 	}
4636039e966SDmitry Chagin 
4646039e966SDmitry Chagin 	return (0);
4656039e966SDmitry Chagin }
46695b86034SDmitry Chagin 
46795b86034SDmitry Chagin bool
linux_trans_osrel(const Elf_Note * note,int32_t * osrel)46895b86034SDmitry Chagin linux_trans_osrel(const Elf_Note *note, int32_t *osrel)
46995b86034SDmitry Chagin {
47095b86034SDmitry Chagin 	const Elf32_Word *desc;
47195b86034SDmitry Chagin 	uintptr_t p;
47295b86034SDmitry Chagin 
47395b86034SDmitry Chagin 	p = (uintptr_t)(note + 1);
47495b86034SDmitry Chagin 	p += roundup2(note->n_namesz, sizeof(Elf32_Addr));
47595b86034SDmitry Chagin 
47695b86034SDmitry Chagin 	desc = (const Elf32_Word *)p;
47795b86034SDmitry Chagin 	if (desc[0] != GNU_ABI_LINUX)
47895b86034SDmitry Chagin 		return (false);
47995b86034SDmitry Chagin 	/*
48095b86034SDmitry Chagin 	 * For Linux we encode osrel using the Linux convention of
48195b86034SDmitry Chagin 	 * 	(version << 16) | (major << 8) | (minor)
48295b86034SDmitry Chagin 	 * See macro in linux_mib.h
48395b86034SDmitry Chagin 	 */
48495b86034SDmitry Chagin 	*osrel = LINUX_KERNVER(desc[1], desc[2], desc[3]);
48595b86034SDmitry Chagin 
48695b86034SDmitry Chagin 	return (true);
48795b86034SDmitry Chagin }
4887d8c9839SDmitry Chagin 
4897d8c9839SDmitry Chagin int
__linuxN(copyout_auxargs)4907d8c9839SDmitry Chagin __linuxN(copyout_auxargs)(struct image_params *imgp, uintptr_t base)
4917d8c9839SDmitry Chagin {
49276f8584eSDmitry Chagin 	struct thread *td = curthread;
4937d8c9839SDmitry Chagin 	Elf_Auxargs *args;
4947d8c9839SDmitry Chagin 	Elf_Auxinfo *aarray, *pos;
4957d8c9839SDmitry Chagin 	struct proc *p;
4967d8c9839SDmitry Chagin 	int error, issetugid;
4977d8c9839SDmitry Chagin 
4987d8c9839SDmitry Chagin 	p = imgp->proc;
4997d8c9839SDmitry Chagin 	issetugid = p->p_flag & P_SUGID ? 1 : 0;
5007d8c9839SDmitry Chagin 	args = imgp->auxargs;
5017d8c9839SDmitry Chagin 	aarray = pos = malloc(LINUX_AT_COUNT * sizeof(*pos), M_TEMP,
5027d8c9839SDmitry Chagin 	    M_WAITOK | M_ZERO);
5037d8c9839SDmitry Chagin 
5047d8c9839SDmitry Chagin 	__linuxN(arch_copyout_auxargs)(imgp, &pos);
5057d8c9839SDmitry Chagin 	/*
5067d8c9839SDmitry Chagin 	 * Do not export AT_CLKTCK when emulating Linux kernel prior to 2.4.0,
5077d8c9839SDmitry Chagin 	 * as it has appeared in the 2.4.0-rc7 first time.
5087d8c9839SDmitry Chagin 	 * Being exported, AT_CLKTCK is returned by sysconf(_SC_CLK_TCK),
5097d8c9839SDmitry Chagin 	 * glibc falls back to the hard-coded CLK_TCK value when aux entry
5107d8c9839SDmitry Chagin 	 * is not present.
5117d8c9839SDmitry Chagin 	 * Also see linux_times() implementation.
5127d8c9839SDmitry Chagin 	 */
513*e185d83fSDmitry Chagin 	if (linux_kernver(td) >= LINUX_KERNVER(2,4,0))
5147d8c9839SDmitry Chagin 		AUXARGS_ENTRY(pos, LINUX_AT_CLKTCK, stclohz);
5157d8c9839SDmitry Chagin 	AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz);
5167d8c9839SDmitry Chagin 	AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
5177d8c9839SDmitry Chagin 	AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
5187d8c9839SDmitry Chagin 	AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
5197d8c9839SDmitry Chagin 	AUXARGS_ENTRY(pos, AT_BASE, args->base);
5207d8c9839SDmitry Chagin 	AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
5217d8c9839SDmitry Chagin 	AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
5227d8c9839SDmitry Chagin 	AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
5237d8c9839SDmitry Chagin 	AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
5247d8c9839SDmitry Chagin 	AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
5257d8c9839SDmitry Chagin 	AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
5267d8c9839SDmitry Chagin 	AUXARGS_ENTRY(pos, LINUX_AT_SECURE, issetugid);
52776f8584eSDmitry Chagin 	if (linux_kernver(td) >= LINUX_KERNVER(2,6,30))
5287d8c9839SDmitry Chagin 		AUXARGS_ENTRY_PTR(pos, LINUX_AT_RANDOM, imgp->canary);
52976f8584eSDmitry Chagin 	if (linux_kernver(td) >= LINUX_KERNVER(2,6,26) && imgp->execpathp != 0)
5307d8c9839SDmitry Chagin 		AUXARGS_ENTRY(pos, LINUX_AT_EXECFN, PTROUT(imgp->execpathp));
5317d8c9839SDmitry Chagin 	if (args->execfd != -1)
5327d8c9839SDmitry Chagin 		AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
53376f8584eSDmitry Chagin 	if (linux_kernver(td) >= LINUX_KERNVER(5,13,0))
53466e8f1f7SDmitry Chagin 		AUXARGS_ENTRY(pos, LINUX_AT_MINSIGSTKSZ,
53566e8f1f7SDmitry Chagin 		    imgp->sysent->sv_minsigstksz);
5367d8c9839SDmitry Chagin 	AUXARGS_ENTRY(pos, AT_NULL, 0);
5377d8c9839SDmitry Chagin 
5387d8c9839SDmitry Chagin 	free(imgp->auxargs, M_TEMP);
5397d8c9839SDmitry Chagin 	imgp->auxargs = NULL;
5407d8c9839SDmitry Chagin 	KASSERT(pos - aarray <= LINUX_AT_COUNT, ("Too many auxargs"));
5417d8c9839SDmitry Chagin 
5427d8c9839SDmitry Chagin 	error = copyout(aarray, PTRIN(base), sizeof(*aarray) * LINUX_AT_COUNT);
5437d8c9839SDmitry Chagin 	free(aarray, M_TEMP);
5447d8c9839SDmitry Chagin 	return (error);
5457d8c9839SDmitry Chagin }
546