hid-for-linus-2024020101

-----BEGIN PGP SIGNATURE-----
 
 iQJHBAABCAAxFiEEoEVH9lhNrxiMPSyI7MXwXhnZSjYFAmW7veITHGJlbnRpc3NA
 a2VybmVsLm9yZwAKCRDsxfBeGdlKNpzjD/97PuMdidU2cmy+N1k5AmFw8io/BO+Y
 hl/wOOMY4n2vaL98m0dte1y+IV2352yAANCfxYH4dO01h0x0BCz5Rk5J55Jsix8G
 jHPyUpGYCRKTNpaWuOE8nKbsCSRDF9ui0LvbgV9So/BwGScLdFCJwY7VNPp16W1s
 d+ccq/3Cy6XiQs2ZygdHogxC1F/youyPXo65IlkwClSI2naozDH+O8inhq+P/Mfl
 +WpR/oDjS3225nh/eKDYvni/u2+Fjc+7fZKskz8dxkR3dKsTrOHLh98hHFHQ2NQU
 lKf2FWxiq9CnvIoFI/f17KsC9CxJ3gTrzqt0JCv5niNkafkw0dzrYlAPVC4CuAwY
 odhwRHZomqY5f+t3qw8TS6haXp3faZVdbwh7Zz2osK2dtBrySa8eCT6H3kEhIQaI
 HKsTv5Fgq8vZ58ciiBCf13Z2nNFxq4bf9tx0haup7ktY1vNocwJ58cdCqIoyKKZS
 vrNRSt+lRzr3reHR2+ezPp0Fo4kDgCsQQHnNpu8IJ1+iD1kUa9gENOrs4MEufUoz
 QMDsI05ENslXjdbTlFci7a4kMth29CA4Y8d7TEkNRhGXVvvGnHB9xV+eX6kLq5UQ
 H28udI8DVXmR6Ctu4uwwYdB/4ilaD21XpfpktDF3EC0/09ff2vmIVr9DkBLevQ6h
 VQyResy9xnY+Wg==
 =yfy5
 -----END PGP SIGNATURE-----

Merge tag 'hid-for-linus-2024020101' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid

Pull HID fixes from Benjamin Tissoires:

 - cleanups in the error path in hid-steam (Dan Carpenter)

 - fixes for Wacom tablets selftests that sneaked in while the CI was
   taking a break during the year end holidays (Benjamin Tissoires)

 - null pointer check in nvidia-shield (Kunwu Chan)

 - memory leak fix in hidraw (Su Hui)

 - another null pointer fix in i2c-hid-of (Johan Hovold)

 - another memory leak fix in HID-BPF this time, as well as a double
   fdget() fix reported by Dan Carpenter (Benjamin Tissoires)

 - fix for Cirque touchpad when they go on suspend (Kai-Heng Feng)

 - new device ID in hid-logitech-hidpp: "Logitech G Pro X SuperLight 2"
   (Jiri Kosina)

* tag 'hid-for-linus-2024020101' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid:
  HID: bpf: use __bpf_kfunc instead of noinline
  HID: bpf: actually free hdev memory after attaching a HID-BPF program
  HID: bpf: remove double fdget()
  HID: i2c-hid-of: fix NULL-deref on failed power up
  HID: hidraw: fix a problem of memory leak in hidraw_release()
  HID: i2c-hid: Skip SET_POWER SLEEP for Cirque touchpad on system suspend
  HID: nvidia-shield: Add missing null pointer checks to LED initialization
  HID: logitech-hidpp: add support for Logitech G Pro X Superlight 2
  selftests/hid: wacom: fix confidence tests
  HID: hid-steam: Fix cleanup in probe()
  HID: hid-steam: remove pointless error message
This commit is contained in:
Linus Torvalds 2024-02-01 10:19:34 -08:00
commit 5c24e4e9e7
12 changed files with 146 additions and 93 deletions

View File

@ -143,6 +143,9 @@ u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, u8 *rdesc, unsigned int *s
}
EXPORT_SYMBOL_GPL(call_hid_bpf_rdesc_fixup);
/* Disables missing prototype warnings */
__bpf_kfunc_start_defs();
/**
* hid_bpf_get_data - Get the kernel memory pointer associated with the context @ctx
*
@ -152,7 +155,7 @@ EXPORT_SYMBOL_GPL(call_hid_bpf_rdesc_fixup);
*
* @returns %NULL on error, an %__u8 memory pointer on success
*/
noinline __u8 *
__bpf_kfunc __u8 *
hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr_buf_size)
{
struct hid_bpf_ctx_kern *ctx_kern;
@ -167,6 +170,7 @@ hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t rdwr
return ctx_kern->data + offset;
}
__bpf_kfunc_end_defs();
/*
* The following set contains all functions we agree BPF programs
@ -241,50 +245,25 @@ int hid_bpf_reconnect(struct hid_device *hdev)
return 0;
}
/**
* hid_bpf_attach_prog - Attach the given @prog_fd to the given HID device
*
* @hid_id: the system unique identifier of the HID device
* @prog_fd: an fd in the user process representing the program to attach
* @flags: any logical OR combination of &enum hid_bpf_attach_flags
*
* @returns an fd of a bpf_link object on success (> %0), an error code otherwise.
* Closing this fd will detach the program from the HID device (unless the bpf_link
* is pinned to the BPF file system).
*/
/* called from syscall */
noinline int
hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags)
static int do_hid_bpf_attach_prog(struct hid_device *hdev, int prog_fd, struct bpf_prog *prog,
__u32 flags)
{
struct hid_device *hdev;
struct device *dev;
int fd, err, prog_type = hid_bpf_get_prog_attach_type(prog_fd);
if (!hid_bpf_ops)
return -EINVAL;
int fd, err, prog_type;
prog_type = hid_bpf_get_prog_attach_type(prog);
if (prog_type < 0)
return prog_type;
if (prog_type >= HID_BPF_PROG_TYPE_MAX)
return -EINVAL;
if ((flags & ~HID_BPF_FLAG_MASK))
return -EINVAL;
dev = bus_find_device(hid_bpf_ops->bus_type, NULL, &hid_id, device_match_id);
if (!dev)
return -EINVAL;
hdev = to_hid_device(dev);
if (prog_type == HID_BPF_PROG_TYPE_DEVICE_EVENT) {
err = hid_bpf_allocate_event_data(hdev);
if (err)
return err;
}
fd = __hid_bpf_attach_prog(hdev, prog_type, prog_fd, flags);
fd = __hid_bpf_attach_prog(hdev, prog_type, prog_fd, prog, flags);
if (fd < 0)
return fd;
@ -299,6 +278,66 @@ hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags)
return fd;
}
/* Disables missing prototype warnings */
__bpf_kfunc_start_defs();
/**
* hid_bpf_attach_prog - Attach the given @prog_fd to the given HID device
*
* @hid_id: the system unique identifier of the HID device
* @prog_fd: an fd in the user process representing the program to attach
* @flags: any logical OR combination of &enum hid_bpf_attach_flags
*
* @returns an fd of a bpf_link object on success (> %0), an error code otherwise.
* Closing this fd will detach the program from the HID device (unless the bpf_link
* is pinned to the BPF file system).
*/
/* called from syscall */
__bpf_kfunc int
hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags)
{
struct hid_device *hdev;
struct bpf_prog *prog;
struct device *dev;
int err, fd;
if (!hid_bpf_ops)
return -EINVAL;
if ((flags & ~HID_BPF_FLAG_MASK))
return -EINVAL;
dev = bus_find_device(hid_bpf_ops->bus_type, NULL, &hid_id, device_match_id);
if (!dev)
return -EINVAL;
hdev = to_hid_device(dev);
/*
* take a ref on the prog itself, it will be released
* on errors or when it'll be detached
*/
prog = bpf_prog_get(prog_fd);
if (IS_ERR(prog)) {
err = PTR_ERR(prog);
goto out_dev_put;
}
fd = do_hid_bpf_attach_prog(hdev, prog_fd, prog, flags);
if (fd < 0) {
err = fd;
goto out_prog_put;
}
return fd;
out_prog_put:
bpf_prog_put(prog);
out_dev_put:
put_device(dev);
return err;
}
/**
* hid_bpf_allocate_context - Allocate a context to the given HID device
*
@ -306,7 +345,7 @@ hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags)
*
* @returns A pointer to &struct hid_bpf_ctx on success, %NULL on error.
*/
noinline struct hid_bpf_ctx *
__bpf_kfunc struct hid_bpf_ctx *
hid_bpf_allocate_context(unsigned int hid_id)
{
struct hid_device *hdev;
@ -323,8 +362,10 @@ hid_bpf_allocate_context(unsigned int hid_id)
hdev = to_hid_device(dev);
ctx_kern = kzalloc(sizeof(*ctx_kern), GFP_KERNEL);
if (!ctx_kern)
if (!ctx_kern) {
put_device(dev);
return NULL;
}
ctx_kern->ctx.hid = hdev;
@ -337,14 +378,19 @@ hid_bpf_allocate_context(unsigned int hid_id)
* @ctx: the HID-BPF context to release
*
*/
noinline void
__bpf_kfunc void
hid_bpf_release_context(struct hid_bpf_ctx *ctx)
{
struct hid_bpf_ctx_kern *ctx_kern;
struct hid_device *hid;
ctx_kern = container_of(ctx, struct hid_bpf_ctx_kern, ctx);
hid = (struct hid_device *)ctx_kern->ctx.hid; /* ignore const */
kfree(ctx_kern);
/* get_device() is called by bus_find_device() */
put_device(&hid->dev);
}
/**
@ -358,7 +404,7 @@ hid_bpf_release_context(struct hid_bpf_ctx *ctx)
*
* @returns %0 on success, a negative error code otherwise.
*/
noinline int
__bpf_kfunc int
hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
enum hid_report_type rtype, enum hid_class_request reqtype)
{
@ -426,6 +472,7 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
kfree(dma_data);
return ret;
}
__bpf_kfunc_end_defs();
/* our HID-BPF entrypoints */
BTF_SET8_START(hid_bpf_fmodret_ids)

View File

@ -12,9 +12,9 @@ struct hid_bpf_ctx_kern {
int hid_bpf_preload_skel(void);
void hid_bpf_free_links_and_skel(void);
int hid_bpf_get_prog_attach_type(int prog_fd);
int hid_bpf_get_prog_attach_type(struct bpf_prog *prog);
int __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type, int prog_fd,
__u32 flags);
struct bpf_prog *prog, __u32 flags);
void __hid_bpf_destroy_device(struct hid_device *hdev);
int hid_bpf_prog_run(struct hid_device *hdev, enum hid_bpf_prog_type type,
struct hid_bpf_ctx_kern *ctx_kern);

View File

@ -196,6 +196,7 @@ static void __hid_bpf_do_release_prog(int map_fd, unsigned int idx)
static void hid_bpf_release_progs(struct work_struct *work)
{
int i, j, n, map_fd = -1;
bool hdev_destroyed;
if (!jmp_table.map)
return;
@ -220,6 +221,12 @@ static void hid_bpf_release_progs(struct work_struct *work)
if (entry->hdev) {
hdev = entry->hdev;
type = entry->type;
/*
* hdev is still valid, even if we are called after hid_destroy_device():
* when hid_bpf_attach() gets called, it takes a ref on the dev through
* bus_find_device()
*/
hdev_destroyed = hdev->bpf.destroyed;
hid_bpf_populate_hdev(hdev, type);
@ -232,12 +239,19 @@ static void hid_bpf_release_progs(struct work_struct *work)
if (test_bit(next->idx, jmp_table.enabled))
continue;
if (next->hdev == hdev && next->type == type)
if (next->hdev == hdev && next->type == type) {
/*
* clear the hdev reference and decrement the device ref
* that was taken during bus_find_device() while calling
* hid_bpf_attach()
*/
next->hdev = NULL;
put_device(&hdev->dev);
}
}
/* if type was rdesc fixup, reconnect device */
if (type == HID_BPF_PROG_TYPE_RDESC_FIXUP)
/* if type was rdesc fixup and the device is not gone, reconnect device */
if (type == HID_BPF_PROG_TYPE_RDESC_FIXUP && !hdev_destroyed)
hid_bpf_reconnect(hdev);
}
}
@ -333,15 +347,10 @@ static int hid_bpf_insert_prog(int prog_fd, struct bpf_prog *prog)
return err;
}
int hid_bpf_get_prog_attach_type(int prog_fd)
int hid_bpf_get_prog_attach_type(struct bpf_prog *prog)
{
struct bpf_prog *prog = NULL;
int i;
int prog_type = HID_BPF_PROG_TYPE_UNDEF;
prog = bpf_prog_get(prog_fd);
if (IS_ERR(prog))
return PTR_ERR(prog);
int i;
for (i = 0; i < HID_BPF_PROG_TYPE_MAX; i++) {
if (hid_bpf_btf_ids[i] == prog->aux->attach_btf_id) {
@ -350,8 +359,6 @@ int hid_bpf_get_prog_attach_type(int prog_fd)
}
}
bpf_prog_put(prog);
return prog_type;
}
@ -388,19 +395,13 @@ static const struct bpf_link_ops hid_bpf_link_lops = {
/* called from syscall */
noinline int
__hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type,
int prog_fd, __u32 flags)
int prog_fd, struct bpf_prog *prog, __u32 flags)
{
struct bpf_link_primer link_primer;
struct hid_bpf_link *link;
struct bpf_prog *prog = NULL;
struct hid_bpf_prog_entry *prog_entry;
int cnt, err = -EINVAL, prog_table_idx = -1;
/* take a ref on the prog itself */
prog = bpf_prog_get(prog_fd);
if (IS_ERR(prog))
return PTR_ERR(prog);
mutex_lock(&hid_bpf_attach_lock);
link = kzalloc(sizeof(*link), GFP_USER);
@ -467,7 +468,6 @@ __hid_bpf_attach_prog(struct hid_device *hdev, enum hid_bpf_prog_type prog_type,
err_unlock:
mutex_unlock(&hid_bpf_attach_lock);
bpf_prog_put(prog);
kfree(link);
return err;

View File

@ -298,6 +298,9 @@
#define USB_VENDOR_ID_CIDC 0x1677
#define I2C_VENDOR_ID_CIRQUE 0x0488
#define I2C_PRODUCT_ID_CIRQUE_1063 0x1063
#define USB_VENDOR_ID_CJTOUCH 0x24b8
#define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020 0x0020
#define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040 0x0040

View File

@ -4610,6 +4610,8 @@ static const struct hid_device_id hidpp_devices[] = {
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC088) },
{ /* Logitech G Pro X Superlight Gaming Mouse over USB */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC094) },
{ /* Logitech G Pro X Superlight 2 Gaming Mouse over USB */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC09b) },
{ /* G935 Gaming Headset */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0x0a87),

View File

@ -800,6 +800,8 @@ static inline int thunderstrike_led_create(struct thunderstrike *ts)
led->name = devm_kasprintf(&ts->base.hdev->dev, GFP_KERNEL,
"thunderstrike%d:blue:led", ts->id);
if (!led->name)
return -ENOMEM;
led->max_brightness = 1;
led->flags = LED_CORE_SUSPENDRESUME | LED_RETAIN_AT_SHUTDOWN;
led->brightness_get = &thunderstrike_led_get_brightness;
@ -831,6 +833,8 @@ static inline int thunderstrike_psy_create(struct shield_device *shield_dev)
shield_dev->battery_dev.desc.name =
devm_kasprintf(&ts->base.hdev->dev, GFP_KERNEL,
"thunderstrike_%d", ts->id);
if (!shield_dev->battery_dev.desc.name)
return -ENOMEM;
shield_dev->battery_dev.psy = power_supply_register(
&hdev->dev, &shield_dev->battery_dev.desc, &psy_cfg);

View File

@ -1109,10 +1109,9 @@ static int steam_probe(struct hid_device *hdev,
return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
steam = devm_kzalloc(&hdev->dev, sizeof(*steam), GFP_KERNEL);
if (!steam) {
ret = -ENOMEM;
goto steam_alloc_fail;
}
if (!steam)
return -ENOMEM;
steam->hdev = hdev;
hid_set_drvdata(hdev, steam);
spin_lock_init(&steam->lock);
@ -1129,14 +1128,14 @@ static int steam_probe(struct hid_device *hdev,
*/
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_HIDRAW);
if (ret)
goto hid_hw_start_fail;
goto err_cancel_work;
ret = hid_hw_open(hdev);
if (ret) {
hid_err(hdev,
"%s:hid_hw_open\n",
__func__);
goto hid_hw_open_fail;
goto err_hw_stop;
}
if (steam->quirks & STEAM_QUIRK_WIRELESS) {
@ -1152,36 +1151,37 @@ static int steam_probe(struct hid_device *hdev,
hid_err(hdev,
"%s:steam_register failed with error %d\n",
__func__, ret);
goto input_register_fail;
goto err_hw_close;
}
}
steam->client_hdev = steam_create_client_hid(hdev);
if (IS_ERR(steam->client_hdev)) {
ret = PTR_ERR(steam->client_hdev);
goto client_hdev_fail;
goto err_stream_unregister;
}
steam->client_hdev->driver_data = steam;
ret = hid_add_device(steam->client_hdev);
if (ret)
goto client_hdev_add_fail;
goto err_destroy;
return 0;
client_hdev_add_fail:
hid_hw_stop(hdev);
client_hdev_fail:
err_destroy:
hid_destroy_device(steam->client_hdev);
input_register_fail:
hid_hw_open_fail:
hid_hw_start_fail:
err_stream_unregister:
if (steam->connected)
steam_unregister(steam);
err_hw_close:
hid_hw_close(hdev);
err_hw_stop:
hid_hw_stop(hdev);
err_cancel_work:
cancel_work_sync(&steam->work_connect);
cancel_delayed_work_sync(&steam->mode_switch);
cancel_work_sync(&steam->rumble_work);
steam_alloc_fail:
hid_err(hdev, "%s: failed with error %d\n",
__func__, ret);
return ret;
}

View File

@ -357,8 +357,11 @@ static int hidraw_release(struct inode * inode, struct file * file)
down_write(&minors_rwsem);
spin_lock_irqsave(&hidraw_table[minor]->list_lock, flags);
for (int i = list->tail; i < list->head; i++)
kfree(list->buffer[i].value);
while (list->tail != list->head) {
kfree(list->buffer[list->tail].value);
list->buffer[list->tail].value = NULL;
list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);
}
list_del(&list->node);
spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags);
kfree(list);

View File

@ -49,6 +49,7 @@
#define I2C_HID_QUIRK_RESET_ON_RESUME BIT(2)
#define I2C_HID_QUIRK_BAD_INPUT_SIZE BIT(3)
#define I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET BIT(4)
#define I2C_HID_QUIRK_NO_SLEEP_ON_SUSPEND BIT(5)
/* Command opcodes */
#define I2C_HID_OPCODE_RESET 0x01
@ -131,6 +132,8 @@ static const struct i2c_hid_quirks {
I2C_HID_QUIRK_RESET_ON_RESUME },
{ USB_VENDOR_ID_ITE, I2C_DEVICE_ID_ITE_LENOVO_LEGION_Y720,
I2C_HID_QUIRK_BAD_INPUT_SIZE },
{ I2C_VENDOR_ID_CIRQUE, I2C_PRODUCT_ID_CIRQUE_1063,
I2C_HID_QUIRK_NO_SLEEP_ON_SUSPEND },
/*
* Sending the wakeup after reset actually break ELAN touchscreen controller
*/
@ -956,7 +959,8 @@ static int i2c_hid_core_suspend(struct i2c_hid *ihid, bool force_poweroff)
return ret;
/* Save some power */
i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP);
if (!(ihid->quirks & I2C_HID_QUIRK_NO_SLEEP_ON_SUSPEND))
i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP);
disable_irq(client->irq);

View File

@ -87,6 +87,7 @@ static int i2c_hid_of_probe(struct i2c_client *client)
if (!ihid_of)
return -ENOMEM;
ihid_of->client = client;
ihid_of->ops.power_up = i2c_hid_of_power_up;
ihid_of->ops.power_down = i2c_hid_of_power_down;

View File

@ -77,17 +77,6 @@ enum hid_bpf_attach_flags {
int hid_bpf_device_event(struct hid_bpf_ctx *ctx);
int hid_bpf_rdesc_fixup(struct hid_bpf_ctx *ctx);
/* Following functions are kfunc that we export to BPF programs */
/* available everywhere in HID-BPF */
__u8 *hid_bpf_get_data(struct hid_bpf_ctx *ctx, unsigned int offset, const size_t __sz);
/* only available in syscall */
int hid_bpf_attach_prog(unsigned int hid_id, int prog_fd, __u32 flags);
int hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz,
enum hid_report_type rtype, enum hid_class_request reqtype);
struct hid_bpf_ctx *hid_bpf_allocate_context(unsigned int hid_id);
void hid_bpf_release_context(struct hid_bpf_ctx *ctx);
/*
* Below is HID internal
*/

View File

@ -880,8 +880,8 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest
does not overlap with other contacts. The value of `t` may be
incremented over time to move the point along a linear path.
"""
x = 50 + 10 * contact_id + t
y = 100 + 100 * contact_id + t
x = 50 + 10 * contact_id + t * 11
y = 100 + 100 * contact_id + t * 11
return test_multitouch.Touch(contact_id, x, y)
def make_contacts(self, n, t=0):
@ -902,8 +902,8 @@ class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest
tracking_id = contact_ids.tracking_id
slot_num = contact_ids.slot_num
x = 50 + 10 * contact_id + t
y = 100 + 100 * contact_id + t
x = 50 + 10 * contact_id + t * 11
y = 100 + 100 * contact_id + t * 11
# If the data isn't supposed to be stored in any slots, there is
# nothing we can check for in the evdev stream.