From: Oliver Neukum <oneukum@suse.com>
To: Alan Stern <stern@rowland.harvard.edu>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: USB list <linux-usb@vger.kernel.org>
Subject: revisiting the issue of hardening the USB enumeration parser
Date: Thu, 16 May 2024 15:48:41 +0200 [thread overview]
Message-ID: <b94e5037-19da-4cc9-9a8a-28df8ada4795@suse.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 1459 bytes --]
Hi,
you convinced me that my last attempt to look at the parser
was fundamentally flawed. Instead I went top down from parsing
the configuration down to endpoints. I found one major issue.
static int find_next_descriptor(unsigned char *buffer, int size,
int dt1, int dt2, int *num_skipped)
{
struct usb_descriptor_header *h;
int n = 0;
unsigned char *buffer0 = buffer;
/* Find the next descriptor of type dt1 or dt2 */
while (size > 0) {
h = (struct usb_descriptor_header *) buffer;
if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2)
break;
buffer += h->bLength;
size -= h->bLength;
++n;
}
/* Store the number of descriptors skipped and return the
* number of bytes skipped */
if (num_skipped)
*num_skipped = n;
return buffer - buffer0;
}
This is called from multiple sites on chains of descriptors.
We do have a check for overflowing the buffer in the while statement.
However, there is no guarantee for make progress. If at some point
in the chain we arrive at a descriptor of neither type we are looking
for and a bLength of 0, size will remain constant and the loop
will go on forever.
AFAICT this is guarded nowhere outside the function against.
So how about the attached patch?
Regards
Oliver
[-- Attachment #2: 0001-USB-find_next_descriptor-prevent-eternal-loop-by-mis.patch --]
[-- Type: text/x-patch, Size: 1294 bytes --]
From 7c18f5673ae416027b813a51ece4e689b4383a6c Mon Sep 17 00:00:00 2001
From: Oliver Neukum <oneukum@suse.com>
Date: Thu, 16 May 2024 15:06:34 +0200
Subject: [PATCH] USB: find_next_descriptor: prevent eternal loop by misformed
descriptors
In find_next_descriptor() is called to operate on chains of descriptors.
The callers make sure that the chain as a whole is of sufficient length
and it is ensured that the buffer is not overflown.
However, the central does not guard against an inner link in the chain
claiming zero length. In that case the loop will make no progress and
go on forever. This case has to be tested for.
Signed-off-by: Oliver Neukum <oneukum@suse.com>
---
drivers/usb/core/config.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 3362af165ef5..65d23fa19b3c 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -34,6 +34,8 @@ static int find_next_descriptor(unsigned char *buffer, int size,
/* Find the next descriptor of type dt1 or dt2 */
while (size > 0) {
h = (struct usb_descriptor_header *) buffer;
+ if (!h->bLength) /* we would loop forever */
+ return 0;
if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2)
break;
buffer += h->bLength;
--
2.45.0
next reply other threads:[~2024-05-16 13:48 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-05-16 13:48 Oliver Neukum [this message]
2024-05-16 16:58 ` revisiting the issue of hardening the USB enumeration parser Alan Stern
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=b94e5037-19da-4cc9-9a8a-28df8ada4795@suse.com \
--to=oneukum@suse.com \
--cc=gregkh@linuxfoundation.org \
--cc=linux-usb@vger.kernel.org \
--cc=stern@rowland.harvard.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox