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/cdefs.h> 41447636e4SEdward Tomasz Napierala __FBSDID("$FreeBSD$"); 42447636e4SEdward Tomasz Napierala 43447636e4SEdward Tomasz Napierala #include <sys/param.h> 446039e966SDmitry Chagin #include <sys/exec.h> 45447636e4SEdward Tomasz Napierala #include <sys/imgact.h> 46447636e4SEdward Tomasz Napierala #include <sys/imgact_elf.h> 4706d5ef0aSEdward Tomasz Napierala #include <sys/lock.h> 4806d5ef0aSEdward Tomasz Napierala #include <sys/malloc.h> 4906d5ef0aSEdward Tomasz Napierala #include <sys/mutex.h> 50447636e4SEdward Tomasz Napierala #include <sys/proc.h> 51447636e4SEdward Tomasz Napierala #include <sys/procfs.h> 52b7924341SAndrew Turner #include <sys/reg.h> 53447636e4SEdward Tomasz Napierala #include <sys/sbuf.h> 546039e966SDmitry Chagin #include <sys/sysent.h> 556039e966SDmitry Chagin 566039e966SDmitry Chagin #include <vm/vm.h> 576039e966SDmitry Chagin #include <vm/pmap.h> 586039e966SDmitry Chagin #include <vm/vm_map.h> 59447636e4SEdward Tomasz Napierala 60447636e4SEdward Tomasz Napierala #include <machine/elf.h> 61447636e4SEdward Tomasz Napierala 626f8439dbSDmitry Chagin #ifdef COMPAT_LINUX32 63447636e4SEdward Tomasz Napierala #define linux_pt_regset linux_pt_regset32 64447636e4SEdward Tomasz Napierala #define bsd_to_linux_regset bsd_to_linux_regset32 65447636e4SEdward Tomasz Napierala #include <machine/../linux32/linux.h> 66447636e4SEdward Tomasz Napierala #else 67447636e4SEdward Tomasz Napierala #include <machine/../linux/linux.h> 68447636e4SEdward Tomasz Napierala #endif 69447636e4SEdward Tomasz Napierala #include <compat/linux/linux_elf.h> 7095b86034SDmitry Chagin #include <compat/linux/linux_mib.h> 716039e966SDmitry Chagin #include <compat/linux/linux_misc.h> 72447636e4SEdward Tomasz Napierala 7374465145SDmitry Chagin struct l_elf_siginfo { 7474465145SDmitry Chagin l_int si_signo; 7574465145SDmitry Chagin l_int si_code; 7674465145SDmitry Chagin l_int si_errno; 7774465145SDmitry Chagin }; 7874465145SDmitry Chagin 7974465145SDmitry Chagin typedef struct linux_pt_regset l_elf_gregset_t; 8074465145SDmitry Chagin 8174465145SDmitry Chagin struct linux_elf_prstatus { 8274465145SDmitry Chagin struct l_elf_siginfo pr_info; 8374465145SDmitry Chagin l_short pr_cursig; 8474465145SDmitry Chagin l_ulong pr_sigpend; 8574465145SDmitry Chagin l_ulong pr_sighold; 8674465145SDmitry Chagin l_pid_t pr_pid; 8774465145SDmitry Chagin l_pid_t pr_ppid; 8874465145SDmitry Chagin l_pid_t pr_pgrp; 8974465145SDmitry Chagin l_pid_t pr_sid; 9074465145SDmitry Chagin l_timeval pr_utime; 9174465145SDmitry Chagin l_timeval pr_stime; 9274465145SDmitry Chagin l_timeval pr_cutime; 9374465145SDmitry Chagin l_timeval pr_cstime; 9474465145SDmitry Chagin l_elf_gregset_t pr_reg; 9574465145SDmitry Chagin l_int pr_fpvalid; 9674465145SDmitry Chagin }; 97447636e4SEdward Tomasz Napierala 98447636e4SEdward Tomasz Napierala #define LINUX_NT_AUXV 6 99447636e4SEdward Tomasz Napierala 100447636e4SEdward Tomasz Napierala static void __linuxN(note_fpregset)(void *, struct sbuf *, size_t *); 101447636e4SEdward Tomasz Napierala static void __linuxN(note_prpsinfo)(void *, struct sbuf *, size_t *); 102447636e4SEdward Tomasz Napierala static void __linuxN(note_prstatus)(void *, struct sbuf *, size_t *); 103447636e4SEdward Tomasz Napierala static void __linuxN(note_threadmd)(void *, struct sbuf *, size_t *); 104447636e4SEdward Tomasz Napierala static void __linuxN(note_nt_auxv)(void *, struct sbuf *, size_t *); 105447636e4SEdward Tomasz Napierala 106447636e4SEdward Tomasz Napierala void 107447636e4SEdward Tomasz Napierala __linuxN(prepare_notes)(struct thread *td, struct note_info_list *list, 108447636e4SEdward Tomasz Napierala size_t *sizep) 109447636e4SEdward Tomasz Napierala { 110447636e4SEdward Tomasz Napierala struct proc *p; 111447636e4SEdward Tomasz Napierala struct thread *thr; 112447636e4SEdward Tomasz Napierala size_t size; 113447636e4SEdward Tomasz Napierala 114447636e4SEdward Tomasz Napierala p = td->td_proc; 115447636e4SEdward Tomasz Napierala size = 0; 116447636e4SEdward Tomasz Napierala 117447636e4SEdward Tomasz Napierala /* 118447636e4SEdward Tomasz Napierala * To have the debugger select the right thread (LWP) as the initial 119447636e4SEdward Tomasz Napierala * thread, we dump the state of the thread passed to us in td first. 120447636e4SEdward Tomasz Napierala * This is the thread that causes the core dump and thus likely to 121447636e4SEdward Tomasz Napierala * be the right thread one wants to have selected in the debugger. 122447636e4SEdward Tomasz Napierala */ 123447636e4SEdward Tomasz Napierala thr = td; 124447636e4SEdward Tomasz Napierala while (thr != NULL) { 125447636e4SEdward Tomasz Napierala size += __elfN(register_note)(td, list, 126447636e4SEdward Tomasz Napierala NT_PRSTATUS, __linuxN(note_prstatus), thr); 127447636e4SEdward Tomasz Napierala size += __elfN(register_note)(td, list, 128447636e4SEdward Tomasz Napierala NT_PRPSINFO, __linuxN(note_prpsinfo), p); 129447636e4SEdward Tomasz Napierala size += __elfN(register_note)(td, list, 130447636e4SEdward Tomasz Napierala LINUX_NT_AUXV, __linuxN(note_nt_auxv), p); 131447636e4SEdward Tomasz Napierala size += __elfN(register_note)(td, list, 132447636e4SEdward Tomasz Napierala NT_FPREGSET, __linuxN(note_fpregset), thr); 133447636e4SEdward Tomasz Napierala size += __elfN(register_note)(td, list, 134447636e4SEdward Tomasz Napierala -1, __linuxN(note_threadmd), thr); 135447636e4SEdward Tomasz Napierala 136447636e4SEdward Tomasz Napierala thr = thr == td ? TAILQ_FIRST(&p->p_threads) : 137447636e4SEdward Tomasz Napierala TAILQ_NEXT(thr, td_plist); 138447636e4SEdward Tomasz Napierala if (thr == td) 139447636e4SEdward Tomasz Napierala thr = TAILQ_NEXT(thr, td_plist); 140447636e4SEdward Tomasz Napierala } 141447636e4SEdward Tomasz Napierala 142447636e4SEdward Tomasz Napierala *sizep = size; 143447636e4SEdward Tomasz Napierala } 144447636e4SEdward Tomasz Napierala 145447636e4SEdward Tomasz Napierala typedef struct linux_elf_prstatus linux_elf_prstatus_t; 1466f8439dbSDmitry Chagin #ifdef COMPAT_LINUX32 147447636e4SEdward Tomasz Napierala typedef struct prpsinfo32 linux_elf_prpsinfo_t; 148447636e4SEdward Tomasz Napierala typedef struct fpreg32 linux_elf_prfpregset_t; 149447636e4SEdward Tomasz Napierala #else 150447636e4SEdward Tomasz Napierala typedef prpsinfo_t linux_elf_prpsinfo_t; 151447636e4SEdward Tomasz Napierala typedef prfpregset_t linux_elf_prfpregset_t; 152447636e4SEdward Tomasz Napierala #endif 153447636e4SEdward Tomasz Napierala 154447636e4SEdward Tomasz Napierala static void 155447636e4SEdward Tomasz Napierala __linuxN(note_prpsinfo)(void *arg, struct sbuf *sb, size_t *sizep) 156447636e4SEdward Tomasz Napierala { 157447636e4SEdward Tomasz Napierala struct sbuf sbarg; 158447636e4SEdward Tomasz Napierala size_t len; 159447636e4SEdward Tomasz Napierala char *cp, *end; 160447636e4SEdward Tomasz Napierala struct proc *p; 161447636e4SEdward Tomasz Napierala linux_elf_prpsinfo_t *psinfo; 162447636e4SEdward Tomasz Napierala int error; 163447636e4SEdward Tomasz Napierala 164447636e4SEdward Tomasz Napierala p = arg; 165447636e4SEdward Tomasz Napierala if (sb != NULL) { 166447636e4SEdward Tomasz Napierala KASSERT(*sizep == sizeof(*psinfo), ("invalid size")); 167447636e4SEdward Tomasz Napierala psinfo = malloc(sizeof(*psinfo), M_TEMP, M_ZERO | M_WAITOK); 168447636e4SEdward Tomasz Napierala psinfo->pr_version = PRPSINFO_VERSION; 169447636e4SEdward Tomasz Napierala psinfo->pr_psinfosz = sizeof(linux_elf_prpsinfo_t); 170447636e4SEdward Tomasz Napierala strlcpy(psinfo->pr_fname, p->p_comm, sizeof(psinfo->pr_fname)); 171447636e4SEdward Tomasz Napierala PROC_LOCK(p); 172447636e4SEdward Tomasz Napierala if (p->p_args != NULL) { 173447636e4SEdward Tomasz Napierala len = sizeof(psinfo->pr_psargs) - 1; 174447636e4SEdward Tomasz Napierala if (len > p->p_args->ar_length) 175447636e4SEdward Tomasz Napierala len = p->p_args->ar_length; 176447636e4SEdward Tomasz Napierala memcpy(psinfo->pr_psargs, p->p_args->ar_args, len); 177447636e4SEdward Tomasz Napierala PROC_UNLOCK(p); 178447636e4SEdward Tomasz Napierala error = 0; 179447636e4SEdward Tomasz Napierala } else { 180447636e4SEdward Tomasz Napierala _PHOLD(p); 181447636e4SEdward Tomasz Napierala PROC_UNLOCK(p); 182447636e4SEdward Tomasz Napierala sbuf_new(&sbarg, psinfo->pr_psargs, 183447636e4SEdward Tomasz Napierala sizeof(psinfo->pr_psargs), SBUF_FIXEDLEN); 184447636e4SEdward Tomasz Napierala error = proc_getargv(curthread, p, &sbarg); 185447636e4SEdward Tomasz Napierala PRELE(p); 18600d17cf3SKonstantin Belousov if (sbuf_finish(&sbarg) == 0) { 187447636e4SEdward Tomasz Napierala len = sbuf_len(&sbarg) - 1; 18800d17cf3SKonstantin Belousov if (len > 0) 18900d17cf3SKonstantin Belousov len--; 19000d17cf3SKonstantin Belousov } else { 191447636e4SEdward Tomasz Napierala len = sizeof(psinfo->pr_psargs) - 1; 19200d17cf3SKonstantin Belousov } 193447636e4SEdward Tomasz Napierala sbuf_delete(&sbarg); 194447636e4SEdward Tomasz Napierala } 19500d17cf3SKonstantin Belousov if (error != 0 || len == 0 || (ssize_t)len == -1) 196447636e4SEdward Tomasz Napierala strlcpy(psinfo->pr_psargs, p->p_comm, 197447636e4SEdward Tomasz Napierala sizeof(psinfo->pr_psargs)); 198447636e4SEdward Tomasz Napierala else { 199447636e4SEdward Tomasz Napierala KASSERT(len < sizeof(psinfo->pr_psargs), 200447636e4SEdward Tomasz Napierala ("len is too long: %zu vs %zu", len, 201447636e4SEdward Tomasz Napierala sizeof(psinfo->pr_psargs))); 202447636e4SEdward Tomasz Napierala cp = psinfo->pr_psargs; 203447636e4SEdward Tomasz Napierala end = cp + len - 1; 204447636e4SEdward Tomasz Napierala for (;;) { 205447636e4SEdward Tomasz Napierala cp = memchr(cp, '\0', end - cp); 206447636e4SEdward Tomasz Napierala if (cp == NULL) 207447636e4SEdward Tomasz Napierala break; 208447636e4SEdward Tomasz Napierala *cp = ' '; 209447636e4SEdward Tomasz Napierala } 210447636e4SEdward Tomasz Napierala } 211447636e4SEdward Tomasz Napierala psinfo->pr_pid = p->p_pid; 212447636e4SEdward Tomasz Napierala sbuf_bcat(sb, psinfo, sizeof(*psinfo)); 213447636e4SEdward Tomasz Napierala free(psinfo, M_TEMP); 214447636e4SEdward Tomasz Napierala } 215447636e4SEdward Tomasz Napierala *sizep = sizeof(*psinfo); 216447636e4SEdward Tomasz Napierala } 217447636e4SEdward Tomasz Napierala 218447636e4SEdward Tomasz Napierala static void 219447636e4SEdward Tomasz Napierala __linuxN(note_prstatus)(void *arg, struct sbuf *sb, size_t *sizep) 220447636e4SEdward Tomasz Napierala { 221447636e4SEdward Tomasz Napierala struct thread *td; 222447636e4SEdward Tomasz Napierala linux_elf_prstatus_t *status; 2236f8439dbSDmitry Chagin #ifdef COMPAT_LINUX32 224447636e4SEdward Tomasz Napierala struct reg32 pr_reg; 225447636e4SEdward Tomasz Napierala #else 226447636e4SEdward Tomasz Napierala struct reg pr_reg; 227447636e4SEdward Tomasz Napierala #endif 228447636e4SEdward Tomasz Napierala 229447636e4SEdward Tomasz Napierala td = arg; 230447636e4SEdward Tomasz Napierala if (sb != NULL) { 231447636e4SEdward Tomasz Napierala KASSERT(*sizep == sizeof(*status), ("invalid size")); 232447636e4SEdward Tomasz Napierala status = malloc(sizeof(*status), M_TEMP, M_ZERO | M_WAITOK); 233447636e4SEdward Tomasz Napierala 234447636e4SEdward Tomasz Napierala /* 235447636e4SEdward Tomasz Napierala * XXX: Some fields missing. 236447636e4SEdward Tomasz Napierala */ 237447636e4SEdward Tomasz Napierala status->pr_cursig = td->td_proc->p_sig; 238447636e4SEdward Tomasz Napierala status->pr_pid = td->td_tid; 239447636e4SEdward Tomasz Napierala 2406f8439dbSDmitry Chagin #ifdef COMPAT_LINUX32 241447636e4SEdward Tomasz Napierala fill_regs32(td, &pr_reg); 242447636e4SEdward Tomasz Napierala #else 243447636e4SEdward Tomasz Napierala fill_regs(td, &pr_reg); 244447636e4SEdward Tomasz Napierala #endif 245447636e4SEdward Tomasz Napierala bsd_to_linux_regset(&pr_reg, &status->pr_reg); 246447636e4SEdward Tomasz Napierala sbuf_bcat(sb, status, sizeof(*status)); 247447636e4SEdward Tomasz Napierala free(status, M_TEMP); 248447636e4SEdward Tomasz Napierala } 249447636e4SEdward Tomasz Napierala *sizep = sizeof(*status); 250447636e4SEdward Tomasz Napierala } 251447636e4SEdward Tomasz Napierala 252447636e4SEdward Tomasz Napierala static void 253447636e4SEdward Tomasz Napierala __linuxN(note_fpregset)(void *arg, struct sbuf *sb, size_t *sizep) 254447636e4SEdward Tomasz Napierala { 255447636e4SEdward Tomasz Napierala struct thread *td; 256447636e4SEdward Tomasz Napierala linux_elf_prfpregset_t *fpregset; 257447636e4SEdward Tomasz Napierala 258447636e4SEdward Tomasz Napierala td = arg; 259447636e4SEdward Tomasz Napierala if (sb != NULL) { 260447636e4SEdward Tomasz Napierala KASSERT(*sizep == sizeof(*fpregset), ("invalid size")); 261447636e4SEdward Tomasz Napierala fpregset = malloc(sizeof(*fpregset), M_TEMP, M_ZERO | M_WAITOK); 2626f8439dbSDmitry Chagin #ifdef COMPAT_LINUX32 263447636e4SEdward Tomasz Napierala fill_fpregs32(td, fpregset); 264447636e4SEdward Tomasz Napierala #else 265447636e4SEdward Tomasz Napierala fill_fpregs(td, fpregset); 266447636e4SEdward Tomasz Napierala #endif 267447636e4SEdward Tomasz Napierala sbuf_bcat(sb, fpregset, sizeof(*fpregset)); 268447636e4SEdward Tomasz Napierala free(fpregset, M_TEMP); 269447636e4SEdward Tomasz Napierala } 270447636e4SEdward Tomasz Napierala *sizep = sizeof(*fpregset); 271447636e4SEdward Tomasz Napierala } 272447636e4SEdward Tomasz Napierala 273447636e4SEdward Tomasz Napierala /* 274447636e4SEdward Tomasz Napierala * Allow for MD specific notes, as well as any MD 275447636e4SEdward Tomasz Napierala * specific preparations for writing MI notes. 276447636e4SEdward Tomasz Napierala */ 277447636e4SEdward Tomasz Napierala static void 278447636e4SEdward Tomasz Napierala __linuxN(note_threadmd)(void *arg, struct sbuf *sb, size_t *sizep) 279447636e4SEdward Tomasz Napierala { 280447636e4SEdward Tomasz Napierala struct thread *td; 281447636e4SEdward Tomasz Napierala void *buf; 282447636e4SEdward Tomasz Napierala size_t size; 283447636e4SEdward Tomasz Napierala 284447636e4SEdward Tomasz Napierala td = arg; 285447636e4SEdward Tomasz Napierala size = *sizep; 286447636e4SEdward Tomasz Napierala if (size != 0 && sb != NULL) 287447636e4SEdward Tomasz Napierala buf = malloc(size, M_TEMP, M_ZERO | M_WAITOK); 288447636e4SEdward Tomasz Napierala else 289447636e4SEdward Tomasz Napierala buf = NULL; 290447636e4SEdward Tomasz Napierala size = 0; 291447636e4SEdward Tomasz Napierala __elfN(dump_thread)(td, buf, &size); 292447636e4SEdward Tomasz Napierala KASSERT(sb == NULL || *sizep == size, ("invalid size")); 293447636e4SEdward Tomasz Napierala if (size != 0 && sb != NULL) 294447636e4SEdward Tomasz Napierala sbuf_bcat(sb, buf, size); 295447636e4SEdward Tomasz Napierala free(buf, M_TEMP); 296447636e4SEdward Tomasz Napierala *sizep = size; 297447636e4SEdward Tomasz Napierala } 298447636e4SEdward Tomasz Napierala 299447636e4SEdward Tomasz Napierala static void 300447636e4SEdward Tomasz Napierala __linuxN(note_nt_auxv)(void *arg, struct sbuf *sb, size_t *sizep) 301447636e4SEdward Tomasz Napierala { 302447636e4SEdward Tomasz Napierala struct proc *p; 303447636e4SEdward Tomasz Napierala size_t size; 304447636e4SEdward Tomasz Napierala 305447636e4SEdward Tomasz Napierala p = arg; 306447636e4SEdward Tomasz Napierala if (sb == NULL) { 307447636e4SEdward Tomasz Napierala size = 0; 308447636e4SEdward Tomasz Napierala sb = sbuf_new(NULL, NULL, LINUX_AT_COUNT * sizeof(Elf_Auxinfo), 309447636e4SEdward Tomasz Napierala SBUF_FIXEDLEN); 310447636e4SEdward Tomasz Napierala sbuf_set_drain(sb, sbuf_count_drain, &size); 311447636e4SEdward Tomasz Napierala PHOLD(p); 312447636e4SEdward Tomasz Napierala proc_getauxv(curthread, p, sb); 313447636e4SEdward Tomasz Napierala PRELE(p); 314447636e4SEdward Tomasz Napierala sbuf_finish(sb); 315447636e4SEdward Tomasz Napierala sbuf_delete(sb); 316447636e4SEdward Tomasz Napierala *sizep = size; 317447636e4SEdward Tomasz Napierala } else { 318447636e4SEdward Tomasz Napierala PHOLD(p); 319447636e4SEdward Tomasz Napierala proc_getauxv(curthread, p, sb); 320447636e4SEdward Tomasz Napierala PRELE(p); 321447636e4SEdward Tomasz Napierala } 322447636e4SEdward Tomasz Napierala } 3236039e966SDmitry Chagin 3246039e966SDmitry Chagin /* 3256039e966SDmitry Chagin * Copy strings out to the new process address space, constructing new arg 3266039e966SDmitry Chagin * and env vector tables. Return a pointer to the base so that it can be used 3276039e966SDmitry Chagin * as the initial stack pointer. 3286039e966SDmitry Chagin */ 3296039e966SDmitry Chagin int 3306039e966SDmitry Chagin __linuxN(copyout_strings)(struct image_params *imgp, uintptr_t *stack_base) 3316039e966SDmitry Chagin { 3326039e966SDmitry Chagin char canary[LINUX_AT_RANDOM_LEN]; 3336039e966SDmitry Chagin char **vectp; 3346039e966SDmitry Chagin char *stringp; 3356039e966SDmitry Chagin uintptr_t destp, ustringp; 3366039e966SDmitry Chagin struct ps_strings *arginfo; 3376039e966SDmitry Chagin struct proc *p; 3386039e966SDmitry Chagin size_t execpath_len; 3396039e966SDmitry Chagin int argc, envc; 3406039e966SDmitry Chagin int error; 3416039e966SDmitry Chagin 3426039e966SDmitry Chagin p = imgp->proc; 3436039e966SDmitry Chagin destp = PROC_PS_STRINGS(p); 3446039e966SDmitry Chagin arginfo = imgp->ps_strings = (void *)destp; 3456039e966SDmitry Chagin 3466039e966SDmitry Chagin /* 3476039e966SDmitry Chagin * Copy the image path for the rtld. 3486039e966SDmitry Chagin */ 3496039e966SDmitry Chagin if (imgp->execpath != NULL && imgp->auxargs != NULL) { 3506039e966SDmitry Chagin execpath_len = strlen(imgp->execpath) + 1; 3516039e966SDmitry Chagin destp -= execpath_len; 3526039e966SDmitry Chagin destp = rounddown2(destp, sizeof(void *)); 3536039e966SDmitry Chagin imgp->execpathp = (void *)destp; 3546039e966SDmitry Chagin error = copyout(imgp->execpath, imgp->execpathp, execpath_len); 3556039e966SDmitry Chagin if (error != 0) 3566039e966SDmitry Chagin return (error); 3576039e966SDmitry Chagin } 3586039e966SDmitry Chagin 3596039e966SDmitry Chagin /* 3606039e966SDmitry Chagin * Prepare the canary for SSP. 3616039e966SDmitry Chagin */ 3626039e966SDmitry Chagin arc4rand(canary, sizeof(canary), 0); 3636039e966SDmitry Chagin destp -= sizeof(canary); 3646039e966SDmitry Chagin imgp->canary = (void *)destp; 3656039e966SDmitry Chagin error = copyout(canary, imgp->canary, sizeof(canary)); 3666039e966SDmitry Chagin if (error != 0) 3676039e966SDmitry Chagin return (error); 3686039e966SDmitry Chagin imgp->canarylen = sizeof(canary); 3696039e966SDmitry Chagin 3706039e966SDmitry Chagin /* 3716039e966SDmitry Chagin * Allocate room for the argument and environment strings. 3726039e966SDmitry Chagin */ 3736039e966SDmitry Chagin destp -= ARG_MAX - imgp->args->stringspace; 3746039e966SDmitry Chagin destp = rounddown2(destp, sizeof(void *)); 3756039e966SDmitry Chagin ustringp = destp; 3766039e966SDmitry Chagin 3776039e966SDmitry Chagin if (imgp->auxargs) { 3786039e966SDmitry Chagin /* 3796039e966SDmitry Chagin * Allocate room on the stack for the ELF auxargs 3806039e966SDmitry Chagin * array. It has up to LINUX_AT_COUNT entries. 3816039e966SDmitry Chagin */ 3826039e966SDmitry Chagin destp -= LINUX_AT_COUNT * sizeof(Elf_Auxinfo); 3836039e966SDmitry Chagin destp = rounddown2(destp, sizeof(void *)); 3846039e966SDmitry Chagin } 3856039e966SDmitry Chagin 3866039e966SDmitry Chagin vectp = (char **)destp; 3876039e966SDmitry Chagin 3886039e966SDmitry Chagin /* 3896039e966SDmitry Chagin * Allocate room for the argv[] and env vectors including the 3906039e966SDmitry Chagin * terminating NULL pointers. 3916039e966SDmitry Chagin */ 3926039e966SDmitry Chagin vectp -= imgp->args->argc + 1 + imgp->args->envc + 1; 3936039e966SDmitry Chagin 3946039e966SDmitry Chagin /* 3956039e966SDmitry Chagin * Starting with 2.24, glibc depends on a 16-byte stack alignment. 3966039e966SDmitry Chagin */ 3976039e966SDmitry Chagin vectp = (char **)((((uintptr_t)vectp + 8) & ~0xF) - 8); 3986039e966SDmitry Chagin 3996039e966SDmitry Chagin /* 4006039e966SDmitry Chagin * vectp also becomes our initial stack base 4016039e966SDmitry Chagin */ 4026039e966SDmitry Chagin *stack_base = (uintptr_t)vectp; 4036039e966SDmitry Chagin 4046039e966SDmitry Chagin stringp = imgp->args->begin_argv; 4056039e966SDmitry Chagin argc = imgp->args->argc; 4066039e966SDmitry Chagin envc = imgp->args->envc; 4076039e966SDmitry Chagin 4086039e966SDmitry Chagin /* 4096039e966SDmitry Chagin * Copy out strings - arguments and environment. 4106039e966SDmitry Chagin */ 4116039e966SDmitry Chagin error = copyout(stringp, (void *)ustringp, 4126039e966SDmitry Chagin ARG_MAX - imgp->args->stringspace); 4136039e966SDmitry Chagin if (error != 0) 4146039e966SDmitry Chagin return (error); 4156039e966SDmitry Chagin 4166039e966SDmitry Chagin /* 4176039e966SDmitry Chagin * Fill in "ps_strings" struct for ps, w, etc. 4186039e966SDmitry Chagin */ 4196039e966SDmitry Chagin imgp->argv = vectp; 4206039e966SDmitry Chagin if (suword(&arginfo->ps_argvstr, (long)(intptr_t)vectp) != 0 || 4216039e966SDmitry Chagin suword32(&arginfo->ps_nargvstr, argc) != 0) 4226039e966SDmitry Chagin return (EFAULT); 4236039e966SDmitry Chagin 4246039e966SDmitry Chagin /* 4256039e966SDmitry Chagin * Fill in argument portion of vector table. 4266039e966SDmitry Chagin */ 4276039e966SDmitry Chagin for (; argc > 0; --argc) { 4286039e966SDmitry Chagin if (suword(vectp++, ustringp) != 0) 4296039e966SDmitry Chagin return (EFAULT); 4306039e966SDmitry Chagin while (*stringp++ != 0) 4316039e966SDmitry Chagin ustringp++; 4326039e966SDmitry Chagin ustringp++; 4336039e966SDmitry Chagin } 4346039e966SDmitry Chagin 4356039e966SDmitry Chagin /* a null vector table pointer separates the argp's from the envp's */ 4366039e966SDmitry Chagin if (suword(vectp++, 0) != 0) 4376039e966SDmitry Chagin return (EFAULT); 4386039e966SDmitry Chagin 4396039e966SDmitry Chagin imgp->envv = vectp; 4406039e966SDmitry Chagin if (suword(&arginfo->ps_envstr, (long)(intptr_t)vectp) != 0 || 4416039e966SDmitry Chagin suword32(&arginfo->ps_nenvstr, envc) != 0) 4426039e966SDmitry Chagin return (EFAULT); 4436039e966SDmitry Chagin 4446039e966SDmitry Chagin /* 4456039e966SDmitry Chagin * Fill in environment portion of vector table. 4466039e966SDmitry Chagin */ 4476039e966SDmitry Chagin for (; envc > 0; --envc) { 4486039e966SDmitry Chagin if (suword(vectp++, ustringp) != 0) 4496039e966SDmitry Chagin return (EFAULT); 4506039e966SDmitry Chagin while (*stringp++ != 0) 4516039e966SDmitry Chagin ustringp++; 4526039e966SDmitry Chagin ustringp++; 4536039e966SDmitry Chagin } 4546039e966SDmitry Chagin 4556039e966SDmitry Chagin /* end of vector table is a null pointer */ 4566039e966SDmitry Chagin if (suword(vectp, 0) != 0) 4576039e966SDmitry Chagin return (EFAULT); 4586039e966SDmitry Chagin 4596039e966SDmitry Chagin if (imgp->auxargs) { 4606039e966SDmitry Chagin vectp++; 4616039e966SDmitry Chagin error = imgp->sysent->sv_copyout_auxargs(imgp, 4626039e966SDmitry Chagin (uintptr_t)vectp); 4636039e966SDmitry Chagin if (error != 0) 4646039e966SDmitry Chagin return (error); 4656039e966SDmitry Chagin } 4666039e966SDmitry Chagin 4676039e966SDmitry Chagin return (0); 4686039e966SDmitry Chagin } 46995b86034SDmitry Chagin 47095b86034SDmitry Chagin bool 47195b86034SDmitry Chagin linux_trans_osrel(const Elf_Note *note, int32_t *osrel) 47295b86034SDmitry Chagin { 47395b86034SDmitry Chagin const Elf32_Word *desc; 47495b86034SDmitry Chagin uintptr_t p; 47595b86034SDmitry Chagin 47695b86034SDmitry Chagin p = (uintptr_t)(note + 1); 47795b86034SDmitry Chagin p += roundup2(note->n_namesz, sizeof(Elf32_Addr)); 47895b86034SDmitry Chagin 47995b86034SDmitry Chagin desc = (const Elf32_Word *)p; 48095b86034SDmitry Chagin if (desc[0] != GNU_ABI_LINUX) 48195b86034SDmitry Chagin return (false); 48295b86034SDmitry Chagin /* 48395b86034SDmitry Chagin * For Linux we encode osrel using the Linux convention of 48495b86034SDmitry Chagin * (version << 16) | (major << 8) | (minor) 48595b86034SDmitry Chagin * See macro in linux_mib.h 48695b86034SDmitry Chagin */ 48795b86034SDmitry Chagin *osrel = LINUX_KERNVER(desc[1], desc[2], desc[3]); 48895b86034SDmitry Chagin 48995b86034SDmitry Chagin return (true); 49095b86034SDmitry Chagin } 4917d8c9839SDmitry Chagin 4927d8c9839SDmitry Chagin int 4937d8c9839SDmitry Chagin __linuxN(copyout_auxargs)(struct image_params *imgp, uintptr_t base) 4947d8c9839SDmitry Chagin { 4957d8c9839SDmitry Chagin Elf_Auxargs *args; 4967d8c9839SDmitry Chagin Elf_Auxinfo *aarray, *pos; 4977d8c9839SDmitry Chagin struct proc *p; 4987d8c9839SDmitry Chagin int error, issetugid; 4997d8c9839SDmitry Chagin 5007d8c9839SDmitry Chagin p = imgp->proc; 5017d8c9839SDmitry Chagin issetugid = p->p_flag & P_SUGID ? 1 : 0; 5027d8c9839SDmitry Chagin args = imgp->auxargs; 5037d8c9839SDmitry Chagin aarray = pos = malloc(LINUX_AT_COUNT * sizeof(*pos), M_TEMP, 5047d8c9839SDmitry Chagin M_WAITOK | M_ZERO); 5057d8c9839SDmitry Chagin 5067d8c9839SDmitry Chagin __linuxN(arch_copyout_auxargs)(imgp, &pos); 5077d8c9839SDmitry Chagin /* 5087d8c9839SDmitry Chagin * Do not export AT_CLKTCK when emulating Linux kernel prior to 2.4.0, 5097d8c9839SDmitry Chagin * as it has appeared in the 2.4.0-rc7 first time. 5107d8c9839SDmitry Chagin * Being exported, AT_CLKTCK is returned by sysconf(_SC_CLK_TCK), 5117d8c9839SDmitry Chagin * glibc falls back to the hard-coded CLK_TCK value when aux entry 5127d8c9839SDmitry Chagin * is not present. 5137d8c9839SDmitry Chagin * Also see linux_times() implementation. 5147d8c9839SDmitry Chagin */ 5157d8c9839SDmitry Chagin if (linux_kernver(curthread) >= LINUX_KERNVER_2004000) 5167d8c9839SDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_CLKTCK, stclohz); 5177d8c9839SDmitry Chagin AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz); 5187d8c9839SDmitry Chagin AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); 5197d8c9839SDmitry Chagin AUXARGS_ENTRY(pos, AT_PHENT, args->phent); 5207d8c9839SDmitry Chagin AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); 5217d8c9839SDmitry Chagin AUXARGS_ENTRY(pos, AT_BASE, args->base); 5227d8c9839SDmitry Chagin AUXARGS_ENTRY(pos, AT_FLAGS, args->flags); 5237d8c9839SDmitry Chagin AUXARGS_ENTRY(pos, AT_ENTRY, args->entry); 5247d8c9839SDmitry Chagin AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid); 5257d8c9839SDmitry Chagin AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid); 5267d8c9839SDmitry Chagin AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid); 5277d8c9839SDmitry Chagin AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid); 5287d8c9839SDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_SECURE, issetugid); 52940c36c46SDmitry Chagin if (p->p_osrel >= LINUX_KERNVER_2006030 || p->p_osrel == 0) 5307d8c9839SDmitry Chagin AUXARGS_ENTRY_PTR(pos, LINUX_AT_RANDOM, imgp->canary); 53170eab81dSDmitry Chagin if ((p->p_osrel >= LINUX_KERNVER_2006026 || p->p_osrel == 0) && 53270eab81dSDmitry Chagin imgp->execpathp != 0) 5337d8c9839SDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_EXECFN, PTROUT(imgp->execpathp)); 5347d8c9839SDmitry Chagin if (args->execfd != -1) 5357d8c9839SDmitry Chagin AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); 536b7a6bcddSDmitry Chagin if (p->p_osrel >= LINUX_KERNVER_5013000 || p->p_osrel == 0) 537*66e8f1f7SDmitry Chagin AUXARGS_ENTRY(pos, LINUX_AT_MINSIGSTKSZ, 538*66e8f1f7SDmitry Chagin imgp->sysent->sv_minsigstksz); 5397d8c9839SDmitry Chagin AUXARGS_ENTRY(pos, AT_NULL, 0); 5407d8c9839SDmitry Chagin 5417d8c9839SDmitry Chagin free(imgp->auxargs, M_TEMP); 5427d8c9839SDmitry Chagin imgp->auxargs = NULL; 5437d8c9839SDmitry Chagin KASSERT(pos - aarray <= LINUX_AT_COUNT, ("Too many auxargs")); 5447d8c9839SDmitry Chagin 5457d8c9839SDmitry Chagin error = copyout(aarray, PTRIN(base), sizeof(*aarray) * LINUX_AT_COUNT); 5467d8c9839SDmitry Chagin free(aarray, M_TEMP); 5477d8c9839SDmitry Chagin return (error); 5487d8c9839SDmitry Chagin } 549