aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Abbott <abbotti@mev.co.uk>2006-06-26 07:59:17 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-07-12 19:03:22 -0400
commit224654004ca688af67cec44d9300e8c3f647577c (patch)
tree79c9f18053299dd1ab09fbab71abcb653e8c99e9
parent00d6058ac93048b525b86fa48b413dcb87ac2728 (diff)
[PATCH] USB serial ftdi_sio: Prevent userspace DoS
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>
-rw-r--r--drivers/usb/serial/ftdi_sio.c103
1 files changed, 90 insertions, 13 deletions
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 9cf4069895c1..ff06c01a555b 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -550,11 +550,17 @@ struct ftdi_private {
550 spinlock_t rx_lock; /* spinlock for receive state */ 550 spinlock_t rx_lock; /* spinlock for receive state */
551 struct work_struct rx_work; 551 struct work_struct rx_work;
552 int rx_processed; 552 int rx_processed;
553 unsigned long rx_bytes;
553 554
554 __u16 interface; /* FT2232C port interface (0 for FT232/245) */ 555 __u16 interface; /* FT2232C port interface (0 for FT232/245) */
555 556
556 int force_baud; /* if non-zero, force the baud rate to this value */ 557 int force_baud; /* if non-zero, force the baud rate to this value */
557 int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */ 558 int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */
559
560 spinlock_t tx_lock; /* spinlock for transmit state */
561 unsigned long tx_bytes;
562 unsigned long tx_outstanding_bytes;
563 unsigned long tx_outstanding_urbs;
558}; 564};
559 565
560/* Used for TIOCMIWAIT */ 566/* Used for TIOCMIWAIT */
@@ -628,6 +634,9 @@ static struct usb_serial_driver ftdi_sio_device = {
628#define HIGH 1 634#define HIGH 1
629#define LOW 0 635#define LOW 0
630 636
637/* number of outstanding urbs to prevent userspace DoS from happening */
638#define URB_UPPER_LIMIT 42
639
631/* 640/*
632 * *************************************************************************** 641 * ***************************************************************************
633 * Utlity functions 642 * Utlity functions
@@ -1158,6 +1167,7 @@ static int ftdi_sio_attach (struct usb_serial *serial)
1158 } 1167 }
1159 1168
1160 spin_lock_init(&priv->rx_lock); 1169 spin_lock_init(&priv->rx_lock);
1170 spin_lock_init(&priv->tx_lock);
1161 init_waitqueue_head(&priv->delta_msr_wait); 1171 init_waitqueue_head(&priv->delta_msr_wait);
1162 /* This will push the characters through immediately rather 1172 /* This will push the characters through immediately rather
1163 than queue a task to deliver them */ 1173 than queue a task to deliver them */
@@ -1272,6 +1282,13 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp)
1272 1282
1273 dbg("%s", __FUNCTION__); 1283 dbg("%s", __FUNCTION__);
1274 1284
1285 spin_lock_irqsave(&priv->tx_lock, flags);
1286 priv->tx_bytes = 0;
1287 spin_unlock_irqrestore(&priv->tx_lock, flags);
1288 spin_lock_irqsave(&priv->rx_lock, flags);
1289 priv->rx_bytes = 0;
1290 spin_unlock_irqrestore(&priv->rx_lock, flags);
1291
1275 if (port->tty) 1292 if (port->tty)
1276 port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; 1293 port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
1277 1294
@@ -1374,6 +1391,7 @@ static int ftdi_write (struct usb_serial_port *port,
1374 int data_offset ; /* will be 1 for the SIO and 0 otherwise */ 1391 int data_offset ; /* will be 1 for the SIO and 0 otherwise */
1375 int status; 1392 int status;
1376 int transfer_size; 1393 int transfer_size;
1394 unsigned long flags;
1377 1395
1378 dbg("%s port %d, %d bytes", __FUNCTION__, port->number, count); 1396 dbg("%s port %d, %d bytes", __FUNCTION__, port->number, count);
1379 1397
@@ -1381,6 +1399,13 @@ static int ftdi_write (struct usb_serial_port *port,
1381 dbg("write request of 0 bytes"); 1399 dbg("write request of 0 bytes");
1382 return 0; 1400 return 0;
1383 } 1401 }
1402 spin_lock_irqsave(&priv->tx_lock, flags);
1403 if (priv->tx_outstanding_urbs > URB_UPPER_LIMIT) {
1404 spin_unlock_irqrestore(&priv->tx_lock, flags);
1405 dbg("%s - write limit hit\n", __FUNCTION__);
1406 return 0;
1407 }
1408 spin_unlock_irqrestore(&priv->tx_lock, flags);
1384 1409
1385 data_offset = priv->write_offset; 1410 data_offset = priv->write_offset;
1386 dbg("data_offset set to %d",data_offset); 1411 dbg("data_offset set to %d",data_offset);
@@ -1447,6 +1472,12 @@ static int ftdi_write (struct usb_serial_port *port,
1447 err("%s - failed submitting write urb, error %d", __FUNCTION__, status); 1472 err("%s - failed submitting write urb, error %d", __FUNCTION__, status);
1448 count = status; 1473 count = status;
1449 kfree (buffer); 1474 kfree (buffer);
1475 } else {
1476 spin_lock_irqsave(&priv->tx_lock, flags);
1477 ++priv->tx_outstanding_urbs;
1478 priv->tx_outstanding_bytes += count;
1479 priv->tx_bytes += count;
1480 spin_unlock_irqrestore(&priv->tx_lock, flags);
1450 } 1481 }
1451 1482
1452 /* we are done with this urb, so let the host driver 1483 /* we are done with this urb, so let the host driver
@@ -1462,7 +1493,11 @@ static int ftdi_write (struct usb_serial_port *port,
1462 1493
1463static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs) 1494static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
1464{ 1495{
1496 unsigned long flags;
1465 struct usb_serial_port *port = (struct usb_serial_port *)urb->context; 1497 struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
1498 struct ftdi_private *priv;
1499 int data_offset; /* will be 1 for the SIO and 0 otherwise */
1500 unsigned long countback;
1466 1501
1467 /* free up the transfer buffer, as usb_free_urb() does not do this */ 1502 /* free up the transfer buffer, as usb_free_urb() does not do this */
1468 kfree (urb->transfer_buffer); 1503 kfree (urb->transfer_buffer);
@@ -1474,34 +1509,67 @@ static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
1474 return; 1509 return;
1475 } 1510 }
1476 1511
1512 priv = usb_get_serial_port_data(port);
1513 if (!priv) {
1514 dbg("%s - bad port private data pointer - exiting", __FUNCTION__);
1515 return;
1516 }
1517 /* account for transferred data */
1518 countback = urb->actual_length;
1519 data_offset = priv->write_offset;
1520 if (data_offset > 0) {
1521 /* Subtract the control bytes */
1522 countback -= (data_offset * ((countback + (PKTSZ - 1)) / PKTSZ));
1523 }
1524 spin_lock_irqsave(&priv->tx_lock, flags);
1525 --priv->tx_outstanding_urbs;
1526 priv->tx_outstanding_bytes -= countback;
1527 spin_unlock_irqrestore(&priv->tx_lock, flags);
1528
1477 usb_serial_port_softint(port); 1529 usb_serial_port_softint(port);
1478} /* ftdi_write_bulk_callback */ 1530} /* ftdi_write_bulk_callback */
1479 1531
1480 1532
1481static int ftdi_write_room( struct usb_serial_port *port ) 1533static int ftdi_write_room( struct usb_serial_port *port )
1482{ 1534{
1535 struct ftdi_private *priv = usb_get_serial_port_data(port);
1536 int room;
1537 unsigned long flags;
1538
1483 dbg("%s - port %d", __FUNCTION__, port->number); 1539 dbg("%s - port %d", __FUNCTION__, port->number);
1484 1540
1485 /* 1541 spin_lock_irqsave(&priv->tx_lock, flags);
1486 * We really can take anything the user throws at us 1542 if (priv->tx_outstanding_urbs < URB_UPPER_LIMIT) {
1487 * but let's pick a nice big number to tell the tty 1543 /*
1488 * layer that we have lots of free space 1544 * We really can take anything the user throws at us
1489 */ 1545 * but let's pick a nice big number to tell the tty
1490 return 2048; 1546 * layer that we have lots of free space
1547 */
1548 room = 2048;
1549 } else {
1550 room = 0;
1551 }
1552 spin_unlock_irqrestore(&priv->tx_lock, flags);
1553 return room;
1491} /* ftdi_write_room */ 1554} /* ftdi_write_room */
1492 1555
1493 1556
1494static int ftdi_chars_in_buffer (struct usb_serial_port *port) 1557static int ftdi_chars_in_buffer (struct usb_serial_port *port)
1495{ /* ftdi_chars_in_buffer */ 1558{ /* ftdi_chars_in_buffer */
1559 struct ftdi_private *priv = usb_get_serial_port_data(port);
1560 int buffered;
1561 unsigned long flags;
1562
1496 dbg("%s - port %d", __FUNCTION__, port->number); 1563 dbg("%s - port %d", __FUNCTION__, port->number);
1497 1564
1498 /* 1565 spin_lock_irqsave(&priv->tx_lock, flags);
1499 * We can't really account for how much data we 1566 buffered = (int)priv->tx_outstanding_bytes;
1500 * have sent out, but hasn't made it through to the 1567 spin_unlock_irqrestore(&priv->tx_lock, flags);
1501 * device, so just tell the tty layer that everything 1568 if (buffered < 0) {
1502 * is flushed. 1569 err("%s outstanding tx bytes is negative!", __FUNCTION__);
1503 */ 1570 buffered = 0;
1504 return 0; 1571 }
1572 return buffered;
1505} /* ftdi_chars_in_buffer */ 1573} /* ftdi_chars_in_buffer */
1506 1574
1507 1575
@@ -1511,6 +1579,8 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
1511 struct usb_serial_port *port = (struct usb_serial_port *)urb->context; 1579 struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
1512 struct tty_struct *tty; 1580 struct tty_struct *tty;
1513 struct ftdi_private *priv; 1581 struct ftdi_private *priv;
1582 unsigned long countread;
1583 unsigned long flags;
1514 1584
1515 if (urb->number_of_packets > 0) { 1585 if (urb->number_of_packets > 0) {
1516 err("%s transfer_buffer_length %d actual_length %d number of packets %d",__FUNCTION__, 1586 err("%s transfer_buffer_length %d actual_length %d number of packets %d",__FUNCTION__,
@@ -1545,6 +1615,13 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
1545 return; 1615 return;
1546 } 1616 }
1547 1617
1618 /* count data bytes, but not status bytes */
1619 countread = urb->actual_length;
1620 countread -= 2 * ((countread + (PKTSZ - 1)) / PKTSZ);
1621 spin_lock_irqsave(&priv->rx_lock, flags);
1622 priv->rx_bytes += countread;
1623 spin_unlock_irqrestore(&priv->rx_lock, flags);
1624
1548 ftdi_process_read(port); 1625 ftdi_process_read(port);
1549 1626
1550} /* ftdi_read_bulk_callback */ 1627} /* ftdi_read_bulk_callback */