>Number:         144194
>Category:       kern
>Synopsis:       [patch] linuxulator: 2 exec bug fixes
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Feb 22 01:50:02 UTC 2010
>Closed-Date:
>Last-Modified:
>Originator:     Gleb Kurtsou
>Release:        
>Organization:
>Environment:
FreeBSD tops 9.0-CURRENT FreeBSD 9.0-CURRENT #17 r203556+e02bf32: Mon Feb 22 
03:04:35 EET 2010     r...@tops:/usr/obj/freebsd-src/local/sys/TOPS  amd64
>Description:
1. After calling exec() in multithreaded linux program threads are not 
destroyed and continue running. They get killed after program being executed 
finishes

2. linux_exit_group doesn't return correct exit code when called from not from 
group leader. Which happens regularly using sun jvm. I've changed exit1() to 
allow process_exit event handler to change p->p_xstat, just like NetBSD does.

There's another PR for this bug: kern/141439
But in that PR doesn't kill group leader, it works because sun jvm calls 
exit_group once again. Expected behavior for exit_group is not to return to 
userspace.

Submitting it as a single PR because second patch 
(linux-exit-group-status-code.patch.txt) relays on the first one
>How-To-Repeat:

>Fix:


Patch attached with submission follows:

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#       linux-exec-kill-threads.patch.txt
#       linux-exit-group-status-code.patch.txt
#
echo x - linux-exec-kill-threads.patch.txt
sed 's/^X//' >linux-exec-kill-threads.patch.txt << 
'ef694d85587f5b6ee852ea1905df69a1'
Xdiff --git a/sys/compat/linux/linux_emul.c b/sys/compat/linux/linux_emul.c
Xindex dc81553..4da2f33 100644
X--- a/sys/compat/linux/linux_emul.c
X+++ b/sys/compat/linux/linux_emul.c
X@@ -257,6 +257,9 @@ linux_proc_exec(void *arg __unused, struct proc *p, struct 
image_params *imgp)
X       if (__predict_false(imgp->sysent == &elf_linux_sysvec
X           && p->p_sysent != &elf_linux_sysvec))
X               linux_proc_init(FIRST_THREAD_IN_PROC(p), p->p_pid, 0);
X+      if (__predict_false(p->p_sysent == &elf_linux_sysvec))
X+              /* Kill threads regerdless of imgp->sysent value */
X+              linux_kill_threads(FIRST_THREAD_IN_PROC(p), SIGKILL);
X       if (__predict_false(imgp->sysent != &elf_linux_sysvec
X           && p->p_sysent == &elf_linux_sysvec)) {
X               struct linux_emuldata *em;
X@@ -334,3 +337,29 @@ linux_set_tid_address(struct thread *td, struct 
linux_set_tid_address_args *args
X       EMUL_UNLOCK(&emul_lock);
X       return 0;
X }
X+
X+void
X+linux_kill_threads(struct thread *td, int sig)
X+{
X+      struct linux_emuldata *em, *td_em, *tmp_em;
X+      struct proc *sp;
X+
X+      td_em = em_find(td->td_proc, EMUL_DONTLOCK);
X+
X+      KASSERT(td_em != NULL, ("linux_kill_threads: emuldata not found.\n"));
X+
X+      EMUL_SHARED_RLOCK(&emul_shared_lock);
X+      LIST_FOREACH_SAFE(em, &td_em->shared->threads, threads, tmp_em) {
X+              if (em->pid == td_em->pid)
X+                      continue;
X+
X+              sp = pfind(em->pid);
X+              if ((sp->p_flag & P_WEXIT) == 0)
X+                      psignal(sp, sig);
X+              PROC_UNLOCK(sp);
X+#ifdef DEBUG
X+              printf(LMSG("linux_kill_threads: kill PID %d\n"), em->pid);
X+#endif
X+      }
X+      EMUL_SHARED_RUNLOCK(&emul_shared_lock);
X+}
Xdiff --git a/sys/compat/linux/linux_emul.h b/sys/compat/linux/linux_emul.h
Xindex 8ce27d7..a46a262 100644
X--- a/sys/compat/linux/linux_emul.h
X+++ b/sys/compat/linux/linux_emul.h
X@@ -76,6 +76,7 @@ int  linux_proc_init(struct thread *, pid_t, int);
X void  linux_proc_exit(void *, struct proc *);
X void  linux_schedtail(void *, struct proc *);
X void  linux_proc_exec(void *, struct proc *, struct image_params *);
X+void  linux_kill_threads(struct thread *, int);
X 
X extern struct sx      emul_shared_lock;
X extern struct mtx     emul_lock;
Xdiff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c
Xindex d2cf6b6..79e9c2b 100644
X--- a/sys/compat/linux/linux_misc.c
X+++ b/sys/compat/linux/linux_misc.c
X@@ -1695,34 +1695,15 @@ linux_setdomainname(struct thread *td, struct 
linux_setdomainname_args *args)
X int
X linux_exit_group(struct thread *td, struct linux_exit_group_args *args)
X {
X-      struct linux_emuldata *em, *td_em, *tmp_em;
X-      struct proc *sp;
X 
X #ifdef DEBUG
X       if (ldebug(exit_group))
X               printf(ARGS(exit_group, "%i"), args->error_code);
X #endif
X 
X-      if (linux_use26(td)) {
X-              td_em = em_find(td->td_proc, EMUL_DONTLOCK);
X-
X-              KASSERT(td_em != NULL, ("exit_group: emuldata not found.\n"));
X-
X-              EMUL_SHARED_RLOCK(&emul_shared_lock);
X-              LIST_FOREACH_SAFE(em, &td_em->shared->threads, threads, tmp_em) 
{
X-                      if (em->pid == td_em->pid)
X-                              continue;
X-
X-                      sp = pfind(em->pid);
X-                      psignal(sp, SIGKILL);
X-                      PROC_UNLOCK(sp);
X-#ifdef DEBUG
X-                      printf(LMSG("linux_sys_exit_group: kill PID %d\n"), 
em->pid);
X-#endif
X-              }
X+      if (linux_use26(td))
X+              linux_kill_threads(td, SIGKILL);
X 
X-              EMUL_SHARED_RUNLOCK(&emul_shared_lock);
X-      }
X       /*
X        * XXX: we should send a signal to the parent if
X        * SIGNAL_EXIT_GROUP is set. We ignore that (temporarily?)
ef694d85587f5b6ee852ea1905df69a1
echo x - linux-exit-group-status-code.patch.txt
sed 's/^X//' >linux-exit-group-status-code.patch.txt << 
'844c33058a401cb53a9012cb32028df6'
Xdiff --git a/sys/compat/linux/linux_emul.c b/sys/compat/linux/linux_emul.c
Xindex 4da2f33..c8c150b 100644
X--- a/sys/compat/linux/linux_emul.c
X+++ b/sys/compat/linux/linux_emul.c
X@@ -157,6 +157,7 @@ linux_proc_exit(void *arg __unused, struct proc *p)
X       struct linux_emuldata *em;
X       int error;
X       struct thread *td = FIRST_THREAD_IN_PROC(p);
X+      int shared_flags, shared_xstat;
X       int *child_clear_tid;
X       struct proc *q, *nq;
X 
X@@ -187,6 +188,8 @@ linux_proc_exit(void *arg __unused, struct proc *p)
X       }
X 
X       EMUL_SHARED_WLOCK(&emul_shared_lock);
X+      shared_flags = em->shared->flags;
X+      shared_xstat = em->shared->xstat;
X       LIST_REMOVE(em, threads);
X 
X       em->shared->refs--;
X@@ -196,6 +199,12 @@ linux_proc_exit(void *arg __unused, struct proc *p)
X       } else  
X               EMUL_SHARED_WUNLOCK(&emul_shared_lock);
X 
X+      if ((shared_flags & EMUL_SHARED_HASXSTAT) != 0) {
X+              PROC_LOCK(p);
X+              p->p_xstat = shared_xstat;
X+              PROC_UNLOCK(p);
X+      }
X+
X       if (child_clear_tid != NULL) {
X               struct linux_sys_futex_args cup;
X               int null = 0;
Xdiff --git a/sys/compat/linux/linux_emul.h b/sys/compat/linux/linux_emul.h
Xindex a46a262..47a6989 100644
X--- a/sys/compat/linux/linux_emul.h
X+++ b/sys/compat/linux/linux_emul.h
X@@ -31,11 +31,16 @@
X #ifndef _LINUX_EMUL_H_
X #define       _LINUX_EMUL_H_
X 
X+#define EMUL_SHARED_HASXSTAT  0x01
X+
X struct linux_emuldata_shared {
X       int     refs;
X       pid_t   group_pid;
X 
X       LIST_HEAD(, linux_emuldata) threads; /* head of list of linux threads */
X+
X+      int     flags;
X+      int     xstat;
X };
X 
X /*
Xdiff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c
Xindex 79e9c2b..c50bf1c 100644
X--- a/sys/compat/linux/linux_misc.c
X+++ b/sys/compat/linux/linux_misc.c
X@@ -1695,14 +1695,22 @@ linux_setdomainname(struct thread *td, struct 
linux_setdomainname_args *args)
X int
X linux_exit_group(struct thread *td, struct linux_exit_group_args *args)
X {
X+      struct linux_emuldata *em;
X 
X #ifdef DEBUG
X       if (ldebug(exit_group))
X               printf(ARGS(exit_group, "%i"), args->error_code);
X #endif
X 
X-      if (linux_use26(td))
X-              linux_kill_threads(td, SIGKILL);
X+      em = em_find(td->td_proc, EMUL_DONTLOCK);
X+      if (em->shared->refs > 1) {
X+              EMUL_SHARED_WLOCK(&emul_shared_lock);
X+              em->shared->flags |= EMUL_SHARED_HASXSTAT;
X+              em->shared->xstat = W_EXITCODE(args->error_code, 0);
X+              EMUL_SHARED_WUNLOCK(&emul_shared_lock);
X+              if (linux_use26(td))
X+                      linux_kill_threads(td, SIGKILL);
X+      }
X 
X       /*
X        * XXX: we should send a signal to the parent if
Xdiff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
Xindex af00f42..9c27e75 100644
X--- a/sys/kern/kern_exit.c
X+++ b/sys/kern/kern_exit.c
X@@ -204,6 +204,7 @@ exit1(struct thread *td, int rv)
X       while (p->p_lock > 0)
X               msleep(&p->p_lock, &p->p_mtx, PWAIT, "exithold", 0);
X 
X+      p->p_xstat = rv;        /* Let event handler change exit status */
X       PROC_UNLOCK(p);
X       /* Drain the limit callout while we don't have the proc locked */
X       callout_drain(&p->p_limco);
X@@ -246,6 +247,7 @@ exit1(struct thread *td, int rv)
X        * P_PPWAIT is set; we will wakeup the parent below.
X        */
X       PROC_LOCK(p);
X+      rv = p->p_xstat;        /* Event handler could change exit status */
X       stopprofclock(p);
X       p->p_flag &= ~(P_TRACED | P_PPWAIT);
X 
X@@ -452,7 +454,6 @@ exit1(struct thread *td, int rv)
X 
X       /* Save exit status. */
X       PROC_LOCK(p);
X-      p->p_xstat = rv;
X       p->p_xthread = td;
X 
X       /* Tell the prison that we are gone. */
844c33058a401cb53a9012cb32028df6
exit



>Release-Note:
>Audit-Trail:
>Unformatted:
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bugs
To unsubscribe, send any mail to "[email protected]"

Reply via email to