From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id ; Thu, 7 Mar 2002 04:37:25 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id ; Thu, 7 Mar 2002 04:37:18 -0500 Received: from dell-paw-3.cambridge.redhat.com ([195.224.55.237]:10742 "HELO executor.cambridge.redhat.com") by vger.kernel.org with SMTP id ; Thu, 7 Mar 2002 04:37:03 -0500 To: torvalds@transmeta.com Cc: linux-kernel@vger.kernel.org, dhowells@redhat.com Subject: [PATCH] execve TGID dethreading bug fix User-Agent: EMH/1.14.1 SEMI/1.14.3 (Ushinoya) FLIM/1.14.3 (=?ISO-8859-4?Q?Unebigory=F2mae?=) APEL/10.3 Emacs/21.1 (i386-redhat-linux-gnu) MULE/5.0 (SAKAKI) MIME-Version: 1.0 (generated by SEMI 1.14.3 - "Ushinoya") Content-Type: text/plain; charset=US-ASCII Date: Thu, 07 Mar 2002 09:36:59 +0000 Message-ID: <3534.1015493819@warthog.cambridge.redhat.com> From: David Howells Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org Hi Linus, I've attached a patch to kill all subsidiary threads in a thread group when the main thread exits. I've made it against 2.5.6-pre3. Features: - It sends the subsidiary threads SIGKILL with SI_DETHREAD. - Subsidiary threads doing an execve() just leave the thread group (rather than forcing the master thread to do an execve() which would be more POSIX like). David diff -uNr linux-2.5.6-pre3/fs/exec.c linux-execve-256p3/fs/exec.c --- linux-2.5.6-pre3/fs/exec.c Thu Mar 7 09:08:50 2002 +++ linux-execve-256p3/fs/exec.c Thu Mar 7 09:13:47 2002 @@ -509,23 +509,49 @@ /* * An execve() will automatically "de-thread" the process. - * Note: we don't have to hold the tasklist_lock to test - * whether we migth need to do this. If we're not part of - * a thread group, there is no way we can become one - * dynamically. And if we are, we only need to protect the - * unlink - even if we race with the last other thread exit, - * at worst the list_del_init() might end up being a no-op. + * - if a master thread (PID==TGID) is doing this, then all subsidiary threads + * will be killed (otherwise there will end up being two independent thread + * groups with the same TGID). + * - if a subsidary thread is doing this, then it just leaves the thread group */ -static inline void de_thread(struct task_struct *tsk) +static void de_thread(struct task_struct *tsk) { - if (!list_empty(&tsk->thread_group)) { - write_lock_irq(&tasklist_lock); + struct task_struct *sub; + struct list_head *head, *ptr; + struct siginfo info; + int pause; + + write_lock_irq(&tasklist_lock); + + if (tsk->tgid != tsk->pid) { + /* subsidiary thread - just escapes the group */ + list_del_init(&tsk->thread_group); + tsk->tgid = tsk->pid; + pause = 0; + } + else { + /* master thread - kill all subsidiary threads */ + info.si_signo = SIGKILL; + info.si_errno = 0; + info.si_code = SI_DETHREAD; + info.si_pid = current->pid; + info.si_uid = current->uid; + + head = tsk->thread_group.next; list_del_init(&tsk->thread_group); - write_unlock_irq(&tasklist_lock); + + list_for_each(ptr,head) { + sub = list_entry(ptr,struct task_struct,thread_group); + send_sig_info(SIGKILL,&info,sub); + } + + pause = 1; } - /* Minor oddity: this might stay the same. */ - tsk->tgid = tsk->pid; + write_unlock_irq(&tasklist_lock); + + /* give the subsidiary threads a chance to clean themselves up */ + if (pause) yield(); } int flush_old_exec(struct linux_binprm * bprm) @@ -566,7 +592,8 @@ flush_thread(); - de_thread(current); + if (!list_empty(¤t->thread_group)) + de_thread(current); if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || permission(bprm->file->f_dentry->d_inode,MAY_READ)) diff -uNr linux-2.5.6-pre3/include/asm-i386/siginfo.h linux-execve-256p3/include/asm-i386/siginfo.h --- linux-2.5.6-pre3/include/asm-i386/siginfo.h Thu Mar 7 09:07:06 2002 +++ linux-execve-256p3/include/asm-i386/siginfo.h Thu Mar 7 09:17:53 2002 @@ -108,6 +108,7 @@ #define SI_ASYNCIO -4 /* sent by AIO completion */ #define SI_SIGIO -5 /* sent by queued SIGIO */ #define SI_TKILL -6 /* sent by tkill system call */ +#define SI_DETHREAD -7 /* sent by execve() killing subsidiary threads */ #define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) #define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0)