[arch-security] CVE-2014-0196: Linux kernel pty layer race condition memory corruption

Mark Lee mark at markelee.com
Mon May 5 14:43:53 EDT 2014


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

To all,

A race condition in the PTY write buffer handling has been discovered in
the Linux kernel. See quoted text below and attachment for patch
submitted by Jiri Slaby and Peter Hurley.

Regards,
Mark

> Hi,
> 
> SUSE customer Ericsson reported a kernel crash to us which turned out
> to be a race condition in the PTY write buffer handling.
> 
> When two processes/threads write to the same pty, the buffer end could
> be overwritten and so memory corruption into adjacent buffers could lead
> to crashes / code execution.
> 
> Jiri Slaby and Peter Hurley localized and fixed this problem.
> 
> CVE-2014-0196 has been assigned to this issue.
> 
> Jiri thinks this was introduced during 2.6.31 development by
> d945cb9cce20ac7143c2de8d88b187f62db99bdc (pty: Rework the pty
> layer to use the normal buffering logic) in 2.6.31-rc3. Until then, pty
> was writing directly to a line discipline without using buffers.
> 
> https://bugzilla.novell.com/show_bug.cgi?id=875690
> 
> Patch is also attached.
> 
> Ciao, Marcus
> 
> 
> n_tty-Fix-n_tty_write-crash-when-echoing-in-raw-mode.patch
> 
> From 34ba81cd3561c5fc6aff3041f3445d69f85b5155 Mon Sep 17 00:00:00 2001
> From: Peter Hurley <peter at hurleysoftware.com>
> Date: Tue, 29 Apr 2014 12:38:36 -0400
> Subject: [PATCH 1/1] n_tty: Fix n_tty_write crash when echoing in raw mode
> 
> The tty atomic_write_lock does not provide an exclusion guarantee for
> the tty driver if the termios settings are LECHO & !OPOST.  And since
> it is unexpected and not allowed to call TTY buffer helpers like
> tty_insert_flip_string concurrently, this may lead to crashes when
> concurrect writers call pty_write. In that case the following two
> writers:
> * the ECHOing from a workqueue and
> * pty_write from the process
> race and can overflow the corresponding TTY buffer like follows.
> 
> If we look into tty_insert_flip_string_fixed_flag, there is:
>   int space = __tty_buffer_request_room(port, goal, flags);
>   struct tty_buffer *tb = port->buf.tail;
>   ...
>   memcpy(char_buf_ptr(tb, tb->used), chars, space);
>   ...
>   tb->used += space;
> 
> so the race of the two can result in something like this:
>               A                                B
> __tty_buffer_request_room
>                                   __tty_buffer_request_room
> memcpy(buf(tb->used), ...)
> tb->used += space;
>                                   memcpy(buf(tb->used), ...) ->BOOM
> 
> B's memcpy is past the tty_buffer due to the previous A's tb->used
> increment.
> 
> Since the N_TTY line discipline input processing can output
> concurrently with a tty write, obtain the N_TTY ldisc output_lock to
> serialize echo output with normal tty writes.  This ensures the tty
> buffer helper tty_insert_flip_string is not called concurrently and
> everything is fine.
> 
> Note that this is nicely reproducible by an ordinary user using
> forkpty and some setup around that (raw termios + ECHO). And it is
> exploitable in kernels at least after commit
> d945cb9cce20ac7143c2de8d88b187f62db99bdc (pty: Rework the pty layer to
> use the normal buffering logic) in 2.6.31-rc3.
> 
> js: add more info to the commit log
> js: switch to bool
> 
> Reported-and-tested-by: Jiri Slaby <jslaby at suse.cz>
> Signed-off-by: Peter Hurley <peter at hurleysoftware.com>
> Signed-off-by: Jiri Slaby <jslaby at suse.cz>
> Cc: Alan Cox <alan at lxorguk.ukuu.org.uk>
> ---
> Hi security team,
> 
> this is a fix for a potentially exploitable hole in the TTY layer.
> linux-distros ML has been informed already (to the best of my
> knowledge).
> 
> We, at suse, would appreciate embargo till Mon May 5th.
> 
> Thanks.
> 
>  drivers/tty/n_tty.c | 10 ++++++++++
>  1 file changed, 10 insertions(+)
> 
> diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
> index 746ae80b972f..94101fc64e02 100644
> --- a/drivers/tty/n_tty.c
> +++ b/drivers/tty/n_tty.c
> @@ -2353,10 +2353,18 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
>  			if (tty->ops->flush_chars)
>  				tty->ops->flush_chars(tty);
>  		} else {
> +			struct n_tty_data *ldata = tty->disc_data;
> +			bool lock;
> +
> +			lock = L_ECHO(tty) || (ldata->icanon && L_ECHONL(tty));
> +			if (lock)
> +				mutex_lock(&ldata->output_lock);
>  			while (nr > 0) {
>  				c = tty->ops->write(tty, b, nr);
>  				if (c < 0) {
>  					retval = c;
> +					if (lock)
> +						mutex_unlock(&ldata->output_lock);
>  					goto break_out;
>  				}
>  				if (!c)
> @@ -2364,6 +2372,8 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
>  				b += c;
>  				nr -= c;
>  			}
> +			if (lock)
> +				mutex_unlock(&ldata->output_lock);
>  		}
>  		if (!nr)
>  			break;
> -- 1.9.2 

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.22 (GNU/Linux)

iF4EAREIAAYFAlNn2+kACgkQZ/Z80n6+J/Z+VwD+NEmrct67a5k4ezgMFHYGQFRe
OaBWcjPwO872ETeOVYQBAIPzEAYUXUz8142uw0xZmCfa43YjRHt8s5HMTBP8pFDe
=kxZq
-----END PGP SIGNATURE-----
-------------- next part --------------
A non-text attachment was scrubbed...
Name: n_tty-Fix-n_tty_write-crash-when-echoing-in-raw-mode.patch
Type: text/x-patch
Size: 3381 bytes
Desc: not available
URL: <http://mailman.archlinux.org/pipermail/arch-security/attachments/20140505/4584f379/attachment.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: n_tty-Fix-n_tty_write-crash-when-echoing-in-raw-mode.patch.sig
Type: application/pgp-signature
Size: 96 bytes
Desc: not available
URL: <http://mailman.archlinux.org/pipermail/arch-security/attachments/20140505/4584f379/attachment.sig>


More information about the arch-security mailing list