linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] HID: core: Provide new max_buffer_size attribute to over-ride the default
@ 2023-01-13 15:05 Lee Jones
  2023-01-13 15:05 ` [PATCH 2/2] HID: uhid: Over-ride the default maximum data buffer value with our own Lee Jones
  2023-01-18  9:03 ` [PATCH 1/2] HID: core: Provide new max_buffer_size attribute to over-ride the default Jiri Kosina
  0 siblings, 2 replies; 6+ messages in thread
From: Lee Jones @ 2023-01-13 15:05 UTC (permalink / raw)
  To: lee, jikos, benjamin.tissoires, avid.rheinsberg; +Cc: linux-kernel, linux-input

Presently, when a report is processed, its size is compared solely
against the value specified by user-space.  If the received report ends
up being smaller than this, the remainder of the buffer is zeroed.  That
is, the space between sizeof(csize) (size of the current report) and the
rsize (size provided by the user - i.e. Report Size * Report Count),
which can be handled up to HID_MAX_BUFFER_SIZE (16k).

This is an issue.  In the case of some low-level drivers, the buffers
are significantly smaller than the default 16k.  For instance, in the
case of uhid, the data buffer is a mere UHID_DATA_MAX (4k).  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 <lee@kernel.org>
---
 drivers/hid/hid-core.c | 32 +++++++++++++++++++++++++-------
 include/linux/hid.h    |  3 +++
 2 files changed, 28 insertions(+), 7 deletions(-)

diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index bd47628da6be0..b10383ca8fc05 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -261,6 +261,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
 {
 	struct hid_report *report;
 	struct hid_field *field;
+	unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE;
 	unsigned int usages;
 	unsigned int offset;
 	unsigned int i;
@@ -291,8 +292,11 @@ 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;
 
+	if (parser->device->ll_driver->max_buffer_size)
+		max_buffer_size = parser->device->ll_driver->max_buffer_size;
+
 	/* Total size check: Allow for possible report index byte */
-	if (report->size > (HID_MAX_BUFFER_SIZE - 1) << 3) {
+	if (report->size > (max_buffer_size - 1) << 3) {
 		hid_err(parser->device, "report is too long\n");
 		return -1;
 	}
@@ -1963,6 +1967,7 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *
 	struct hid_report_enum *report_enum = hid->report_enum + type;
 	struct hid_report *report;
 	struct hid_driver *hdrv;
+	int max_buffer_size = HID_MAX_BUFFER_SIZE;
 	u32 rsize, csize = size;
 	u8 *cdata = data;
 	int ret = 0;
@@ -1978,10 +1983,13 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *
 
 	rsize = hid_compute_report_size(report);
 
-	if (report_enum->numbered && rsize >= HID_MAX_BUFFER_SIZE)
-		rsize = HID_MAX_BUFFER_SIZE - 1;
-	else if (rsize > HID_MAX_BUFFER_SIZE)
-		rsize = HID_MAX_BUFFER_SIZE;
+	if (hid->ll_driver->max_buffer_size)
+		max_buffer_size = hid->ll_driver->max_buffer_size;
+
+	if (report_enum->numbered && rsize >= max_buffer_size)
+		rsize = max_buffer_size - 1;
+	else if (rsize > max_buffer_size)
+		rsize = max_buffer_size;
 
 	if (csize < rsize) {
 		dbg_hid("report %d is too short, (%d < %d)\n", report->id,
@@ -2384,7 +2392,12 @@ int hid_hw_raw_request(struct hid_device *hdev,
 		       unsigned char reportnum, __u8 *buf,
 		       size_t len, enum hid_report_type rtype, enum hid_class_request reqtype)
 {
-	if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf)
+	unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE;
+
+	if (hdev->ll_driver->max_buffer_size)
+		max_buffer_size = hdev->ll_driver->max_buffer_size;
+
+	if (len < 1 || len > max_buffer_size || !buf)
 		return -EINVAL;
 
 	return hdev->ll_driver->raw_request(hdev, reportnum, buf, len,
@@ -2403,7 +2416,12 @@ EXPORT_SYMBOL_GPL(hid_hw_raw_request);
  */
 int hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len)
 {
-	if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf)
+	unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE;
+
+	if (hdev->ll_driver->max_buffer_size)
+		max_buffer_size = hdev->ll_driver->max_buffer_size;
+
+	if (len < 1 || len > max_buffer_size || !buf)
 		return -EINVAL;
 
 	if (hdev->ll_driver->output_report)
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 8677ae38599e4..f9b500b26f67c 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -826,6 +826,7 @@ struct hid_driver {
  * @output_report: send output report to device
  * @idle: send idle request to device
  * @may_wakeup: return if device may act as a wakeup source during system-suspend
+ * @max_buffer_size: over-ride maximum data buffer size (default: HID_MAX_BUFFER_SIZE)
  */
 struct hid_ll_driver {
 	int (*start)(struct hid_device *hdev);
@@ -851,6 +852,8 @@ struct hid_ll_driver {
 
 	int (*idle)(struct hid_device *hdev, int report, int idle, int reqtype);
 	bool (*may_wakeup)(struct hid_device *hdev);
+
+	unsigned int max_buffer_size;
 };
 
 extern struct hid_ll_driver i2c_hid_ll_driver;
-- 
2.39.0.314.g84b9a713c41-goog


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/2] HID: uhid: Over-ride the default maximum data buffer value with our own
  2023-01-13 15:05 [PATCH 1/2] HID: core: Provide new max_buffer_size attribute to over-ride the default Lee Jones
@ 2023-01-13 15:05 ` Lee Jones
  2023-01-18  9:03 ` [PATCH 1/2] HID: core: Provide new max_buffer_size attribute to over-ride the default Jiri Kosina
  1 sibling, 0 replies; 6+ messages in thread
From: Lee Jones @ 2023-01-13 15:05 UTC (permalink / raw)
  To: lee, jikos, benjamin.tissoires, avid.rheinsberg; +Cc: linux-kernel, linux-input

The default maximum data buffer size for this interface is UHID_DATA_MAX
(4k).  When data buffers are being processed, ensure this value is used
when ensuring the sanity, rather than a value between the user provided
value and HID_MAX_BUFFER_SIZE (16k).

Signed-off-by: Lee Jones <lee@kernel.org>
---
 drivers/hid/uhid.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 2a918aeb0af13..59ac757c1d471 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -395,6 +395,7 @@ struct hid_ll_driver uhid_hid_driver = {
 	.parse = uhid_hid_parse,
 	.raw_request = uhid_hid_raw_request,
 	.output_report = uhid_hid_output_report,
+	.max_buffer_size = UHID_DATA_MAX,
 };
 EXPORT_SYMBOL_GPL(uhid_hid_driver);
 
-- 
2.39.0.314.g84b9a713c41-goog


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] HID: core: Provide new max_buffer_size attribute to over-ride the default
  2023-01-13 15:05 [PATCH 1/2] HID: core: Provide new max_buffer_size attribute to over-ride the default Lee Jones
  2023-01-13 15:05 ` [PATCH 2/2] HID: uhid: Over-ride the default maximum data buffer value with our own Lee Jones
@ 2023-01-18  9:03 ` Jiri Kosina
  2023-01-18 11:09   ` Lee Jones
  1 sibling, 1 reply; 6+ messages in thread
From: Jiri Kosina @ 2023-01-18  9:03 UTC (permalink / raw)
  To: Lee Jones; +Cc: benjamin.tissoires, avid.rheinsberg, linux-kernel, linux-input

On Fri, 13 Jan 2023, Lee Jones wrote:

> Presently, when a report is processed, its size is compared solely 
> against the value specified by user-space.  

While I am generally fine with the idea, I don't understand this sentence. 
What exactly do you mean by 'specified by user-space'? It's defined as a 
compile-time constant.

Thanks,

-- 
Jiri Kosina
SUSE Labs


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] HID: core: Provide new max_buffer_size attribute to over-ride the default
  2023-01-18  9:03 ` [PATCH 1/2] HID: core: Provide new max_buffer_size attribute to over-ride the default Jiri Kosina
@ 2023-01-18 11:09   ` Lee Jones
  2023-01-18 14:55     ` Jiri Kosina
  0 siblings, 1 reply; 6+ messages in thread
From: Lee Jones @ 2023-01-18 11:09 UTC (permalink / raw)
  To: Jiri Kosina
  Cc: benjamin.tissoires, avid.rheinsberg, linux-kernel, linux-input

On Wed, 18 Jan 2023, Jiri Kosina wrote:

> On Fri, 13 Jan 2023, Lee Jones wrote:
> 
> > Presently, when a report is processed, its size is compared solely 
> > against the value specified by user-space.  
> 
> While I am generally fine with the idea, I don't understand this sentence. 
> What exactly do you mean by 'specified by user-space'? It's defined as a 
> compile-time constant.
> 
> > If the received report ends up being smaller than this, the
> > remainder of the buffer is zeroed. 

Apologies for any ambiguity.

"its size" == "compile-time constant"

Would "its maximum size" read better?

These sentences are an attempt to describe this statement:

    if (csize < rsize) {
        dbg_hid("report %d is too short, (%d < %d)\n", report->id,
            csize, rsize);
        memset(cdata + csize, 0, rsize - csize);
    }

Where csize is "the [size of the] received report" and rsize is the
"value [size] specified by user-space".  Thus, if user-space says the
report will be 8-Bytes (rsize) and it actually only only submits 6-Bytes
(csize), then the subsystem will complain that the "report is too short"
and it will attempt to zero the seemingly unused 2-Bytes.

-- 
Lee Jones [李琼斯]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] HID: core: Provide new max_buffer_size attribute to over-ride the default
  2023-01-18 11:09   ` Lee Jones
@ 2023-01-18 14:55     ` Jiri Kosina
  2023-01-18 15:11       ` Lee Jones
  0 siblings, 1 reply; 6+ messages in thread
From: Jiri Kosina @ 2023-01-18 14:55 UTC (permalink / raw)
  To: Lee Jones; +Cc: benjamin.tissoires, avid.rheinsberg, linux-kernel, linux-input

On Wed, 18 Jan 2023, Lee Jones wrote:

> > > Presently, when a report is processed, its size is compared solely 
> > > against the value specified by user-space.  
> > 
> > While I am generally fine with the idea, I don't understand this sentence. 
> > What exactly do you mean by 'specified by user-space'? It's defined as a 
> > compile-time constant.
> > 
> > > If the received report ends up being smaller than this, the
> > > remainder of the buffer is zeroed. 
> 
> Apologies for any ambiguity.
> 
> "its size" == "compile-time constant"
> 
> Would "its maximum size" read better?

I think that the confusion comes from the fact that the changelog is 
written solely with the UHID usercase on mind ... ? (which is dealt with 
in the independent followup patch).

Thanks,

-- 
Jiri Kosina
SUSE Labs


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] HID: core: Provide new max_buffer_size attribute to over-ride the default
  2023-01-18 14:55     ` Jiri Kosina
@ 2023-01-18 15:11       ` Lee Jones
  0 siblings, 0 replies; 6+ messages in thread
From: Lee Jones @ 2023-01-18 15:11 UTC (permalink / raw)
  To: Jiri Kosina
  Cc: benjamin.tissoires, avid.rheinsberg, linux-kernel, linux-input

On Wed, 18 Jan 2023, Jiri Kosina wrote:

> On Wed, 18 Jan 2023, Lee Jones wrote:
> 
> > > > Presently, when a report is processed, its size is compared solely 
> > > > against the value specified by user-space.  
> > > 
> > > While I am generally fine with the idea, I don't understand this sentence. 
> > > What exactly do you mean by 'specified by user-space'? It's defined as a 
> > > compile-time constant.
> > > 
> > > > If the received report ends up being smaller than this, the
> > > > remainder of the buffer is zeroed. 
> > 
> > Apologies for any ambiguity.
> > 
> > "its size" == "compile-time constant"
> > 
> > Would "its maximum size" read better?
> 
> I think that the confusion comes from the fact that the changelog is 
> written solely with the UHID usercase on mind ... ? (which is dealt with 
> in the independent followup patch).

Quite possibly, yes.  Since this is the way the bug was reported to me
and how I presently view it.  However, I suppose reports do not always
originate from user-space.  Good point.

How would you like me to move forward?  Would you like me to re-write
the commit log to be more generic?

-- 
Lee Jones [李琼斯]

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2023-01-18 15:16 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-13 15:05 [PATCH 1/2] HID: core: Provide new max_buffer_size attribute to over-ride the default Lee Jones
2023-01-13 15:05 ` [PATCH 2/2] HID: uhid: Over-ride the default maximum data buffer value with our own Lee Jones
2023-01-18  9:03 ` [PATCH 1/2] HID: core: Provide new max_buffer_size attribute to over-ride the default Jiri Kosina
2023-01-18 11:09   ` Lee Jones
2023-01-18 14:55     ` Jiri Kosina
2023-01-18 15:11       ` Lee Jones

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).