In article <20000827051241.A24890@hq.fsmlabs.com>,
<yodaiken@fsmlabs.com> wrote:
>
>POSIX says nothing, as far as I can tell, about the effect of exec on
>threads. However, it does say pending signals must be inherited. It's
>unclear what should happen in Linux, but it might be good for the new
>process to still be a thread in the thread group -- although it won't
>be sharing memory anymore.
No. Simply for security purposes we _definitely_ need to "de-thread" the
process when it does an exec. Otherwise we have "interesting" issues
with suid execs that are part of a non-suid thread group.
We could choose to just not allow suid execs, but I think they do
potentially make sense, and I don't see why Linux shouldn't allow a
thread to exec a suid binary (we break the shared VM part automatically,
we might as well break the shared thread part).
Note that for _pthreads_ this kind of exec is illegal anyway. Silly
POSIX threads standard had to take user-level threading models into
account, so under POSIX threads an execve() needs to kill off all other
threads. Another senseless limitation - one that we can _emulate_, of
course, but not one that we should consider part of the native thread
environment.
Btw, here's a simple thread-group patch. It doesn't actually _do_
anything with the thread group part, but this is the kind of frame-work
I've envisioned. Completely untested, of course, but with these kinds
of security issues taken into account.
Comments? At least it's small and simple..
Linus
---- diff -u --recursive --new-file penguin/linux/fs/exec.c linux/fs/exec.c --- penguin/linux/fs/exec.c Mon Aug 14 10:19:55 2000 +++ linux/fs/exec.c Sun Aug 27 17:29:52 2000 @@ -496,6 +496,25 @@ write_unlock(&files->file_lock); } +/* + * 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. + */ +static inline void de_thread(struct task_struct *tsk) +{ + if (!list_empty(&tsk->thread_group)) { + write_lock_irq(&tasklist_lock); + list_del_init(&tsk->thread_group); + write_unlock_irq(&tasklist_lock); + } + tsk->tgid = tsk->pid; +} + int flush_old_exec(struct linux_binprm * bprm) { char * name; @@ -533,6 +552,8 @@ current->comm[i] = '\0'; flush_thread(); + + de_thread(current); if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || permission(bprm->file->f_dentry->d_inode,MAY_READ)) diff -u --recursive --new-file penguin/linux/include/linux/sched.h linux/include/linux/sched.h --- penguin/linux/include/linux/sched.h Wed Aug 23 11:35:07 2000 +++ linux/include/linux/sched.h Sun Aug 27 17:31:18 2000 @@ -38,6 +38,7 @@ #define CLONE_PTRACE 0x00002000 /* set if we want to let tracing continue on the child too */ #define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release */ #define CLONE_PARENT 0x00008000 /* set if we want to have the same parent as the cloner */ +#define CLONE_THREAD 0x00010000 /* set if we want to clone the "thread group" */ /* * These are the constant used to fake the fixed-point load-average @@ -311,6 +312,7 @@ pid_t pgrp; pid_t tty_old_pgrp; pid_t session; + pid_t tgid; /* boolean value for session group leader */ int leader; /* @@ -319,6 +321,7 @@ * p->p_pptr->pid) */ struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr; + struct list_head thread_group; /* PID hash table linkage. */ struct task_struct *pidhash_next; @@ -435,6 +438,7 @@ prev_task: &tsk, \ p_opptr: &tsk, \ p_pptr: &tsk, \ + thread_group: LIST_HEAD_INIT(tsk.thread_group), \ wait_chldexit: __WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\ real_timer: { \ function: it_real_fn \ @@ -818,6 +822,7 @@ nr_threads--; unhash_pid(p); REMOVE_LINKS(p); + list_del(&p->thread_group); write_unlock_irq(&tasklist_lock); } diff -u --recursive --new-file penguin/linux/kernel/fork.c linux/kernel/fork.c --- penguin/linux/kernel/fork.c Wed Aug 23 11:33:48 2000 +++ linux/kernel/fork.c Sun Aug 27 17:32:08 2000 @@ -661,7 +661,13 @@ * Let it rip! */ retval = p->pid; + p->tgid = retval; + INIT_LIST_HEAD(&p->thread_group); write_lock_irq(&tasklist_lock); + if (clone_flags & CLONE_THREAD) { + p->tgid = current->tgid; + list_add(&p->thread_group, ¤t->thread_group); + } SET_LINKS(p); hash_pid(p); nr_threads++; - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org Please read the FAQ at http://www.tux.org/lkml/
This archive was generated by hypermail 2b29 : Thu Aug 31 2000 - 21:00:20 EST