[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