USB: ftdi_sio: fix DMA buffers on stack
authorJohan Hovold <jhovold@gmail.com>
Thu, 24 Dec 2009 11:42:09 +0000 (12:42 +0100)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 2 Mar 2010 22:53:37 +0000 (14:53 -0800)
Also remove unnecessary buffer allocations for zero-length transfers.

Reported-by: Matti Aarnio <matti.aarnio@zmailer.org>
Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/serial/ftdi_sio.c

index 59b6cbf..a6e5a0d 100644 (file)
@@ -935,7 +935,6 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set,
                                                        unsigned int clear)
 {
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       char *buf;
        unsigned urb_value;
        int rv;
 
@@ -944,10 +943,6 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set,
                return 0;       /* no change */
        }
 
-       buf = kmalloc(1, GFP_NOIO);
-       if (!buf)
-               return -ENOMEM;
-
        clear &= ~set;  /* 'set' takes precedence over 'clear' */
        urb_value = 0;
        if (clear & TIOCM_DTR)
@@ -963,9 +958,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set,
                               FTDI_SIO_SET_MODEM_CTRL_REQUEST,
                               FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
                               urb_value, priv->interface,
-                              buf, 0, WDR_TIMEOUT);
-
-       kfree(buf);
+                              NULL, 0, WDR_TIMEOUT);
        if (rv < 0) {
                dbg("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
                                __func__,
@@ -1124,16 +1117,11 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty,
 static int change_speed(struct tty_struct *tty, struct usb_serial_port *port)
 {
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       char *buf;
        __u16 urb_value;
        __u16 urb_index;
        __u32 urb_index_value;
        int rv;
 
-       buf = kmalloc(1, GFP_NOIO);
-       if (!buf)
-               return -ENOMEM;
-
        urb_index_value = get_ftdi_divisor(tty, port);
        urb_value = (__u16)urb_index_value;
        urb_index = (__u16)(urb_index_value >> 16);
@@ -1146,9 +1134,7 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port)
                            FTDI_SIO_SET_BAUDRATE_REQUEST,
                            FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
                            urb_value, urb_index,
-                           buf, 0, WDR_SHORT_TIMEOUT);
-
-       kfree(buf);
+                           NULL, 0, WDR_SHORT_TIMEOUT);
        return rv;
 }
 
@@ -1156,7 +1142,6 @@ static int write_latency_timer(struct usb_serial_port *port)
 {
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        struct usb_device *udev = port->serial->dev;
-       char buf[1];
        int rv = 0;
        int l = priv->latency;
 
@@ -1170,8 +1155,7 @@ static int write_latency_timer(struct usb_serial_port *port)
                             FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
                             FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
                             l, priv->interface,
-                            buf, 0, WDR_TIMEOUT);
-
+                            NULL, 0, WDR_TIMEOUT);
        if (rv < 0)
                dev_err(&port->dev, "Unable to write latency timer: %i\n", rv);
        return rv;
@@ -1445,7 +1429,6 @@ static ssize_t store_event_char(struct device *dev,
        struct usb_serial_port *port = to_usb_serial_port(dev);
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        struct usb_device *udev = port->serial->dev;
-       char buf[1];
        int v = simple_strtoul(valbuf, NULL, 10);
        int rv = 0;
 
@@ -1456,8 +1439,7 @@ static ssize_t store_event_char(struct device *dev,
                             FTDI_SIO_SET_EVENT_CHAR_REQUEST,
                             FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE,
                             v, priv->interface,
-                            buf, 0, WDR_TIMEOUT);
-
+                            NULL, 0, WDR_TIMEOUT);
        if (rv < 0) {
                dbg("Unable to write event character: %i", rv);
                return -EIO;
@@ -1636,7 +1618,6 @@ static int ftdi_NDI_device_setup(struct usb_serial *serial)
        struct usb_device *udev = serial->dev;
        int latency = ndi_latency_timer;
        int rv = 0;
-       char buf[1];
 
        if (latency == 0)
                latency = 1;
@@ -1649,7 +1630,7 @@ static int ftdi_NDI_device_setup(struct usb_serial *serial)
        rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
                                FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
                                FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
-                               latency, 0, buf, 0, WDR_TIMEOUT);
+                               latency, 0, NULL, 0, WDR_TIMEOUT);
        return 0;
 }
 
@@ -1737,9 +1718,7 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
        struct usb_device *dev = port->serial->dev;
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
-
        int result = 0;
-       char buf[1]; /* Needed for the usb_control_msg I think */
 
        dbg("%s", __func__);
 
@@ -1754,7 +1733,7 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
        usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
                        FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
                        FTDI_SIO_RESET_SIO,
-                       priv->interface, buf, 0, WDR_TIMEOUT);
+                       priv->interface, NULL, 0, WDR_TIMEOUT);
 
        /* Termios defaults are set by usb_serial_init. We don't change
           port->tty->termios - this would lose speed settings, etc.
@@ -1782,7 +1761,6 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
 static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
 {
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       char buf[1];
 
        mutex_lock(&port->serial->disc_mutex);
        if (!port->serial->disconnected) {
@@ -1791,7 +1769,7 @@ static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
                            usb_sndctrlpipe(port->serial->dev, 0),
                            FTDI_SIO_SET_FLOW_CTRL_REQUEST,
                            FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
-                           0, priv->interface, buf, 0,
+                           0, priv->interface, NULL, 0,
                            WDR_TIMEOUT) < 0) {
                            dev_err(&port->dev, "error from flowcontrol urb\n");
                }
@@ -2160,7 +2138,6 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state)
        struct usb_serial_port *port = tty->driver_data;
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        __u16 urb_value = 0;
-       char buf[1];
 
        /* break_state = -1 to turn on break, and 0 to turn off break */
        /* see drivers/char/tty_io.c to see it used */
@@ -2176,7 +2153,7 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state)
                        FTDI_SIO_SET_DATA_REQUEST,
                        FTDI_SIO_SET_DATA_REQUEST_TYPE,
                        urb_value , priv->interface,
-                       buf, 0, WDR_TIMEOUT) < 0) {
+                       NULL, 0, WDR_TIMEOUT) < 0) {
                dev_err(&port->dev, "%s FAILED to enable/disable break state "
                        "(state was %d)\n", __func__, break_state);
        }
@@ -2200,7 +2177,6 @@ static void ftdi_set_termios(struct tty_struct *tty,
        struct ktermios *termios = tty->termios;
        unsigned int cflag = termios->c_cflag;
        __u16 urb_value; /* will hold the new flags */
-       char buf[1]; /* Perhaps I should dynamically alloc this? */
 
        /* Added for xon/xoff support */
        unsigned int iflag = termios->c_iflag;
@@ -2266,7 +2242,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
                            FTDI_SIO_SET_DATA_REQUEST,
                            FTDI_SIO_SET_DATA_REQUEST_TYPE,
                            urb_value , priv->interface,
-                           buf, 0, WDR_SHORT_TIMEOUT) < 0) {
+                           NULL, 0, WDR_SHORT_TIMEOUT) < 0) {
                dev_err(&port->dev, "%s FAILED to set "
                        "databits/stopbits/parity\n", __func__);
        }
@@ -2278,7 +2254,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST,
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
                                    0, priv->interface,
-                                   buf, 0, WDR_TIMEOUT) < 0) {
+                                   NULL, 0, WDR_TIMEOUT) < 0) {
                        dev_err(&port->dev,
                                "%s error from disable flowcontrol urb\n",
                                __func__);
@@ -2304,7 +2280,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST,
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
                                    0 , (FTDI_SIO_RTS_CTS_HS | priv->interface),
-                                   buf, 0, WDR_TIMEOUT) < 0) {
+                                   NULL, 0, WDR_TIMEOUT) < 0) {
                        dev_err(&port->dev,
                                "urb failed to set to rts/cts flow control\n");
                }
@@ -2336,7 +2312,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
                                            FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
                                            urb_value , (FTDI_SIO_XON_XOFF_HS
                                                         | priv->interface),
-                                           buf, 0, WDR_TIMEOUT) < 0) {
+                                           NULL, 0, WDR_TIMEOUT) < 0) {
                                dev_err(&port->dev, "urb failed to set to "
                                        "xon/xoff flow control\n");
                        }
@@ -2350,7 +2326,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
                                            FTDI_SIO_SET_FLOW_CTRL_REQUEST,
                                            FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
                                            0, priv->interface,
-                                           buf, 0, WDR_TIMEOUT) < 0) {
+                                           NULL, 0, WDR_TIMEOUT) < 0) {
                                dev_err(&port->dev,
                                        "urb failed to clear flow control\n");
                        }
@@ -2364,10 +2340,15 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
 {
        struct usb_serial_port *port = tty->driver_data;
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       unsigned char buf[2];
+       unsigned char *buf;
        int ret;
 
        dbg("%s TIOCMGET", __func__);
+
+       buf = kmalloc(2, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
        switch (priv->chip_type) {
        case SIO:
                /* Request the status from the device */
@@ -2378,7 +2359,7 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
                           0, 0,
                           buf, 1, WDR_TIMEOUT);
                if (ret < 0)
-                       return ret;
+                       goto out;
                break;
        case FT8U232AM:
        case FT232BM:
@@ -2396,17 +2377,21 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
                                   0, priv->interface,
                                   buf, 2, WDR_TIMEOUT);
                if (ret < 0)
-                       return ret;
+                       goto out;
                break;
        default:
-               return -EFAULT;
+               ret = -EFAULT;
+               goto out;
        }
 
-       return  (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
+       ret = (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
                (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) |
                (buf[0]  & FTDI_SIO_RI_MASK  ? TIOCM_RI  : 0) |
                (buf[0]  & FTDI_SIO_RLSD_MASK ? TIOCM_CD  : 0) |
                priv->last_dtr_rts;
+out:
+       kfree(buf);
+       return ret;
 }
 
 static int ftdi_tiocmset(struct tty_struct *tty, struct file *file,