]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
HID: bpf: protect HID-BPF prog_list access by a SRCU
authorBenjamin Tissoires <bentiss@kernel.org>
Wed, 26 Jun 2024 13:46:24 +0000 (15:46 +0200)
committerBenjamin Tissoires <bentiss@kernel.org>
Thu, 27 Jun 2024 08:58:22 +0000 (10:58 +0200)
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/20240626-hid_hw_req_bpf-v2-3-cfd60fb6c79f@kernel.org
Acked-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
drivers/hid/bpf/hid_bpf_dispatch.c
drivers/hid/bpf/hid_bpf_struct_ops.c
drivers/hid/hid-core.c
include/linux/hid_bpf.h

index 2df31decaac3f09ebbfe0a7531fe8a832f881082..c026248e3d73265c30235ad8f640c722dbe082f1 100644 (file)
@@ -506,13 +506,17 @@ void hid_bpf_destroy_device(struct hid_device *hdev)
        hdev->bpf.destroyed = true;
 
        __hid_bpf_ops_destroy_device(hdev);
+
+       synchronize_srcu(&hdev->bpf.srcu);
+       cleanup_srcu_struct(&hdev->bpf.srcu);
 }
 EXPORT_SYMBOL_GPL(hid_bpf_destroy_device);
 
-void hid_bpf_device_init(struct hid_device *hdev)
+int hid_bpf_device_init(struct hid_device *hdev)
 {
        INIT_LIST_HEAD(&hdev->bpf.prog_list);
        mutex_init(&hdev->bpf.prog_list_lock);
+       return init_srcu_struct(&hdev->bpf.srcu);
 }
 EXPORT_SYMBOL_GPL(hid_bpf_device_init);
 
index 8063db1c8d62d18ea2dba19be98bec76dec95c6b..d34731a1b45788eb69c05ae5511c14e522b0bc72 100644 (file)
@@ -214,6 +214,7 @@ static int hid_bpf_reg(void *kdata)
                list_add_rcu(&ops->list, &hdev->bpf.prog_list);
        else
                list_add_tail_rcu(&ops->list, &hdev->bpf.prog_list);
+       synchronize_srcu(&hdev->bpf.srcu);
 
 out_unlock:
        mutex_unlock(&hdev->bpf.prog_list_lock);
@@ -244,6 +245,7 @@ static void hid_bpf_unreg(void *kdata)
        mutex_lock(&hdev->bpf.prog_list_lock);
 
        list_del_rcu(&ops->list);
+       synchronize_srcu(&hdev->bpf.srcu);
 
        reconnect = hdev->bpf.rdesc_ops == ops;
        if (reconnect)
index 0775a32f5272689a1a58c4572aeb51b4a6e372c9..ad08289752da0387a8260a6893547b030ccb6b83 100644 (file)
@@ -2875,9 +2875,15 @@ struct hid_device *hid_allocate_device(void)
        mutex_init(&hdev->ll_open_lock);
        kref_init(&hdev->ref);
 
-       hid_bpf_device_init(hdev);
+       ret = hid_bpf_device_init(hdev);
+       if (ret)
+               goto out_err;
 
        return hdev;
+
+out_err:
+       hid_destroy_device(hdev);
+       return ERR_PTR(ret);
 }
 EXPORT_SYMBOL_GPL(hid_allocate_device);
 
index a54741db0415c2e97bb09549b05396cb761c507a..f93845de5cac8e6dd29ae58cbe6c161ba96f6286 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <linux/bpf.h>
 #include <linux/mutex.h>
+#include <linux/srcu.h>
 #include <uapi/linux/hid.h>
 
 struct hid_device;
@@ -145,6 +146,7 @@ struct hid_bpf {
        struct hid_bpf_ops *rdesc_ops;
        struct list_head prog_list;
        struct mutex prog_list_lock;    /* protects prog_list update */
+       struct srcu_struct srcu;        /* protects prog_list read-only access */
 };
 
 #ifdef CONFIG_HID_BPF
@@ -153,7 +155,7 @@ u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type t
 int hid_bpf_connect_device(struct hid_device *hdev);
 void hid_bpf_disconnect_device(struct hid_device *hdev);
 void hid_bpf_destroy_device(struct hid_device *hid);
-void hid_bpf_device_init(struct hid_device *hid);
+int hid_bpf_device_init(struct hid_device *hid);
 u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size);
 #else /* CONFIG_HID_BPF */
 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
 static inline int hid_bpf_connect_device(struct hid_device *hdev) { return 0; }
 static inline void hid_bpf_disconnect_device(struct hid_device *hdev) {}
 static inline void hid_bpf_destroy_device(struct hid_device *hid) {}
-static inline void hid_bpf_device_init(struct hid_device *hid) {}
+static inline int hid_bpf_device_init(struct hid_device *hid) { return 0; }
 #define call_hid_bpf_rdesc_fixup(_hdev, _rdesc, _size) \
                ((u8 *)kmemdup(_rdesc, *(_size), GFP_KERNEL))