1161304Snetchild/*- 2161304Snetchild * Copyright (c) 2006 Roman Divacky 3293493Sdchagin * Copyright (c) 2013 Dmitry Chagin 4161304Snetchild * All rights reserved. 5161304Snetchild * 6161304Snetchild * Redistribution and use in source and binary forms, with or without 7161304Snetchild * modification, are permitted provided that the following conditions 8161304Snetchild * are met: 9161304Snetchild * 1. Redistributions of source code must retain the above copyright 10161304Snetchild * notice, this list of conditions and the following disclaimer 11161304Snetchild * in this position and unchanged. 12161304Snetchild * 2. Redistributions in binary form must reproduce the above copyright 13161304Snetchild * notice, this list of conditions and the following disclaimer in the 14161304Snetchild * documentation and/or other materials provided with the distribution. 15161304Snetchild * 3. The name of the author may not be used to endorse or promote products 16161304Snetchild * derived from this software without specific prior written permission 17161304Snetchild * 18161304Snetchild * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19161304Snetchild * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20161304Snetchild * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21161304Snetchild * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22161304Snetchild * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23161304Snetchild * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24161304Snetchild * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25161304Snetchild * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26161304Snetchild * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27161304Snetchild * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28161304Snetchild */ 29161304Snetchild 30161304Snetchild#include <sys/cdefs.h> 31161304Snetchild__FBSDID("$FreeBSD$"); 32161304Snetchild 33161304Snetchild#include <sys/param.h> 34161304Snetchild#include <sys/systm.h> 35161304Snetchild#include <sys/imgact.h> 36166420Skib#include <sys/kernel.h> 37293493Sdchagin#include <sys/ktr.h> 38161304Snetchild#include <sys/lock.h> 39161304Snetchild#include <sys/malloc.h> 40161304Snetchild#include <sys/mutex.h> 41161304Snetchild#include <sys/sx.h> 42161304Snetchild#include <sys/proc.h> 43161304Snetchild#include <sys/syscallsubr.h> 44215706Sdim#include <sys/sysent.h> 45161304Snetchild 46178976Srdivacky#include <compat/linux/linux_emul.h> 47246085Sjhb#include <compat/linux/linux_misc.h> 48302962Sdchagin#include <compat/linux/linux_persona.h> 49293493Sdchagin#include <compat/linux/linux_util.h> 50178976Srdivacky 51235063Snetchild 52293493Sdchagin/* 53293528Sdchagin * This returns reference to the thread emuldata entry (if found) 54293493Sdchagin * 55293493Sdchagin * Hold PROC_LOCK when referencing emuldata from other threads. 56293493Sdchagin */ 57161304Snetchildstruct linux_emuldata * 58293493Sdchaginem_find(struct thread *td) 59161304Snetchild{ 60161304Snetchild struct linux_emuldata *em; 61161304Snetchild 62293493Sdchagin em = td->td_emuldata; 63161304Snetchild 64161304Snetchild return (em); 65161304Snetchild} 66161304Snetchild 67293528Sdchagin/* 68293528Sdchagin * This returns reference to the proc pemuldata entry (if found) 69293528Sdchagin * 70293528Sdchagin * Hold PROC_LOCK when referencing proc pemuldata from other threads. 71293528Sdchagin * Hold LINUX_PEM_LOCK wher referencing pemuldata members. 72293528Sdchagin */ 73293528Sdchaginstruct linux_pemuldata * 74293528Sdchaginpem_find(struct proc *p) 75293528Sdchagin{ 76293528Sdchagin struct linux_pemuldata *pem; 77293528Sdchagin 78293528Sdchagin pem = p->p_emuldata; 79293528Sdchagin 80293528Sdchagin return (pem); 81293528Sdchagin} 82293528Sdchagin 83293493Sdchaginvoid 84293493Sdchaginlinux_proc_init(struct thread *td, struct thread *newtd, int flags) 85161304Snetchild{ 86293493Sdchagin struct linux_emuldata *em; 87293528Sdchagin struct linux_pemuldata *pem; 88293546Sdchagin struct epoll_emuldata *emd; 89293559Sdchagin struct proc *p; 90161304Snetchild 91293493Sdchagin if (newtd != NULL) { 92293559Sdchagin p = newtd->td_proc; 93293559Sdchagin 94293493Sdchagin /* non-exec call */ 95293493Sdchagin em = malloc(sizeof(*em), M_TEMP, M_WAITOK | M_ZERO); 96167157Sjkim if (flags & LINUX_CLONE_THREAD) { 97293546Sdchagin LINUX_CTR1(proc_init, "thread newtd(%d)", 98293546Sdchagin newtd->td_tid); 99293546Sdchagin 100293493Sdchagin em->em_tid = newtd->td_tid; 101161304Snetchild } else { 102293559Sdchagin LINUX_CTR1(proc_init, "fork newtd(%d)", p->p_pid); 103235063Snetchild 104293559Sdchagin em->em_tid = p->p_pid; 105293528Sdchagin 106293532Sdchagin pem = malloc(sizeof(*pem), M_LINUX, M_WAITOK | M_ZERO); 107293528Sdchagin sx_init(&pem->pem_sx, "lpemlk"); 108293559Sdchagin p->p_emuldata = pem; 109161304Snetchild } 110293493Sdchagin newtd->td_emuldata = em; 111161304Snetchild } else { 112293559Sdchagin p = td->td_proc; 113293559Sdchagin 114235063Snetchild /* exec */ 115293559Sdchagin LINUX_CTR1(proc_init, "exec newtd(%d)", p->p_pid); 116235063Snetchild 117161304Snetchild /* lookup the old one */ 118293493Sdchagin em = em_find(td); 119161304Snetchild KASSERT(em != NULL, ("proc_init: emuldata not found in exec case.\n")); 120293493Sdchagin 121293559Sdchagin em->em_tid = p->p_pid; 122293558Sdchagin em->flags = 0; 123293558Sdchagin em->pdeath_signal = 0; 124293558Sdchagin em->robust_futexes = NULL; 125293558Sdchagin em->child_clear_tid = NULL; 126293558Sdchagin em->child_set_tid = NULL; 127293546Sdchagin 128293546Sdchagin /* epoll should be destroyed in a case of exec. */ 129293559Sdchagin pem = pem_find(p); 130293546Sdchagin KASSERT(pem != NULL, ("proc_exit: proc emuldata not found.\n")); 131302962Sdchagin pem->persona = 0; 132293546Sdchagin if (pem->epoll != NULL) { 133293546Sdchagin emd = pem->epoll; 134293546Sdchagin pem->epoll = NULL; 135293546Sdchagin free(emd, M_EPOLL); 136293546Sdchagin } 137161304Snetchild } 138161304Snetchild 139293493Sdchagin} 140293493Sdchagin 141293493Sdchaginvoid 142293493Sdchaginlinux_proc_exit(void *arg __unused, struct proc *p) 143293493Sdchagin{ 144293528Sdchagin struct linux_pemuldata *pem; 145293546Sdchagin struct epoll_emuldata *emd; 146293493Sdchagin struct thread *td = curthread; 147293493Sdchagin 148293528Sdchagin if (__predict_false(SV_CURPROC_ABI() != SV_ABI_LINUX)) 149293528Sdchagin return; 150293528Sdchagin 151293560Sdchagin LINUX_CTR3(proc_exit, "thread(%d) proc(%d) p %p", 152293560Sdchagin td->td_tid, p->p_pid, p); 153293560Sdchagin 154293528Sdchagin pem = pem_find(p); 155293528Sdchagin if (pem == NULL) 156293528Sdchagin return; 157293528Sdchagin (p->p_sysent->sv_thread_detach)(td); 158293528Sdchagin 159293528Sdchagin p->p_emuldata = NULL; 160293528Sdchagin 161293546Sdchagin if (pem->epoll != NULL) { 162293546Sdchagin emd = pem->epoll; 163293546Sdchagin pem->epoll = NULL; 164293546Sdchagin free(emd, M_EPOLL); 165293546Sdchagin } 166293546Sdchagin 167293528Sdchagin sx_destroy(&pem->pem_sx); 168293532Sdchagin free(pem, M_LINUX); 169293493Sdchagin} 170293493Sdchagin 171293493Sdchaginint 172293493Sdchaginlinux_common_execve(struct thread *td, struct image_args *eargs) 173293493Sdchagin{ 174293528Sdchagin struct linux_pemuldata *pem; 175293546Sdchagin struct epoll_emuldata *emd; 176293600Sdchagin struct vmspace *oldvmspace; 177293493Sdchagin struct linux_emuldata *em; 178293493Sdchagin struct proc *p; 179293493Sdchagin int error; 180293493Sdchagin 181293493Sdchagin p = td->td_proc; 182293493Sdchagin 183293600Sdchagin error = pre_execve(td, &oldvmspace); 184293600Sdchagin if (error != 0) 185293600Sdchagin return (error); 186235063Snetchild 187293493Sdchagin error = kern_execve(td, eargs, NULL); 188293600Sdchagin post_execve(td, error, oldvmspace); 189293493Sdchagin if (error != 0) 190293493Sdchagin return (error); 191161304Snetchild 192293493Sdchagin /* 193293493Sdchagin * In a case of transition from Linux binary execing to 194293528Sdchagin * FreeBSD binary we destroy linux emuldata thread & proc entries. 195293493Sdchagin */ 196293493Sdchagin if (SV_CURPROC_ABI() != SV_ABI_LINUX) { 197293493Sdchagin PROC_LOCK(p); 198293493Sdchagin em = em_find(td); 199293528Sdchagin KASSERT(em != NULL, ("proc_exec: thread emuldata not found.\n")); 200293493Sdchagin td->td_emuldata = NULL; 201293528Sdchagin 202293528Sdchagin pem = pem_find(p); 203293528Sdchagin KASSERT(pem != NULL, ("proc_exec: proc pemuldata not found.\n")); 204293528Sdchagin p->p_emuldata = NULL; 205162184Snetchild PROC_UNLOCK(p); 206161304Snetchild 207293546Sdchagin if (pem->epoll != NULL) { 208293546Sdchagin emd = pem->epoll; 209293546Sdchagin pem->epoll = NULL; 210293546Sdchagin free(emd, M_EPOLL); 211293546Sdchagin } 212293546Sdchagin 213293493Sdchagin free(em, M_TEMP); 214293532Sdchagin free(pem, M_LINUX); 215293493Sdchagin } 216165688Snetchild return (0); 217161304Snetchild} 218161304Snetchild 219293493Sdchaginvoid 220293493Sdchaginlinux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp) 221293493Sdchagin{ 222293493Sdchagin struct thread *td = curthread; 223293603Sdchagin struct thread *othertd; 224302962Sdchagin#if defined(__amd64__) 225302962Sdchagin struct linux_pemuldata *pem; 226302962Sdchagin#endif 227293493Sdchagin 228293493Sdchagin /* 229293603Sdchagin * In a case of execing from linux binary properly detach 230293603Sdchagin * other threads from the user space. 231293603Sdchagin */ 232293603Sdchagin if (__predict_false(SV_PROC_ABI(p) == SV_ABI_LINUX)) { 233293603Sdchagin FOREACH_THREAD_IN_PROC(p, othertd) { 234293603Sdchagin if (td != othertd) 235293603Sdchagin (p->p_sysent->sv_thread_detach)(othertd); 236293603Sdchagin } 237293603Sdchagin } 238293603Sdchagin 239293603Sdchagin /* 240293493Sdchagin * In a case of execing to linux binary we create linux 241293493Sdchagin * emuldata thread entry. 242293493Sdchagin */ 243293493Sdchagin if (__predict_false((imgp->sysent->sv_flags & SV_ABI_MASK) == 244293493Sdchagin SV_ABI_LINUX)) { 245293546Sdchagin 246293493Sdchagin if (SV_PROC_ABI(p) == SV_ABI_LINUX) 247293493Sdchagin linux_proc_init(td, NULL, 0); 248293493Sdchagin else 249293493Sdchagin linux_proc_init(td, td, 0); 250302962Sdchagin#if defined(__amd64__) 251302962Sdchagin /* 252302962Sdchagin * An IA32 executable which has executable stack will have the 253302962Sdchagin * READ_IMPLIES_EXEC personality flag set automatically. 254302962Sdchagin */ 255302962Sdchagin if (SV_PROC_FLAG(td->td_proc, SV_ILP32) && 256302962Sdchagin imgp->stack_prot & VM_PROT_EXECUTE) { 257302962Sdchagin pem = pem_find(p); 258302962Sdchagin pem->persona |= LINUX_READ_IMPLIES_EXEC; 259302962Sdchagin } 260302962Sdchagin#endif 261293493Sdchagin } 262293493Sdchagin} 263293493Sdchagin 264161304Snetchildvoid 265293493Sdchaginlinux_thread_dtor(void *arg __unused, struct thread *td) 266161304Snetchild{ 267293493Sdchagin struct linux_emuldata *em; 268161304Snetchild 269293493Sdchagin em = em_find(td); 270293493Sdchagin if (em == NULL) 271293493Sdchagin return; 272293493Sdchagin td->td_emuldata = NULL; 273161304Snetchild 274293560Sdchagin LINUX_CTR1(thread_dtor, "thread(%d)", em->em_tid); 275165688Snetchild 276293493Sdchagin free(em, M_TEMP); 277161304Snetchild} 278161304Snetchild 279161304Snetchildvoid 280219405Sdchaginlinux_schedtail(struct thread *td) 281161304Snetchild{ 282161304Snetchild struct linux_emuldata *em; 283219405Sdchagin struct proc *p; 284161304Snetchild int error = 0; 285161304Snetchild int *child_set_tid; 286161304Snetchild 287219405Sdchagin p = td->td_proc; 288219405Sdchagin 289293493Sdchagin em = em_find(td); 290293528Sdchagin KASSERT(em != NULL, ("linux_schedtail: thread emuldata not found.\n")); 291161304Snetchild child_set_tid = em->child_set_tid; 292161304Snetchild 293235063Snetchild if (child_set_tid != NULL) { 294293557Sdchagin error = copyout(&em->em_tid, child_set_tid, 295293493Sdchagin sizeof(em->em_tid)); 296293560Sdchagin LINUX_CTR4(schedtail, "thread(%d) %p stored %d error %d", 297293493Sdchagin td->td_tid, child_set_tid, em->em_tid, error); 298293493Sdchagin } else 299293560Sdchagin LINUX_CTR1(schedtail, "thread(%d)", em->em_tid); 300161304Snetchild} 301