Skip to content

Commit e29fd84

Browse files
author
Jiri Kosina
committed
Merge branch 'for-6.10/hid-bpf' into for-linus
- updates to HID-BPF infrastructure, with some of the specific fixes (e.g. rdesc fixups) abstracted into separate BPF programs for consumption by libevdev/udev-hid-bpf (Benjamin Tissoires)
2 parents bc5fbae + 89ea968 commit e29fd84

26 files changed

+3834
-278
lines changed

Documentation/hid/hid-bpf.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ Available API that can be used in syscall HID-BPF programs:
179179
-----------------------------------------------------------
180180

181181
.. kernel-doc:: drivers/hid/bpf/hid_bpf_dispatch.c
182-
:functions: hid_bpf_attach_prog hid_bpf_hw_request hid_bpf_allocate_context hid_bpf_release_context
182+
:functions: hid_bpf_attach_prog hid_bpf_hw_request hid_bpf_hw_output_report hid_bpf_input_report hid_bpf_allocate_context hid_bpf_release_context
183183

184184
General overview of a HID-BPF program
185185
=====================================

drivers/hid/bpf/hid_bpf_dispatch.c

Lines changed: 155 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -143,48 +143,6 @@ u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *s
143143
}
144144
EXPORT_SYMBOL_GPL(call_hid_bpf_rdesc_fixup);
145145

146-
/* Disables missing prototype warnings */
147-
__bpf_kfunc_start_defs();
148-
149-
/**
150-
* hid_bpf_get_data - Get the kernel memory pointer associated with the context @ctx
151-
*
152-
* @ctx: The HID-BPF context
153-
* @offset: The offset within the memory
154-
* @rdwr_buf_size: the const size of the buffer
155-
*
156-
* @returns %NULL on error, an %__u8 memory pointer on success
157-
*/
158-
__bpf_kfunc __u8 *
159-
hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr_buf_size)
160-
{
161-
struct hid_bpf_ctx_kern *ctx_kern;
162-
163-
if (!ctx)
164-
return NULL;
165-
166-
ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx);
167-
168-
if (rdwr_buf_size + offset > ctx->allocated_size)
169-
return NULL;
170-
171-
return ctx_kern->data + offset;
172-
}
173-
__bpf_kfunc_end_defs();
174-
175-
/*
176-
* The following set contains all functions we agree BPF programs
177-
* can use.
178-
*/
179-
BTF_KFUNCS_START(hid_bpf_kfunc_ids)
180-
BTF_ID_FLAGS(func, hid_bpf_get_data, KF_RET_NULL)
181-
BTF_KFUNCS_END(hid_bpf_kfunc_ids)
182-
183-
static const struct btf_kfunc_id_set hid_bpf_kfunc_set = {
184-
.owner = THIS_MODULE,
185-
.set = &hid_bpf_kfunc_ids,
186-
};
187-
188146
static int device_match_id(struct device *dev, const void *id)
189147
{
190148
struct hid_device *hdev = to_hid_device(dev);
@@ -281,6 +239,31 @@ static int do_hid_bpf_attach_prog(struct hid_device *hdev, int prog_fd, struct b
281239
/* Disables missing prototype warnings */
282240
__bpf_kfunc_start_defs();
283241

242+
/**
243+
* hid_bpf_get_data - Get the kernel memory pointer associated with the context @ctx
244+
*
245+
* @ctx: The HID-BPF context
246+
* @offset: The offset within the memory
247+
* @rdwr_buf_size: the const size of the buffer
248+
*
249+
* @returns %NULL on error, an %__u8 memory pointer on success
250+
*/
251+
__bpf_kfunc __u8 *
252+
hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr_buf_size)
253+
{
254+
struct hid_bpf_ctx_kern *ctx_kern;
255+
256+
if (!ctx)
257+
return NULL;
258+
259+
ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx);
260+
261+
if (rdwr_buf_size + offset > ctx->allocated_size)
262+
return NULL;
263+
264+
return ctx_kern->data + offset;
265+
}
266+
284267
/**
285268
* hid_bpf_attach_prog - Attach the given @prog_fd to the given HID device
286269
*
@@ -393,6 +376,46 @@ hid_bpf_release_context(struct hid_bpf_ctx *ctx)
393376
put_device(&hid->dev);
394377
}
395378

379+
static int
380+
__hid_bpf_hw_check_params(struct hid_bpf_ctx *ctx, __u8 *buf, size_t *buf__sz,
381+
enum hid_report_type rtype)
382+
{
383+
struct hid_report_enum *report_enum;
384+
struct hid_report *report;
385+
struct hid_device *hdev;
386+
u32 report_len;
387+
388+
/* check arguments */
389+
if (!ctx || !hid_bpf_ops || !buf)
390+
return -EINVAL;
391+
392+
switch (rtype) {
393+
case HID_INPUT_REPORT:
394+
case HID_OUTPUT_REPORT:
395+
case HID_FEATURE_REPORT:
396+
break;
397+
default:
398+
return -EINVAL;
399+
}
400+
401+
if (*buf__sz < 1)
402+
return -EINVAL;
403+
404+
hdev = (struct hid_device *)ctx->hid; /* discard const */
405+
406+
report_enum = hdev->report_enum + rtype;
407+
report = hid_bpf_ops->hid_get_report(report_enum, buf);
408+
if (!report)
409+
return -EINVAL;
410+
411+
report_len = hid_report_len(report);
412+
413+
if (*buf__sz > report_len)
414+
*buf__sz = report_len;
415+
416+
return 0;
417+
}
418+
396419
/**
397420
* hid_bpf_hw_request - Communicate with a HID device
398421
*
@@ -409,24 +432,14 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
409432
enum hid_report_type rtype, enum hid_class_request reqtype)
410433
{
411434
struct hid_device *hdev;
412-
struct hid_report *report;
413-
struct hid_report_enum *report_enum;
435+
size_t size = buf__sz;
414436
u8 *dma_data;
415-
u32 report_len;
416437
int ret;
417438

418439
/* check arguments */
419-
if (!ctx || !hid_bpf_ops || !buf)
420-
return -EINVAL;
421-
422-
switch (rtype) {
423-
case HID_INPUT_REPORT:
424-
case HID_OUTPUT_REPORT:
425-
case HID_FEATURE_REPORT:
426-
break;
427-
default:
428-
return -EINVAL;
429-
}
440+
ret = __hid_bpf_hw_check_params(ctx, buf, &size, rtype);
441+
if (ret)
442+
return ret;
430443

431444
switch (reqtype) {
432445
case HID_REQ_GET_REPORT:
@@ -440,29 +453,16 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
440453
return -EINVAL;
441454
}
442455

443-
if (buf__sz < 1)
444-
return -EINVAL;
445-
446456
hdev = (struct hid_device *)ctx->hid; /* discard const */
447457

448-
report_enum = hdev->report_enum + rtype;
449-
report = hid_bpf_ops->hid_get_report(report_enum, buf);
450-
if (!report)
451-
return -EINVAL;
452-
453-
report_len = hid_report_len(report);
454-
455-
if (buf__sz > report_len)
456-
buf__sz = report_len;
457-
458-
dma_data = kmemdup(buf, buf__sz, GFP_KERNEL);
458+
dma_data = kmemdup(buf, size, GFP_KERNEL);
459459
if (!dma_data)
460460
return -ENOMEM;
461461

462462
ret = hid_bpf_ops->hid_hw_raw_request(hdev,
463463
dma_data[0],
464464
dma_data,
465-
buf__sz,
465+
size,
466466
rtype,
467467
reqtype);
468468

@@ -472,8 +472,90 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
472472
kfree(dma_data);
473473
return ret;
474474
}
475+
476+
/**
477+
* hid_bpf_hw_output_report - Send an output report to a HID device
478+
*
479+
* @ctx: the HID-BPF context previously allocated in hid_bpf_allocate_context()
480+
* @buf: a %PTR_TO_MEM buffer
481+
* @buf__sz: the size of the data to transfer
482+
*
483+
* Returns the number of bytes transferred on success, a negative error code otherwise.
484+
*/
485+
__bpf_kfunc int
486+
hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz)
487+
{
488+
struct hid_device *hdev;
489+
size_t size = buf__sz;
490+
u8 *dma_data;
491+
int ret;
492+
493+
/* check arguments */
494+
ret = __hid_bpf_hw_check_params(ctx, buf, &size, HID_OUTPUT_REPORT);
495+
if (ret)
496+
return ret;
497+
498+
hdev = (struct hid_device *)ctx->hid; /* discard const */
499+
500+
dma_data = kmemdup(buf, size, GFP_KERNEL);
501+
if (!dma_data)
502+
return -ENOMEM;
503+
504+
ret = hid_bpf_ops->hid_hw_output_report(hdev,
505+
dma_data,
506+
size);
507+
508+
kfree(dma_data);
509+
return ret;
510+
}
511+
512+
/**
513+
* hid_bpf_input_report - Inject a HID report in the kernel from a HID device
514+
*
515+
* @ctx: the HID-BPF context previously allocated in hid_bpf_allocate_context()
516+
* @type: the type of the report (%HID_INPUT_REPORT, %HID_FEATURE_REPORT, %HID_OUTPUT_REPORT)
517+
* @buf: a %PTR_TO_MEM buffer
518+
* @buf__sz: the size of the data to transfer
519+
*
520+
* Returns %0 on success, a negative error code otherwise.
521+
*/
522+
__bpf_kfunc int
523+
hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf,
524+
const size_t buf__sz)
525+
{
526+
struct hid_device *hdev;
527+
size_t size = buf__sz;
528+
int ret;
529+
530+
/* check arguments */
531+
ret = __hid_bpf_hw_check_params(ctx, buf, &size, type);
532+
if (ret)
533+
return ret;
534+
535+
hdev = (struct hid_device *)ctx->hid; /* discard const */
536+
537+
return hid_bpf_ops->hid_input_report(hdev, type, buf, size, 0);
538+
}
475539
__bpf_kfunc_end_defs();
476540

541+
/*
542+
* The following set contains all functions we agree BPF programs
543+
* can use.
544+
*/
545+
BTF_KFUNCS_START(hid_bpf_kfunc_ids)
546+
BTF_ID_FLAGS(func, hid_bpf_get_data, KF_RET_NULL)
547+
BTF_ID_FLAGS(func, hid_bpf_allocate_context, KF_ACQUIRE | KF_RET_NULL | KF_SLEEPABLE)
548+
BTF_ID_FLAGS(func, hid_bpf_release_context, KF_RELEASE | KF_SLEEPABLE)
549+
BTF_ID_FLAGS(func, hid_bpf_hw_request, KF_SLEEPABLE)
550+
BTF_ID_FLAGS(func, hid_bpf_hw_output_report, KF_SLEEPABLE)
551+
BTF_ID_FLAGS(func, hid_bpf_input_report, KF_SLEEPABLE)
552+
BTF_KFUNCS_END(hid_bpf_kfunc_ids)
553+
554+
static const struct btf_kfunc_id_set hid_bpf_kfunc_set = {
555+
.owner = THIS_MODULE,
556+
.set = &hid_bpf_kfunc_ids,
557+
};
558+
477559
/* our HID-BPF entrypoints */
478560
BTF_SET8_START(hid_bpf_fmodret_ids)
479561
BTF_ID_FLAGS(func, hid_bpf_device_event)
@@ -492,6 +574,8 @@ BTF_ID_FLAGS(func, hid_bpf_attach_prog)
492574
BTF_ID_FLAGS(func, hid_bpf_allocate_context, KF_ACQUIRE | KF_RET_NULL)
493575
BTF_ID_FLAGS(func, hid_bpf_release_context, KF_RELEASE)
494576
BTF_ID_FLAGS(func, hid_bpf_hw_request)
577+
BTF_ID_FLAGS(func, hid_bpf_hw_output_report)
578+
BTF_ID_FLAGS(func, hid_bpf_input_report)
495579
BTF_KFUNCS_END(hid_bpf_syscall_kfunc_ids)
496580

497581
static const struct btf_kfunc_id_set hid_bpf_syscall_kfunc_set = {

0 commit comments

Comments
 (0)