1 /* $NetBSD: linux_exec.c,v 1.92 2007/02/19 15:10:03 cube Exp $ */ 2 3 /*- 4 * Copyright (c) 1994, 1995, 1998, 2000, 2007 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas, Frank van der Linden, Eric Haszlakiewicz and 9 * Thor Lancelot Simon. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 #include <sys/cdefs.h> 41 __KERNEL_RCSID(0, "$NetBSD: linux_exec.c,v 1.92 2007/02/19 15:10:03 cube Exp $"); 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/kernel.h> 46 #include <sys/proc.h> 47 #include <sys/malloc.h> 48 #include <sys/namei.h> 49 #include <sys/vnode.h> 50 #include <sys/mount.h> 51 #include <sys/exec.h> 52 #include <sys/exec_elf.h> 53 54 #include <sys/mman.h> 55 #include <sys/syscallargs.h> 56 57 #include <sys/ptrace.h> /* For proc_reparent() */ 58 59 #include <uvm/uvm_extern.h> 60 61 #include <machine/cpu.h> 62 #include <machine/reg.h> 63 64 #include <compat/linux/common/linux_types.h> 65 #include <compat/linux/common/linux_signal.h> 66 #include <compat/linux/common/linux_util.h> 67 #include <compat/linux/common/linux_sched.h> 68 #include <compat/linux/common/linux_machdep.h> 69 #include <compat/linux/common/linux_exec.h> 70 #include <compat/linux/common/linux_futex.h> 71 72 #include <compat/linux/linux_syscallargs.h> 73 #include <compat/linux/linux_syscall.h> 74 #include <compat/linux/common/linux_misc.h> 75 #include <compat/linux/common/linux_errno.h> 76 #include <compat/linux/common/linux_emuldata.h> 77 78 extern struct sysent linux_sysent[]; 79 extern const char * const linux_syscallnames[]; 80 extern char linux_sigcode[], linux_esigcode[]; 81 82 static void linux_e_proc_exec __P((struct proc *, struct exec_package *)); 83 static void linux_e_proc_fork __P((struct proc *, struct proc *, int)); 84 static void linux_e_proc_exit __P((struct proc *)); 85 static void linux_e_proc_init __P((struct proc *, struct proc *, int)); 86 87 #ifdef LINUX_NPTL 88 void linux_userret(void); 89 #endif 90 91 /* 92 * Execve(2). Just check the alternate emulation path, and pass it on 93 * to the NetBSD execve(). 94 */ 95 int 96 linux_sys_execve(l, v, retval) 97 struct lwp *l; 98 void *v; 99 register_t *retval; 100 { 101 struct linux_sys_execve_args /* { 102 syscallarg(const char *) path; 103 syscallarg(char **) argv; 104 syscallarg(char **) envp; 105 } */ *uap = v; 106 struct proc *p = l->l_proc; 107 struct sys_execve_args ap; 108 caddr_t sg; 109 110 sg = stackgap_init(p, 0); 111 CHECK_ALT_EXIST(l, &sg, SCARG(uap, path)); 112 113 SCARG(&ap, path) = SCARG(uap, path); 114 SCARG(&ap, argp) = SCARG(uap, argp); 115 SCARG(&ap, envp) = SCARG(uap, envp); 116 117 return sys_execve(l, &ap, retval); 118 } 119 120 /* 121 * Emulation switch. 122 */ 123 124 struct uvm_object *emul_linux_object; 125 126 const struct emul emul_linux = { 127 "linux", 128 "/emul/linux", 129 #ifndef __HAVE_MINIMAL_EMUL 130 0, 131 (const int *)native_to_linux_errno, 132 LINUX_SYS_syscall, 133 LINUX_SYS_NSYSENT, 134 #endif 135 linux_sysent, 136 linux_syscallnames, 137 linux_sendsig, 138 linux_trapsignal, 139 NULL, 140 linux_sigcode, 141 linux_esigcode, 142 &emul_linux_object, 143 linux_setregs, 144 linux_e_proc_exec, 145 linux_e_proc_fork, 146 linux_e_proc_exit, 147 NULL, 148 NULL, 149 #ifdef __HAVE_SYSCALL_INTERN 150 linux_syscall_intern, 151 #else 152 #error Implement __HAVE_SYSCALL_INTERN for this platform 153 #endif 154 NULL, 155 NULL, 156 157 uvm_default_mapaddr, 158 159 linux_usertrap, 160 0, 161 NULL, /* e_startlwp */ 162 }; 163 164 static void 165 linux_e_proc_init(p, parent, forkflags) 166 struct proc *p, *parent; 167 int forkflags; 168 { 169 struct linux_emuldata *e = p->p_emuldata; 170 struct linux_emuldata_shared *s; 171 struct linux_emuldata *ep = NULL; 172 173 if (!e) { 174 /* allocate new Linux emuldata */ 175 MALLOC(e, void *, sizeof(struct linux_emuldata), 176 M_EMULDATA, M_WAITOK); 177 } else { 178 e->s->refs--; 179 if (e->s->refs == 0) 180 FREE(e->s, M_EMULDATA); 181 } 182 183 memset(e, '\0', sizeof(struct linux_emuldata)); 184 185 e->proc = p; 186 187 if (parent) 188 ep = parent->p_emuldata; 189 190 if (forkflags & FORK_SHAREVM) { 191 #ifdef DIAGNOSTIC 192 if (ep == NULL) { 193 killproc(p, "FORK_SHAREVM while emuldata is NULL\n"); 194 FREE(e, M_EMULDATA); 195 return; 196 } 197 #endif 198 s = ep->s; 199 s->refs++; 200 } else { 201 struct vmspace *vm; 202 203 MALLOC(s, void *, sizeof(struct linux_emuldata_shared), 204 M_EMULDATA, M_WAITOK); 205 s->refs = 1; 206 207 /* 208 * Set the process idea of the break to the real value. 209 * For fork, we use parent's vmspace since our's 210 * is not setup at the time of this call and is going 211 * to be copy of parent's anyway. For exec, just 212 * use our own vmspace. 213 */ 214 vm = (parent) ? parent->p_vmspace : p->p_vmspace; 215 s->p_break = vm->vm_daddr + ctob(vm->vm_dsize); 216 217 /* 218 * Linux threads are emulated as NetBSD processes (not lwp) 219 * We use native PID for Linux TID. The Linux TID is the 220 * PID of the first process in the group. It is stored 221 * here 222 */ 223 s->group_pid = p->p_pid; 224 225 /* 226 * Initialize the list of threads in the group 227 */ 228 LIST_INIT(&s->threads); 229 230 s->xstat = 0; 231 s->flags = 0; 232 } 233 234 e->s = s; 235 236 /* 237 * Add this thread in the group thread list 238 */ 239 LIST_INSERT_HEAD(&s->threads, e, threads); 240 241 #ifdef LINUX_NPTL 242 if (ep != NULL) { 243 e->parent_tidptr = ep->parent_tidptr; 244 e->child_tidptr = ep->child_tidptr; 245 e->clone_flags = ep->clone_flags; 246 } 247 #endif /* LINUX_NPTL */ 248 249 p->p_emuldata = e; 250 } 251 252 /* 253 * Allocate new per-process structures. Called when executing Linux 254 * process. We can reuse the old emuldata - if it's not null, 255 * the executed process is of same emulation as original forked one. 256 */ 257 static void 258 linux_e_proc_exec(struct proc *p, struct exec_package *epp) 259 { 260 /* exec, use our vmspace */ 261 linux_e_proc_init(p, NULL, 0); 262 } 263 264 /* 265 * Emulation per-process exit hook. 266 */ 267 static void 268 linux_e_proc_exit(p) 269 struct proc *p; 270 { 271 struct linux_emuldata *e = p->p_emuldata; 272 273 #ifdef LINUX_NPTL 274 linux_nptl_proc_exit(p); 275 #endif 276 /* Remove the thread for the group thread list */ 277 LIST_REMOVE(e, threads); 278 279 /* free Linux emuldata and set the pointer to null */ 280 e->s->refs--; 281 if (e->s->refs == 0) 282 FREE(e->s, M_EMULDATA); 283 FREE(e, M_EMULDATA); 284 p->p_emuldata = NULL; 285 } 286 287 /* 288 * Emulation fork hook. 289 */ 290 static void 291 linux_e_proc_fork(p, parent, forkflags) 292 struct proc *p, *parent; 293 int forkflags; 294 { 295 /* 296 * The new process might share some vmspace-related stuff 297 * with parent, depending on fork flags (CLONE_VM et.al). 298 * Force allocation of new base emuldata, and share the 299 * VM-related parts only if necessary. 300 */ 301 p->p_emuldata = NULL; 302 linux_e_proc_init(p, parent, forkflags); 303 304 #ifdef LINUX_NPTL 305 linux_nptl_proc_fork(p, parent, linux_userret); 306 #endif 307 308 return; 309 } 310 311 #ifdef LINUX_NPTL 312 void 313 linux_userret(void) 314 { 315 struct lwp *l = curlwp; 316 struct proc *p = l->l_proc; 317 struct linux_emuldata *led = p->p_emuldata; 318 int error; 319 320 /* LINUX_CLONE_CHILD_SETTID: copy child's TID to child's memory */ 321 if (led->clone_flags & LINUX_CLONE_CHILD_SETTID) { 322 if ((error = copyout(&l->l_proc->p_pid, 323 led->child_tidptr, sizeof(l->l_proc->p_pid))) != 0) 324 printf("linux_userret: LINUX_CLONE_CHILD_SETTID " 325 "failed (led->child_tidptr = %p, p->p_pid = %d)\n", 326 led->child_tidptr, p->p_pid); 327 } 328 329 /* LINUX_CLONE_SETTLS: allocate a new TLS */ 330 if (led->clone_flags & LINUX_CLONE_SETTLS) { 331 if (linux_set_newtls(l, linux_get_newtls(l)) != 0) 332 printf("linux_userret: linux_set_tls failed"); 333 } 334 335 return; 336 } 337 338 void 339 linux_nptl_proc_exit(p) 340 struct proc *p; 341 { 342 struct linux_emuldata *e = p->p_emuldata; 343 344 rw_enter(&proclist_lock, RW_WRITER); 345 346 /* 347 * Check if we are a thread group leader victim of another 348 * thread doing exit_group(). If we are, change the exit code. 349 */ 350 if ((e->s->group_pid == p->p_pid) && 351 (e->s->flags & LINUX_LES_INEXITGROUP)) { 352 p->p_xstat = e->s->xstat; 353 } 354 355 /* 356 * Members of the thread groups others than the leader should 357 * exit quietely: no zombie stage, no signal. We do that by 358 * reparenting to init. init will collect us and nobody will 359 * notice what happened. 360 */ 361 #ifdef DEBUG_LINUX 362 printf("%s:%d e->s->group_pid = %d, p->p_pid = %d, flags = 0x%x\n", 363 __func__, __LINE__, e->s->group_pid, p->p_pid, e->s->flags); 364 #endif 365 if (e->s->group_pid != p->p_pid) { 366 proc_reparent(p, initproc); 367 cv_broadcast(&initproc->p_waitcv); 368 } 369 370 rw_exit(&proclist_lock); 371 372 /* Emulate LINUX_CLONE_CHILD_CLEARTID */ 373 if (e->clear_tid != NULL) { 374 int error; 375 int null = 0; 376 struct linux_sys_futex_args cup; 377 register_t retval; 378 379 error = copyout(&null, e->clear_tid, sizeof(null)); 380 #ifdef DEBUG_LINUX 381 if (error != 0) 382 printf("%s: cannot clear TID\n", __func__); 383 #endif 384 385 SCARG(&cup, uaddr) = e->clear_tid; 386 SCARG(&cup, op) = LINUX_FUTEX_WAKE; 387 SCARG(&cup, val) = 0x7fffffff; /* Awake everyone */ 388 SCARG(&cup, timeout) = NULL; 389 SCARG(&cup, uaddr2) = NULL; 390 SCARG(&cup, val3) = 0; 391 if ((error = linux_sys_futex(curlwp, &cup, &retval)) != 0) 392 printf("%s: linux_sys_futex failed\n", __func__); 393 } 394 395 return; 396 } 397 398 void 399 linux_nptl_proc_fork(p, parent, luserret) 400 struct proc *p; 401 struct proc *parent; 402 void (*luserret)(void); 403 { 404 #ifdef LINUX_NPTL 405 struct linux_emuldata *e; 406 #endif 407 408 e = p->p_emuldata; 409 410 /* LINUX_CLONE_CHILD_CLEARTID: clear TID in child's memory on exit() */ 411 if (e->clone_flags & LINUX_CLONE_CHILD_CLEARTID) 412 e->clear_tid = e->child_tidptr; 413 414 /* LINUX_CLONE_PARENT_SETTID: set child's TID in parent's memory */ 415 if (e->clone_flags & LINUX_CLONE_PARENT_SETTID) { 416 if (copyout_proc(parent, &p->p_pid, 417 e->parent_tidptr, sizeof(p->p_pid)) != 0) 418 printf("%s: LINUX_CLONE_PARENT_SETTID " 419 "failed (e->parent_tidptr = %p, " 420 "parent->p_pid = %d, p->p_pid = %d)\n", 421 __func__, e->parent_tidptr, 422 parent->p_pid, p->p_pid); 423 } 424 425 /* 426 * CLONE_CHILD_SETTID and LINUX_CLONE_SETTLS require child's VM 427 * setup to be completed, we postpone them until userret time. 428 */ 429 if (e->clone_flags & 430 (LINUX_CLONE_CHILD_CLEARTID | LINUX_CLONE_SETTLS)) 431 p->p_userret = luserret; 432 433 return; 434 } 435 436 void 437 linux_nptl_proc_init(p, parent) 438 struct proc *p; 439 struct proc *parent; 440 { 441 struct linux_emuldata *e = p->p_emuldata; 442 struct linux_emuldata *ep; 443 444 if ((parent != NULL) && (parent->p_emuldata != NULL)) { 445 ep = parent->p_emuldata; 446 447 e->parent_tidptr = ep->parent_tidptr; 448 e->child_tidptr = ep->child_tidptr; 449 e->clone_flags = ep->clone_flags; 450 } 451 452 return; 453 } 454 455 456 #endif /* LINUX_NPTL */ 457