Skip to content

Commit b1a37ed

Browse files
lag-linaroJiri Kosina
authored andcommitted
HID: core: Provide new max_buffer_size attribute to over-ride the default
Presently, when a report is processed, its proposed size, provided by the user of the API (as Report Size * Report Count) is compared against the subsystem default HID_MAX_BUFFER_SIZE (16k). However, some low-level HID drivers allocate a reduced amount of memory to their buffers (e.g. UHID only allocates UHID_DATA_MAX (4k) buffers), rending this check inadequate in some cases. In these circumstances, if the received report ends up being smaller than the proposed report size, the remainder of the buffer is zeroed. That is, the space between sizeof(csize) (size of the current report) and the rsize (size proposed i.e. Report Size * Report Count), which can be handled up to HID_MAX_BUFFER_SIZE (16k). Meaning that memset() shoots straight past the end of the buffer boundary and starts zeroing out in-use values, often resulting in calamity. This patch introduces a new variable into 'struct hid_ll_driver' where individual low-level drivers can over-ride the default maximum value of HID_MAX_BUFFER_SIZE (16k) with something more sympathetic to the interface. Signed-off-by: Lee Jones <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 6c71297 commit b1a37ed

File tree

2 files changed

+28
-7
lines changed

2 files changed

+28
-7
lines changed

drivers/hid/hid-core.c

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
256256
{
257257
struct hid_report *report;
258258
struct hid_field *field;
259+
unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE;
259260
unsigned int usages;
260261
unsigned int offset;
261262
unsigned int i;
@@ -286,8 +287,11 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
286287
offset = report->size;
287288
report->size += parser->global.report_size * parser->global.report_count;
288289

290+
if (parser->device->ll_driver->max_buffer_size)
291+
max_buffer_size = parser->device->ll_driver->max_buffer_size;
292+
289293
/* Total size check: Allow for possible report index byte */
290-
if (report->size > (HID_MAX_BUFFER_SIZE - 1) << 3) {
294+
if (report->size > (max_buffer_size - 1) << 3) {
291295
hid_err(parser->device, "report is too long\n");
292296
return -1;
293297
}
@@ -1963,6 +1967,7 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *
19631967
struct hid_report_enum *report_enum = hid->report_enum + type;
19641968
struct hid_report *report;
19651969
struct hid_driver *hdrv;
1970+
int max_buffer_size = HID_MAX_BUFFER_SIZE;
19661971
u32 rsize, csize = size;
19671972
u8 *cdata = data;
19681973
int ret = 0;
@@ -1978,10 +1983,13 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *
19781983

19791984
rsize = hid_compute_report_size(report);
19801985

1981-
if (report_enum->numbered && rsize >= HID_MAX_BUFFER_SIZE)
1982-
rsize = HID_MAX_BUFFER_SIZE - 1;
1983-
else if (rsize > HID_MAX_BUFFER_SIZE)
1984-
rsize = HID_MAX_BUFFER_SIZE;
1986+
if (hid->ll_driver->max_buffer_size)
1987+
max_buffer_size = hid->ll_driver->max_buffer_size;
1988+
1989+
if (report_enum->numbered && rsize >= max_buffer_size)
1990+
rsize = max_buffer_size - 1;
1991+
else if (rsize > max_buffer_size)
1992+
rsize = max_buffer_size;
19851993

19861994
if (csize < rsize) {
19871995
dbg_hid("report %d is too short, (%d < %d)\n", report->id,
@@ -2396,7 +2404,12 @@ int hid_hw_raw_request(struct hid_device *hdev,
23962404
unsigned char reportnum, __u8 *buf,
23972405
size_t len, enum hid_report_type rtype, enum hid_class_request reqtype)
23982406
{
2399-
if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf)
2407+
unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE;
2408+
2409+
if (hdev->ll_driver->max_buffer_size)
2410+
max_buffer_size = hdev->ll_driver->max_buffer_size;
2411+
2412+
if (len < 1 || len > max_buffer_size || !buf)
24002413
return -EINVAL;
24012414

24022415
return hdev->ll_driver->raw_request(hdev, reportnum, buf, len,
@@ -2415,7 +2428,12 @@ EXPORT_SYMBOL_GPL(hid_hw_raw_request);
24152428
*/
24162429
int hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len)
24172430
{
2418-
if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf)
2431+
unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE;
2432+
2433+
if (hdev->ll_driver->max_buffer_size)
2434+
max_buffer_size = hdev->ll_driver->max_buffer_size;
2435+
2436+
if (len < 1 || len > max_buffer_size || !buf)
24192437
return -EINVAL;
24202438

24212439
if (hdev->ll_driver->output_report)

include/linux/hid.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,7 @@ struct hid_driver {
834834
* @output_report: send output report to device
835835
* @idle: send idle request to device
836836
* @may_wakeup: return if device may act as a wakeup source during system-suspend
837+
* @max_buffer_size: over-ride maximum data buffer size (default: HID_MAX_BUFFER_SIZE)
837838
*/
838839
struct hid_ll_driver {
839840
int (*start)(struct hid_device *hdev);
@@ -859,6 +860,8 @@ struct hid_ll_driver {
859860

860861
int (*idle)(struct hid_device *hdev, int report, int idle, int reqtype);
861862
bool (*may_wakeup)(struct hid_device *hdev);
863+
864+
unsigned int max_buffer_size;
862865
};
863866

864867
extern bool hid_is_usb(const struct hid_device *hdev);

0 commit comments

Comments
 (0)