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