Skip to content

Commit 6cd735f

Browse files
author
Benjamin Tissoires
committed
HID: bpf: protect HID-BPF prog_list access by a SRCU
We want to add sleepable callbacks for hid_hw_raw_request() and hid_hw_output_report(), but we can not use a plain RCU for those. Prepare for a SRCU so we can extend HID-BPF. This changes a little bit how hid_bpf_device_init() behaves, as it may now fail, so there is a tiny hid-core.c change to accommodate for this. Link: https://patch.msgid.link/[email protected] Acked-by: Jiri Kosina <[email protected]> Signed-off-by: Benjamin Tissoires <[email protected]>
1 parent 67eccf1 commit 6cd735f

File tree

4 files changed

+18
-4
lines changed

4 files changed

+18
-4
lines changed

drivers/hid/bpf/hid_bpf_dispatch.c

+5-1
Original file line numberDiff line numberDiff line change
@@ -506,13 +506,17 @@ void hid_bpf_destroy_device(struct hid_device *hdev)
506506
hdev->bpf.destroyed = true;
507507

508508
__hid_bpf_ops_destroy_device(hdev);
509+
510+
synchronize_srcu(&hdev->bpf.srcu);
511+
cleanup_srcu_struct(&hdev->bpf.srcu);
509512
}
510513
EXPORT_SYMBOL_GPL(hid_bpf_destroy_device);
511514

512-
void hid_bpf_device_init(struct hid_device *hdev)
515+
int hid_bpf_device_init(struct hid_device *hdev)
513516
{
514517
INIT_LIST_HEAD(&hdev->bpf.prog_list);
515518
mutex_init(&hdev->bpf.prog_list_lock);
519+
return init_srcu_struct(&hdev->bpf.srcu);
516520
}
517521
EXPORT_SYMBOL_GPL(hid_bpf_device_init);
518522

drivers/hid/bpf/hid_bpf_struct_ops.c

+2
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ static int hid_bpf_reg(void *kdata)
214214
list_add_rcu(&ops->list, &hdev->bpf.prog_list);
215215
else
216216
list_add_tail_rcu(&ops->list, &hdev->bpf.prog_list);
217+
synchronize_srcu(&hdev->bpf.srcu);
217218

218219
out_unlock:
219220
mutex_unlock(&hdev->bpf.prog_list_lock);
@@ -244,6 +245,7 @@ static void hid_bpf_unreg(void *kdata)
244245
mutex_lock(&hdev->bpf.prog_list_lock);
245246

246247
list_del_rcu(&ops->list);
248+
synchronize_srcu(&hdev->bpf.srcu);
247249

248250
reconnect = hdev->bpf.rdesc_ops == ops;
249251
if (reconnect)

drivers/hid/hid-core.c

+7-1
Original file line numberDiff line numberDiff line change
@@ -2875,9 +2875,15 @@ struct hid_device *hid_allocate_device(void)
28752875
mutex_init(&hdev->ll_open_lock);
28762876
kref_init(&hdev->ref);
28772877

2878-
hid_bpf_device_init(hdev);
2878+
ret = hid_bpf_device_init(hdev);
2879+
if (ret)
2880+
goto out_err;
28792881

28802882
return hdev;
2883+
2884+
out_err:
2885+
hid_destroy_device(hdev);
2886+
return ERR_PTR(ret);
28812887
}
28822888
EXPORT_SYMBOL_GPL(hid_allocate_device);
28832889

include/linux/hid_bpf.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <linux/bpf.h>
77
#include <linux/mutex.h>
8+
#include <linux/srcu.h>
89
#include <uapi/linux/hid.h>
910

1011
struct hid_device;
@@ -145,6 +146,7 @@ struct hid_bpf {
145146
struct hid_bpf_ops *rdesc_ops;
146147
struct list_head prog_list;
147148
struct mutex prog_list_lock; /* protects prog_list update */
149+
struct srcu_struct srcu; /* protects prog_list read-only access */
148150
};
149151

150152
#ifdef CONFIG_HID_BPF
@@ -153,7 +155,7 @@ u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type t
153155
int hid_bpf_connect_device(struct hid_device *hdev);
154156
void hid_bpf_disconnect_device(struct hid_device *hdev);
155157
void hid_bpf_destroy_device(struct hid_device *hid);
156-
void hid_bpf_device_init(struct hid_device *hid);
158+
int hid_bpf_device_init(struct hid_device *hid);
157159
u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size);
158160
#else /* CONFIG_HID_BPF */
159161
static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type,
@@ -162,7 +164,7 @@ static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid
162164
static inline int hid_bpf_connect_device(struct hid_device *hdev) { return 0; }
163165
static inline void hid_bpf_disconnect_device(struct hid_device *hdev) {}
164166
static inline void hid_bpf_destroy_device(struct hid_device *hid) {}
165-
static inline void hid_bpf_device_init(struct hid_device *hid) {}
167+
static inline int hid_bpf_device_init(struct hid_device *hid) { return 0; }
166168
#define call_hid_bpf_rdesc_fixup(_hdev, _rdesc, _size) \
167169
((u8 *)kmemdup(_rdesc, *(_size), GFP_KERNEL))
168170

0 commit comments

Comments
 (0)