Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Wed, 5 Aug 2009 15:26:21 -0400
From: "Michael K. Johnson" <johnsonm@...th.com>
To: oss-security@...ts.openwall.com
Cc: "Steven M. Christey" <coley@...us.mitre.org>
Subject: Re: CVE request - kernel: execve: must clear current->clear_child_tid

This seems to me a potential security issue specifically because as
far as I can see clear_child_tid isn't reset on exec of set{u,g}id
executables.  (Otherwise it would just be a bug...)  Regarding a
non-threaded setuid program, a direct attack seems hard since the
maps and smaps files are hidden to other users.  Am I missing some
of the potential impact here?

On Tue, Aug 04, 2009 at 04:09:09PM +0800, Eugene Teo wrote:
> clone() syscall has special support for TID of created threads.  This
> support includes two features.
> 
> One (CLONE_CHILD_SETTID) is to set an integer into user memory with the
> TID value.
> 
> One (CLONE_CHILD_CLEARTID) is to clear this same integer once the
> created thread dies.
> 
> The integer location is a user provided pointer, provided at clone() time.
> 
> kernel keeps this pointer value into current->clear_child_tid.
> 
> At execve() time, we should make sure kernel doesnt keep this user
> provided pointer, as full user memory is replaced by a new one.
> 
> As glibc fork() actually uses clone() syscall with CLONE_CHILD_SETTID
> and CLONE_CHILD_CLEARTID set, chances are high that we might corrupt
> user memory in forked processes.
> 
> Following sequence could happen:
> 
> 1) bash (or any program) starts a new process, by a fork() call that
> glibc maps to a clone( ...  CLONE_CHILD_SETTID |
> CLONE_CHILD_CLEARTID...) syscall
> 
> 2) When new process starts, its current->clear_child_tid is set to a
> location that has a meaning only in bash (or initial program) context
> (&THREAD_SELF->tid)
> 
> 3) This new process does the execve() syscall to start a new program.
> current->clear_child_tid is left unchanged (a non NULL value)
> 
> 4) If this new program creates some threads, and initial thread exits,
> kernel will attempt to clear the integer pointed by
> current->clear_child_tid from mm_release() :
> 
>         if (tsk->clear_child_tid
>             && !(tsk->flags & PF_SIGNALED)
>             && atomic_read(&mm->mm_users) > 1) {
>                 u32 __user * tidptr = tsk->clear_child_tid;
>                 tsk->clear_child_tid = NULL;
> 
>                 /*
>                  * We don't check the error code - if userspace has
>                  * not set up a proper pointer then tough luck.
>                  */
> << here >>      put_user(0, tidptr);
>                 sys_futex(tidptr, FUTEX_WAKE, 1, NULL, NULL, 0);
>         }
> 
> 5) OR : if new program is not multi-threaded, but spied by /proc/pid
> users (ps command for example), mm_users > 1, and the exiting program
> could corrupt 4 bytes in a persistent memory area (shm or memory mapped
> file)
> 
> If current->clear_child_tid points to a writeable portion of memory of
> the new program, kernel happily and silently corrupts 4 bytes of memory,
> with unexpected effects.
> 
> References:
> http://article.gmane.org/gmane.linux.kernel/871942
> https://bugzilla.redhat.com/show_bug.cgi?id=515423
> 
> Patch is not in upstream kernel yet.
> 
> Thanks, Eugene

Powered by blists - more mailing lists

Please check out the Open Source Software Security Wiki, which is counterpart to this mailing list.

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.