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_util.h> 49 50 51 /* 52 * This returns reference to the thread emuldata entry (if found) 53 * 54 * Hold PROC_LOCK when referencing emuldata from other threads. 55 */ 56 struct linux_emuldata * 57 em_find(struct thread *td) 58 { 59 struct linux_emuldata *em; 60 61 em = td->td_emuldata; 62 63 return (em); 64 } 65 66 /* 67 * This returns reference to the proc pemuldata entry (if found) 68 * 69 * Hold PROC_LOCK when referencing proc pemuldata from other threads. 70 * Hold LINUX_PEM_LOCK wher referencing pemuldata members. 71 */ 72 struct linux_pemuldata * 73 pem_find(struct proc *p) 74 { 75 struct linux_pemuldata *pem; 76 77 pem = p->p_emuldata; 78 79 return (pem); 80 } 81 82 void 83 linux_proc_init(struct thread *td, struct thread *newtd, int flags) 84 { 85 struct linux_emuldata *em; 86 struct linux_pemuldata *pem; 87 struct epoll_emuldata *emd; 88 struct proc *p; 89 90 if (newtd != NULL) { 91 p = newtd->td_proc; 92 93 /* non-exec call */ 94 em = malloc(sizeof(*em), M_TEMP, M_WAITOK | M_ZERO); 95 if (flags & LINUX_CLONE_THREAD) { 96 LINUX_CTR1(proc_init, "thread newtd(%d)", 97 newtd->td_tid); 98 99 em->em_tid = newtd->td_tid; 100 } else { 101 LINUX_CTR1(proc_init, "fork newtd(%d)", p->p_pid); 102 103 em->em_tid = p->p_pid; 104 105 pem = malloc(sizeof(*pem), M_LINUX, M_WAITOK | M_ZERO); 106 sx_init(&pem->pem_sx, "lpemlk"); 107 p->p_emuldata = pem; 108 } 109 newtd->td_emuldata = em; 110 } else { 111 p = td->td_proc; 112 113 /* exec */ 114 LINUX_CTR1(proc_init, "exec newtd(%d)", p->p_pid); 115 116 /* lookup the old one */ 117 em = em_find(td); 118 KASSERT(em != NULL, ("proc_init: emuldata not found in exec case.\n")); 119 120 em->em_tid = p->p_pid; 121 em->flags = 0; 122 em->pdeath_signal = 0; 123 em->robust_futexes = NULL; 124 em->child_clear_tid = NULL; 125 em->child_set_tid = NULL; 126 127 /* epoll should be destroyed in a case of exec. */ 128 pem = pem_find(p); 129 KASSERT(pem != NULL, ("proc_exit: proc emuldata not found.\n")); 130 131 if (pem->epoll != NULL) { 132 emd = pem->epoll; 133 pem->epoll = NULL; 134 free(emd, M_EPOLL); 135 } 136 } 137 138 } 139 140 void 141 linux_proc_exit(void *arg __unused, struct proc *p) 142 { 143 struct linux_pemuldata *pem; 144 struct epoll_emuldata *emd; 145 struct thread *td = curthread; 146 147 if (__predict_false(SV_CURPROC_ABI() != SV_ABI_LINUX)) 148 return; 149 150 LINUX_CTR3(proc_exit, "thread(%d) proc(%d) p %p", 151 td->td_tid, p->p_pid, p); 152 153 pem = pem_find(p); 154 if (pem == NULL) 155 return; 156 (p->p_sysent->sv_thread_detach)(td); 157 158 p->p_emuldata = NULL; 159 160 if (pem->epoll != NULL) { 161 emd = pem->epoll; 162 pem->epoll = NULL; 163 free(emd, M_EPOLL); 164 } 165 166 sx_destroy(&pem->pem_sx); 167 free(pem, M_LINUX); 168 } 169 170 int 171 linux_common_execve(struct thread *td, struct image_args *eargs) 172 { 173 struct linux_pemuldata *pem; 174 struct epoll_emuldata *emd; 175 struct vmspace *oldvmspace; 176 struct linux_emuldata *em; 177 struct proc *p; 178 int error; 179 180 p = td->td_proc; 181 182 error = pre_execve(td, &oldvmspace); 183 if (error != 0) 184 return (error); 185 186 error = kern_execve(td, eargs, NULL); 187 post_execve(td, error, oldvmspace); 188 if (error != 0) 189 return (error); 190 191 /* 192 * In a case of transition from Linux binary execing to 193 * FreeBSD binary we destroy linux emuldata thread & proc entries. 194 */ 195 if (SV_CURPROC_ABI() != SV_ABI_LINUX) { 196 PROC_LOCK(p); 197 em = em_find(td); 198 KASSERT(em != NULL, ("proc_exec: thread emuldata not found.\n")); 199 td->td_emuldata = NULL; 200 201 pem = pem_find(p); 202 KASSERT(pem != NULL, ("proc_exec: proc pemuldata not found.\n")); 203 p->p_emuldata = NULL; 204 PROC_UNLOCK(p); 205 206 if (pem->epoll != NULL) { 207 emd = pem->epoll; 208 pem->epoll = NULL; 209 free(emd, M_EPOLL); 210 } 211 212 free(em, M_TEMP); 213 free(pem, M_LINUX); 214 } 215 return (0); 216 } 217 218 void 219 linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp) 220 { 221 struct thread *td = curthread; 222 struct thread *othertd; 223 224 /* 225 * In a case of execing from linux binary properly detach 226 * other threads from the user space. 227 */ 228 if (__predict_false(SV_PROC_ABI(p) == SV_ABI_LINUX)) { 229 FOREACH_THREAD_IN_PROC(p, othertd) { 230 if (td != othertd) 231 (p->p_sysent->sv_thread_detach)(othertd); 232 } 233 } 234 235 /* 236 * In a case of execing to linux binary we create linux 237 * emuldata thread entry. 238 */ 239 if (__predict_false((imgp->sysent->sv_flags & SV_ABI_MASK) == 240 SV_ABI_LINUX)) { 241 242 if (SV_PROC_ABI(p) == SV_ABI_LINUX) 243 linux_proc_init(td, NULL, 0); 244 else 245 linux_proc_init(td, td, 0); 246 } 247 } 248 249 void 250 linux_thread_dtor(void *arg __unused, struct thread *td) 251 { 252 struct linux_emuldata *em; 253 254 em = em_find(td); 255 if (em == NULL) 256 return; 257 td->td_emuldata = NULL; 258 259 LINUX_CTR1(thread_dtor, "thread(%d)", em->em_tid); 260 261 free(em, M_TEMP); 262 } 263 264 void 265 linux_schedtail(struct thread *td) 266 { 267 struct linux_emuldata *em; 268 struct proc *p; 269 int error = 0; 270 int *child_set_tid; 271 272 p = td->td_proc; 273 274 em = em_find(td); 275 KASSERT(em != NULL, ("linux_schedtail: thread emuldata not found.\n")); 276 child_set_tid = em->child_set_tid; 277 278 if (child_set_tid != NULL) { 279 error = copyout(&em->em_tid, child_set_tid, 280 sizeof(em->em_tid)); 281 LINUX_CTR4(schedtail, "thread(%d) %p stored %d error %d", 282 td->td_tid, child_set_tid, em->em_tid, error); 283 } else 284 LINUX_CTR1(schedtail, "thread(%d)", em->em_tid); 285 } 286