Skip to content

Commit 7583910

Browse files
author
Benjamin Tissoires
committed
HID: bpf: prevent infinite recursions with hid_hw_raw_requests hooks
When we attach a sleepable hook to hid_hw_raw_requests, we can (and in many cases should) call ourself hid_bpf_raw_request(), to actually fetch data from the device itself. However, this means that we might enter an infinite loop between hid_hw_raw_requests hooks and hid_bpf_hw_request() call. To prevent that, if a hid_bpf_hw_request() call is emitted, we prevent any new call of this kfunc by storing the information in the context. This way we can always trace/monitor/filter the incoming bpf requests, while preventing those loops to happen. I don't think exposing "from_bpf" is very interesting because while writing such a bpf program, you need to match at least the report number and/or the source of the call. So a blind "if there is a hid_hw_raw_request() call, I'm emitting another one" makes no real sense. Link: https://patch.msgid.link/[email protected] Acked-by: Jiri Kosina <[email protected]> Signed-off-by: Benjamin Tissoires <[email protected]>
1 parent 8bd0488 commit 7583910

File tree

6 files changed

+20
-11
lines changed

6 files changed

+20
-11
lines changed

drivers/hid/bpf/hid_bpf_dispatch.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ int dispatch_hid_bpf_raw_requests(struct hid_device *hdev,
7878
unsigned char reportnum, u8 *buf,
7979
u32 size, enum hid_report_type rtype,
8080
enum hid_class_request reqtype,
81-
u64 source)
81+
u64 source, bool from_bpf)
8282
{
8383
struct hid_bpf_ctx_kern ctx_kern = {
8484
.ctx = {
@@ -87,6 +87,7 @@ int dispatch_hid_bpf_raw_requests(struct hid_device *hdev,
8787
.size = size,
8888
},
8989
.data = buf,
90+
.from_bpf = from_bpf,
9091
};
9192
struct hid_bpf_ops *e;
9293
int ret, idx;
@@ -364,11 +365,17 @@ __bpf_kfunc int
364365
hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
365366
enum hid_report_type rtype, enum hid_class_request reqtype)
366367
{
368+
struct hid_bpf_ctx_kern *ctx_kern;
367369
struct hid_device *hdev;
368370
size_t size = buf__sz;
369371
u8 *dma_data;
370372
int ret;
371373

374+
ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx);
375+
376+
if (ctx_kern->from_bpf)
377+
return -EDEADLOCK;
378+
372379
/* check arguments */
373380
ret = __hid_bpf_hw_check_params(ctx, buf, &size, rtype);
374381
if (ret)
@@ -398,7 +405,8 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
398405
size,
399406
rtype,
400407
reqtype,
401-
(__u64)ctx);
408+
(__u64)ctx,
409+
true); /* prevent infinite recursions */
402410

403411
if (ret > 0)
404412
memcpy(buf, dma_data, ret);

drivers/hid/bpf/hid_bpf_dispatch.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
struct hid_bpf_ctx_kern {
99
struct hid_bpf_ctx ctx;
1010
u8 *data;
11+
bool from_bpf;
1112
};
1213

1314
struct hid_device *hid_get_device(unsigned int hid_id);

drivers/hid/hid-core.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2403,7 +2403,7 @@ int __hid_hw_raw_request(struct hid_device *hdev,
24032403
unsigned char reportnum, __u8 *buf,
24042404
size_t len, enum hid_report_type rtype,
24052405
enum hid_class_request reqtype,
2406-
__u64 source)
2406+
__u64 source, bool from_bpf)
24072407
{
24082408
unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE;
24092409
int ret;
@@ -2415,7 +2415,7 @@ int __hid_hw_raw_request(struct hid_device *hdev,
24152415
return -EINVAL;
24162416

24172417
ret = dispatch_hid_bpf_raw_requests(hdev, reportnum, buf, len, rtype,
2418-
reqtype, source);
2418+
reqtype, source, from_bpf);
24192419
if (ret)
24202420
return ret;
24212421

@@ -2441,7 +2441,7 @@ int hid_hw_raw_request(struct hid_device *hdev,
24412441
unsigned char reportnum, __u8 *buf,
24422442
size_t len, enum hid_report_type rtype, enum hid_class_request reqtype)
24432443
{
2444-
return __hid_hw_raw_request(hdev, reportnum, buf, len, rtype, reqtype, 0);
2444+
return __hid_hw_raw_request(hdev, reportnum, buf, len, rtype, reqtype, 0, false);
24452445
}
24462446
EXPORT_SYMBOL_GPL(hid_hw_raw_request);
24472447

drivers/hid/hidraw.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
151151
}
152152

153153
ret = __hid_hw_raw_request(dev, buf[0], buf, count, report_type,
154-
HID_REQ_SET_REPORT, (__u64)file);
154+
HID_REQ_SET_REPORT, (__u64)file, false);
155155

156156
out_free:
157157
kfree(buf);
@@ -228,7 +228,7 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t
228228
}
229229

230230
ret = __hid_hw_raw_request(dev, report_number, buf, count, report_type,
231-
HID_REQ_GET_REPORT, (__u64)file);
231+
HID_REQ_GET_REPORT, (__u64)file, false);
232232

233233
if (ret < 0)
234234
goto out_free;

include/linux/hid.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1129,7 +1129,7 @@ int __hid_hw_raw_request(struct hid_device *hdev,
11291129
unsigned char reportnum, __u8 *buf,
11301130
size_t len, enum hid_report_type rtype,
11311131
enum hid_class_request reqtype,
1132-
__u64 source);
1132+
__u64 source, bool from_bpf);
11331133
int __hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len, __u64 source);
11341134
int hid_hw_raw_request(struct hid_device *hdev,
11351135
unsigned char reportnum, __u8 *buf,

include/linux/hid_bpf.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ struct hid_ops {
6868
unsigned char reportnum, __u8 *buf,
6969
size_t len, enum hid_report_type rtype,
7070
enum hid_class_request reqtype,
71-
__u64 source);
71+
__u64 source, bool from_bpf);
7272
int (*hid_hw_output_report)(struct hid_device *hdev, __u8 *buf, size_t len,
7373
__u64 source);
7474
int (*hid_input_report)(struct hid_device *hid, enum hid_report_type type,
@@ -181,7 +181,7 @@ int dispatch_hid_bpf_raw_requests(struct hid_device *hdev,
181181
unsigned char reportnum, __u8 *buf,
182182
u32 size, enum hid_report_type rtype,
183183
enum hid_class_request reqtype,
184-
__u64 source);
184+
__u64 source, bool from_bpf);
185185
int hid_bpf_connect_device(struct hid_device *hdev);
186186
void hid_bpf_disconnect_device(struct hid_device *hdev);
187187
void hid_bpf_destroy_device(struct hid_device *hid);
@@ -195,7 +195,7 @@ static inline int dispatch_hid_bpf_raw_requests(struct hid_device *hdev,
195195
unsigned char reportnum, u8 *buf,
196196
u32 size, enum hid_report_type rtype,
197197
enum hid_class_request reqtype,
198-
u64 source) { return 0; }
198+
u64 source, bool from_bpf) { return 0; }
199199
static inline int hid_bpf_connect_device(struct hid_device *hdev) { return 0; }
200200
static inline void hid_bpf_disconnect_device(struct hid_device *hdev) {}
201201
static inline void hid_bpf_destroy_device(struct hid_device *hid) {}

0 commit comments

Comments
 (0)