[kernel] r7177 - in dists/sid/linux-2.6.16/debian: . patches

Dann Frazier dannf at costa.debian.org
Thu Aug 17 03:27:11 UTC 2006


Author: dannf
Date: Thu Aug 17 03:27:10 2006
New Revision: 7177

Added:
   dists/sid/linux-2.6.16/debian/patches/usb-serial-ftdi_sio-dos.patch
Modified:
   dists/sid/linux-2.6.16/debian/changelog
   dists/sid/linux-2.6.16/debian/patches/series/18

Log:
* usb-serial-ftdi_sio-dos.patch: fix userspace DoS in ftdi_sio driver

Modified: dists/sid/linux-2.6.16/debian/changelog
==============================================================================
--- dists/sid/linux-2.6.16/debian/changelog	(original)
+++ dists/sid/linux-2.6.16/debian/changelog	Thu Aug 17 03:27:10 2006
@@ -8,14 +8,12 @@
   * fs-ext3-bad-nfs-handle.patch: avoid triggering ext3_error on bad NFS
     file handle (CVE-2006-3468)
   * cdrom-bad-cgc.buflen-assign.patch: fix buffer overflow in dvd_read_bca
-    which could potentially be used by a local user to trigger a buffer
-    overflow via a specially crafted DVD, USB stick, or similar automatically
-    mounted device (CVE-2006-2935)
+  * usb-serial-ftdi_sio-dos.patch: fix userspace DoS in ftdi_sio driver
 
   [ Bastian Blank ]
   * Update xen patch to changeset 9762.
 
- -- dann frazier <dannf at debian.org>  Wed, 16 Aug 2006 21:11:12 -0600
+ -- dann frazier <dannf at debian.org>  Wed, 16 Aug 2006 21:25:43 -0600
 
 linux-2.6.16 (2.6.16-17) unstable; urgency=high
 

Modified: dists/sid/linux-2.6.16/debian/patches/series/18
==============================================================================
--- dists/sid/linux-2.6.16/debian/patches/series/18	(original)
+++ dists/sid/linux-2.6.16/debian/patches/series/18	Thu Aug 17 03:27:10 2006
@@ -1,2 +1,3 @@
 + fs-ext3-bad-nfs-handle.patch
 + cdrom-bad-cgc.buflen-assign.patch
++ usb-serial-ftdi_sio-dos.patch

Added: dists/sid/linux-2.6.16/debian/patches/usb-serial-ftdi_sio-dos.patch
==============================================================================
--- (empty file)
+++ dists/sid/linux-2.6.16/debian/patches/usb-serial-ftdi_sio-dos.patch	Thu Aug 17 03:27:10 2006
@@ -0,0 +1,183 @@
+From: Ian Abbott <abbotti at mev.co.uk>
+Date: Mon, 26 Jun 2006 11:59:17 +0000 (+0100)
+Subject: USB serial ftdi_sio: Prevent userspace DoS (CVE-2006-2936)
+X-Git-Url: http://www.kernel.org/git/?p=linux/kernel/git/stable/linux-2.6.17.y.git;a=commitdiff;h=ba4532fa45b99a866d253877372f086503a944c6
+
+USB serial ftdi_sio: Prevent userspace DoS (CVE-2006-2936)
+
+This patch limits the amount of outstanding 'write' data that can be
+queued up for the ftdi_sio driver, to prevent userspace DoS attacks (or
+simple accidents) that use up all the system memory by writing lots of
+data to the serial port.
+
+The original patch was by Guillaume Autran, who in turn based it on the
+same mechanism implemented in the 'visor' driver.  I (Ian Abbott)
+re-targeted the patch to the latest sources, fixed a couple of errors,
+renamed his new structure members, and updated the implementations of
+the 'write_room' and 'chars_in_buffer' methods to take account of the
+number of outstanding 'write' bytes.  It seems to work fine, though at
+low baud rates it is still possible to queue up an amount of data that
+takes an age to shift (a job for another day!).
+
+Signed-off-by: Ian Abbott <abbotti at mev.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
+---
+
+--- a/drivers/usb/serial/ftdi_sio.c
++++ b/drivers/usb/serial/ftdi_sio.c
+@@ -553,6 +553,10 @@ struct ftdi_private {
+ 
+ 	int force_baud;		/* if non-zero, force the baud rate to this value */
+ 	int force_rtscts;	/* if non-zero, force RTS-CTS to always be enabled */
++
++	spinlock_t tx_lock;	/* spinlock for transmit state */
++	unsigned long tx_outstanding_bytes;
++	unsigned long tx_outstanding_urbs;
+ };
+ 
+ /* Used for TIOCMIWAIT */
+@@ -626,6 +630,9 @@ static struct usb_serial_driver ftdi_sio
+ #define HIGH 1
+ #define LOW 0
+ 
++/* number of outstanding urbs to prevent userspace DoS from happening */
++#define URB_UPPER_LIMIT	42
++
+ /*
+  * ***************************************************************************
+  * Utlity functions
+@@ -1156,6 +1163,7 @@ static int ftdi_sio_attach (struct usb_s
+ 	}
+ 
+ 	spin_lock_init(&priv->rx_lock);
++	spin_lock_init(&priv->tx_lock);
+         init_waitqueue_head(&priv->delta_msr_wait);
+ 	/* This will push the characters through immediately rather
+ 	   than queue a task to deliver them */
+@@ -1372,6 +1380,7 @@ static int ftdi_write (struct usb_serial
+ 	int data_offset ;       /* will be 1 for the SIO and 0 otherwise */
+ 	int status;
+ 	int transfer_size;
++	unsigned long flags;
+ 
+ 	dbg("%s port %d, %d bytes", __FUNCTION__, port->number, count);
+ 
+@@ -1379,6 +1388,13 @@ static int ftdi_write (struct usb_serial
+ 		dbg("write request of 0 bytes");
+ 		return 0;
+ 	}
++	spin_lock_irqsave(&priv->tx_lock, flags);
++	if (priv->tx_outstanding_urbs > URB_UPPER_LIMIT) {
++		spin_unlock_irqrestore(&priv->tx_lock, flags);
++		dbg("%s - write limit hit\n", __FUNCTION__);
++		return 0;
++	}
++	spin_unlock_irqrestore(&priv->tx_lock, flags);
+ 	
+ 	data_offset = priv->write_offset;
+         dbg("data_offset set to %d",data_offset);
+@@ -1445,6 +1461,11 @@ static int ftdi_write (struct usb_serial
+ 		err("%s - failed submitting write urb, error %d", __FUNCTION__, status);
+ 		count = status;
+ 		kfree (buffer);
++	} else {
++		spin_lock_irqsave(&priv->tx_lock, flags);
++		++priv->tx_outstanding_urbs;
++		priv->tx_outstanding_bytes += count;
++		spin_unlock_irqrestore(&priv->tx_lock, flags);
+ 	}
+ 
+ 	/* we are done with this urb, so let the host driver
+@@ -1460,7 +1481,11 @@ static int ftdi_write (struct usb_serial
+ 
+ static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
+ {
++	unsigned long flags;
+ 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
++	struct ftdi_private *priv;
++	int data_offset;       /* will be 1 for the SIO and 0 otherwise */
++	unsigned long countback;
+ 
+ 	/* free up the transfer buffer, as usb_free_urb() does not do this */
+ 	kfree (urb->transfer_buffer);
+@@ -1472,34 +1497,67 @@ static void ftdi_write_bulk_callback (st
+ 		return;
+ 	}
+ 
++	priv = usb_get_serial_port_data(port);
++	if (!priv) {
++		dbg("%s - bad port private data pointer - exiting", __FUNCTION__);
++		return;
++	}
++	/* account for transferred data */
++	countback = urb->actual_length;
++	data_offset = priv->write_offset;
++	if (data_offset > 0) {
++		/* Subtract the control bytes */
++		countback -= (data_offset * ((countback + (PKTSZ - 1)) / PKTSZ));
++	}
++	spin_lock_irqsave(&priv->tx_lock, flags);
++	--priv->tx_outstanding_urbs;
++	priv->tx_outstanding_bytes -= countback;
++	spin_unlock_irqrestore(&priv->tx_lock, flags);
++
+ 	schedule_work(&port->work);
+ } /* ftdi_write_bulk_callback */
+ 
+ 
+ static int ftdi_write_room( struct usb_serial_port *port )
+ {
++	struct ftdi_private *priv = usb_get_serial_port_data(port);
++	int room;
++	unsigned long flags;
++
+ 	dbg("%s - port %d", __FUNCTION__, port->number);
+ 
+-	/*
+-	 * We really can take anything the user throws at us
+-	 * but let's pick a nice big number to tell the tty
+-	 * layer that we have lots of free space
+-	 */
+-	return 2048;
++	spin_lock_irqsave(&priv->tx_lock, flags);
++	if (priv->tx_outstanding_urbs < URB_UPPER_LIMIT) {
++		/*
++		 * We really can take anything the user throws at us
++		 * but let's pick a nice big number to tell the tty
++		 * layer that we have lots of free space
++		 */
++		room = 2048;
++	} else {
++		room = 0;
++	}
++	spin_unlock_irqrestore(&priv->tx_lock, flags);
++	return room;
+ } /* ftdi_write_room */
+ 
+ 
+ static int ftdi_chars_in_buffer (struct usb_serial_port *port)
+ { /* ftdi_chars_in_buffer */
++	struct ftdi_private *priv = usb_get_serial_port_data(port);
++	int buffered;
++	unsigned long flags;
++
+ 	dbg("%s - port %d", __FUNCTION__, port->number);
+ 
+-	/* 
+-	 * We can't really account for how much data we
+-	 * have sent out, but hasn't made it through to the
+-	 * device, so just tell the tty layer that everything
+-	 * is flushed.
+-	 */
+-	return 0;
++	spin_lock_irqsave(&priv->tx_lock, flags);
++	buffered = (int)priv->tx_outstanding_bytes;
++	spin_unlock_irqrestore(&priv->tx_lock, flags);
++	if (buffered < 0) {
++		err("%s outstanding tx bytes is negative!", __FUNCTION__);
++		buffered = 0;
++	}
++	return buffered;
+ } /* ftdi_chars_in_buffer */
+ 
+ 



More information about the Kernel-svn-changes mailing list