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
commitbc689c2fb406fe5ae3ea591f27752a83113838a6 (patch)
tree36dba24202914356211c75de36494a0b90722672
parent0d707bd5b6ee2c32b11affb0dbb74330109296f8 (diff)
downloadsrc-bc689c2fb406fe5ae3ea591f27752a83113838a6.tar.gz
src-bc689c2fb406fe5ae3ea591f27752a83113838a6.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/12.1/; 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 885c72fe33b0..2913de594200 100644
--- a/lib/libusbhid/parse.c
+++ b/lib/libusbhid/parse.c
@@ -403,26 +403,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 9e9909178fa9..84faf5815890 100644
--- a/sys/dev/usb/usb_hid.c
+++ b/sys/dev/usb/usb_hid.c
@@ -436,36 +436,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);