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 "opt_compat.h" 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/sdt.h> 44 #include <sys/sx.h> 45 #include <sys/proc.h> 46 #include <sys/syscallsubr.h> 47 #include <sys/sysent.h> 48 #include <sys/sysproto.h> 49 #include <sys/unistd.h> 50 51 #ifdef COMPAT_LINUX32 52 #include <machine/../linux32/linux.h> 53 #include <machine/../linux32/linux32_proto.h> 54 #else 55 #include <machine/../linux/linux.h> 56 #include <machine/../linux/linux_proto.h> 57 #endif 58 59 #include <compat/linux/linux_dtrace.h> 60 #include <compat/linux/linux_emul.h> 61 #include <compat/linux/linux_futex.h> 62 #include <compat/linux/linux_misc.h> 63 #include <compat/linux/linux_util.h> 64 65 /** 66 * Special DTrace provider for the linuxulator. 67 * 68 * In this file we define the provider for the entire linuxulator. All 69 * modules (= files of the linuxulator) use it. 70 * 71 * We define a different name depending on the emulated bitsize, see 72 * ../../<ARCH>/linux{,32}/linux.h, e.g.: 73 * native bitsize = linuxulator 74 * amd64, 32bit emulation = linuxulator32 75 */ 76 LIN_SDT_PROVIDER_DEFINE(LINUX_DTRACE); 77 78 /** 79 * DTrace probes in this module. 80 */ 81 LIN_SDT_PROBE_DEFINE1(emul, em_find, entry, "struct thread *"); 82 LIN_SDT_PROBE_DEFINE0(emul, em_find, return); 83 LIN_SDT_PROBE_DEFINE3(emul, proc_init, entry, "struct thread *", 84 "struct thread *", "int"); 85 LIN_SDT_PROBE_DEFINE0(emul, proc_init, create_thread); 86 LIN_SDT_PROBE_DEFINE0(emul, proc_init, fork); 87 LIN_SDT_PROBE_DEFINE0(emul, proc_init, exec); 88 LIN_SDT_PROBE_DEFINE0(emul, proc_init, return); 89 LIN_SDT_PROBE_DEFINE1(emul, proc_exit, entry, "struct proc *"); 90 LIN_SDT_PROBE_DEFINE1(emul, linux_thread_detach, entry, "struct thread *"); 91 LIN_SDT_PROBE_DEFINE0(emul, linux_thread_detach, futex_failed); 92 LIN_SDT_PROBE_DEFINE1(emul, linux_thread_detach, child_clear_tid_error, "int"); 93 LIN_SDT_PROBE_DEFINE0(emul, linux_thread_detach, return); 94 LIN_SDT_PROBE_DEFINE2(emul, proc_exec, entry, "struct proc *", 95 "struct image_params *"); 96 LIN_SDT_PROBE_DEFINE0(emul, proc_exec, return); 97 LIN_SDT_PROBE_DEFINE0(emul, linux_schedtail, entry); 98 LIN_SDT_PROBE_DEFINE1(emul, linux_schedtail, copyout_error, "int"); 99 LIN_SDT_PROBE_DEFINE0(emul, linux_schedtail, return); 100 LIN_SDT_PROBE_DEFINE1(emul, linux_set_tid_address, entry, "int *"); 101 LIN_SDT_PROBE_DEFINE0(emul, linux_set_tid_address, return); 102 103 /* 104 * This returns reference to the emuldata entry (if found) 105 * 106 * Hold PROC_LOCK when referencing emuldata from other threads. 107 */ 108 struct linux_emuldata * 109 em_find(struct thread *td) 110 { 111 struct linux_emuldata *em; 112 113 LIN_SDT_PROBE1(emul, em_find, entry, td); 114 115 em = td->td_emuldata; 116 117 LIN_SDT_PROBE1(emul, em_find, return, em); 118 119 return (em); 120 } 121 122 void 123 linux_proc_init(struct thread *td, struct thread *newtd, int flags) 124 { 125 struct linux_emuldata *em; 126 127 LIN_SDT_PROBE3(emul, proc_init, entry, td, newtd, flags); 128 129 if (newtd != NULL) { 130 /* non-exec call */ 131 em = malloc(sizeof(*em), M_TEMP, M_WAITOK | M_ZERO); 132 em->pdeath_signal = 0; 133 em->flags = 0; 134 em->robust_futexes = NULL; 135 if (flags & LINUX_CLONE_THREAD) { 136 LIN_SDT_PROBE0(emul, proc_init, create_thread); 137 138 em->em_tid = newtd->td_tid; 139 } else { 140 LIN_SDT_PROBE0(emul, proc_init, fork); 141 142 em->em_tid = newtd->td_proc->p_pid; 143 } 144 newtd->td_emuldata = em; 145 } else { 146 /* exec */ 147 LIN_SDT_PROBE0(emul, proc_init, exec); 148 149 /* lookup the old one */ 150 em = em_find(td); 151 KASSERT(em != NULL, ("proc_init: emuldata not found in exec case.\n")); 152 153 em->em_tid = td->td_proc->p_pid; 154 } 155 156 em->child_clear_tid = NULL; 157 em->child_set_tid = NULL; 158 159 LIN_SDT_PROBE0(emul, proc_init, return); 160 } 161 162 void 163 linux_proc_exit(void *arg __unused, struct proc *p) 164 { 165 struct thread *td = curthread; 166 167 if (__predict_false(SV_CURPROC_ABI() != SV_ABI_LINUX)) { 168 LIN_SDT_PROBE1(emul, proc_exit, entry, p); 169 (p->p_sysent->sv_thread_detach)(td); 170 } 171 } 172 173 int 174 linux_common_execve(struct thread *td, struct image_args *eargs) 175 { 176 struct linux_emuldata *em; 177 struct proc *p; 178 int error; 179 180 p = td->td_proc; 181 182 /* 183 * Unlike FreeBSD abort all other threads before 184 * proceeding exec. 185 */ 186 PROC_LOCK(p); 187 /* See exit1() comments. */ 188 thread_suspend_check(0); 189 while (p->p_flag & P_HADTHREADS) { 190 if (!thread_single(p, SINGLE_EXIT)) 191 break; 192 thread_suspend_check(0); 193 } 194 PROC_UNLOCK(p); 195 196 error = kern_execve(td, eargs, NULL); 197 if (error != 0) 198 return (error); 199 200 /* 201 * In a case of transition from Linux binary execing to 202 * FreeBSD binary we destroy linux emuldata thread entry. 203 */ 204 if (SV_CURPROC_ABI() != SV_ABI_LINUX) { 205 PROC_LOCK(p); 206 em = em_find(td); 207 KASSERT(em != NULL, ("proc_exec: emuldata not found.\n")); 208 td->td_emuldata = NULL; 209 PROC_UNLOCK(p); 210 211 free(em, M_TEMP); 212 } 213 return (0); 214 } 215 216 void 217 linux_proc_exec(void *arg __unused, struct proc *p, struct image_params *imgp) 218 { 219 struct thread *td = curthread; 220 221 /* 222 * In a case of execing to linux binary we create linux 223 * emuldata thread entry. 224 */ 225 if (__predict_false((imgp->sysent->sv_flags & SV_ABI_MASK) == 226 SV_ABI_LINUX)) { 227 LIN_SDT_PROBE2(emul, proc_exec, entry, p, imgp); 228 if (SV_PROC_ABI(p) == SV_ABI_LINUX) 229 linux_proc_init(td, NULL, 0); 230 else 231 linux_proc_init(td, td, 0); 232 233 LIN_SDT_PROBE0(emul, proc_exec, return); 234 } 235 } 236 237 void 238 linux_thread_detach(struct thread *td) 239 { 240 struct linux_sys_futex_args cup; 241 struct linux_emuldata *em; 242 int *child_clear_tid; 243 int null = 0; 244 int error; 245 246 LIN_SDT_PROBE1(emul, linux_thread_detach, entry, td); 247 248 em = em_find(td); 249 KASSERT(em != NULL, ("thread_detach: emuldata not found.\n")); 250 251 LINUX_CTR1(exit, "thread detach(%d)", em->em_tid); 252 253 release_futexes(td, em); 254 255 child_clear_tid = em->child_clear_tid; 256 257 if (child_clear_tid != NULL) { 258 259 LINUX_CTR2(exit, "thread detach(%d) %p", 260 em->em_tid, child_clear_tid); 261 262 error = copyout(&null, child_clear_tid, sizeof(null)); 263 if (error) { 264 LIN_SDT_PROBE1(emul, linux_thread_detach, 265 child_clear_tid_error, error); 266 267 LIN_SDT_PROBE0(emul, linux_thread_detach, return); 268 return; 269 } 270 271 cup.uaddr = child_clear_tid; 272 cup.op = LINUX_FUTEX_WAKE; 273 cup.val = 1; /* wake one */ 274 cup.timeout = NULL; 275 cup.uaddr2 = NULL; 276 cup.val3 = 0; 277 error = linux_sys_futex(td, &cup); 278 /* 279 * this cannot happen at the moment and if this happens it 280 * probably means there is a user space bug 281 */ 282 if (error) { 283 LIN_SDT_PROBE0(emul, linux_thread_detach, futex_failed); 284 printf(LMSG("futex stuff in thread_detach failed.\n")); 285 } 286 } 287 288 LIN_SDT_PROBE0(emul, linux_thread_detach, return); 289 } 290 291 void 292 linux_thread_dtor(void *arg __unused, struct thread *td) 293 { 294 struct linux_emuldata *em; 295 296 em = em_find(td); 297 if (em == NULL) 298 return; 299 td->td_emuldata = NULL; 300 301 LINUX_CTR1(exit, "thread dtor(%d)", em->em_tid); 302 303 free(em, M_TEMP); 304 } 305 306 void 307 linux_schedtail(struct thread *td) 308 { 309 struct linux_emuldata *em; 310 struct proc *p; 311 int error = 0; 312 int *child_set_tid; 313 314 LIN_SDT_PROBE1(emul, linux_schedtail, entry, td); 315 316 p = td->td_proc; 317 318 em = em_find(td); 319 KASSERT(em != NULL, ("linux_schedtail: emuldata not found.\n")); 320 child_set_tid = em->child_set_tid; 321 322 if (child_set_tid != NULL) { 323 error = copyout(&em->em_tid, (int *)child_set_tid, 324 sizeof(em->em_tid)); 325 LINUX_CTR4(clone, "schedtail(%d) %p stored %d error %d", 326 td->td_tid, child_set_tid, em->em_tid, error); 327 328 if (error != 0) { 329 LIN_SDT_PROBE1(emul, linux_schedtail, copyout_error, 330 error); 331 } 332 } else 333 LINUX_CTR1(clone, "schedtail(%d)", em->em_tid); 334 335 LIN_SDT_PROBE0(emul, linux_schedtail, return); 336 } 337 338 int 339 linux_set_tid_address(struct thread *td, struct linux_set_tid_address_args *args) 340 { 341 struct linux_emuldata *em; 342 343 LIN_SDT_PROBE1(emul, linux_set_tid_address, entry, args->tidptr); 344 345 em = em_find(td); 346 KASSERT(em != NULL, ("set_tid_address: emuldata not found.\n")); 347 348 em->child_clear_tid = args->tidptr; 349 350 td->td_retval[0] = em->em_tid; 351 352 LINUX_CTR3(set_tid_address, "tidptr(%d) %p, returns %d", 353 em->em_tid, args->tidptr, td->td_retval[0]); 354 355 LIN_SDT_PROBE0(emul, linux_set_tid_address, return); 356 return (0); 357 } 358