From 4d99af4084655b8bf6ff0797328fd23c118adc3a Mon Sep 17 00:00:00 2001 From: gordon Date: Tue, 9 Jun 2020 16:13:54 +0000 Subject: [PATCH] Fix USB HID descriptor parsing error. Approved by: so Approved by: re (implicit) Security: FreeBSD-SA-20:17.usb Security: CVE-2020-7456 --- lib/libusbhid/parse.c | 34 +++++++++++++++------------- sys/dev/usb/usb_hid.c | 52 +++++++++++++++++++++---------------------- 2 files changed, 44 insertions(+), 42 deletions(-) diff --git a/lib/libusbhid/parse.c b/lib/libusbhid/parse.c index 7a2b3f41eea..943af269653 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 80491802965..8893d47d669 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); -- 2.45.0