[kernel] r16435 - in dists/sid/linux-2.6/debian: . patches/bugfix/all patches/series

Dann Frazier dannf at alioth.debian.org
Thu Oct 14 05:43:12 UTC 2010


Author: dannf
Date: Thu Oct 14 05:43:04 2010
New Revision: 16435

Log:
hvc_console: Fix race between hvc_close and hvc_remove (CVE-2010-2653)

Added:
   dists/sid/linux-2.6/debian/patches/bugfix/all/hvc_console-fix-race-between-hvc_close-and-hvc_remove-2.patch
   dists/sid/linux-2.6/debian/patches/bugfix/all/hvc_console-fix-race-between-hvc_close-and-hvc_remove.patch
Modified:
   dists/sid/linux-2.6/debian/changelog
   dists/sid/linux-2.6/debian/patches/series/25

Modified: dists/sid/linux-2.6/debian/changelog
==============================================================================
--- dists/sid/linux-2.6/debian/changelog	Thu Oct 14 04:53:39 2010	(r16434)
+++ dists/sid/linux-2.6/debian/changelog	Thu Oct 14 05:43:04 2010	(r16435)
@@ -33,8 +33,9 @@
   * drm/i915: Sanity check pread/pwrite (CVE-2010-2962)
   * drm/i915: Rephrase pwrite bounds checking to avoid any potential overflow
   * GFS2: Fix writing to non-page aligned gfs2_quota structures (CVE-2010-1436)
+  * hvc_console: Fix race between hvc_close and hvc_remove (CVE-2010-2653)
 
- -- Ben Hutchings <ben at decadent.org.uk>  Thu, 30 Sep 2010 12:28:58 +0100
+ -- dann frazier <dannf at debian.org>  Wed, 13 Oct 2010 22:55:30 -0600
 
 linux-2.6 (2.6.32-24) unstable; urgency=high
 

Added: dists/sid/linux-2.6/debian/patches/bugfix/all/hvc_console-fix-race-between-hvc_close-and-hvc_remove-2.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/bugfix/all/hvc_console-fix-race-between-hvc_close-and-hvc_remove-2.patch	Thu Oct 14 05:43:04 2010	(r16435)
@@ -0,0 +1,66 @@
+commit 320718ee074acce5ffced6506cb51af1388942aa
+Author: Anton Blanchard <anton at samba.org>
+Date:   Tue Apr 6 21:42:38 2010 +1000
+
+    hvc_console: Fix race between hvc_close and hvc_remove
+    
+    I don't claim to understand the tty layer, but it seems like hvc_open and
+    hvc_close should be balanced in their kref reference counting.
+    
+    Right now we get a kref every call to hvc_open:
+    
+            if (hp->count++ > 0) {
+                    tty_kref_get(tty); <----- here
+                    spin_unlock_irqrestore(&hp->lock, flags);
+                    hvc_kick();
+                    return 0;
+            } /* else count == 0 */
+    
+            tty->driver_data = hp;
+    
+            hp->tty = tty_kref_get(tty); <------ or here if hp->count was 0
+    
+    But hvc_close has:
+    
+            tty_kref_get(tty);
+    
+            if (--hp->count == 0) {
+    ...
+                    /* Put the ref obtained in hvc_open() */
+                    tty_kref_put(tty);
+    ...
+            }
+    
+            tty_kref_put(tty);
+    
+    Since the outside kref get/put balance we only do a single kref_put when
+    count reaches 0.
+    
+    The patch below changes things to call tty_kref_put once for every
+    hvc_close call, and with that my machine boots fine.
+    
+    Signed-off-by: Anton Blanchard <anton at samba.org>
+    Acked-by: Amit Shah <amit.shah at redhat.com>
+    Signed-off-by: Rusty Russell <rusty at rustcorp.com.au>
+
+diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
+index d3890e8..35cca4c 100644
+--- a/drivers/char/hvc_console.c
++++ b/drivers/char/hvc_console.c
+@@ -368,16 +368,12 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
+ 	hp = tty->driver_data;
+ 
+ 	spin_lock_irqsave(&hp->lock, flags);
+-	tty_kref_get(tty);
+ 
+ 	if (--hp->count == 0) {
+ 		/* We are done with the tty pointer now. */
+ 		hp->tty = NULL;
+ 		spin_unlock_irqrestore(&hp->lock, flags);
+ 
+-		/* Put the ref obtained in hvc_open() */
+-		tty_kref_put(tty);
+-
+ 		if (hp->ops->notifier_del)
+ 			hp->ops->notifier_del(hp, hp->data);
+ 

Added: dists/sid/linux-2.6/debian/patches/bugfix/all/hvc_console-fix-race-between-hvc_close-and-hvc_remove.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/bugfix/all/hvc_console-fix-race-between-hvc_close-and-hvc_remove.patch	Thu Oct 14 05:43:04 2010	(r16435)
@@ -0,0 +1,165 @@
+commit e74d098c66543d0731de62eb747ccd5b636a6f4c
+Author: Amit Shah <amit.shah at redhat.com>
+Date:   Fri Mar 12 11:53:15 2010 +0530
+
+    hvc_console: Fix race between hvc_close and hvc_remove
+    
+    Alan pointed out a race in the code where hvc_remove is invoked. The
+    recent virtio_console work is the first user of hvc_remove().
+    
+    Alan describes it thus:
+    
+    The hvc_console assumes that a close and remove call can't occur at the
+    same time.
+    
+    In addition tty_hangup(tty) is problematic as tty_hangup is asynchronous
+    itself....
+    
+    So this can happen
+    
+            hvc_close                               hvc_remove
+            hung up ? - no
+                                                    lock
+                                                    tty = hp->tty
+                                                    unlock
+            lock
+            hp->tty = NULL
+            unlock
+            notify del
+            kref_put the hvc struct
+            close completes
+            tty is destroyed
+                                                    tty_hangup dead tty
+                                                    tty->ops will be NULL
+                                                    NULL->...
+    
+    This patch adds some tty krefs and also converts to using tty_vhangup().
+    
+    Reported-by: Alan Cox <alan at lxorguk.ukuu.org.uk>
+    Signed-off-by: Amit Shah <amit.shah at redhat.com>
+    CC: Alan Cox <alan at lxorguk.ukuu.org.uk>
+    CC: linuxppc-dev at ozlabs.org
+    CC: Rusty Russell <rusty at rustcorp.com.au>
+    Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+
+diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
+index 465185f..ba55bba 100644
+--- a/drivers/char/hvc_console.c
++++ b/drivers/char/hvc_console.c
+@@ -312,6 +312,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
+ 	spin_lock_irqsave(&hp->lock, flags);
+ 	/* Check and then increment for fast path open. */
+ 	if (hp->count++ > 0) {
++		tty_kref_get(tty);
+ 		spin_unlock_irqrestore(&hp->lock, flags);
+ 		hvc_kick();
+ 		return 0;
+@@ -319,7 +320,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
+ 
+ 	tty->driver_data = hp;
+ 
+-	hp->tty = tty;
++	hp->tty = tty_kref_get(tty);
+ 
+ 	spin_unlock_irqrestore(&hp->lock, flags);
+ 
+@@ -336,6 +337,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
+ 		spin_lock_irqsave(&hp->lock, flags);
+ 		hp->tty = NULL;
+ 		spin_unlock_irqrestore(&hp->lock, flags);
++		tty_kref_put(tty);
+ 		tty->driver_data = NULL;
+ 		kref_put(&hp->kref, destroy_hvc_struct);
+ 		printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
+@@ -363,13 +365,18 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
+ 		return;
+ 
+ 	hp = tty->driver_data;
++
+ 	spin_lock_irqsave(&hp->lock, flags);
++	tty_kref_get(tty);
+ 
+ 	if (--hp->count == 0) {
+ 		/* We are done with the tty pointer now. */
+ 		hp->tty = NULL;
+ 		spin_unlock_irqrestore(&hp->lock, flags);
+ 
++		/* Put the ref obtained in hvc_open() */
++		tty_kref_put(tty);
++
+ 		if (hp->ops->notifier_del)
+ 			hp->ops->notifier_del(hp, hp->data);
+ 
+@@ -389,6 +396,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
+ 		spin_unlock_irqrestore(&hp->lock, flags);
+ 	}
+ 
++	tty_kref_put(tty);
+ 	kref_put(&hp->kref, destroy_hvc_struct);
+ }
+ 
+@@ -424,10 +432,11 @@ static void hvc_hangup(struct tty_struct *tty)
+ 	spin_unlock_irqrestore(&hp->lock, flags);
+ 
+ 	if (hp->ops->notifier_hangup)
+-			hp->ops->notifier_hangup(hp, hp->data);
++		hp->ops->notifier_hangup(hp, hp->data);
+ 
+ 	while(temp_open_count) {
+ 		--temp_open_count;
++		tty_kref_put(tty);
+ 		kref_put(&hp->kref, destroy_hvc_struct);
+ 	}
+ }
+@@ -592,7 +601,7 @@ int hvc_poll(struct hvc_struct *hp)
+ 	}
+ 
+ 	/* No tty attached, just skip */
+-	tty = hp->tty;
++	tty = tty_kref_get(hp->tty);
+ 	if (tty == NULL)
+ 		goto bail;
+ 
+@@ -672,6 +681,8 @@ int hvc_poll(struct hvc_struct *hp)
+ 
+ 		tty_flip_buffer_push(tty);
+ 	}
++	if (tty)
++		tty_kref_put(tty);
+ 
+ 	return poll_mask;
+ }
+@@ -807,7 +818,7 @@ int hvc_remove(struct hvc_struct *hp)
+ 	struct tty_struct *tty;
+ 
+ 	spin_lock_irqsave(&hp->lock, flags);
+-	tty = hp->tty;
++	tty = tty_kref_get(hp->tty);
+ 
+ 	if (hp->index < MAX_NR_HVC_CONSOLES)
+ 		vtermnos[hp->index] = -1;
+@@ -819,18 +830,18 @@ int hvc_remove(struct hvc_struct *hp)
+ 	/*
+ 	 * We 'put' the instance that was grabbed when the kref instance
+ 	 * was initialized using kref_init().  Let the last holder of this
+-	 * kref cause it to be removed, which will probably be the tty_hangup
++	 * kref cause it to be removed, which will probably be the tty_vhangup
+ 	 * below.
+ 	 */
+ 	kref_put(&hp->kref, destroy_hvc_struct);
+ 
+ 	/*
+-	 * This function call will auto chain call hvc_hangup.  The tty should
+-	 * always be valid at this time unless a simultaneous tty close already
+-	 * cleaned up the hvc_struct.
++	 * This function call will auto chain call hvc_hangup.
+ 	 */
+-	if (tty)
+-		tty_hangup(tty);
++	if (tty) {
++		tty_vhangup(tty);
++		tty_kref_put(tty);
++	}
+ 	return 0;
+ }
+ EXPORT_SYMBOL_GPL(hvc_remove);

Modified: dists/sid/linux-2.6/debian/patches/series/25
==============================================================================
--- dists/sid/linux-2.6/debian/patches/series/25	Thu Oct 14 04:53:39 2010	(r16434)
+++ dists/sid/linux-2.6/debian/patches/series/25	Thu Oct 14 05:43:04 2010	(r16435)
@@ -21,3 +21,5 @@
 + bugfix/all/gfs2-clean-up-gfs_adjust_quota-and_do_glock.patch
 + bugfix/all/gfs2-fix-writing-to-non-page-aligned-gfs2_quota-structures.patch
 + bugfix/all/gfs2-BUG-in-gfs2_adjust_quota.patch
++ bugfix/all/hvc_console-fix-race-between-hvc_close-and-hvc_remove.patch
++ bugfix/all/hvc_console-fix-race-between-hvc_close-and-hvc_remove-2.patch



More information about the Kernel-svn-changes mailing list