* usb-serial-ftdi_sio-dos.patch: fix userspace DoS in ftdi_sio driver
svn path=/dists/sid/linux-2.6.16/; revision=7177
This commit is contained in:
parent
b42e895c12
commit
547a695c98
|
@ -8,14 +8,12 @@ linux-2.6.16 (2.6.16-18) UNRELEASED; urgency=low
|
|||
* 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@debian.org> Wed, 16 Aug 2006 21:11:12 -0600
|
||||
-- dann frazier <dannf@debian.org> Wed, 16 Aug 2006 21:25:43 -0600
|
||||
|
||||
linux-2.6.16 (2.6.16-17) unstable; urgency=high
|
||||
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
+ fs-ext3-bad-nfs-handle.patch
|
||||
+ cdrom-bad-cgc.buflen-assign.patch
|
||||
+ usb-serial-ftdi_sio-dos.patch
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
From: Ian Abbott <abbotti@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@mev.co.uk>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@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 */
|
||||
|
||||
|
Loading…
Reference in New Issue