* [PATCH v3 0/4] cdc-acm: reassemble fragmented notifications
[not found] <1479118868.21146.4.camel@suse.com>
@ 2017-03-30 20:15 ` Tobias Herzog
2017-03-30 20:15 ` [PATCH v3 1/4] cdc-acm: fix possible invalid access when processing notification Tobias Herzog
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: Tobias Herzog @ 2017-03-30 20:15 UTC (permalink / raw)
To: oneukum; +Cc: gregkh, linux-usb, linux-kernel, stable
USB devices may have very limitited endpoint packet sizes, so that
notifications can not be transferred within one single usb packet.
This patchset adds the ability to reassemble notifications that are
transmitted fragmented.
v3:
* reordering patches (security issues first)
* fixed possible alignment bug
* allocate buffer with size=2^x
* additional code comments + fixed typos in commit messages
v2:
* reuse an allocated buffer for further notifications
* fixed issues with endianess
* check buffer allocation (kmalloc)
* don't use hard coded size of notification-header
* fixed typo + code structure (unneeded goto)
Tobias Herzog (4):
cdc-acm: fix possible invalid access when processing notification
cdc-acm: reassemble fragmented notifications
cdc-acm: log message for serial state notification
cdc-acm: remove unused element of struct acm
drivers/usb/class/cdc-acm.c | 127 ++++++++++++++++++++++++++++++++------------
drivers/usb/class/cdc-acm.h | 4 +-
2 files changed, 97 insertions(+), 34 deletions(-)
--
2.1.4
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 1/4] cdc-acm: fix possible invalid access when processing notification
2017-03-30 20:15 ` [PATCH v3 0/4] cdc-acm: reassemble fragmented notifications Tobias Herzog
@ 2017-03-30 20:15 ` Tobias Herzog
2017-03-31 9:31 ` Oliver Neukum
2017-03-30 20:15 ` [PATCH v3 2/4] cdc-acm: reassemble fragmented notifications Tobias Herzog
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Tobias Herzog @ 2017-03-30 20:15 UTC (permalink / raw)
To: oneukum; +Cc: gregkh, linux-usb, linux-kernel, stable
Notifications may only be 8 bytes long. Accessing the 9th and
10th byte of unimplemented/unknown notifications may be insecure.
Also check the length of known notifications before accessing anything
behind the 8th byte.
Signed-off-by: Tobias Herzog <t-herzog@gmx.de>
---
drivers/usb/class/cdc-acm.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index e35b150..f554e2f 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -322,6 +322,12 @@ static void acm_ctrl_irq(struct urb *urb)
break;
case USB_CDC_NOTIFY_SERIAL_STATE:
+ if (le16_to_cpu(dr->wLength) != 2) {
+ dev_dbg(&acm->control->dev,
+ "%s - malformed serial state\n", __func__);
+ break;
+ }
+
newctrl = get_unaligned_le16(data);
if (!acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
@@ -358,11 +364,10 @@ static void acm_ctrl_irq(struct urb *urb)
default:
dev_dbg(&acm->control->dev,
- "%s - unknown notification %d received: index %d "
- "len %d data0 %d data1 %d\n",
+ "%s - unknown notification %d received: index %d len %d\n",
__func__,
- dr->bNotificationType, dr->wIndex,
- dr->wLength, data[0], data[1]);
+ dr->bNotificationType, dr->wIndex, dr->wLength);
+
break;
}
exit:
--
2.1.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 2/4] cdc-acm: reassemble fragmented notifications
2017-03-30 20:15 ` [PATCH v3 0/4] cdc-acm: reassemble fragmented notifications Tobias Herzog
2017-03-30 20:15 ` [PATCH v3 1/4] cdc-acm: fix possible invalid access when processing notification Tobias Herzog
@ 2017-03-30 20:15 ` Tobias Herzog
2017-03-31 9:33 ` Oliver Neukum
2017-03-30 20:15 ` [PATCH v3 3/4] cdc-acm: log message for serial state notification Tobias Herzog
2017-03-30 20:15 ` [PATCH v3 4/4] cdc-acm: remove unused element of struct acm Tobias Herzog
3 siblings, 1 reply; 9+ messages in thread
From: Tobias Herzog @ 2017-03-30 20:15 UTC (permalink / raw)
To: oneukum; +Cc: gregkh, linux-usb, linux-kernel, stable
USB devices may have very limited endpoint packet sizes, so that
notifications can not be transferred within one single usb packet.
Reassembling of multiple packages may be necessary.
Signed-off-by: Tobias Herzog <t-herzog@gmx.de>
---
drivers/usb/class/cdc-acm.c | 112 ++++++++++++++++++++++++++++++++------------
drivers/usb/class/cdc-acm.h | 3 ++
2 files changed, 86 insertions(+), 29 deletions(-)
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index f554e2f..58efa15 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -35,6 +35,7 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/log2.h>
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/tty_driver.h>
@@ -282,39 +283,13 @@ static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL);
* Interrupt handlers for various ACM device responses
*/
-/* control interface reports status changes with "interrupt" transfers */
-static void acm_ctrl_irq(struct urb *urb)
+static void acm_process_notification(struct acm *acm, unsigned char *buf)
{
- struct acm *acm = urb->context;
- struct usb_cdc_notification *dr = urb->transfer_buffer;
- unsigned char *data;
int newctrl;
int difference;
- int retval;
- int status = urb->status;
-
- switch (status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dev_dbg(&acm->control->dev,
- "%s - urb shutting down with status: %d\n",
- __func__, status);
- return;
- default:
- dev_dbg(&acm->control->dev,
- "%s - nonzero urb status received: %d\n",
- __func__, status);
- goto exit;
- }
+ struct usb_cdc_notification *dr = (struct usb_cdc_notification *)buf;
+ unsigned char *data = buf + sizeof(struct usb_cdc_notification);
- usb_mark_last_busy(acm->dev);
-
- data = (unsigned char *)(dr + 1);
switch (dr->bNotificationType) {
case USB_CDC_NOTIFY_NETWORK_CONNECTION:
dev_dbg(&acm->control->dev,
@@ -367,9 +342,83 @@ static void acm_ctrl_irq(struct urb *urb)
"%s - unknown notification %d received: index %d len %d\n",
__func__,
dr->bNotificationType, dr->wIndex, dr->wLength);
+ }
+}
+/* control interface reports status changes with "interrupt" transfers */
+static void acm_ctrl_irq(struct urb *urb)
+{
+ struct acm *acm = urb->context;
+ struct usb_cdc_notification *dr = urb->transfer_buffer;
+ unsigned int current_size = urb->actual_length;
+ unsigned int expected_size, copy_size, alloc_size;
+ int retval;
+ int status = urb->status;
+
+ switch (status) {
+ case 0:
+ /* success */
break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ acm->nb_index = 0;
+ dev_dbg(&acm->control->dev,
+ "%s - urb shutting down with status: %d\n",
+ __func__, status);
+ return;
+ default:
+ dev_dbg(&acm->control->dev,
+ "%s - nonzero urb status received: %d\n",
+ __func__, status);
+ goto exit;
+ }
+
+ usb_mark_last_busy(acm->dev);
+
+ if (acm->nb_index)
+ dr = (struct usb_cdc_notification *)acm->notification_buffer;
+
+ /* size = notification-header + (optional) data */
+ expected_size = sizeof(struct usb_cdc_notification) +
+ le16_to_cpu(dr->wLength);
+
+ if (current_size < expected_size) {
+ /* notification is transmitted fragmented, reassemble */
+ if (acm->nb_size < expected_size) {
+ if (acm->nb_size) {
+ kfree(acm->notification_buffer);
+ acm->nb_size = 0;
+ }
+ alloc_size = roundup_pow_of_two(expected_size);
+ /*
+ * kmalloc ensures a valid notification_buffer after a
+ * use of kfree in case the previous allocation was too
+ * small. Final freeing is done on disconnect.
+ */
+ acm->notification_buffer =
+ kmalloc(alloc_size, GFP_ATOMIC);
+ if (!acm->notification_buffer)
+ goto exit;
+ acm->nb_size = alloc_size;
+ }
+
+ copy_size = min(current_size,
+ expected_size - acm->nb_index);
+
+ memcpy(&acm->notification_buffer[acm->nb_index],
+ urb->transfer_buffer, copy_size);
+ acm->nb_index += copy_size;
+ current_size = acm->nb_index;
}
+
+ if (current_size >= expected_size) {
+ /* notification complete */
+ acm_process_notification(acm, (unsigned char *)dr);
+ acm->nb_index = 0;
+ }
+
exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval && retval != -EPERM)
@@ -1493,6 +1542,9 @@ static int acm_probe(struct usb_interface *intf,
epctrl->bInterval ? epctrl->bInterval : 16);
acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
acm->ctrlurb->transfer_dma = acm->ctrl_dma;
+ acm->notification_buffer = NULL;
+ acm->nb_index = 0;
+ acm->nb_size = 0;
dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
@@ -1585,6 +1637,8 @@ static void acm_disconnect(struct usb_interface *intf)
usb_free_coherent(acm->dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
acm_read_buffers_free(acm);
+ kfree(acm->notification_buffer);
+
if (!acm->combined_interfaces)
usb_driver_release_interface(&acm_driver, intf == acm->control ?
acm->data : acm->control);
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
index c980f11..b519138 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -98,6 +98,9 @@ struct acm {
struct acm_wb *putbuffer; /* for acm_tty_put_char() */
int rx_buflimit;
spinlock_t read_lock;
+ u8 *notification_buffer; /* to reassemble fragmented notifications */
+ unsigned int nb_index;
+ unsigned int nb_size;
int write_used; /* number of non-empty write buffers */
int transmitting;
spinlock_t write_lock;
--
2.1.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 3/4] cdc-acm: log message for serial state notification
2017-03-30 20:15 ` [PATCH v3 0/4] cdc-acm: reassemble fragmented notifications Tobias Herzog
2017-03-30 20:15 ` [PATCH v3 1/4] cdc-acm: fix possible invalid access when processing notification Tobias Herzog
2017-03-30 20:15 ` [PATCH v3 2/4] cdc-acm: reassemble fragmented notifications Tobias Herzog
@ 2017-03-30 20:15 ` Tobias Herzog
2017-03-31 9:34 ` Oliver Neukum
2017-03-30 20:15 ` [PATCH v3 4/4] cdc-acm: remove unused element of struct acm Tobias Herzog
3 siblings, 1 reply; 9+ messages in thread
From: Tobias Herzog @ 2017-03-30 20:15 UTC (permalink / raw)
To: oneukum; +Cc: gregkh, linux-usb, linux-kernel, stable
Adds a similar log message to USB_CDC_NOTIFY_SERIAL_STATE as it is
already done with USB_CDC_NOTIFY_NETWORK_CONNECTION.
Signed-off-by: Tobias Herzog <t-herzog@gmx.de>
---
drivers/usb/class/cdc-acm.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 58efa15..c784319 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -304,6 +304,8 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf)
}
newctrl = get_unaligned_le16(data);
+ dev_dbg(&acm->control->dev,
+ "%s - serial state: 0x%x\n", __func__, newctrl);
if (!acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
dev_dbg(&acm->control->dev,
--
2.1.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v3 4/4] cdc-acm: remove unused element of struct acm
2017-03-30 20:15 ` [PATCH v3 0/4] cdc-acm: reassemble fragmented notifications Tobias Herzog
` (2 preceding siblings ...)
2017-03-30 20:15 ` [PATCH v3 3/4] cdc-acm: log message for serial state notification Tobias Herzog
@ 2017-03-30 20:15 ` Tobias Herzog
2017-03-31 9:35 ` Oliver Neukum
3 siblings, 1 reply; 9+ messages in thread
From: Tobias Herzog @ 2017-03-30 20:15 UTC (permalink / raw)
To: oneukum; +Cc: gregkh, linux-usb, linux-kernel, stable
write_used was introduced with commit 884b600f63dc ("[PATCH] USB: fix acm
trouble with terminals") but never used since.
Signed-off-by: Tobias Herzog <t-herzog@gmx.de>
---
drivers/usb/class/cdc-acm.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
index b519138..7a2b3de 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -101,7 +101,6 @@ struct acm {
u8 *notification_buffer; /* to reassemble fragmented notifications */
unsigned int nb_index;
unsigned int nb_size;
- int write_used; /* number of non-empty write buffers */
int transmitting;
spinlock_t write_lock;
struct mutex mutex;
--
2.1.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v3 1/4] cdc-acm: fix possible invalid access when processing notification
2017-03-30 20:15 ` [PATCH v3 1/4] cdc-acm: fix possible invalid access when processing notification Tobias Herzog
@ 2017-03-31 9:31 ` Oliver Neukum
0 siblings, 0 replies; 9+ messages in thread
From: Oliver Neukum @ 2017-03-31 9:31 UTC (permalink / raw)
To: Tobias Herzog; +Cc: gregkh, linux-kernel, linux-usb, stable
Am Donnerstag, den 30.03.2017, 22:15 +0200 schrieb Tobias Herzog:
> Notifications may only be 8 bytes long. Accessing the 9th and
> 10th byte of unimplemented/unknown notifications may be insecure.
> Also check the length of known notifications before accessing anything
> behind the 8th byte.
>
> Signed-off-by: Tobias Herzog <t-herzog@gmx.de>
Acked-by: Oliver Neukum <oneukum@suse.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 2/4] cdc-acm: reassemble fragmented notifications
2017-03-30 20:15 ` [PATCH v3 2/4] cdc-acm: reassemble fragmented notifications Tobias Herzog
@ 2017-03-31 9:33 ` Oliver Neukum
0 siblings, 0 replies; 9+ messages in thread
From: Oliver Neukum @ 2017-03-31 9:33 UTC (permalink / raw)
To: Tobias Herzog; +Cc: gregkh, linux-kernel, linux-usb, stable
Am Donnerstag, den 30.03.2017, 22:15 +0200 schrieb Tobias Herzog:
> USB devices may have very limited endpoint packet sizes, so that
> notifications can not be transferred within one single usb packet.
> Reassembling of multiple packages may be necessary.
>
> Signed-off-by: Tobias Herzog <t-herzog@gmx.de>
Acked-by: Oliver Neukum <oneukum@suse.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 3/4] cdc-acm: log message for serial state notification
2017-03-30 20:15 ` [PATCH v3 3/4] cdc-acm: log message for serial state notification Tobias Herzog
@ 2017-03-31 9:34 ` Oliver Neukum
0 siblings, 0 replies; 9+ messages in thread
From: Oliver Neukum @ 2017-03-31 9:34 UTC (permalink / raw)
To: Tobias Herzog; +Cc: gregkh, linux-kernel, linux-usb, stable
Am Donnerstag, den 30.03.2017, 22:15 +0200 schrieb Tobias Herzog:
> Adds a similar log message to USB_CDC_NOTIFY_SERIAL_STATE as it is
> already done with USB_CDC_NOTIFY_NETWORK_CONNECTION.
>
> Signed-off-by: Tobias Herzog <t-herzog@gmx.de>
Acked-by: Oliver Neukum <oneukum@suse.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 4/4] cdc-acm: remove unused element of struct acm
2017-03-30 20:15 ` [PATCH v3 4/4] cdc-acm: remove unused element of struct acm Tobias Herzog
@ 2017-03-31 9:35 ` Oliver Neukum
0 siblings, 0 replies; 9+ messages in thread
From: Oliver Neukum @ 2017-03-31 9:35 UTC (permalink / raw)
To: Tobias Herzog; +Cc: gregkh, linux-kernel, linux-usb, stable
Am Donnerstag, den 30.03.2017, 22:15 +0200 schrieb Tobias Herzog:
> write_used was introduced with commit 884b600f63dc ("[PATCH] USB: fix acm
> trouble with terminals") but never used since.
>
> Signed-off-by: Tobias Herzog <t-herzog@gmx.de>
Acked-by: Oliver Neukum <oneukum@suse.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2017-03-31 9:36 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <1479118868.21146.4.camel@suse.com>
2017-03-30 20:15 ` [PATCH v3 0/4] cdc-acm: reassemble fragmented notifications Tobias Herzog
2017-03-30 20:15 ` [PATCH v3 1/4] cdc-acm: fix possible invalid access when processing notification Tobias Herzog
2017-03-31 9:31 ` Oliver Neukum
2017-03-30 20:15 ` [PATCH v3 2/4] cdc-acm: reassemble fragmented notifications Tobias Herzog
2017-03-31 9:33 ` Oliver Neukum
2017-03-30 20:15 ` [PATCH v3 3/4] cdc-acm: log message for serial state notification Tobias Herzog
2017-03-31 9:34 ` Oliver Neukum
2017-03-30 20:15 ` [PATCH v3 4/4] cdc-acm: remove unused element of struct acm Tobias Herzog
2017-03-31 9:35 ` Oliver Neukum
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).