1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 2006 Roman Divacky 5 * Copyright (c) 2013 Dmitry Chagin 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer 13 * in this position and unchanged. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/imgact.h> 38 #include <sys/kernel.h> 39 #include <sys/ktr.h> 40 #include <sys/lock.h> 41 #include <sys/malloc.h> 42 #include <sys/mutex.h> 43 #include <sys/sx.h> 44 #include <sys/proc.h> 45 #include <sys/syscallsubr.h> 46 #include <sys/sysent.h> 47 48 #include <compat/linux/linux_emul.h> 49 #include <compat/linux/linux_misc.h> 50 #include <compat/linux/linux_persona.h> 51 #include <compat/linux/linux_util.h> 52 53 54 /* 55 * This returns reference to the thread emuldata entry (if found) 56 * 57 * Hold PROC_LOCK when referencing emuldata from other threads. 58 */ 59 struct linux_emuldata * 60 em_find(struct thread *td) 61 { 62 struct linux_emuldata *em; 63 64 em = td->td_emuldata; 65 66 return (em); 67 } 68 69 /* 70 * This returns reference to the proc pemuldata entry (if found) 71 * 72 * Hold PROC_LOCK when referencing proc pemuldata from other threads. 73 * Hold LINUX_PEM_LOCK wher referencing pemuldata members. 74 */ 75 struct linux_pemuldata * 76 pem_find(struct proc *p) 77 { 78 struct linux_pemuldata *pem; 79 80 pem = p->p_emuldata; 81 82 return (pem); 83 } 84 85 void 86 linux_proc_init(struct thread *td, struct thread *newtd, int flags) 87 { 88 struct linux_emuldata *em; 89 struct linux_pemuldata *pem; 90 struct epoll_emuldata *emd; 91 struct proc *p; 92 93 if (newtd != NULL) { 94 p = newtd->td_proc; 95 96 /* non-exec call */ 97 em = malloc(sizeof(*em), M_TEMP, M_WAITOK | M_ZERO); 98 if (flags & LINUX_CLONE_THREAD) { 99 LINUX_CTR1(proc_init, "thread newtd(%d)", 100 newtd->td_tid); 101 102 em->em_tid = newtd->td_tid; 103 } else { 104 LINUX_CTR1(proc_init, "fork newtd(%d)", p->p_pid); 105 106 em->em_tid = p->p_pid; 107 108 pem = malloc(sizeof(*pem), M_LINUX, M_WAITOK | M_ZERO); 109 sx_init(&pem->pem_sx, "lpemlk"); 110 p->p_emuldata = pem; 111 } 112 newtd->td_emuldata = em; 113 } else { 114 p = td->td_proc; 115 116 /* exec */ 117 LINUX_CTR1(proc_init, "exec newtd(%d)", p->p_pid); 118 119 /* lookup the old one */ 120 em = em_find(td); 121 KASSERT(em != NULL, ("proc_init: emuldata not found in exec case.\n")); 122 123 em->em_tid = p->p_pid; 124 em->flags = 0; 125 em->pdeath_signal = 0; 126 em->robust_futexes = NULL; 127 em->child_clear_tid = NULL; 128 em->child_set_tid = NULL; 129 130 /* epoll should be destroyed in a case of exec. */ 131 pem = pem_find(p); 132 KASSERT(pem != NULL, ("proc_exit: proc emuldata not found.\n")); 133 pem->persona = 0; 134 if (pem->epoll != NULL) { 135 emd = pem->epoll; 136 pem->epoll = NULL; 137 free(emd, M_EPOLL); 138 } 139 } 140 141 } 142 143 void 144 linux_proc_exit(void *arg __unused, struct proc *p) 145 { 146 struct linux_pemuldata *pem; 147 struct epoll_emuldata *emd; 148 struct thread *td = curthread; 149 150 if (__predict_false(SV_CURPROC_ABI() != SV_ABI_LINUX)) 151 return; 152 153 LINUX_CTR3(proc_exit, "thread(%d) proc(%d) p %p", 154 td->td_tid, p->p_pid, p); 155 156 pem = pem_find(p); 157 if (pem == NULL) 158 return; 159 (p->p_sysent->sv_thread_detach)(td); 160 161 p->p_emuldata = NULL; 162 163 if (pem->epoll != NULL) { 164 emd = pem->epoll; 165 pem->epoll = NULL; 166 free(emd, M_EPOLL); 167 } 168 169 sx_destroy(&pem->pem_sx); 170 free(pem, M_LINUX); 171 } 172 173 int 174 linux_common_execve(struct thread *td, struct image_args *eargs) 175 { 176 struct linux_pemuldata *pem; 177 struct epoll_emuldata *emd; 178 struct vmspace *oldvmspace; 179 struct linux_emuldata *em; 180 struct proc *p; 181 int error; 182 183 p = td->td_proc; 184 185 error = pre_execve(td, &oldvmspace); 186 if (error != 0) 187 return (error); 188 189 error = kern_execve(td, eargs, NULL); 190 post_execve(td, error, oldvmspace); 191 if (error != EJUSTRETURN) 192 return (error); 193 194 /* 195 * In a case of transition from Linux binary execing to 196 * FreeBSD binary we destroy linux emuldata thread & proc entries. 197 */ 198 if (SV_CURPROC_ABI() != SV_ABI_LINUX) { 199 PROC_LOCK(p); 200 em = em_find(td); 201 KASSERT(em != NULL, ("proc_exec: thread emuldata not found.\n")); 202 td->td_emuldata = NULL; 203 204 pem = pem_find(p); 205 KASSERT(pem != NULL, ("proc_exec: proc pemuldata not found.\n")); 206 p->p_emuldata = NULL; 207 PROC_UNLOCK(p); 208 209 if (pem->epoll != NULL) { 210 emd = pem->epoll; 211 pem->epoll = NULL; 212 free(emd, M_EPOLL); 213 } 214 215 free(em, M_TEMP); 216 free(pem, M_LINUX); 217 } 218 return (EJUSTRETURN); 219 } 220 221 void 222 linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp) 223 { 224 struct thread *td = curthread; 225 struct thread *othertd; 226 #if defined(__amd64__) 227 struct linux_pemuldata *pem; 228 #endif 229 230 /* 231 * In a case of execing from linux binary properly detach 232 * other threads from the user space. 233 */ 234 if (__predict_false(SV_PROC_ABI(p) == SV_ABI_LINUX)) { 235 FOREACH_THREAD_IN_PROC(p, othertd) { 236 if (td != othertd) 237 (p->p_sysent->sv_thread_detach)(othertd); 238 } 239 } 240 241 /* 242 * In a case of execing to linux binary we create linux 243 * emuldata thread entry. 244 */ 245 if (__predict_false((imgp->sysent->sv_flags & SV_ABI_MASK) == 246 SV_ABI_LINUX)) { 247 248 if (SV_PROC_ABI(p) == SV_ABI_LINUX) 249 linux_proc_init(td, NULL, 0); 250 else 251 linux_proc_init(td, td, 0); 252 #if defined(__amd64__) 253 /* 254 * An IA32 executable which has executable stack will have the 255 * READ_IMPLIES_EXEC personality flag set automatically. 256 */ 257 if (SV_PROC_FLAG(td->td_proc, SV_ILP32) && 258 imgp->stack_prot & VM_PROT_EXECUTE) { 259 pem = pem_find(p); 260 pem->persona |= LINUX_READ_IMPLIES_EXEC; 261 } 262 #endif 263 } 264 } 265 266 void 267 linux_thread_dtor(void *arg __unused, struct thread *td) 268 { 269 struct linux_emuldata *em; 270 271 em = em_find(td); 272 if (em == NULL) 273 return; 274 td->td_emuldata = NULL; 275 276 LINUX_CTR1(thread_dtor, "thread(%d)", em->em_tid); 277 278 free(em, M_TEMP); 279 } 280 281 void 282 linux_schedtail(struct thread *td) 283 { 284 struct linux_emuldata *em; 285 struct proc *p; 286 int error = 0; 287 int *child_set_tid; 288 289 p = td->td_proc; 290 291 em = em_find(td); 292 KASSERT(em != NULL, ("linux_schedtail: thread emuldata not found.\n")); 293 child_set_tid = em->child_set_tid; 294 295 if (child_set_tid != NULL) { 296 error = copyout(&em->em_tid, child_set_tid, 297 sizeof(em->em_tid)); 298 LINUX_CTR4(schedtail, "thread(%d) %p stored %d error %d", 299 td->td_tid, child_set_tid, em->em_tid, error); 300 } else 301 LINUX_CTR1(schedtail, "thread(%d)", em->em_tid); 302 } 303