aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGordon Tetlow <gordon@FreeBSD.org>2020-06-09 16:13:54 +0000
committerGordon Tetlow <gordon@FreeBSD.org>2020-06-09 16:13:54 +0000
commit6148d12361aa7dfdec8972eb63b9af30c25fde9a (patch)
tree444d1e0a8c9e325353a77c87ae960f08a5d921c0
parent3b0e7a0da27381c2a786977d6fbf2a1422123c5d (diff)
downloadsrc-6148d12361aa7dfdec8972eb63b9af30c25fde9a.tar.gz
src-6148d12361aa7dfdec8972eb63b9af30c25fde9a.zip
Fix USB HID descriptor parsing error.
Approved by: so Approved by: re (implicit) Security: FreeBSD-SA-20:17.usb Security: CVE-2020-7456
Notes
Notes: svn path=/releng/11.4/; revision=361972
-rw-r--r--lib/libusbhid/parse.c34
-rw-r--r--sys/dev/usb/usb_hid.c52
2 files changed, 44 insertions, 42 deletions
diff --git a/lib/libusbhid/parse.c b/lib/libusbhid/parse.c
index 7a2b3f41eea9..943af2696536 100644
--- a/lib/libusbhid/parse.c
+++ b/lib/libusbhid/parse.c
@@ -401,26 +401,28 @@ hid_get_item_raw(hid_data_t s, hid_item_t *h)
s->loc_count = dval & mask;
break;
case 10: /* Push */
+ /* stop parsing, if invalid push level */
+ if ((s->pushlevel + 1) >= MAXPUSH)
+ return (0);
s->pushlevel ++;
- if (s->pushlevel < MAXPUSH) {
- s->cur[s->pushlevel] = *c;
- /* store size and count */
- c->report_size = s->loc_size;
- c->report_count = s->loc_count;
- /* update current item pointer */
- c = &s->cur[s->pushlevel];
- }
+ s->cur[s->pushlevel] = *c;
+ /* store size and count */
+ c->report_size = s->loc_size;
+ c->report_count = s->loc_count;
+ /* update current item pointer */
+ c = &s->cur[s->pushlevel];
break;
case 11: /* Pop */
+ /* stop parsing, if invalid push level */
+ if (s->pushlevel == 0)
+ return (0);
s->pushlevel --;
- if (s->pushlevel < MAXPUSH) {
- c = &s->cur[s->pushlevel];
- /* restore size and count */
- s->loc_size = c->report_size;
- s->loc_count = c->report_count;
- c->report_size = 0;
- c->report_count = 0;
- }
+ c = &s->cur[s->pushlevel];
+ /* restore size and count */
+ s->loc_size = c->report_size;
+ s->loc_count = c->report_count;
+ c->report_size = 0;
+ c->report_count = 0;
break;
default:
break;
diff --git a/sys/dev/usb/usb_hid.c b/sys/dev/usb/usb_hid.c
index 80491802965f..8893d47d6693 100644
--- a/sys/dev/usb/usb_hid.c
+++ b/sys/dev/usb/usb_hid.c
@@ -434,36 +434,36 @@ hid_get_item(struct hid_data *s, struct hid_item *h)
s->loc_count = dval & mask;
break;
case 10: /* Push */
- s->pushlevel ++;
- if (s->pushlevel < MAXPUSH) {
- s->cur[s->pushlevel] = *c;
- /* store size and count */
- c->loc.size = s->loc_size;
- c->loc.count = s->loc_count;
- /* update current item pointer */
- c = &s->cur[s->pushlevel];
- } else {
- DPRINTFN(0, "Cannot push "
- "item @ %d\n", s->pushlevel);
+ /* stop parsing, if invalid push level */
+ if ((s->pushlevel + 1) >= MAXPUSH) {
+ DPRINTFN(0, "Cannot push item @ %d\n", s->pushlevel);
+ return (0);
}
+ s->pushlevel ++;
+ s->cur[s->pushlevel] = *c;
+ /* store size and count */
+ c->loc.size = s->loc_size;
+ c->loc.count = s->loc_count;
+ /* update current item pointer */
+ c = &s->cur[s->pushlevel];
break;
case 11: /* Pop */
- s->pushlevel --;
- if (s->pushlevel < MAXPUSH) {
- /* preserve position */
- oldpos = c->loc.pos;
- c = &s->cur[s->pushlevel];
- /* restore size and count */
- s->loc_size = c->loc.size;
- s->loc_count = c->loc.count;
- /* set default item location */
- c->loc.pos = oldpos;
- c->loc.size = 0;
- c->loc.count = 0;
- } else {
- DPRINTFN(0, "Cannot pop "
- "item @ %d\n", s->pushlevel);
+ /* stop parsing, if invalid push level */
+ if (s->pushlevel == 0) {
+ DPRINTFN(0, "Cannot pop item @ 0\n");
+ return (0);
}
+ s->pushlevel --;
+ /* preserve position */
+ oldpos = c->loc.pos;
+ c = &s->cur[s->pushlevel];
+ /* restore size and count */
+ s->loc_size = c->loc.size;
+ s->loc_count = c->loc.count;
+ /* set default item location */
+ c->loc.pos = oldpos;
+ c->loc.size = 0;
+ c->loc.count = 0;
break;
default:
DPRINTFN(0, "Global bTag=%d\n", bTag);