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