1 /* $NetBSD: linux_exec.c,v 1.95 2007/04/22 08:29:57 dsl 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.95 2007/04/22 08:29:57 dsl 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 sys_execve_args ap; 107 108 SCARG(&ap, path) = SCARG(uap, path); 109 SCARG(&ap, argp) = SCARG(uap, argp); 110 SCARG(&ap, envp) = SCARG(uap, envp); 111 112 return sys_execve(l, &ap, retval); 113 } 114 115 /* 116 * Emulation switch. 117 */ 118 119 struct uvm_object *emul_linux_object; 120 121 const struct emul emul_linux = { 122 "linux", 123 "/emul/linux", 124 #ifndef __HAVE_MINIMAL_EMUL 125 0, 126 (const int *)native_to_linux_errno, 127 LINUX_SYS_syscall, 128 LINUX_SYS_NSYSENT, 129 #endif 130 linux_sysent, 131 linux_syscallnames, 132 linux_sendsig, 133 linux_trapsignal, 134 NULL, 135 linux_sigcode, 136 linux_esigcode, 137 &emul_linux_object, 138 linux_setregs, 139 linux_e_proc_exec, 140 linux_e_proc_fork, 141 linux_e_proc_exit, 142 NULL, 143 NULL, 144 #ifdef __HAVE_SYSCALL_INTERN 145 linux_syscall_intern, 146 #else 147 #error Implement __HAVE_SYSCALL_INTERN for this platform 148 #endif 149 NULL, 150 NULL, 151 152 uvm_default_mapaddr, 153 154 linux_usertrap, 155 0, 156 NULL, /* e_startlwp */ 157 }; 158 159 static void 160 linux_e_proc_init(p, parent, forkflags) 161 struct proc *p, *parent; 162 int forkflags; 163 { 164 struct linux_emuldata *e = p->p_emuldata; 165 struct linux_emuldata_shared *s; 166 struct linux_emuldata *ep = NULL; 167 168 if (!e) { 169 /* allocate new Linux emuldata */ 170 MALLOC(e, void *, sizeof(struct linux_emuldata), 171 M_EMULDATA, M_WAITOK); 172 } else { 173 e->s->refs--; 174 if (e->s->refs == 0) 175 FREE(e->s, M_EMULDATA); 176 } 177 178 memset(e, '\0', sizeof(struct linux_emuldata)); 179 180 e->proc = p; 181 182 if (parent) 183 ep = parent->p_emuldata; 184 185 if (forkflags & FORK_SHAREVM) { 186 #ifdef DIAGNOSTIC 187 if (ep == NULL) { 188 killproc(p, "FORK_SHAREVM while emuldata is NULL\n"); 189 FREE(e, M_EMULDATA); 190 return; 191 } 192 #endif 193 s = ep->s; 194 s->refs++; 195 } else { 196 struct vmspace *vm; 197 198 MALLOC(s, void *, sizeof(struct linux_emuldata_shared), 199 M_EMULDATA, M_WAITOK); 200 s->refs = 1; 201 202 /* 203 * Set the process idea of the break to the real value. 204 * For fork, we use parent's vmspace since our's 205 * is not setup at the time of this call and is going 206 * to be copy of parent's anyway. For exec, just 207 * use our own vmspace. 208 */ 209 vm = (parent) ? parent->p_vmspace : p->p_vmspace; 210 s->p_break = (char *)vm->vm_daddr + ctob(vm->vm_dsize); 211 212 /* 213 * Linux threads are emulated as NetBSD processes (not lwp) 214 * We use native PID for Linux TID. The Linux TID is the 215 * PID of the first process in the group. It is stored 216 * here 217 */ 218 s->group_pid = p->p_pid; 219 220 /* 221 * Initialize the list of threads in the group 222 */ 223 LIST_INIT(&s->threads); 224 225 s->xstat = 0; 226 s->flags = 0; 227 } 228 229 e->s = s; 230 231 /* 232 * Add this thread in the group thread list 233 */ 234 LIST_INSERT_HEAD(&s->threads, e, threads); 235 236 #ifdef LINUX_NPTL 237 if (ep != NULL) { 238 e->parent_tidptr = ep->parent_tidptr; 239 e->child_tidptr = ep->child_tidptr; 240 e->clone_flags = ep->clone_flags; 241 } 242 #endif /* LINUX_NPTL */ 243 244 p->p_emuldata = e; 245 } 246 247 /* 248 * Allocate new per-process structures. Called when executing Linux 249 * process. We can reuse the old emuldata - if it's not null, 250 * the executed process is of same emulation as original forked one. 251 */ 252 static void 253 linux_e_proc_exec(struct proc *p, struct exec_package *epp) 254 { 255 /* exec, use our vmspace */ 256 linux_e_proc_init(p, NULL, 0); 257 } 258 259 /* 260 * Emulation per-process exit hook. 261 */ 262 static void 263 linux_e_proc_exit(p) 264 struct proc *p; 265 { 266 struct linux_emuldata *e = p->p_emuldata; 267 268 #ifdef LINUX_NPTL 269 linux_nptl_proc_exit(p); 270 #endif 271 /* Remove the thread for the group thread list */ 272 LIST_REMOVE(e, threads); 273 274 /* free Linux emuldata and set the pointer to null */ 275 e->s->refs--; 276 if (e->s->refs == 0) 277 FREE(e->s, M_EMULDATA); 278 FREE(e, M_EMULDATA); 279 p->p_emuldata = NULL; 280 } 281 282 /* 283 * Emulation fork hook. 284 */ 285 static void 286 linux_e_proc_fork(p, parent, forkflags) 287 struct proc *p, *parent; 288 int forkflags; 289 { 290 /* 291 * The new process might share some vmspace-related stuff 292 * with parent, depending on fork flags (CLONE_VM et.al). 293 * Force allocation of new base emuldata, and share the 294 * VM-related parts only if necessary. 295 */ 296 p->p_emuldata = NULL; 297 linux_e_proc_init(p, parent, forkflags); 298 299 #ifdef LINUX_NPTL 300 linux_nptl_proc_fork(p, parent, linux_userret); 301 #endif 302 303 return; 304 } 305 306 #ifdef LINUX_NPTL 307 void 308 linux_userret(void) 309 { 310 struct lwp *l = curlwp; 311 struct proc *p = l->l_proc; 312 struct linux_emuldata *led = p->p_emuldata; 313 int error; 314 315 /* LINUX_CLONE_CHILD_SETTID: copy child's TID to child's memory */ 316 if (led->clone_flags & LINUX_CLONE_CHILD_SETTID) { 317 if ((error = copyout(&l->l_proc->p_pid, 318 led->child_tidptr, sizeof(l->l_proc->p_pid))) != 0) 319 printf("linux_userret: LINUX_CLONE_CHILD_SETTID " 320 "failed (led->child_tidptr = %p, p->p_pid = %d)\n", 321 led->child_tidptr, p->p_pid); 322 } 323 324 /* LINUX_CLONE_SETTLS: allocate a new TLS */ 325 if (led->clone_flags & LINUX_CLONE_SETTLS) { 326 if (linux_set_newtls(l, linux_get_newtls(l)) != 0) 327 printf("linux_userret: linux_set_tls failed"); 328 } 329 330 return; 331 } 332 333 void 334 linux_nptl_proc_exit(p) 335 struct proc *p; 336 { 337 struct linux_emuldata *e = p->p_emuldata; 338 339 mutex_enter(&proclist_lock); 340 341 /* 342 * Check if we are a thread group leader victim of another 343 * thread doing exit_group(). If we are, change the exit code. 344 */ 345 if ((e->s->group_pid == p->p_pid) && 346 (e->s->flags & LINUX_LES_INEXITGROUP)) { 347 p->p_xstat = e->s->xstat; 348 } 349 350 /* 351 * Members of the thread groups others than the leader should 352 * exit quietely: no zombie stage, no signal. We do that by 353 * reparenting to init. init will collect us and nobody will 354 * notice what happened. 355 */ 356 #ifdef DEBUG_LINUX 357 printf("%s:%d e->s->group_pid = %d, p->p_pid = %d, flags = 0x%x\n", 358 __func__, __LINE__, e->s->group_pid, p->p_pid, e->s->flags); 359 #endif 360 if (e->s->group_pid != p->p_pid) { 361 proc_reparent(p, initproc); 362 cv_broadcast(&initproc->p_waitcv); 363 } 364 365 mutex_exit(&proclist_lock); 366 367 /* Emulate LINUX_CLONE_CHILD_CLEARTID */ 368 if (e->clear_tid != NULL) { 369 int error; 370 int null = 0; 371 struct linux_sys_futex_args cup; 372 register_t retval; 373 374 error = copyout(&null, e->clear_tid, sizeof(null)); 375 #ifdef DEBUG_LINUX 376 if (error != 0) 377 printf("%s: cannot clear TID\n", __func__); 378 #endif 379 380 SCARG(&cup, uaddr) = e->clear_tid; 381 SCARG(&cup, op) = LINUX_FUTEX_WAKE; 382 SCARG(&cup, val) = 0x7fffffff; /* Awake everyone */ 383 SCARG(&cup, timeout) = NULL; 384 SCARG(&cup, uaddr2) = NULL; 385 SCARG(&cup, val3) = 0; 386 if ((error = linux_sys_futex(curlwp, &cup, &retval)) != 0) 387 printf("%s: linux_sys_futex failed\n", __func__); 388 } 389 390 return; 391 } 392 393 void 394 linux_nptl_proc_fork(p, parent, luserret) 395 struct proc *p; 396 struct proc *parent; 397 void (*luserret)(void); 398 { 399 #ifdef LINUX_NPTL 400 struct linux_emuldata *e; 401 #endif 402 403 e = p->p_emuldata; 404 405 /* LINUX_CLONE_CHILD_CLEARTID: clear TID in child's memory on exit() */ 406 if (e->clone_flags & LINUX_CLONE_CHILD_CLEARTID) 407 e->clear_tid = e->child_tidptr; 408 409 /* LINUX_CLONE_PARENT_SETTID: set child's TID in parent's memory */ 410 if (e->clone_flags & LINUX_CLONE_PARENT_SETTID) { 411 if (copyout_proc(parent, &p->p_pid, 412 e->parent_tidptr, sizeof(p->p_pid)) != 0) 413 printf("%s: LINUX_CLONE_PARENT_SETTID " 414 "failed (e->parent_tidptr = %p, " 415 "parent->p_pid = %d, p->p_pid = %d)\n", 416 __func__, e->parent_tidptr, 417 parent->p_pid, p->p_pid); 418 } 419 420 /* 421 * CLONE_CHILD_SETTID and LINUX_CLONE_SETTLS require child's VM 422 * setup to be completed, we postpone them until userret time. 423 */ 424 if (e->clone_flags & 425 (LINUX_CLONE_CHILD_CLEARTID | LINUX_CLONE_SETTLS)) 426 p->p_userret = luserret; 427 428 return; 429 } 430 431 void 432 linux_nptl_proc_init(p, parent) 433 struct proc *p; 434 struct proc *parent; 435 { 436 struct linux_emuldata *e = p->p_emuldata; 437 struct linux_emuldata *ep; 438 439 if ((parent != NULL) && (parent->p_emuldata != NULL)) { 440 ep = parent->p_emuldata; 441 442 e->parent_tidptr = ep->parent_tidptr; 443 e->child_tidptr = ep->child_tidptr; 444 e->clone_flags = ep->clone_flags; 445 } 446 447 return; 448 } 449 450 451 #endif /* LINUX_NPTL */ 452