All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] cdc-acm: reassemble fragmented notifications
       [not found] <1479118868.21146.4.camel@suse.com>
@ 2017-03-14 20:14 ` Tobias Herzog
  2017-03-14 20:14   ` [PATCH 2/4] cdc-acm: fix possible invalid access when processing notification Tobias Herzog
                     ` (3 more replies)
  2017-03-18 18:52 ` [PATCH v2 0/4] " Tobias Herzog
  2017-03-30 20:15 ` [PATCH v3 0/4] cdc-acm: reassemble fragmented notifications Tobias Herzog
  2 siblings, 4 replies; 26+ messages in thread
From: Tobias Herzog @ 2017-03-14 20:14 UTC (permalink / raw)
  To: oneukum; +Cc: gregkh, linux-usb, linux-kernel

USB devices may have very limitited 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 | 102 +++++++++++++++++++++++++++++++-------------
 drivers/usb/class/cdc-acm.h |   2 +
 2 files changed, 75 insertions(+), 29 deletions(-)

diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index e35b150..40714fe 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -282,39 +282,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;
+	struct usb_cdc_notification *dr = (struct usb_cdc_notification *)buf;
+	unsigned char *data = (unsigned char *)(dr + 1);
 
-	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;
-	}
-
-	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,
@@ -363,8 +337,74 @@ static void acm_ctrl_irq(struct urb *urb)
 			__func__,
 			dr->bNotificationType, dr->wIndex,
 			dr->wLength, data[0], data[1]);
+	}
+}
+
+/* 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;
+	int retval;
+	int status = urb->status;
+
+	switch (status) {
+	case 0:
+		/* success */
 		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		/* this urb is terminated, clean up */
+		kfree(acm->notification_buffer);
+		acm->notification_buffer = NULL;
+		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->notification_buffer)
+		dr = (struct usb_cdc_notification *)acm->notification_buffer;
+
+	/* assume the first package contains at least two bytes */
+	expected_size = dr->wLength + 8;
+
+	if (current_size < expected_size) {
+		/* notification is transmitted framented, reassemble */
+		if (!acm->notification_buffer) {
+			acm->notification_buffer =
+					kmalloc(expected_size, GFP_ATOMIC);
+			acm->nb_index = 0;
+		}
+
+		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)
+		goto exit;
+
+	/* notification complete */
+	acm_process_notification(acm, (unsigned char *)dr);
+
+	kfree(acm->notification_buffer);
+	acm->notification_buffer = NULL;
+
 exit:
 	retval = usb_submit_urb(urb, GFP_ATOMIC);
 	if (retval && retval != -EPERM)
@@ -1488,6 +1528,8 @@ 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;
 
 	dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
 
@@ -1580,6 +1622,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..bc07fb2 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -98,6 +98,8 @@ 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;
 	int write_used;					/* number of non-empty write buffers */
 	int transmitting;
 	spinlock_t write_lock;
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 2/4] cdc-acm: fix possible invalid access when processing notification
  2017-03-14 20:14 ` [PATCH 1/4] cdc-acm: reassemble fragmented notifications Tobias Herzog
@ 2017-03-14 20:14   ` Tobias Herzog
  2017-03-15  9:26     ` Oliver Neukum
  2017-03-14 20:14   ` [PATCH 3/4] cdc-acm: log message for serial state notification Tobias Herzog
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 26+ messages in thread
From: Tobias Herzog @ 2017-03-14 20:14 UTC (permalink / raw)
  To: oneukum; +Cc: gregkh, linux-usb, linux-kernel

Notifications may only be 8 bytes so 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 | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 40714fe..b99127e 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -296,6 +296,12 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf)
 		break;
 
 	case USB_CDC_NOTIFY_SERIAL_STATE:
+		if (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)) {
@@ -332,11 +338,10 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf)
 
 	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->wLength);
 	}
 }
 
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH 3/4] cdc-acm: log message for serial state notification
  2017-03-14 20:14 ` [PATCH 1/4] cdc-acm: reassemble fragmented notifications Tobias Herzog
  2017-03-14 20:14   ` [PATCH 2/4] cdc-acm: fix possible invalid access when processing notification Tobias Herzog
@ 2017-03-14 20:14   ` Tobias Herzog
  2017-03-14 20:14   ` [PATCH 4/4] cdc-acm: remove unused element of struct acm Tobias Herzog
  2017-03-15  9:26   ` [PATCH 1/4] cdc-acm: reassemble fragmented notifications Oliver Neukum
  3 siblings, 0 replies; 26+ messages in thread
From: Tobias Herzog @ 2017-03-14 20:14 UTC (permalink / raw)
  To: oneukum; +Cc: gregkh, linux-usb, linux-kernel

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 b99127e..2402b26 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -303,6 +303,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] 26+ messages in thread

* [PATCH 4/4] cdc-acm: remove unused element of struct acm
  2017-03-14 20:14 ` [PATCH 1/4] cdc-acm: reassemble fragmented notifications Tobias Herzog
  2017-03-14 20:14   ` [PATCH 2/4] cdc-acm: fix possible invalid access when processing notification Tobias Herzog
  2017-03-14 20:14   ` [PATCH 3/4] cdc-acm: log message for serial state notification Tobias Herzog
@ 2017-03-14 20:14   ` Tobias Herzog
  2017-03-15  9:26   ` [PATCH 1/4] cdc-acm: reassemble fragmented notifications Oliver Neukum
  3 siblings, 0 replies; 26+ messages in thread
From: Tobias Herzog @ 2017-03-14 20:14 UTC (permalink / raw)
  To: oneukum; +Cc: gregkh, linux-usb, linux-kernel

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 bc07fb2..a916c62 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -100,7 +100,6 @@ struct acm {
 	spinlock_t read_lock;
 	u8 *notification_buffer;			/* to reassemble fragmented notifications */
 	unsigned int nb_index;
-	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] 26+ messages in thread

* Re: [PATCH 1/4] cdc-acm: reassemble fragmented notifications
  2017-03-14 20:14 ` [PATCH 1/4] cdc-acm: reassemble fragmented notifications Tobias Herzog
                     ` (2 preceding siblings ...)
  2017-03-14 20:14   ` [PATCH 4/4] cdc-acm: remove unused element of struct acm Tobias Herzog
@ 2017-03-15  9:26   ` Oliver Neukum
  2017-03-18 18:52     ` Tobias Herzog
  3 siblings, 1 reply; 26+ messages in thread
From: Oliver Neukum @ 2017-03-15  9:26 UTC (permalink / raw)
  To: Tobias Herzog; +Cc: gregkh, linux-kernel, linux-usb

Am Dienstag, den 14.03.2017, 21:14 +0100 schrieb Tobias Herzog:
> USB devices may have very limitited endpoint packet sizes, so that
> notifications can not be transferred within one single usb packet.
> Reassembling of multiple packages may be necessary.

Hi,

thank you for the patch. Unfortunately it has some issue.
Please see the comments inside.

	Regards
		Oliver

> 
> Signed-off-by: Tobias Herzog <t-herzog@gmx.de>
> ---
>  drivers/usb/class/cdc-acm.c | 102 +++++++++++++++++++++++++++++++-------------
>  drivers/usb/class/cdc-acm.h |   2 +
>  2 files changed, 75 insertions(+), 29 deletions(-)
> 
> diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
> index e35b150..40714fe 100644
> --- a/drivers/usb/class/cdc-acm.c
> +++ b/drivers/usb/class/cdc-acm.c
> @@ -282,39 +282,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;
> +	struct usb_cdc_notification *dr = (struct usb_cdc_notification *)buf;
> +	unsigned char *data = (unsigned char *)(dr + 1);
>  
> -	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;
> -	}
> -
> -	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,
> @@ -363,8 +337,74 @@ static void acm_ctrl_irq(struct urb *urb)
>  			__func__,
>  			dr->bNotificationType, dr->wIndex,
>  			dr->wLength, data[0], data[1]);
> +	}
> +}
> +
> +/* 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;
> +	int retval;
> +	int status = urb->status;
> +
> +	switch (status) {
> +	case 0:
> +		/* success */
>  		break;
> +	case -ECONNRESET:
> +	case -ENOENT:
> +	case -ESHUTDOWN:
> +		/* this urb is terminated, clean up */
> +		kfree(acm->notification_buffer);
> +		acm->notification_buffer = NULL;

Why? Disconnect() will free it anyway. It should be enough
to discard the content.

> +		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->notification_buffer)
> +		dr = (struct usb_cdc_notification *)acm->notification_buffer;
> +
> +	/* assume the first package contains at least two bytes */
> +	expected_size = dr->wLength + 8;

You need the explain where you got the 8 from. In fact a define would
be best.

> +
> +	if (current_size < expected_size) {
> +		/* notification is transmitted framented, reassemble */

Please fix the typo.

> +		if (!acm->notification_buffer) {
> +			acm->notification_buffer =
> +					kmalloc(expected_size, GFP_ATOMIC);

This can fail. You _must_ check for that.

> +			acm->nb_index = 0;
> +		}
> +
> +		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)
> +		goto exit;

This is an unneeded goto.

> +	/* notification complete */
> +	acm_process_notification(acm, (unsigned char *)dr);
> +
> +	kfree(acm->notification_buffer);

Why? If one message was fragmented, the next one will also likely be
fragmented. Why release the buffer before you know whether it can be
reused?

> +	acm->notification_buffer = NULL;
> +
>  exit:
>  	retval = usb_submit_urb(urb, GFP_ATOMIC);
>  	if (retval && retval != -EPERM)
> @@ -1488,6 +1528,8 @@ 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;
>  
>  	dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
>  
> @@ -1580,6 +1622,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..bc07fb2 100644
> --- a/drivers/usb/class/cdc-acm.h
> +++ b/drivers/usb/class/cdc-acm.h
> @@ -98,6 +98,8 @@ 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;
>  	int write_used;					/* number of non-empty write buffers */
>  	int transmitting;
>  	spinlock_t write_lock;

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2/4] cdc-acm: fix possible invalid access when processing notification
  2017-03-14 20:14   ` [PATCH 2/4] cdc-acm: fix possible invalid access when processing notification Tobias Herzog
@ 2017-03-15  9:26     ` Oliver Neukum
  0 siblings, 0 replies; 26+ messages in thread
From: Oliver Neukum @ 2017-03-15  9:26 UTC (permalink / raw)
  To: Tobias Herzog; +Cc: gregkh, linux-kernel, linux-usb

Am Dienstag, den 14.03.2017, 21:14 +0100 schrieb Tobias Herzog:
> Notifications may only be 8 bytes so 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 | 11 ++++++++---
>  1 file changed, 8 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
> index 40714fe..b99127e 100644
> --- a/drivers/usb/class/cdc-acm.c
> +++ b/drivers/usb/class/cdc-acm.c
> @@ -296,6 +296,12 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf)
>  		break;
>  
>  	case USB_CDC_NOTIFY_SERIAL_STATE:
> +		if (dr->wLength != 2) {

Endianness

> +			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)) {
> @@ -332,11 +338,10 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf)
>  
>  	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->wLength);
>  	}
>  }
>  

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 1/4] cdc-acm: reassemble fragmented notifications
  2017-03-15  9:26   ` [PATCH 1/4] cdc-acm: reassemble fragmented notifications Oliver Neukum
@ 2017-03-18 18:52     ` Tobias Herzog
  0 siblings, 0 replies; 26+ messages in thread
From: Tobias Herzog @ 2017-03-18 18:52 UTC (permalink / raw)
  To: Oliver Neukum; +Cc: gregkh, linux-kernel, linux-usb

Hi,

thank you for your feedback. I tried to fix all issues with v2. I was
just unsure with one point (see comment).


/tobias


> Am Dienstag, den 14.03.2017, 21:14 +0100 schrieb Tobias Herzog:
> > 
> > USB devices may have very limitited endpoint packet sizes, so that
> > notifications can not be transferred within one single usb packet.
> > Reassembling of multiple packages may be necessary.
> Hi,
> 
> thank you for the patch. Unfortunately it has some issue.
> Please see the comments inside.
> 
> 	Regards
> 		Oliver
> 
> > 
> > 
> > Signed-off-by: Tobias Herzog <t-herzog@gmx.de>
> > ---
> >  drivers/usb/class/cdc-acm.c | 102 +++++++++++++++++++++++++++++++-
> > ------------
> >  drivers/usb/class/cdc-acm.h |   2 +
> >  2 files changed, 75 insertions(+), 29 deletions(-)
> > 
> > diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-
> > acm.c
> > index e35b150..40714fe 100644
> > --- a/drivers/usb/class/cdc-acm.c
> > +++ b/drivers/usb/class/cdc-acm.c
> > @@ -282,39 +282,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;
> > +	struct usb_cdc_notification *dr = (struct
> > usb_cdc_notification *)buf;
> > +	unsigned char *data = (unsigned char *)(dr + 1);
> >  
> > -	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;
> > -	}
> > -
> > -	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,
> > @@ -363,8 +337,74 @@ static void acm_ctrl_irq(struct urb *urb)
> >  			__func__,
> >  			dr->bNotificationType, dr->wIndex,
> >  			dr->wLength, data[0], data[1]);
> > +	}
> > +}
> > +
> > +/* 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;
> > +	int retval;
> > +	int status = urb->status;
> > +
> > +	switch (status) {
> > +	case 0:
> > +		/* success */
> >  		break;
> > +	case -ECONNRESET:
> > +	case -ENOENT:
> > +	case -ESHUTDOWN:
> > +		/* this urb is terminated, clean up */
> > +		kfree(acm->notification_buffer);
> > +		acm->notification_buffer = NULL;
> Why? Disconnect() will free it anyway. It should be enough
> to discard the content.
> 
> > 
> > +		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->notification_buffer)
> > +		dr = (struct usb_cdc_notification *)acm-
> > >notification_buffer;
> > +
> > +	/* assume the first package contains at least two bytes */
> > +	expected_size = dr->wLength + 8;
> You need the explain where you got the 8 from. In fact a define would
> be best.
I feel better to use 'sizeof(struct usb_cdc_notification)' here, than
using an separate, hard-coded define. In fact this is really what we
want here, as the buffer needs to cover the notification header (i.e.
struct usb_cdc_notification) + the additional (optional) data.

> 
> > 
> > +
> > +	if (current_size < expected_size) {
> > +		/* notification is transmitted framented,
> > reassemble */
> Please fix the typo.
> 
> > 
> > +		if (!acm->notification_buffer) {
> > +			acm->notification_buffer =
> > +					kmalloc(expected_size,
> > GFP_ATOMIC);
> This can fail. You _must_ check for that.
> 
> > 
> > +			acm->nb_index = 0;
> > +		}
> > +
> > +		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)
> > +		goto exit;
> This is an unneeded goto.
> 
> > 
> > +	/* notification complete */
> > +	acm_process_notification(acm, (unsigned char *)dr);
> > +
> > +	kfree(acm->notification_buffer);
> Why? If one message was fragmented, the next one will also likely be
> fragmented. Why release the buffer before you know whether it can be
> reused?
> 
> > 
> > +	acm->notification_buffer = NULL;
> > +
> >  exit:
> >  	retval = usb_submit_urb(urb, GFP_ATOMIC);
> >  	if (retval && retval != -EPERM)
> > @@ -1488,6 +1528,8 @@ 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;
> >  
> >  	dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
> >  
> > @@ -1580,6 +1622,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..bc07fb2 100644
> > --- a/drivers/usb/class/cdc-acm.h
> > +++ b/drivers/usb/class/cdc-acm.h
> > @@ -98,6 +98,8 @@ 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;
> >  	int write_used;					/*
> > number of non-empty write buffers */
> >  	int transmitting;
> >  	spinlock_t write_lock;

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH v2 0/4] cdc-acm: reassemble fragmented notifications
       [not found] <1479118868.21146.4.camel@suse.com>
  2017-03-14 20:14 ` [PATCH 1/4] cdc-acm: reassemble fragmented notifications Tobias Herzog
@ 2017-03-18 18:52 ` Tobias Herzog
  2017-03-18 18:52   ` [PATCH v2 1/4] " Tobias Herzog
                     ` (3 more replies)
  2017-03-30 20:15 ` [PATCH v3 0/4] cdc-acm: reassemble fragmented notifications Tobias Herzog
  2 siblings, 4 replies; 26+ messages in thread
From: Tobias Herzog @ 2017-03-18 18:52 UTC (permalink / raw)
  To: oneukum; +Cc: gregkh, linux-usb, linux-kernel

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.

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: reassemble fragmented notifications
  cdc-acm: fix possible invalid access when processing notification
  cdc-acm: log message for serial state notification
  cdc-acm: remove unused element of struct acm

 drivers/usb/class/cdc-acm.c | 119 ++++++++++++++++++++++++++++++++------------
 drivers/usb/class/cdc-acm.h |   4 +-
 2 files changed, 90 insertions(+), 33 deletions(-)

-- 
2.1.4

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH v2 1/4] cdc-acm: reassemble fragmented notifications
  2017-03-18 18:52 ` [PATCH v2 0/4] " Tobias Herzog
@ 2017-03-18 18:52   ` Tobias Herzog
  2017-03-20 15:02     ` Oliver Neukum
  2017-03-18 18:52   ` [PATCH v2 2/4] cdc-acm: fix possible invalid access when processing notification Tobias Herzog
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 26+ messages in thread
From: Tobias Herzog @ 2017-03-18 18:52 UTC (permalink / raw)
  To: oneukum; +Cc: gregkh, linux-usb, linux-kernel

USB devices may have very limitited 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 | 106 ++++++++++++++++++++++++++++++++------------
 drivers/usb/class/cdc-acm.h |   3 ++
 2 files changed, 80 insertions(+), 29 deletions(-)

diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index e35b150..74acca1 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -282,39 +282,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 = (unsigned char *)(dr + 1);
 
-	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,
@@ -363,8 +337,77 @@ static void acm_ctrl_irq(struct urb *urb)
 			__func__,
 			dr->bNotificationType, dr->wIndex,
 			dr->wLength, data[0], data[1]);
+	}
+}
+
+/* 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;
+	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;
+			}
+			acm->notification_buffer =
+					kmalloc(expected_size, GFP_ATOMIC);
+			if (!acm->notification_buffer)
+				goto exit;
+			acm->nb_size = expected_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)
@@ -1488,6 +1531,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);
 
@@ -1580,6 +1626,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] 26+ messages in thread

* [PATCH v2 2/4] cdc-acm: fix possible invalid access when processing notification
  2017-03-18 18:52 ` [PATCH v2 0/4] " Tobias Herzog
  2017-03-18 18:52   ` [PATCH v2 1/4] " Tobias Herzog
@ 2017-03-18 18:52   ` Tobias Herzog
  2017-03-19  9:50     ` Sergei Shtylyov
  2017-03-20 15:04     ` Oliver Neukum
  2017-03-18 18:52   ` [PATCH v2 3/4] cdc-acm: log message for serial state notification Tobias Herzog
  2017-03-18 18:52   ` [PATCH v2 4/4] cdc-acm: remove unused element of struct acm Tobias Herzog
  3 siblings, 2 replies; 26+ messages in thread
From: Tobias Herzog @ 2017-03-18 18:52 UTC (permalink / raw)
  To: oneukum; +Cc: gregkh, linux-usb, linux-kernel

Notifications may only be 8 bytes so 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 | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 74acca1..a7c8878 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -296,6 +296,12 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf)
 		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)) {
@@ -332,11 +338,10 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf)
 
 	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->wLength);
 	}
 }
 
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v2 3/4] cdc-acm: log message for serial state notification
  2017-03-18 18:52 ` [PATCH v2 0/4] " Tobias Herzog
  2017-03-18 18:52   ` [PATCH v2 1/4] " Tobias Herzog
  2017-03-18 18:52   ` [PATCH v2 2/4] cdc-acm: fix possible invalid access when processing notification Tobias Herzog
@ 2017-03-18 18:52   ` Tobias Herzog
  2017-03-18 18:52   ` [PATCH v2 4/4] cdc-acm: remove unused element of struct acm Tobias Herzog
  3 siblings, 0 replies; 26+ messages in thread
From: Tobias Herzog @ 2017-03-18 18:52 UTC (permalink / raw)
  To: oneukum; +Cc: gregkh, linux-usb, linux-kernel

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 a7c8878..8fcd036 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -303,6 +303,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] 26+ messages in thread

* [PATCH v2 4/4] cdc-acm: remove unused element of struct acm
  2017-03-18 18:52 ` [PATCH v2 0/4] " Tobias Herzog
                     ` (2 preceding siblings ...)
  2017-03-18 18:52   ` [PATCH v2 3/4] cdc-acm: log message for serial state notification Tobias Herzog
@ 2017-03-18 18:52   ` Tobias Herzog
  3 siblings, 0 replies; 26+ messages in thread
From: Tobias Herzog @ 2017-03-18 18:52 UTC (permalink / raw)
  To: oneukum; +Cc: gregkh, linux-usb, linux-kernel

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] 26+ messages in thread

* Re: [PATCH v2 2/4] cdc-acm: fix possible invalid access when processing notification
  2017-03-18 18:52   ` [PATCH v2 2/4] cdc-acm: fix possible invalid access when processing notification Tobias Herzog
@ 2017-03-19  9:50     ` Sergei Shtylyov
  2017-03-20 15:04     ` Oliver Neukum
  1 sibling, 0 replies; 26+ messages in thread
From: Sergei Shtylyov @ 2017-03-19  9:50 UTC (permalink / raw)
  To: Tobias Herzog, oneukum; +Cc: gregkh, linux-usb, linux-kernel

On 3/18/2017 9:52 PM, Tobias Herzog wrote:

> Notifications may only be 8 bytes so long. Accessing the 9th and

    s/so//.
    "So long and thanks for all the fish!" :-)

> 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>
[...]

MBR, Sergei

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v2 1/4] cdc-acm: reassemble fragmented notifications
  2017-03-18 18:52   ` [PATCH v2 1/4] " Tobias Herzog
@ 2017-03-20 15:02     ` Oliver Neukum
  2017-03-24 21:50       ` Tobias Herzog
  0 siblings, 1 reply; 26+ messages in thread
From: Oliver Neukum @ 2017-03-20 15:02 UTC (permalink / raw)
  To: Tobias Herzog; +Cc: gregkh, linux-kernel, linux-usb

Am Samstag, den 18.03.2017, 19:52 +0100 schrieb Tobias Herzog:
> USB devices may have very limitited endpoint packet sizes, so that
> notifications can not be transferred within one single usb packet.
> Reassembling of multiple packages may be necessary.

Hi,

almost perfect.
A few new issue. Comments inline.

> 
> +	struct usb_cdc_notification *dr = (struct usb_cdc_notification *)buf;
> +	unsigned char *data = (unsigned char *)(dr + 1);

This is border line incorrect. It depends on the compiler not
adding padding. Please make it

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,
> @@ -363,8 +337,77 @@ static void acm_ctrl_irq(struct urb *urb)
>  			__func__,
>  			dr->bNotificationType, dr->wIndex,
>  			dr->wLength, data[0], data[1]);
> +	}
> +}
> +
> +/* 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;
> +	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;
> +			}
> +			acm->notification_buffer =
> +					kmalloc(expected_size, GFP_ATOMIC);

Given how kmalloc works you'd better round this up to a power of two.

> +			if (!acm->notification_buffer)
> +				goto exit;

This is most subtle. Please add a comment that this prevents a double
free if we get a disconnect()

> +			acm->nb_size = expected_size;
> +		}

	Regards
		Oliver

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v2 2/4] cdc-acm: fix possible invalid access when processing notification
  2017-03-18 18:52   ` [PATCH v2 2/4] cdc-acm: fix possible invalid access when processing notification Tobias Herzog
  2017-03-19  9:50     ` Sergei Shtylyov
@ 2017-03-20 15:04     ` Oliver Neukum
  1 sibling, 0 replies; 26+ messages in thread
From: Oliver Neukum @ 2017-03-20 15:04 UTC (permalink / raw)
  To: Tobias Herzog; +Cc: gregkh, linux-kernel, linux-usb

Am Samstag, den 18.03.2017, 19:52 +0100 schrieb Tobias Herzog:
> Notifications may only be 8 bytes so 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.
> 

This is fixing a potential security issue. Please make it first in the
series and CC it to stable@vger.kernel.org

	Regards
		Oliver

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v2 1/4] cdc-acm: reassemble fragmented notifications
  2017-03-20 15:02     ` Oliver Neukum
@ 2017-03-24 21:50       ` Tobias Herzog
  2017-03-28  8:04         ` Oliver Neukum
  0 siblings, 1 reply; 26+ messages in thread
From: Tobias Herzog @ 2017-03-24 21:50 UTC (permalink / raw)
  To: Oliver Neukum; +Cc: gregkh, linux-kernel, linux-usb

Hi Oliver,

thank you for your patience... :) I have a question to one of your
comments (see below).

Best regards,
Tobias

> Am Samstag, den 18.03.2017, 19:52 +0100 schrieb Tobias Herzog:
> > 
> > USB devices may have very limitited endpoint packet sizes, so that
> > notifications can not be transferred within one single usb packet.
> > Reassembling of multiple packages may be necessary.
> Hi,
> 
> almost perfect.
> A few new issue. Comments inline.
> 
> > 
> > 
> > +	struct usb_cdc_notification *dr = (struct
> > usb_cdc_notification *)buf;
> > +	unsigned char *data = (unsigned char *)(dr + 1);
> This is border line incorrect. It depends on the compiler not
> adding padding. Please make it
> 
> 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,
> > @@ -363,8 +337,77 @@ static void acm_ctrl_irq(struct urb *urb)
> >  			__func__,
> >  			dr->bNotificationType, dr->wIndex,
> >  			dr->wLength, data[0], data[1]);
> > +	}
> > +}
> > +
> > +/* 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;
> > +	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;
> > +			}
> > +			acm->notification_buffer =
> > +					kmalloc(expected_size,
> > GFP_ATOMIC);
> Given how kmalloc works you'd better round this up to a power of two.
> 
> > 
> > +			if (!acm->notification_buffer)
> > +				goto exit;
> This is most subtle. Please add a comment that this prevents a double
> free if we get a disconnect()
I'm unsure if I got this right: Are you talking about the fact, that
the use of 'kmalloc' will make 'acm->notification_buffer' valid again
(i.e. NULL or pointing to a correctly allocated block), after it was
"invalidated" by 'kfree' (in case the previously allocated buffer was
too small)?
The 'goto exit'-thing for me is just not to use the buffer if
allocation fails. Or am I missing anything here?
> 
> > 
> > +			acm->nb_size = expected_size;
> > +		}
> 	Regards
> 		Oliver
> 

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v2 1/4] cdc-acm: reassemble fragmented notifications
  2017-03-24 21:50       ` Tobias Herzog
@ 2017-03-28  8:04         ` Oliver Neukum
  0 siblings, 0 replies; 26+ messages in thread
From: Oliver Neukum @ 2017-03-28  8:04 UTC (permalink / raw)
  To: Tobias Herzog; +Cc: gregkh, linux-kernel, linux-usb

Am Freitag, den 24.03.2017, 22:50 +0100 schrieb Tobias Herzog:
> Hi Oliver,
> 
> thank you for your patience... :) I have a question to one of your
> comments (see below).
> 
> Best regards,
> Tobias
> 
> > 
> > Am Samstag, den 18.03.2017, 19:52 +0100 schrieb Tobias Herzog:
> > > 
> > > 
> > > USB devices may have very limitited endpoint packet sizes, so that
> > > notifications can not be transferred within one single usb packet.
> > > Reassembling of multiple packages may be necessary.
> > Hi,
> > 
> > almost perfect.
> > A few new issue. Comments inline.
> > 
> > > 
> > > 
> > > 
> > > +	struct usb_cdc_notification *dr = (struct
> > > usb_cdc_notification *)buf;
> > > +	unsigned char *data = (unsigned char *)(dr + 1);
> > This is border line incorrect. It depends on the compiler not
> > adding padding. Please make it
> > 
> > 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,
> > > @@ -363,8 +337,77 @@ static void acm_ctrl_irq(struct urb *urb)
> > >  			__func__,
> > >  			dr->bNotificationType, dr->wIndex,
> > >  			dr->wLength, data[0], data[1]);
> > > +	}
> > > +}
> > > +
> > > +/* 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;
> > > +	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;
> > > +			}
> > > +			acm->notification_buffer =
> > > +					kmalloc(expected_size,
> > > GFP_ATOMIC);
> > Given how kmalloc works you'd better round this up to a power of two.
> > 
> > > 
> > > 
> > > +			if (!acm->notification_buffer)
> > > +				goto exit;
> > This is most subtle. Please add a comment that this prevents a double
> > free if we get a disconnect()
> I'm unsure if I got this right: Are you talking about the fact, that
> the use of 'kmalloc' will make 'acm->notification_buffer' valid again
> (i.e. NULL or pointing to a correctly allocated block), after it was

yes

> "invalidated" by 'kfree' (in case the previously allocated buffer was
> too small)?
> The 'goto exit'-thing for me is just not to use the buffer if
> allocation fails. Or am I missing anything here?

You need to consider the hot unplug case.

	Regards
		Oliver

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH v3 0/4] cdc-acm: reassemble fragmented notifications
       [not found] <1479118868.21146.4.camel@suse.com>
  2017-03-14 20:14 ` [PATCH 1/4] cdc-acm: reassemble fragmented notifications Tobias Herzog
  2017-03-18 18:52 ` [PATCH v2 0/4] " Tobias Herzog
@ 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)
  2 siblings, 4 replies; 26+ 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] 26+ 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; 26+ 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] 26+ 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; 26+ 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] 26+ 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; 26+ 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] 26+ 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; 26+ 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] 26+ 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; 26+ 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] 26+ 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; 26+ 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] 26+ 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; 26+ 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] 26+ 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; 26+ 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] 26+ messages in thread

end of thread, other threads:[~2017-03-31  9:36 UTC | newest]

Thread overview: 26+ 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-14 20:14 ` [PATCH 1/4] cdc-acm: reassemble fragmented notifications Tobias Herzog
2017-03-14 20:14   ` [PATCH 2/4] cdc-acm: fix possible invalid access when processing notification Tobias Herzog
2017-03-15  9:26     ` Oliver Neukum
2017-03-14 20:14   ` [PATCH 3/4] cdc-acm: log message for serial state notification Tobias Herzog
2017-03-14 20:14   ` [PATCH 4/4] cdc-acm: remove unused element of struct acm Tobias Herzog
2017-03-15  9:26   ` [PATCH 1/4] cdc-acm: reassemble fragmented notifications Oliver Neukum
2017-03-18 18:52     ` Tobias Herzog
2017-03-18 18:52 ` [PATCH v2 0/4] " Tobias Herzog
2017-03-18 18:52   ` [PATCH v2 1/4] " Tobias Herzog
2017-03-20 15:02     ` Oliver Neukum
2017-03-24 21:50       ` Tobias Herzog
2017-03-28  8:04         ` Oliver Neukum
2017-03-18 18:52   ` [PATCH v2 2/4] cdc-acm: fix possible invalid access when processing notification Tobias Herzog
2017-03-19  9:50     ` Sergei Shtylyov
2017-03-20 15:04     ` Oliver Neukum
2017-03-18 18:52   ` [PATCH v2 3/4] cdc-acm: log message for serial state notification Tobias Herzog
2017-03-18 18:52   ` [PATCH v2 4/4] cdc-acm: remove unused element of struct acm Tobias Herzog
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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.