USB HID descriptors may push/pop the current state to allow
description of items residing in a so-called union. FreeBSD currently only supports 4 such pop levels. If the push level is not restored within the processing of the same HID item, an invalid memory location may be used for subsequent HID item processing. Verify that the push level is always valid when processing HID items. Reported by: Andy Nguyen (Google) MFC after: 3 days Sponsored by: Mellanox Technologies
This commit is contained in:
parent
48f25cc3c2
commit
eff8154913
@ -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];
|
||||
}
|
||||
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;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -436,22 +436,26 @@ hid_get_item(struct hid_data *s, struct hid_item *h)
|
||||
s->loc_count = dval & mask;
|
||||
break;
|
||||
case 10: /* Push */
|
||||
/* stop parsing, if invalid push level */
|
||||
if ((s->pushlevel + 1) >= MAXPUSH) {
|
||||
DPRINTFN(0, "Cannot push item @ %d\n", s->pushlevel);
|
||||
return (0);
|
||||
}
|
||||
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);
|
||||
}
|
||||
break;
|
||||
case 11: /* Pop */
|
||||
/* stop parsing, if invalid push level */
|
||||
if (s->pushlevel == 0) {
|
||||
DPRINTFN(0, "Cannot pop item @ 0\n");
|
||||
return (0);
|
||||
}
|
||||
s->pushlevel --;
|
||||
if (s->pushlevel < MAXPUSH) {
|
||||
/* preserve position */
|
||||
oldpos = c->loc.pos;
|
||||
c = &s->cur[s->pushlevel];
|
||||
@ -462,10 +466,6 @@ hid_get_item(struct hid_data *s, struct hid_item *h)
|
||||
c->loc.pos = oldpos;
|
||||
c->loc.size = 0;
|
||||
c->loc.count = 0;
|
||||
} else {
|
||||
DPRINTFN(0, "Cannot pop "
|
||||
"item @ %d\n", s->pushlevel);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DPRINTFN(0, "Global bTag=%d\n", bTag);
|
||||
|
Loading…
Reference in New Issue
Block a user