Commit 67eccf15 authored by Benjamin Tissoires's avatar Benjamin Tissoires

HID: add source argument to HID low level functions

This allows to know who actually sent what when we process the request
to the device.
This will be useful for a BPF firewall program to allow or not requests
coming from a dedicated hidraw node client.

Link: https://patch.msgid.link/20240626-hid_hw_req_bpf-v2-2-cfd60fb6c79f@kernel.orgAcked-by: default avatarJiri Kosina <jkosina@suse.com>
Signed-off-by: default avatarBenjamin Tissoires <bentiss@kernel.org>
parent ebae0b2a
...@@ -24,7 +24,7 @@ EXPORT_SYMBOL(hid_ops); ...@@ -24,7 +24,7 @@ EXPORT_SYMBOL(hid_ops);
u8 * u8 *
dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type, u8 *data, dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type, u8 *data,
u32 *size, int interrupt) u32 *size, int interrupt, u64 source)
{ {
struct hid_bpf_ctx_kern ctx_kern = { struct hid_bpf_ctx_kern ctx_kern = {
.ctx = { .ctx = {
...@@ -50,7 +50,7 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type ...@@ -50,7 +50,7 @@ dispatch_hid_bpf_device_event(struct hid_device *hdev, enum hid_report_type type
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(e, &hdev->bpf.prog_list, list) { list_for_each_entry_rcu(e, &hdev->bpf.prog_list, list) {
if (e->hid_device_event) { if (e->hid_device_event) {
ret = e->hid_device_event(&ctx_kern.ctx, type); ret = e->hid_device_event(&ctx_kern.ctx, type, source);
if (ret < 0) { if (ret < 0) {
rcu_read_unlock(); rcu_read_unlock();
return ERR_PTR(ret); return ERR_PTR(ret);
...@@ -359,7 +359,8 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, ...@@ -359,7 +359,8 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
dma_data, dma_data,
size, size,
rtype, rtype,
reqtype); reqtype,
(__u64)ctx);
if (ret > 0) if (ret > 0)
memcpy(buf, dma_data, ret); memcpy(buf, dma_data, ret);
...@@ -398,7 +399,8 @@ hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz) ...@@ -398,7 +399,8 @@ hid_bpf_hw_output_report(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz)
ret = hid_ops->hid_hw_output_report(hdev, ret = hid_ops->hid_hw_output_report(hdev,
dma_data, dma_data,
size); size,
(__u64)ctx);
kfree(dma_data); kfree(dma_data);
return ret; return ret;
...@@ -429,7 +431,7 @@ hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf ...@@ -429,7 +431,7 @@ hid_bpf_input_report(struct hid_bpf_ctx *ctx, enum hid_report_type type, u8 *buf
hdev = (struct hid_device *)ctx->hid; /* discard const */ hdev = (struct hid_device *)ctx->hid; /* discard const */
return hid_ops->hid_input_report(hdev, type, buf, size, 0); return hid_ops->hid_input_report(hdev, type, buf, size, 0, (__u64)ctx);
} }
__bpf_kfunc_end_defs(); __bpf_kfunc_end_defs();
......
...@@ -257,7 +257,7 @@ static void hid_bpf_unreg(void *kdata) ...@@ -257,7 +257,7 @@ static void hid_bpf_unreg(void *kdata)
hid_put_device(hdev); hid_put_device(hdev);
} }
static int __hid_bpf_device_event(struct hid_bpf_ctx *ctx, enum hid_report_type type) static int __hid_bpf_device_event(struct hid_bpf_ctx *ctx, enum hid_report_type type, __u64 source)
{ {
return 0; return 0;
} }
......
...@@ -2025,19 +2025,9 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 * ...@@ -2025,19 +2025,9 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *
} }
EXPORT_SYMBOL_GPL(hid_report_raw_event); EXPORT_SYMBOL_GPL(hid_report_raw_event);
/**
* hid_input_report - report data from lower layer (usb, bt...) static int __hid_input_report(struct hid_device *hid, enum hid_report_type type,
* u8 *data, u32 size, int interrupt, u64 source)
* @hid: hid device
* @type: HID report type (HID_*_REPORT)
* @data: report contents
* @size: size of data parameter
* @interrupt: distinguish between interrupt and control transfers
*
* This is data entry for lower layers.
*/
int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size,
int interrupt)
{ {
struct hid_report_enum *report_enum; struct hid_report_enum *report_enum;
struct hid_driver *hdrv; struct hid_driver *hdrv;
...@@ -2057,7 +2047,7 @@ int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data ...@@ -2057,7 +2047,7 @@ int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data
report_enum = hid->report_enum + type; report_enum = hid->report_enum + type;
hdrv = hid->driver; hdrv = hid->driver;
data = dispatch_hid_bpf_device_event(hid, type, data, &size, interrupt); data = dispatch_hid_bpf_device_event(hid, type, data, &size, interrupt, source);
if (IS_ERR(data)) { if (IS_ERR(data)) {
ret = PTR_ERR(data); ret = PTR_ERR(data);
goto unlock; goto unlock;
...@@ -2092,6 +2082,23 @@ int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data ...@@ -2092,6 +2082,23 @@ int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data
up(&hid->driver_input_lock); up(&hid->driver_input_lock);
return ret; return ret;
} }
/**
* hid_input_report - report data from lower layer (usb, bt...)
*
* @hid: hid device
* @type: HID report type (HID_*_REPORT)
* @data: report contents
* @size: size of data parameter
* @interrupt: distinguish between interrupt and control transfers
*
* This is data entry for lower layers.
*/
int hid_input_report(struct hid_device *hid, enum hid_report_type type, u8 *data, u32 size,
int interrupt)
{
return __hid_input_report(hid, type, data, size, interrupt, 0);
}
EXPORT_SYMBOL_GPL(hid_input_report); EXPORT_SYMBOL_GPL(hid_input_report);
bool hid_match_one_id(const struct hid_device *hdev, bool hid_match_one_id(const struct hid_device *hdev,
...@@ -2392,6 +2399,24 @@ void hid_hw_request(struct hid_device *hdev, ...@@ -2392,6 +2399,24 @@ void hid_hw_request(struct hid_device *hdev,
} }
EXPORT_SYMBOL_GPL(hid_hw_request); EXPORT_SYMBOL_GPL(hid_hw_request);
int __hid_hw_raw_request(struct hid_device *hdev,
unsigned char reportnum, __u8 *buf,
size_t len, enum hid_report_type rtype,
enum hid_class_request reqtype,
__u64 source)
{
unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE;
if (hdev->ll_driver->max_buffer_size)
max_buffer_size = hdev->ll_driver->max_buffer_size;
if (len < 1 || len > max_buffer_size || !buf)
return -EINVAL;
return hdev->ll_driver->raw_request(hdev, reportnum, buf, len,
rtype, reqtype);
}
/** /**
* hid_hw_raw_request - send report request to device * hid_hw_raw_request - send report request to device
* *
...@@ -2409,6 +2434,12 @@ EXPORT_SYMBOL_GPL(hid_hw_request); ...@@ -2409,6 +2434,12 @@ EXPORT_SYMBOL_GPL(hid_hw_request);
int hid_hw_raw_request(struct hid_device *hdev, int hid_hw_raw_request(struct hid_device *hdev,
unsigned char reportnum, __u8 *buf, unsigned char reportnum, __u8 *buf,
size_t len, enum hid_report_type rtype, enum hid_class_request reqtype) size_t len, enum hid_report_type rtype, enum hid_class_request reqtype)
{
return __hid_hw_raw_request(hdev, reportnum, buf, len, rtype, reqtype, 0);
}
EXPORT_SYMBOL_GPL(hid_hw_raw_request);
int __hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len, __u64 source)
{ {
unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE; unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE;
...@@ -2418,10 +2449,11 @@ int hid_hw_raw_request(struct hid_device *hdev, ...@@ -2418,10 +2449,11 @@ int hid_hw_raw_request(struct hid_device *hdev,
if (len < 1 || len > max_buffer_size || !buf) if (len < 1 || len > max_buffer_size || !buf)
return -EINVAL; return -EINVAL;
return hdev->ll_driver->raw_request(hdev, reportnum, buf, len, if (hdev->ll_driver->output_report)
rtype, reqtype); return hdev->ll_driver->output_report(hdev, buf, len);
return -ENOSYS;
} }
EXPORT_SYMBOL_GPL(hid_hw_raw_request);
/** /**
* hid_hw_output_report - send output report to device * hid_hw_output_report - send output report to device
...@@ -2434,18 +2466,7 @@ EXPORT_SYMBOL_GPL(hid_hw_raw_request); ...@@ -2434,18 +2466,7 @@ EXPORT_SYMBOL_GPL(hid_hw_raw_request);
*/ */
int hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len) int hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len)
{ {
unsigned int max_buffer_size = HID_MAX_BUFFER_SIZE; return __hid_hw_output_report(hdev, buf, len, 0);
if (hdev->ll_driver->max_buffer_size)
max_buffer_size = hdev->ll_driver->max_buffer_size;
if (len < 1 || len > max_buffer_size || !buf)
return -EINVAL;
if (hdev->ll_driver->output_report)
return hdev->ll_driver->output_report(hdev, buf, len);
return -ENOSYS;
} }
EXPORT_SYMBOL_GPL(hid_hw_output_report); EXPORT_SYMBOL_GPL(hid_hw_output_report);
...@@ -2972,9 +2993,9 @@ EXPORT_SYMBOL_GPL(hid_check_keys_pressed); ...@@ -2972,9 +2993,9 @@ EXPORT_SYMBOL_GPL(hid_check_keys_pressed);
#ifdef CONFIG_HID_BPF #ifdef CONFIG_HID_BPF
static struct hid_ops __hid_ops = { static struct hid_ops __hid_ops = {
.hid_get_report = hid_get_report, .hid_get_report = hid_get_report,
.hid_hw_raw_request = hid_hw_raw_request, .hid_hw_raw_request = __hid_hw_raw_request,
.hid_hw_output_report = hid_hw_output_report, .hid_hw_output_report = __hid_hw_output_report,
.hid_input_report = hid_input_report, .hid_input_report = __hid_input_report,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.bus_type = &hid_bus_type, .bus_type = &hid_bus_type,
}; };
......
...@@ -140,7 +140,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, ...@@ -140,7 +140,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
if ((report_type == HID_OUTPUT_REPORT) && if ((report_type == HID_OUTPUT_REPORT) &&
!(dev->quirks & HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP)) { !(dev->quirks & HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP)) {
ret = hid_hw_output_report(dev, buf, count); ret = __hid_hw_output_report(dev, buf, count, (__u64)file);
/* /*
* compatibility with old implementation of USB-HID and I2C-HID: * compatibility with old implementation of USB-HID and I2C-HID:
* if the device does not support receiving output reports, * if the device does not support receiving output reports,
...@@ -150,8 +150,8 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, ...@@ -150,8 +150,8 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
goto out_free; goto out_free;
} }
ret = hid_hw_raw_request(dev, buf[0], buf, count, report_type, ret = __hid_hw_raw_request(dev, buf[0], buf, count, report_type,
HID_REQ_SET_REPORT); HID_REQ_SET_REPORT, (__u64)file);
out_free: out_free:
kfree(buf); kfree(buf);
...@@ -227,8 +227,8 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t ...@@ -227,8 +227,8 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t
goto out_free; goto out_free;
} }
ret = hid_hw_raw_request(dev, report_number, buf, count, report_type, ret = __hid_hw_raw_request(dev, report_number, buf, count, report_type,
HID_REQ_GET_REPORT); HID_REQ_GET_REPORT, (__u64)file);
if (ret < 0) if (ret < 0)
goto out_free; goto out_free;
......
...@@ -1125,6 +1125,12 @@ int __must_check hid_hw_open(struct hid_device *hdev); ...@@ -1125,6 +1125,12 @@ int __must_check hid_hw_open(struct hid_device *hdev);
void hid_hw_close(struct hid_device *hdev); void hid_hw_close(struct hid_device *hdev);
void hid_hw_request(struct hid_device *hdev, void hid_hw_request(struct hid_device *hdev,
struct hid_report *report, enum hid_class_request reqtype); struct hid_report *report, enum hid_class_request reqtype);
int __hid_hw_raw_request(struct hid_device *hdev,
unsigned char reportnum, __u8 *buf,
size_t len, enum hid_report_type rtype,
enum hid_class_request reqtype,
__u64 source);
int __hid_hw_output_report(struct hid_device *hdev, __u8 *buf, size_t len, __u64 source);
int hid_hw_raw_request(struct hid_device *hdev, int hid_hw_raw_request(struct hid_device *hdev,
unsigned char reportnum, __u8 *buf, unsigned char reportnum, __u8 *buf,
size_t len, enum hid_report_type rtype, size_t len, enum hid_report_type rtype,
......
...@@ -66,10 +66,12 @@ struct hid_ops { ...@@ -66,10 +66,12 @@ struct hid_ops {
int (*hid_hw_raw_request)(struct hid_device *hdev, int (*hid_hw_raw_request)(struct hid_device *hdev,
unsigned char reportnum, __u8 *buf, unsigned char reportnum, __u8 *buf,
size_t len, enum hid_report_type rtype, size_t len, enum hid_report_type rtype,
enum hid_class_request reqtype); enum hid_class_request reqtype,
int (*hid_hw_output_report)(struct hid_device *hdev, __u8 *buf, size_t len); __u64 source);
int (*hid_hw_output_report)(struct hid_device *hdev, __u8 *buf, size_t len,
__u64 source);
int (*hid_input_report)(struct hid_device *hid, enum hid_report_type type, int (*hid_input_report)(struct hid_device *hid, enum hid_report_type type,
u8 *data, u32 size, int interrupt); u8 *data, u32 size, int interrupt, u64 source);
struct module *owner; struct module *owner;
const struct bus_type *bus_type; const struct bus_type *bus_type;
}; };
...@@ -110,7 +112,8 @@ struct hid_bpf_ops { ...@@ -110,7 +112,8 @@ struct hid_bpf_ops {
* *
* Context: Interrupt context. * Context: Interrupt context.
*/ */
int (*hid_device_event)(struct hid_bpf_ctx *ctx, enum hid_report_type report_type); int (*hid_device_event)(struct hid_bpf_ctx *ctx, enum hid_report_type report_type,
__u64 source);
/** /**
* @hid_rdesc_fixup: called when the probe function parses the report descriptor * @hid_rdesc_fixup: called when the probe function parses the report descriptor
...@@ -146,7 +149,7 @@ struct hid_bpf { ...@@ -146,7 +149,7 @@ struct hid_bpf {
#ifdef CONFIG_HID_BPF #ifdef CONFIG_HID_BPF
u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, u8 *data, u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, u8 *data,
u32 *size, int interrupt); u32 *size, int interrupt, u64 source);
int hid_bpf_connect_device(struct hid_device *hdev); int hid_bpf_connect_device(struct hid_device *hdev);
void hid_bpf_disconnect_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_destroy_device(struct hid_device *hid);
...@@ -154,7 +157,8 @@ void hid_bpf_device_init(struct hid_device *hid); ...@@ -154,7 +157,8 @@ void hid_bpf_device_init(struct hid_device *hid);
u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size); u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *size);
#else /* CONFIG_HID_BPF */ #else /* CONFIG_HID_BPF */
static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type, static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type,
u8 *data, u32 *size, int interrupt) { return data; } u8 *data, u32 *size, int interrupt,
u64 source) { return data; }
static inline int hid_bpf_connect_device(struct hid_device *hdev) { return 0; } 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_disconnect_device(struct hid_device *hdev) {}
static inline void hid_bpf_destroy_device(struct hid_device *hid) {} static inline void hid_bpf_destroy_device(struct hid_device *hid) {}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment