Turns out that USB, I2C and other transport drivers (except uhid which
just passes the data) still need to have the report ID in the first
byte.

Because they expect the first byte to be the report ID or 0, when the
report ID is 0, they strip that first byte before forwarding to the
device. This means that the transport layer forwards a buffer of size
N-1 to the device, which gets rejected.

Fixes: 5599f8019661 ("HID: bpf: export hid_hw_output_report as a BPF kfunc")
Signed-off-by: Benjamin Tissoires <[email protected]>
---
 drivers/hid/bpf/hid_bpf_dispatch.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c 
b/drivers/hid/bpf/hid_bpf_dispatch.c
index 536f6d01fd14..b1de1dd0f21d 100644
--- a/drivers/hid/bpf/hid_bpf_dispatch.c
+++ b/drivers/hid/bpf/hid_bpf_dispatch.c
@@ -359,7 +359,7 @@ hid_bpf_release_context(struct hid_bpf_ctx *ctx)
 
 static int
 __hid_bpf_hw_check_params(struct hid_bpf_ctx *ctx, __u8 *buf, size_t *buf__sz,
-                         enum hid_report_type rtype)
+                         enum hid_report_type rtype, bool hw_request)
 {
        struct hid_report_enum *report_enum;
        struct hid_report *report;
@@ -388,6 +388,10 @@ __hid_bpf_hw_check_params(struct hid_bpf_ctx *ctx, __u8 
*buf, size_t *buf__sz,
 
        report_len = hid_report_len(report);
 
+       /* unnumbered reports need to have a report ID reserved in the first 
byte */
+       if (hw_request && report_enum->numbered == 0)
+               report_len += 1;
+
        if (*buf__sz > report_len)
                *buf__sz = report_len;
 
@@ -420,7 +424,7 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, 
size_t buf__sz,
                return -EDEADLOCK;
 
        /* check arguments */
-       ret = __hid_bpf_hw_check_params(ctx, buf, &size, rtype);
+       ret = __hid_bpf_hw_check_params(ctx, buf, &size, rtype, true);
        if (ret)
                return ret;
 
@@ -480,7 +484,7 @@ hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 
*buf, size_t buf__sz)
                return -EDEADLOCK;
 
        /* check arguments */
-       ret = __hid_bpf_hw_check_params(ctx, buf, &size, HID_OUTPUT_REPORT);
+       ret = __hid_bpf_hw_check_params(ctx, buf, &size, HID_OUTPUT_REPORT, 
true);
        if (ret)
                return ret;
 
@@ -506,7 +510,7 @@ __hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum 
hid_report_type type, u8 *b
                return -EDEADLOCK;
 
        /* check arguments */
-       ret = __hid_bpf_hw_check_params(ctx, buf, &size, type);
+       ret = __hid_bpf_hw_check_params(ctx, buf, &size, type, false);
        if (ret)
                return ret;
 

-- 
2.55.0


Reply via email to