diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2019-12-10 16:26:11 -0500 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2019-12-11 15:17:39 +0100 |
commit | 8ec321e96e056de84022c032ffea253431a83c3c (patch) | |
tree | 2ed11e54974a5997dd15b2c83eaf09dc0ee8ede8 /drivers/hid/hid-core.c | |
parent | 348b80b273fbf4ce2a307f9e38eadecf37828cad (diff) | |
download | linux-stable-8ec321e96e056de84022c032ffea253431a83c3c.tar.gz linux-stable-8ec321e96e056de84022c032ffea253431a83c3c.tar.bz2 linux-stable-8ec321e96e056de84022c032ffea253431a83c3c.zip |
HID: Fix slab-out-of-bounds read in hid_field_extract
The syzbot fuzzer found a slab-out-of-bounds bug in the HID report
handler. The bug was caused by a report descriptor which included a
field with size 12 bits and count 4899, for a total size of 7349
bytes.
The usbhid driver uses at most a single-page 4-KB buffer for reports.
In the test there wasn't any problem about overflowing the buffer,
since only one byte was received from the device. Rather, the bug
occurred when the HID core tried to extract the data from the report
fields, which caused it to try reading data beyond the end of the
allocated buffer.
This patch fixes the problem by rejecting any report whose total
length exceeds the HID_MAX_BUFFER_SIZE limit (minus one byte to allow
for a possible report index). In theory a device could have a report
longer than that, but if there was such a thing we wouldn't handle it
correctly anyway.
Reported-and-tested-by: syzbot+09ef48aa58261464b621@syzkaller.appspotmail.com
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
CC: <stable@vger.kernel.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-core.c')
-rw-r--r-- | drivers/hid/hid-core.c | 6 |
1 files changed, 6 insertions, 0 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index e0b241bd3070..851fe54ea59e 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -288,6 +288,12 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign offset = report->size; report->size += parser->global.report_size * parser->global.report_count; + /* Total size check: Allow for possible report index byte */ + if (report->size > (HID_MAX_BUFFER_SIZE - 1) << 3) { + hid_err(parser->device, "report is too long\n"); + return -1; + } + if (!parser->local.usage_index) /* Ignore padding fields */ return 0; |