diff --git a/sys/amd64/linux32/linux32_dummy.c b/sys/amd64/linux32/linux32_dummy.c index 2d1e4f5efeb3..fc4d5518b72a 100644 --- a/sys/amd64/linux32/linux32_dummy.c +++ b/sys/amd64/linux32/linux32_dummy.c @@ -53,7 +53,6 @@ DUMMY(bdflush); DUMMY(sysfs); DUMMY(query_module); DUMMY(nfsservctl); -DUMMY(prctl); DUMMY(rt_sigtimedwait); DUMMY(rt_sigqueueinfo); DUMMY(capget); diff --git a/sys/amd64/linux32/syscalls.master b/sys/amd64/linux32/syscalls.master index 6836441a82e4..10e9999021fb 100644 --- a/sys/amd64/linux32/syscalls.master +++ b/sys/amd64/linux32/syscalls.master @@ -298,7 +298,8 @@ l_gid16_t egid, l_gid16_t sgid); } 171 AUE_GETRESGID STD { int linux_getresgid16(l_gid16_t *rgid, \ l_gid16_t *egid, l_gid16_t *sgid); } -172 AUE_PRCTL STD { int linux_prctl(void); } +172 AUE_PRCTL STD { int linux_prctl(l_int option, l_int arg2, l_int arg3, \ + l_int arg4, l_int arg5); } 173 AUE_NULL STD { int linux_rt_sigreturn( \ struct l_ucontext *ucp); } 174 AUE_NULL STD { int linux_rt_sigaction(l_int sig, \ diff --git a/sys/compat/linux/linux_emul.c b/sys/compat/linux/linux_emul.c index 2f92ebda8c03..a2471accd7dc 100644 --- a/sys/compat/linux/linux_emul.c +++ b/sys/compat/linux/linux_emul.c @@ -84,6 +84,7 @@ linux_proc_init(struct thread *td, pid_t child, int flags) /* non-exec call */ em = malloc(sizeof *em, M_LINUX, M_WAITOK | M_ZERO); em->pid = child; + em->pdeath_signal = 0; if (flags & CLONE_VM) { /* handled later in the code */ } else { @@ -151,6 +152,7 @@ linux_proc_exit(void *arg __unused, struct proc *p) int error; struct thread *td = FIRST_THREAD_IN_PROC(p); int *child_clear_tid; + struct proc *q, *nq; if (__predict_true(p->p_sysent != &elf_linux_sysvec)) return; @@ -204,6 +206,26 @@ linux_proc_exit(void *arg __unused, struct proc *p) /* clean the stuff up */ free(em, M_LINUX); + + /* this is a little weird but rewritten from exit1() */ + sx_xlock(&proctree_lock); + q = LIST_FIRST(&p->p_children); + for (; q != NULL; q = nq) { + nq = LIST_NEXT(q, p_sibling); + if (q->p_flag & P_WEXIT) + continue; + if (__predict_false(q->p_sysent != &elf_linux_sysvec)) + continue; + em = em_find(q, EMUL_UNLOCKED); + KASSERT(em != NULL, ("linux_reparent: emuldata not found: %i\n", q->p_pid)); + if (em->pdeath_signal != 0) { + PROC_LOCK(q); + psignal(q, em->pdeath_signal); + PROC_UNLOCK(q); + } + EMUL_UNLOCK(&emul_lock); + } + sx_xunlock(&proctree_lock); } /* @@ -251,7 +273,7 @@ linux_schedtail(void *arg __unused, struct proc *p) int error = 0; int *child_set_tid; - if (p->p_sysent != &elf_linux_sysvec) + if (__predict_true(p->p_sysent != &elf_linux_sysvec)) return; retry: diff --git a/sys/compat/linux/linux_emul.h b/sys/compat/linux/linux_emul.h index 0c431758f1b7..ddc3e5ba3cc0 100644 --- a/sys/compat/linux/linux_emul.h +++ b/sys/compat/linux/linux_emul.h @@ -50,6 +50,8 @@ struct linux_emuldata { struct linux_emuldata_shared *shared; + int pdeath_signal; /* parent death signal */ + LIST_ENTRY(linux_emuldata) threads; /* list of linux threads */ }; diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index fe0b803fdb5f..eedc18545b71 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -76,6 +76,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #ifdef COMPAT_LINUX32 #include @@ -86,6 +87,7 @@ __FBSDID("$FreeBSD$"); #endif #include +#include #include #ifdef __i386__ @@ -1546,3 +1548,52 @@ linux_exit_group(struct thread *td, struct linux_exit_group_args *args) return (0); } + +int +linux_prctl(struct thread *td, struct linux_prctl_args *args) +{ + int error = 0; + struct proc *p = td->td_proc; + char comm[LINUX_MAX_COMM_LEN]; + struct linux_emuldata *em; + +#ifdef DEBUG + if (ldebug(prctl)) + printf(ARGS(prctl, "%d, %d, %d, %d, %d"), args->option, args->arg2, + args->arg3, args->arg4, args->arg5); +#endif + + switch (args->option) { + case LINUX_PR_SET_PDEATHSIG: + if (!LINUX_SIG_VALID(args->arg2)) + return (EINVAL); + em = em_find(p, EMUL_UNLOCKED); + KASSERT(em != NULL, ("prctl: emuldata not found.\n")); + em->pdeath_signal = args->arg2; + EMUL_UNLOCK(&emul_lock); + break; + case LINUX_PR_GET_PDEATHSIG: + em = em_find(p, EMUL_UNLOCKED); + KASSERT(em != NULL, ("prctl: emuldata not found.\n")); + error = copyout(&em->pdeath_signal, (void *)(register_t) args->arg2, sizeof(em->pdeath_signal)); + EMUL_UNLOCK(&emul_lock); + break; + case LINUX_PR_SET_NAME: + comm[LINUX_MAX_COMM_LEN-1] = 0; + error = copyin(comm, (void *)(register_t) args->arg2, LINUX_MAX_COMM_LEN-1); + if (error) + return (error); + PROC_LOCK(p); + strcpy(p->p_comm, comm); + PROC_UNLOCK(p); + break; + case LINUX_PR_GET_NAME: + error = copyout(&p->p_comm, (void *)(register_t) args->arg2, MAXCOMLEN+1); + break; + default: + error = EINVAL; + break; + } + + return (error); +} diff --git a/sys/compat/linux/linux_misc.h b/sys/compat/linux/linux_misc.h new file mode 100644 index 000000000000..c2986c3d1284 --- /dev/null +++ b/sys/compat/linux/linux_misc.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2006 Roman Divacky + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _LINUX_MISC_H_ +#define _LINUX_MISC_H_ + +/* defines for prctl */ +#define LINUX_PR_SET_PDEATHSIG 1 /* Second arg is a signal */ +#define LINUX_PR_GET_PDEATHSIG 2 /* Second arg is a ptr to return the signal */ +#define LINUX_PR_SET_NAME 15 /* Set process name */ +#define LINUX_PR_GET_NAME 16 /* Get process name */ + +#define LINUX_MAX_COMM_LEN 16 /* max length of the proc name */ + +#endif /* _LINUX_MISC_H_ */ + diff --git a/sys/i386/linux/linux_dummy.c b/sys/i386/linux/linux_dummy.c index ccc548d4b93e..5f3afc4546ff 100644 --- a/sys/i386/linux/linux_dummy.c +++ b/sys/i386/linux/linux_dummy.c @@ -56,7 +56,6 @@ DUMMY(sysfs); DUMMY(vm86); DUMMY(query_module); DUMMY(nfsservctl); -DUMMY(prctl); DUMMY(rt_sigtimedwait); DUMMY(rt_sigqueueinfo); DUMMY(capget); diff --git a/sys/i386/linux/syscalls.master b/sys/i386/linux/syscalls.master index 6b0058419220..24c98bede6c7 100644 --- a/sys/i386/linux/syscalls.master +++ b/sys/i386/linux/syscalls.master @@ -301,7 +301,8 @@ l_gid16_t egid, l_gid16_t sgid); } 171 AUE_GETRESGID STD { int linux_getresgid16(l_gid16_t *rgid, \ l_gid16_t *egid, l_gid16_t *sgid); } -172 AUE_PRCTL STD { int linux_prctl(void); } +172 AUE_PRCTL STD { int linux_prctl(l_int option, l_int arg2, l_int arg3, \ + l_int arg4, l_int arg5); } 173 AUE_NULL STD { int linux_rt_sigreturn( \ struct l_ucontext *ucp); } 174 AUE_NULL STD { int linux_rt_sigaction(l_int sig, \