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> 44*6039e966SDmitry 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> 54*6039e966SDmitry Chagin #include <sys/sysent.h> 55*6039e966SDmitry Chagin 56*6039e966SDmitry Chagin #include <vm/vm.h> 57*6039e966SDmitry Chagin #include <vm/pmap.h> 58*6039e966SDmitry 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> 70*6039e966SDmitry Chagin #include <compat/linux/linux_misc.h> 71447636e4SEdward Tomasz Napierala 7274465145SDmitry Chagin struct l_elf_siginfo { 7374465145SDmitry Chagin l_int si_signo; 7474465145SDmitry Chagin l_int si_code; 7574465145SDmitry Chagin l_int si_errno; 7674465145SDmitry Chagin }; 7774465145SDmitry Chagin 7874465145SDmitry Chagin typedef struct linux_pt_regset l_elf_gregset_t; 7974465145SDmitry Chagin 8074465145SDmitry Chagin struct linux_elf_prstatus { 8174465145SDmitry Chagin struct l_elf_siginfo pr_info; 8274465145SDmitry Chagin l_short pr_cursig; 8374465145SDmitry Chagin l_ulong pr_sigpend; 8474465145SDmitry Chagin l_ulong pr_sighold; 8574465145SDmitry Chagin l_pid_t pr_pid; 8674465145SDmitry Chagin l_pid_t pr_ppid; 8774465145SDmitry Chagin l_pid_t pr_pgrp; 8874465145SDmitry Chagin l_pid_t pr_sid; 8974465145SDmitry Chagin l_timeval pr_utime; 9074465145SDmitry Chagin l_timeval pr_stime; 9174465145SDmitry Chagin l_timeval pr_cutime; 9274465145SDmitry Chagin l_timeval pr_cstime; 9374465145SDmitry Chagin l_elf_gregset_t pr_reg; 9474465145SDmitry Chagin l_int pr_fpvalid; 9574465145SDmitry Chagin }; 96447636e4SEdward Tomasz Napierala 97447636e4SEdward Tomasz Napierala #define LINUX_NT_AUXV 6 98447636e4SEdward Tomasz Napierala 99447636e4SEdward Tomasz Napierala static void __linuxN(note_fpregset)(void *, struct sbuf *, size_t *); 100447636e4SEdward Tomasz Napierala static void __linuxN(note_prpsinfo)(void *, struct sbuf *, size_t *); 101447636e4SEdward Tomasz Napierala static void __linuxN(note_prstatus)(void *, struct sbuf *, size_t *); 102447636e4SEdward Tomasz Napierala static void __linuxN(note_threadmd)(void *, struct sbuf *, size_t *); 103447636e4SEdward Tomasz Napierala static void __linuxN(note_nt_auxv)(void *, struct sbuf *, size_t *); 104447636e4SEdward Tomasz Napierala 105447636e4SEdward Tomasz Napierala void 106447636e4SEdward Tomasz Napierala __linuxN(prepare_notes)(struct thread *td, struct note_info_list *list, 107447636e4SEdward Tomasz Napierala size_t *sizep) 108447636e4SEdward Tomasz Napierala { 109447636e4SEdward Tomasz Napierala struct proc *p; 110447636e4SEdward Tomasz Napierala struct thread *thr; 111447636e4SEdward Tomasz Napierala size_t size; 112447636e4SEdward Tomasz Napierala 113447636e4SEdward Tomasz Napierala p = td->td_proc; 114447636e4SEdward Tomasz Napierala size = 0; 115447636e4SEdward Tomasz Napierala 116447636e4SEdward Tomasz Napierala /* 117447636e4SEdward Tomasz Napierala * To have the debugger select the right thread (LWP) as the initial 118447636e4SEdward Tomasz Napierala * thread, we dump the state of the thread passed to us in td first. 119447636e4SEdward Tomasz Napierala * This is the thread that causes the core dump and thus likely to 120447636e4SEdward Tomasz Napierala * be the right thread one wants to have selected in the debugger. 121447636e4SEdward Tomasz Napierala */ 122447636e4SEdward Tomasz Napierala thr = td; 123447636e4SEdward Tomasz Napierala while (thr != NULL) { 124447636e4SEdward Tomasz Napierala size += __elfN(register_note)(td, list, 125447636e4SEdward Tomasz Napierala NT_PRSTATUS, __linuxN(note_prstatus), thr); 126447636e4SEdward Tomasz Napierala size += __elfN(register_note)(td, list, 127447636e4SEdward Tomasz Napierala NT_PRPSINFO, __linuxN(note_prpsinfo), p); 128447636e4SEdward Tomasz Napierala size += __elfN(register_note)(td, list, 129447636e4SEdward Tomasz Napierala LINUX_NT_AUXV, __linuxN(note_nt_auxv), p); 130447636e4SEdward Tomasz Napierala size += __elfN(register_note)(td, list, 131447636e4SEdward Tomasz Napierala NT_FPREGSET, __linuxN(note_fpregset), thr); 132447636e4SEdward Tomasz Napierala size += __elfN(register_note)(td, list, 133447636e4SEdward Tomasz Napierala -1, __linuxN(note_threadmd), thr); 134447636e4SEdward Tomasz Napierala 135447636e4SEdward Tomasz Napierala thr = thr == td ? TAILQ_FIRST(&p->p_threads) : 136447636e4SEdward Tomasz Napierala TAILQ_NEXT(thr, td_plist); 137447636e4SEdward Tomasz Napierala if (thr == td) 138447636e4SEdward Tomasz Napierala thr = TAILQ_NEXT(thr, td_plist); 139447636e4SEdward Tomasz Napierala } 140447636e4SEdward Tomasz Napierala 141447636e4SEdward Tomasz Napierala *sizep = size; 142447636e4SEdward Tomasz Napierala } 143447636e4SEdward Tomasz Napierala 144447636e4SEdward Tomasz Napierala typedef struct linux_elf_prstatus linux_elf_prstatus_t; 1456f8439dbSDmitry Chagin #ifdef COMPAT_LINUX32 146447636e4SEdward Tomasz Napierala typedef struct prpsinfo32 linux_elf_prpsinfo_t; 147447636e4SEdward Tomasz Napierala typedef struct fpreg32 linux_elf_prfpregset_t; 148447636e4SEdward Tomasz Napierala #else 149447636e4SEdward Tomasz Napierala typedef prpsinfo_t linux_elf_prpsinfo_t; 150447636e4SEdward Tomasz Napierala typedef prfpregset_t linux_elf_prfpregset_t; 151447636e4SEdward Tomasz Napierala #endif 152447636e4SEdward Tomasz Napierala 153447636e4SEdward Tomasz Napierala static void 154447636e4SEdward Tomasz Napierala __linuxN(note_prpsinfo)(void *arg, struct sbuf *sb, size_t *sizep) 155447636e4SEdward Tomasz Napierala { 156447636e4SEdward Tomasz Napierala struct sbuf sbarg; 157447636e4SEdward Tomasz Napierala size_t len; 158447636e4SEdward Tomasz Napierala char *cp, *end; 159447636e4SEdward Tomasz Napierala struct proc *p; 160447636e4SEdward Tomasz Napierala linux_elf_prpsinfo_t *psinfo; 161447636e4SEdward Tomasz Napierala int error; 162447636e4SEdward Tomasz Napierala 163447636e4SEdward Tomasz Napierala p = arg; 164447636e4SEdward Tomasz Napierala if (sb != NULL) { 165447636e4SEdward Tomasz Napierala KASSERT(*sizep == sizeof(*psinfo), ("invalid size")); 166447636e4SEdward Tomasz Napierala psinfo = malloc(sizeof(*psinfo), M_TEMP, M_ZERO | M_WAITOK); 167447636e4SEdward Tomasz Napierala psinfo->pr_version = PRPSINFO_VERSION; 168447636e4SEdward Tomasz Napierala psinfo->pr_psinfosz = sizeof(linux_elf_prpsinfo_t); 169447636e4SEdward Tomasz Napierala strlcpy(psinfo->pr_fname, p->p_comm, sizeof(psinfo->pr_fname)); 170447636e4SEdward Tomasz Napierala PROC_LOCK(p); 171447636e4SEdward Tomasz Napierala if (p->p_args != NULL) { 172447636e4SEdward Tomasz Napierala len = sizeof(psinfo->pr_psargs) - 1; 173447636e4SEdward Tomasz Napierala if (len > p->p_args->ar_length) 174447636e4SEdward Tomasz Napierala len = p->p_args->ar_length; 175447636e4SEdward Tomasz Napierala memcpy(psinfo->pr_psargs, p->p_args->ar_args, len); 176447636e4SEdward Tomasz Napierala PROC_UNLOCK(p); 177447636e4SEdward Tomasz Napierala error = 0; 178447636e4SEdward Tomasz Napierala } else { 179447636e4SEdward Tomasz Napierala _PHOLD(p); 180447636e4SEdward Tomasz Napierala PROC_UNLOCK(p); 181447636e4SEdward Tomasz Napierala sbuf_new(&sbarg, psinfo->pr_psargs, 182447636e4SEdward Tomasz Napierala sizeof(psinfo->pr_psargs), SBUF_FIXEDLEN); 183447636e4SEdward Tomasz Napierala error = proc_getargv(curthread, p, &sbarg); 184447636e4SEdward Tomasz Napierala PRELE(p); 18500d17cf3SKonstantin Belousov if (sbuf_finish(&sbarg) == 0) { 186447636e4SEdward Tomasz Napierala len = sbuf_len(&sbarg) - 1; 18700d17cf3SKonstantin Belousov if (len > 0) 18800d17cf3SKonstantin Belousov len--; 18900d17cf3SKonstantin Belousov } else { 190447636e4SEdward Tomasz Napierala len = sizeof(psinfo->pr_psargs) - 1; 19100d17cf3SKonstantin Belousov } 192447636e4SEdward Tomasz Napierala sbuf_delete(&sbarg); 193447636e4SEdward Tomasz Napierala } 19400d17cf3SKonstantin Belousov if (error != 0 || len == 0 || (ssize_t)len == -1) 195447636e4SEdward Tomasz Napierala strlcpy(psinfo->pr_psargs, p->p_comm, 196447636e4SEdward Tomasz Napierala sizeof(psinfo->pr_psargs)); 197447636e4SEdward Tomasz Napierala else { 198447636e4SEdward Tomasz Napierala KASSERT(len < sizeof(psinfo->pr_psargs), 199447636e4SEdward Tomasz Napierala ("len is too long: %zu vs %zu", len, 200447636e4SEdward Tomasz Napierala sizeof(psinfo->pr_psargs))); 201447636e4SEdward Tomasz Napierala cp = psinfo->pr_psargs; 202447636e4SEdward Tomasz Napierala end = cp + len - 1; 203447636e4SEdward Tomasz Napierala for (;;) { 204447636e4SEdward Tomasz Napierala cp = memchr(cp, '\0', end - cp); 205447636e4SEdward Tomasz Napierala if (cp == NULL) 206447636e4SEdward Tomasz Napierala break; 207447636e4SEdward Tomasz Napierala *cp = ' '; 208447636e4SEdward Tomasz Napierala } 209447636e4SEdward Tomasz Napierala } 210447636e4SEdward Tomasz Napierala psinfo->pr_pid = p->p_pid; 211447636e4SEdward Tomasz Napierala sbuf_bcat(sb, psinfo, sizeof(*psinfo)); 212447636e4SEdward Tomasz Napierala free(psinfo, M_TEMP); 213447636e4SEdward Tomasz Napierala } 214447636e4SEdward Tomasz Napierala *sizep = sizeof(*psinfo); 215447636e4SEdward Tomasz Napierala } 216447636e4SEdward Tomasz Napierala 217447636e4SEdward Tomasz Napierala static void 218447636e4SEdward Tomasz Napierala __linuxN(note_prstatus)(void *arg, struct sbuf *sb, size_t *sizep) 219447636e4SEdward Tomasz Napierala { 220447636e4SEdward Tomasz Napierala struct thread *td; 221447636e4SEdward Tomasz Napierala linux_elf_prstatus_t *status; 2226f8439dbSDmitry Chagin #ifdef COMPAT_LINUX32 223447636e4SEdward Tomasz Napierala struct reg32 pr_reg; 224447636e4SEdward Tomasz Napierala #else 225447636e4SEdward Tomasz Napierala struct reg pr_reg; 226447636e4SEdward Tomasz Napierala #endif 227447636e4SEdward Tomasz Napierala 228447636e4SEdward Tomasz Napierala td = arg; 229447636e4SEdward Tomasz Napierala if (sb != NULL) { 230447636e4SEdward Tomasz Napierala KASSERT(*sizep == sizeof(*status), ("invalid size")); 231447636e4SEdward Tomasz Napierala status = malloc(sizeof(*status), M_TEMP, M_ZERO | M_WAITOK); 232447636e4SEdward Tomasz Napierala 233447636e4SEdward Tomasz Napierala /* 234447636e4SEdward Tomasz Napierala * XXX: Some fields missing. 235447636e4SEdward Tomasz Napierala */ 236447636e4SEdward Tomasz Napierala status->pr_cursig = td->td_proc->p_sig; 237447636e4SEdward Tomasz Napierala status->pr_pid = td->td_tid; 238447636e4SEdward Tomasz Napierala 2396f8439dbSDmitry Chagin #ifdef COMPAT_LINUX32 240447636e4SEdward Tomasz Napierala fill_regs32(td, &pr_reg); 241447636e4SEdward Tomasz Napierala #else 242447636e4SEdward Tomasz Napierala fill_regs(td, &pr_reg); 243447636e4SEdward Tomasz Napierala #endif 244447636e4SEdward Tomasz Napierala bsd_to_linux_regset(&pr_reg, &status->pr_reg); 245447636e4SEdward Tomasz Napierala sbuf_bcat(sb, status, sizeof(*status)); 246447636e4SEdward Tomasz Napierala free(status, M_TEMP); 247447636e4SEdward Tomasz Napierala } 248447636e4SEdward Tomasz Napierala *sizep = sizeof(*status); 249447636e4SEdward Tomasz Napierala } 250447636e4SEdward Tomasz Napierala 251447636e4SEdward Tomasz Napierala static void 252447636e4SEdward Tomasz Napierala __linuxN(note_fpregset)(void *arg, struct sbuf *sb, size_t *sizep) 253447636e4SEdward Tomasz Napierala { 254447636e4SEdward Tomasz Napierala struct thread *td; 255447636e4SEdward Tomasz Napierala linux_elf_prfpregset_t *fpregset; 256447636e4SEdward Tomasz Napierala 257447636e4SEdward Tomasz Napierala td = arg; 258447636e4SEdward Tomasz Napierala if (sb != NULL) { 259447636e4SEdward Tomasz Napierala KASSERT(*sizep == sizeof(*fpregset), ("invalid size")); 260447636e4SEdward Tomasz Napierala fpregset = malloc(sizeof(*fpregset), M_TEMP, M_ZERO | M_WAITOK); 2616f8439dbSDmitry Chagin #ifdef COMPAT_LINUX32 262447636e4SEdward Tomasz Napierala fill_fpregs32(td, fpregset); 263447636e4SEdward Tomasz Napierala #else 264447636e4SEdward Tomasz Napierala fill_fpregs(td, fpregset); 265447636e4SEdward Tomasz Napierala #endif 266447636e4SEdward Tomasz Napierala sbuf_bcat(sb, fpregset, sizeof(*fpregset)); 267447636e4SEdward Tomasz Napierala free(fpregset, M_TEMP); 268447636e4SEdward Tomasz Napierala } 269447636e4SEdward Tomasz Napierala *sizep = sizeof(*fpregset); 270447636e4SEdward Tomasz Napierala } 271447636e4SEdward Tomasz Napierala 272447636e4SEdward Tomasz Napierala /* 273447636e4SEdward Tomasz Napierala * Allow for MD specific notes, as well as any MD 274447636e4SEdward Tomasz Napierala * specific preparations for writing MI notes. 275447636e4SEdward Tomasz Napierala */ 276447636e4SEdward Tomasz Napierala static void 277447636e4SEdward Tomasz Napierala __linuxN(note_threadmd)(void *arg, struct sbuf *sb, size_t *sizep) 278447636e4SEdward Tomasz Napierala { 279447636e4SEdward Tomasz Napierala struct thread *td; 280447636e4SEdward Tomasz Napierala void *buf; 281447636e4SEdward Tomasz Napierala size_t size; 282447636e4SEdward Tomasz Napierala 283447636e4SEdward Tomasz Napierala td = arg; 284447636e4SEdward Tomasz Napierala size = *sizep; 285447636e4SEdward Tomasz Napierala if (size != 0 && sb != NULL) 286447636e4SEdward Tomasz Napierala buf = malloc(size, M_TEMP, M_ZERO | M_WAITOK); 287447636e4SEdward Tomasz Napierala else 288447636e4SEdward Tomasz Napierala buf = NULL; 289447636e4SEdward Tomasz Napierala size = 0; 290447636e4SEdward Tomasz Napierala __elfN(dump_thread)(td, buf, &size); 291447636e4SEdward Tomasz Napierala KASSERT(sb == NULL || *sizep == size, ("invalid size")); 292447636e4SEdward Tomasz Napierala if (size != 0 && sb != NULL) 293447636e4SEdward Tomasz Napierala sbuf_bcat(sb, buf, size); 294447636e4SEdward Tomasz Napierala free(buf, M_TEMP); 295447636e4SEdward Tomasz Napierala *sizep = size; 296447636e4SEdward Tomasz Napierala } 297447636e4SEdward Tomasz Napierala 298447636e4SEdward Tomasz Napierala static void 299447636e4SEdward Tomasz Napierala __linuxN(note_nt_auxv)(void *arg, struct sbuf *sb, size_t *sizep) 300447636e4SEdward Tomasz Napierala { 301447636e4SEdward Tomasz Napierala struct proc *p; 302447636e4SEdward Tomasz Napierala size_t size; 303447636e4SEdward Tomasz Napierala 304447636e4SEdward Tomasz Napierala p = arg; 305447636e4SEdward Tomasz Napierala if (sb == NULL) { 306447636e4SEdward Tomasz Napierala size = 0; 307447636e4SEdward Tomasz Napierala sb = sbuf_new(NULL, NULL, LINUX_AT_COUNT * sizeof(Elf_Auxinfo), 308447636e4SEdward Tomasz Napierala SBUF_FIXEDLEN); 309447636e4SEdward Tomasz Napierala sbuf_set_drain(sb, sbuf_count_drain, &size); 310447636e4SEdward Tomasz Napierala PHOLD(p); 311447636e4SEdward Tomasz Napierala proc_getauxv(curthread, p, sb); 312447636e4SEdward Tomasz Napierala PRELE(p); 313447636e4SEdward Tomasz Napierala sbuf_finish(sb); 314447636e4SEdward Tomasz Napierala sbuf_delete(sb); 315447636e4SEdward Tomasz Napierala *sizep = size; 316447636e4SEdward Tomasz Napierala } else { 317447636e4SEdward Tomasz Napierala PHOLD(p); 318447636e4SEdward Tomasz Napierala proc_getauxv(curthread, p, sb); 319447636e4SEdward Tomasz Napierala PRELE(p); 320447636e4SEdward Tomasz Napierala } 321447636e4SEdward Tomasz Napierala } 322*6039e966SDmitry Chagin 323*6039e966SDmitry Chagin /* 324*6039e966SDmitry Chagin * Copy strings out to the new process address space, constructing new arg 325*6039e966SDmitry Chagin * and env vector tables. Return a pointer to the base so that it can be used 326*6039e966SDmitry Chagin * as the initial stack pointer. 327*6039e966SDmitry Chagin */ 328*6039e966SDmitry Chagin int 329*6039e966SDmitry Chagin __linuxN(copyout_strings)(struct image_params *imgp, uintptr_t *stack_base) 330*6039e966SDmitry Chagin { 331*6039e966SDmitry Chagin char canary[LINUX_AT_RANDOM_LEN]; 332*6039e966SDmitry Chagin char **vectp; 333*6039e966SDmitry Chagin char *stringp; 334*6039e966SDmitry Chagin uintptr_t destp, ustringp; 335*6039e966SDmitry Chagin struct ps_strings *arginfo; 336*6039e966SDmitry Chagin struct proc *p; 337*6039e966SDmitry Chagin size_t execpath_len; 338*6039e966SDmitry Chagin int argc, envc; 339*6039e966SDmitry Chagin int error; 340*6039e966SDmitry Chagin 341*6039e966SDmitry Chagin p = imgp->proc; 342*6039e966SDmitry Chagin destp = PROC_PS_STRINGS(p); 343*6039e966SDmitry Chagin arginfo = imgp->ps_strings = (void *)destp; 344*6039e966SDmitry Chagin 345*6039e966SDmitry Chagin /* 346*6039e966SDmitry Chagin * Copy the image path for the rtld. 347*6039e966SDmitry Chagin */ 348*6039e966SDmitry Chagin if (imgp->execpath != NULL && imgp->auxargs != NULL) { 349*6039e966SDmitry Chagin execpath_len = strlen(imgp->execpath) + 1; 350*6039e966SDmitry Chagin destp -= execpath_len; 351*6039e966SDmitry Chagin destp = rounddown2(destp, sizeof(void *)); 352*6039e966SDmitry Chagin imgp->execpathp = (void *)destp; 353*6039e966SDmitry Chagin error = copyout(imgp->execpath, imgp->execpathp, execpath_len); 354*6039e966SDmitry Chagin if (error != 0) 355*6039e966SDmitry Chagin return (error); 356*6039e966SDmitry Chagin } 357*6039e966SDmitry Chagin 358*6039e966SDmitry Chagin /* 359*6039e966SDmitry Chagin * Prepare the canary for SSP. 360*6039e966SDmitry Chagin */ 361*6039e966SDmitry Chagin arc4rand(canary, sizeof(canary), 0); 362*6039e966SDmitry Chagin destp -= sizeof(canary); 363*6039e966SDmitry Chagin imgp->canary = (void *)destp; 364*6039e966SDmitry Chagin error = copyout(canary, imgp->canary, sizeof(canary)); 365*6039e966SDmitry Chagin if (error != 0) 366*6039e966SDmitry Chagin return (error); 367*6039e966SDmitry Chagin imgp->canarylen = sizeof(canary); 368*6039e966SDmitry Chagin 369*6039e966SDmitry Chagin /* 370*6039e966SDmitry Chagin * Allocate room for the argument and environment strings. 371*6039e966SDmitry Chagin */ 372*6039e966SDmitry Chagin destp -= ARG_MAX - imgp->args->stringspace; 373*6039e966SDmitry Chagin destp = rounddown2(destp, sizeof(void *)); 374*6039e966SDmitry Chagin ustringp = destp; 375*6039e966SDmitry Chagin 376*6039e966SDmitry Chagin if (imgp->auxargs) { 377*6039e966SDmitry Chagin /* 378*6039e966SDmitry Chagin * Allocate room on the stack for the ELF auxargs 379*6039e966SDmitry Chagin * array. It has up to LINUX_AT_COUNT entries. 380*6039e966SDmitry Chagin */ 381*6039e966SDmitry Chagin destp -= LINUX_AT_COUNT * sizeof(Elf_Auxinfo); 382*6039e966SDmitry Chagin destp = rounddown2(destp, sizeof(void *)); 383*6039e966SDmitry Chagin } 384*6039e966SDmitry Chagin 385*6039e966SDmitry Chagin vectp = (char **)destp; 386*6039e966SDmitry Chagin 387*6039e966SDmitry Chagin /* 388*6039e966SDmitry Chagin * Allocate room for the argv[] and env vectors including the 389*6039e966SDmitry Chagin * terminating NULL pointers. 390*6039e966SDmitry Chagin */ 391*6039e966SDmitry Chagin vectp -= imgp->args->argc + 1 + imgp->args->envc + 1; 392*6039e966SDmitry Chagin 393*6039e966SDmitry Chagin /* 394*6039e966SDmitry Chagin * Starting with 2.24, glibc depends on a 16-byte stack alignment. 395*6039e966SDmitry Chagin */ 396*6039e966SDmitry Chagin vectp = (char **)((((uintptr_t)vectp + 8) & ~0xF) - 8); 397*6039e966SDmitry Chagin 398*6039e966SDmitry Chagin /* 399*6039e966SDmitry Chagin * vectp also becomes our initial stack base 400*6039e966SDmitry Chagin */ 401*6039e966SDmitry Chagin *stack_base = (uintptr_t)vectp; 402*6039e966SDmitry Chagin 403*6039e966SDmitry Chagin stringp = imgp->args->begin_argv; 404*6039e966SDmitry Chagin argc = imgp->args->argc; 405*6039e966SDmitry Chagin envc = imgp->args->envc; 406*6039e966SDmitry Chagin 407*6039e966SDmitry Chagin /* 408*6039e966SDmitry Chagin * Copy out strings - arguments and environment. 409*6039e966SDmitry Chagin */ 410*6039e966SDmitry Chagin error = copyout(stringp, (void *)ustringp, 411*6039e966SDmitry Chagin ARG_MAX - imgp->args->stringspace); 412*6039e966SDmitry Chagin if (error != 0) 413*6039e966SDmitry Chagin return (error); 414*6039e966SDmitry Chagin 415*6039e966SDmitry Chagin /* 416*6039e966SDmitry Chagin * Fill in "ps_strings" struct for ps, w, etc. 417*6039e966SDmitry Chagin */ 418*6039e966SDmitry Chagin imgp->argv = vectp; 419*6039e966SDmitry Chagin if (suword(&arginfo->ps_argvstr, (long)(intptr_t)vectp) != 0 || 420*6039e966SDmitry Chagin suword32(&arginfo->ps_nargvstr, argc) != 0) 421*6039e966SDmitry Chagin return (EFAULT); 422*6039e966SDmitry Chagin 423*6039e966SDmitry Chagin /* 424*6039e966SDmitry Chagin * Fill in argument portion of vector table. 425*6039e966SDmitry Chagin */ 426*6039e966SDmitry Chagin for (; argc > 0; --argc) { 427*6039e966SDmitry Chagin if (suword(vectp++, ustringp) != 0) 428*6039e966SDmitry Chagin return (EFAULT); 429*6039e966SDmitry Chagin while (*stringp++ != 0) 430*6039e966SDmitry Chagin ustringp++; 431*6039e966SDmitry Chagin ustringp++; 432*6039e966SDmitry Chagin } 433*6039e966SDmitry Chagin 434*6039e966SDmitry Chagin /* a null vector table pointer separates the argp's from the envp's */ 435*6039e966SDmitry Chagin if (suword(vectp++, 0) != 0) 436*6039e966SDmitry Chagin return (EFAULT); 437*6039e966SDmitry Chagin 438*6039e966SDmitry Chagin imgp->envv = vectp; 439*6039e966SDmitry Chagin if (suword(&arginfo->ps_envstr, (long)(intptr_t)vectp) != 0 || 440*6039e966SDmitry Chagin suword32(&arginfo->ps_nenvstr, envc) != 0) 441*6039e966SDmitry Chagin return (EFAULT); 442*6039e966SDmitry Chagin 443*6039e966SDmitry Chagin /* 444*6039e966SDmitry Chagin * Fill in environment portion of vector table. 445*6039e966SDmitry Chagin */ 446*6039e966SDmitry Chagin for (; envc > 0; --envc) { 447*6039e966SDmitry Chagin if (suword(vectp++, ustringp) != 0) 448*6039e966SDmitry Chagin return (EFAULT); 449*6039e966SDmitry Chagin while (*stringp++ != 0) 450*6039e966SDmitry Chagin ustringp++; 451*6039e966SDmitry Chagin ustringp++; 452*6039e966SDmitry Chagin } 453*6039e966SDmitry Chagin 454*6039e966SDmitry Chagin /* end of vector table is a null pointer */ 455*6039e966SDmitry Chagin if (suword(vectp, 0) != 0) 456*6039e966SDmitry Chagin return (EFAULT); 457*6039e966SDmitry Chagin 458*6039e966SDmitry Chagin if (imgp->auxargs) { 459*6039e966SDmitry Chagin vectp++; 460*6039e966SDmitry Chagin error = imgp->sysent->sv_copyout_auxargs(imgp, 461*6039e966SDmitry Chagin (uintptr_t)vectp); 462*6039e966SDmitry Chagin if (error != 0) 463*6039e966SDmitry Chagin return (error); 464*6039e966SDmitry Chagin } 465*6039e966SDmitry Chagin 466*6039e966SDmitry Chagin return (0); 467*6039e966SDmitry Chagin } 468