1 /* $NetBSD: linux_exec.c,v 1.84 2006/06/25 16:15:39 manu Exp $ */ 2 3 /*- 4 * Copyright (c) 1994, 1995, 1998, 2000 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.84 2006/06/25 16:15:39 manu 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/sa.h> 56 #include <sys/syscallargs.h> 57 58 #include <uvm/uvm_extern.h> 59 60 #include <machine/cpu.h> 61 #include <machine/reg.h> 62 63 #include <compat/linux/common/linux_types.h> 64 #include <compat/linux/common/linux_signal.h> 65 #include <compat/linux/common/linux_util.h> 66 #include <compat/linux/common/linux_exec.h> 67 #include <compat/linux/common/linux_machdep.h> 68 #include <compat/linux/common/linux_futex.h> 69 70 #include <compat/linux/linux_syscallargs.h> 71 #include <compat/linux/linux_syscall.h> 72 #include <compat/linux/common/linux_misc.h> 73 #include <compat/linux/common/linux_errno.h> 74 #include <compat/linux/common/linux_emuldata.h> 75 76 extern struct sysent linux_sysent[]; 77 extern const char * const linux_syscallnames[]; 78 extern char linux_sigcode[], linux_esigcode[]; 79 80 static void linux_e_proc_exec __P((struct proc *, struct exec_package *)); 81 static void linux_e_proc_fork __P((struct proc *, struct proc *, int)); 82 static void linux_e_proc_exit __P((struct proc *)); 83 static void linux_e_proc_init __P((struct proc *, struct proc *, int)); 84 85 #ifdef LINUX_NPTL 86 static void linux_userret __P((struct lwp *, void *)); 87 #endif 88 89 /* 90 * Execve(2). Just check the alternate emulation path, and pass it on 91 * to the NetBSD execve(). 92 */ 93 int 94 linux_sys_execve(l, v, retval) 95 struct lwp *l; 96 void *v; 97 register_t *retval; 98 { 99 struct linux_sys_execve_args /* { 100 syscallarg(const char *) path; 101 syscallarg(char **) argv; 102 syscallarg(char **) envp; 103 } */ *uap = v; 104 struct proc *p = l->l_proc; 105 struct sys_execve_args ap; 106 caddr_t sg; 107 108 sg = stackgap_init(p, 0); 109 CHECK_ALT_EXIST(l, &sg, SCARG(uap, path)); 110 111 SCARG(&ap, path) = SCARG(uap, path); 112 SCARG(&ap, argp) = SCARG(uap, argp); 113 SCARG(&ap, envp) = SCARG(uap, envp); 114 115 return sys_execve(l, &ap, retval); 116 } 117 118 /* 119 * Emulation switch. 120 */ 121 122 struct uvm_object *emul_linux_object; 123 124 const struct emul emul_linux = { 125 "linux", 126 "/emul/linux", 127 #ifndef __HAVE_MINIMAL_EMUL 128 0, 129 (const int *)native_to_linux_errno, 130 LINUX_SYS_syscall, 131 LINUX_SYS_NSYSENT, 132 #endif 133 linux_sysent, 134 linux_syscallnames, 135 linux_sendsig, 136 linux_trapsignal, 137 NULL, 138 linux_sigcode, 139 linux_esigcode, 140 &emul_linux_object, 141 linux_setregs, 142 linux_e_proc_exec, 143 linux_e_proc_fork, 144 linux_e_proc_exit, 145 NULL, 146 NULL, 147 #ifdef __HAVE_SYSCALL_INTERN 148 linux_syscall_intern, 149 #else 150 #error Implement __HAVE_SYSCALL_INTERN for this platform 151 #endif 152 NULL, 153 NULL, 154 155 uvm_default_mapaddr, 156 157 linux_usertrap, 158 }; 159 160 static void 161 linux_e_proc_init(p, parent, forkflags) 162 struct proc *p, *parent; 163 int forkflags; 164 { 165 struct linux_emuldata *e = p->p_emuldata; 166 struct linux_emuldata_shared *s; 167 struct linux_emuldata *ep = NULL; 168 169 if (!e) { 170 /* allocate new Linux emuldata */ 171 MALLOC(e, void *, sizeof(struct linux_emuldata), 172 M_EMULDATA, M_WAITOK); 173 } else { 174 e->s->refs--; 175 if (e->s->refs == 0) 176 FREE(e->s, M_EMULDATA); 177 } 178 179 memset(e, '\0', sizeof(struct linux_emuldata)); 180 181 e->proc = p; 182 183 if (parent) 184 ep = parent->p_emuldata; 185 186 if (forkflags & FORK_SHAREVM) { 187 #ifdef DIAGNOSTIC 188 if (ep == NULL) { 189 killproc(p, "FORK_SHAREVM while emuldata is NULL\n"); 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 = 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 226 e->s = s; 227 228 /* 229 * Add this thread in the group thread list 230 */ 231 LIST_INSERT_HEAD(&s->threads, e, threads); 232 233 #ifdef LINUX_NPTL 234 /* 235 * initialize TID pointers. ep->child_clear_tid and 236 * ep->child_set_tid will not be used beyond this point. 237 */ 238 e->child_clear_tid = NULL; 239 e->child_set_tid = NULL; 240 if (ep != NULL) { 241 e->clear_tid = ep->child_clear_tid; 242 e->set_tid = ep->child_set_tid; 243 e->set_tls = ep->set_tls; 244 ep->child_clear_tid = NULL; 245 ep->child_set_tid = NULL; 246 ep->set_tls = 0; 247 } else { 248 e->clear_tid = NULL; 249 e->set_tid = NULL; 250 e->set_tls = 0; 251 } 252 #endif /* LINUX_NPTL */ 253 254 p->p_emuldata = e; 255 } 256 257 /* 258 * Allocate new per-process structures. Called when executing Linux 259 * process. We can reuse the old emuldata - if it's not null, 260 * the executed process is of same emulation as original forked one. 261 */ 262 static void 263 linux_e_proc_exec(p, epp) 264 struct proc *p; 265 struct exec_package *epp; 266 { 267 /* exec, use our vmspace */ 268 linux_e_proc_init(p, NULL, 0); 269 } 270 271 /* 272 * Emulation per-process exit hook. 273 */ 274 static void 275 linux_e_proc_exit(p) 276 struct proc *p; 277 { 278 struct linux_emuldata *e = p->p_emuldata; 279 280 #ifdef LINUX_NPTL 281 /* Emulate LINUX_CLONE_CHILD_CLEARTID */ 282 if (e->clear_tid != NULL) { 283 int error; 284 int null = 0; 285 struct linux_sys_futex_args cup; 286 register_t retval; 287 struct lwp *l; 288 289 error = copyout(&null, e->clear_tid, sizeof(null)); 290 #ifdef DEBUG_LINUX 291 if (error != 0) 292 printf("linux_e_proc_exit: cannot clear TID\n"); 293 #endif 294 295 l = proc_representative_lwp(p); 296 SCARG(&cup, uaddr) = e->clear_tid; 297 SCARG(&cup, op) = LINUX_FUTEX_WAKE; 298 SCARG(&cup, val) = 0x7fffffff; /* Awake everyone */ 299 SCARG(&cup, timeout) = NULL; 300 SCARG(&cup, uaddr2) = NULL; 301 SCARG(&cup, val3) = 0; 302 if ((error = linux_sys_futex(l, &cup, &retval)) != 0) 303 printf("linux_e_proc_exit: linux_sys_futex failed\n"); 304 } 305 #endif /* LINUX_NPTL */ 306 307 /* Remove the thread for the group thread list */ 308 LIST_REMOVE(e, threads); 309 310 /* free Linux emuldata and set the pointer to null */ 311 e->s->refs--; 312 if (e->s->refs == 0) 313 FREE(e->s, M_EMULDATA); 314 FREE(e, M_EMULDATA); 315 p->p_emuldata = NULL; 316 } 317 318 /* 319 * Emulation fork hook. 320 */ 321 static void 322 linux_e_proc_fork(p, parent, forkflags) 323 struct proc *p, *parent; 324 int forkflags; 325 { 326 #ifdef LINUX_NPTL 327 struct linux_emuldata *e; 328 #endif 329 330 /* 331 * The new process might share some vmspace-related stuff 332 * with parent, depending on fork flags (CLONE_VM et.al). 333 * Force allocation of new base emuldata, and share the 334 * VM-related parts only if necessary. 335 */ 336 p->p_emuldata = NULL; 337 linux_e_proc_init(p, parent, forkflags); 338 339 #ifdef LINUX_NPTL 340 /* 341 * Emulate LINUX_CLONE_CHILD_SETTID and LINUX_CLONE_TLS: 342 * This cannot be done right now because the child VM 343 * is not set up. We will do it at userret time. 344 */ 345 e = p->p_emuldata; 346 if ((e->set_tid != NULL) || (e->set_tls != 0)) 347 p->p_userret = (*linux_userret); 348 #endif 349 350 return; 351 } 352 353 #ifdef LINUX_NPTL 354 static void 355 linux_userret(l, arg) 356 struct lwp *l; 357 void *arg; 358 { 359 struct proc *p = l->l_proc; 360 struct linux_emuldata *led = p->p_emuldata; 361 int error; 362 363 p->p_userret = NULL; 364 365 /* Emulate LINUX_CLONE_CHILD_SETTID */ 366 if (led->set_tid != NULL) { 367 if ((error = copyout(&p->p_pid, 368 led->set_tid, sizeof(p->p_pid))) != 0) 369 printf("linux_userret: cannot set TID\n"); 370 } 371 372 /* Emulate LINUX_CLONE_NEWTLS */ 373 if (led->set_tls != 0) { 374 if (linux_set_newtls(l, led->set_tls) != 0) 375 printf("linux_userret: cannot set TLS\n"); 376 } 377 378 return; 379 } 380 #endif /* LINUX_NPTL */ 381