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