[PATCH OLK-5.10 V1 0/5] Fix CVE-2026-90329
5 commits in total. PATCH 3 for CVE fix, PATCH 1 and 2 as stable dependencies, PATCH 4 and 5 as fix. Dan Carpenter (1): HID: fix an error code in hid_check_device_match() Dmitry Torokhov (2): HID: split apart hid_device_probe to make logic more apparent HID: ensure timely release of driver-allocated resources Vitaly Kuznetsov (1): HID: hyperv: streamline driver probe to avoid devres issues Yousef Alhouseen (1): HID: synchronize input before cleaning up a failed probe drivers/hid/hid-core.c | 120 ++++++++++++++++++++++++--------------- drivers/hid/hid-hyperv.c | 58 +++++++++++++------ include/linux/hid.h | 1 + 3 files changed, 115 insertions(+), 64 deletions(-) -- 2.34.1
From: Dmitry Torokhov <dmitry.torokhov@gmail.com> stable inclusion from stable-v5.10.270 commit e51882f2bf470ef77484ebd3b648553173253511 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/19484 CVE: CVE-2026-90329 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- [ Upstream commit 207733f9266194b3cd90ddae723a1f82eb64030b ] hid_device_probe() has a complex flow and locks and unlocks a mutex. Move the most of the logic into __hid_device_probe() and hid_check_device_match() and leave the locking in hid_device_probe() which makes the code more clear. Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz> Stable-dep-of: 207853d46f7e ("HID: synchronize input before cleaning up a failed probe") Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Yao Yiqi <yaoyiqi3@huawei.com> --- drivers/hid/hid-core.c | 101 ++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 47 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index b17bdbc9d2a7..31378bb8c559 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2283,64 +2283,71 @@ bool hid_compare_device_paths(struct hid_device *hdev_a, } EXPORT_SYMBOL_GPL(hid_compare_device_paths); +static bool hid_check_device_match(struct hid_device *hdev, + struct hid_driver *hdrv, + const struct hid_device_id **id) +{ + *id = hid_match_device(hdev, hdrv); + if (!*id) + return -ENODEV; + + if (hdrv->match) + return hdrv->match(hdev, hid_ignore_special_drivers); + + /* + * hid-generic implements .match(), so we must be dealing with a + * different HID driver here, and can simply check if + * hid_ignore_special_drivers is set or not. + */ + return !hid_ignore_special_drivers; +} + +static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv) +{ + const struct hid_device_id *id; + int ret; + + if (!hid_check_device_match(hdev, hdrv, &id)) + return -ENODEV; + + /* reset the quirks that has been previously set */ + hdev->quirks = hid_lookup_quirk(hdev); + hdev->driver = hdrv; + + if (hdrv->probe) { + ret = hdrv->probe(hdev, id); + } else { /* default probe */ + ret = hid_open_report(hdev); + if (!ret) + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + } + + if (ret) { + hid_close_report(hdev); + hdev->driver = NULL; + } + + return ret; +} + static int hid_device_probe(struct device *dev) { - struct hid_driver *hdrv = to_hid_driver(dev->driver); struct hid_device *hdev = to_hid_device(dev); - const struct hid_device_id *id; + struct hid_driver *hdrv = to_hid_driver(dev->driver); int ret = 0; - if (down_interruptible(&hdev->driver_input_lock)) { - ret = -EINTR; - goto end; - } - hdev->io_started = false; + if (down_interruptible(&hdev->driver_input_lock)) + return -EINTR; + hdev->io_started = false; clear_bit(ffs(HID_STAT_REPROBED), &hdev->status); - if (!hdev->driver) { - id = hid_match_device(hdev, hdrv); - if (id == NULL) { - ret = -ENODEV; - goto unlock; - } + if (!hdev->driver) + ret = __hid_device_probe(hdev, hdrv); - if (hdrv->match) { - if (!hdrv->match(hdev, hid_ignore_special_drivers)) { - ret = -ENODEV; - goto unlock; - } - } else { - /* - * hid-generic implements .match(), so if - * hid_ignore_special_drivers is set, we can safely - * return. - */ - if (hid_ignore_special_drivers) { - ret = -ENODEV; - goto unlock; - } - } - - /* reset the quirks that has been previously set */ - hdev->quirks = hid_lookup_quirk(hdev); - hdev->driver = hdrv; - if (hdrv->probe) { - ret = hdrv->probe(hdev, id); - } else { /* default probe */ - ret = hid_open_report(hdev); - if (!ret) - ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); - } - if (ret) { - hid_close_report(hdev); - hdev->driver = NULL; - } - } -unlock: if (!hdev->io_started) up(&hdev->driver_input_lock); -end: + return ret; } -- 2.34.1
From: Dmitry Torokhov <dmitry.torokhov@gmail.com> stable inclusion from stable-v5.10.270 commit e6ea3de7abef998aaab9f04a7a11a7c5f56bbe57 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/19484 CVE: CVE-2026-90329 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- [ Upstream commit 62c68e7cee332e08e625af3bca3318814086490d ] More and more drivers rely on devres to manage their resources, however if bus' probe() and release() methods are not trivial and control some of resources as well (for example enable or disable clocks, or attach device to a power domain), we need to make sure that driver-allocated resources are released immediately after driver's remove() method returns, and not postponed until driver core gets around to releasing resources. In case of HID we should not try to close the report and release associated memory until after all devres callbacks are executed. To fix that we open a new devres group before calling driver's probe() and explicitly release it when we return from driver's remove(). This is similar to what we did for I2C bus in commit 5b5475826c52 ("i2c: ensure timely release of driver-allocated resources"). It is tempting to try and move this into driver core, but actually doing so is challenging, we need to split bus' remove() method into pre- and post-remove methods, which would make the logic even less clear. Reported-by: Stephen Boyd <swboyd@chromium.org> Link: https://lore.kernel.org/r/20230505232417.1377393-1-swboyd@chromium.org Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz> Stable-dep-of: 207853d46f7e ("HID: synchronize input before cleaning up a failed probe") Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Yao Yiqi <yaoyiqi3@huawei.com> --- drivers/hid/hid-core.c | 17 +++++++++++++++++ include/linux/hid.h | 1 + 2 files changed, 18 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 31378bb8c559..934d782b42b8 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2310,6 +2310,10 @@ static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv) if (!hid_check_device_match(hdev, hdrv, &id)) return -ENODEV; + hdev->devres_group_id = devres_open_group(&hdev->dev, NULL, GFP_KERNEL); + if (!hdev->devres_group_id) + return -ENOMEM; + /* reset the quirks that has been previously set */ hdev->quirks = hid_lookup_quirk(hdev); hdev->driver = hdrv; @@ -2322,7 +2326,16 @@ static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv) ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); } + /* + * Note that we are not closing the devres group opened above so + * even resources that were attached to the device after probe is + * run are released when hid_device_remove() is executed. This is + * needed as some drivers would allocate additional resources, + * for example when updating firmware. + */ + if (ret) { + devres_release_group(&hdev->dev, hdev->devres_group_id); hid_close_report(hdev); hdev->driver = NULL; } @@ -2365,6 +2378,10 @@ static int hid_device_remove(struct device *dev) hdrv->remove(hdev); else /* default remove */ hid_hw_stop(hdev); + + /* Release all devres resources allocated by the driver */ + devres_release_group(&hdev->dev, hdev->devres_group_id); + hid_close_report(hdev); hdev->driver = NULL; } diff --git a/include/linux/hid.h b/include/linux/hid.h index ab56fffb74a2..bb128a3dee63 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -570,6 +570,7 @@ struct hid_device { /* device report descriptor */ struct semaphore driver_input_lock; /* protects the current driver */ struct device dev; /* device */ struct hid_driver *driver; + void *devres_group_id; /* ID of probe devres group */ struct hid_ll_driver *ll_driver; struct mutex ll_open_lock; -- 2.34.1
From: Yousef Alhouseen <alhouseenyousef@gmail.com> stable inclusion from stable-v5.10.270 commit 3ffb088a2ed34ca982cfc2c81d107ce370aa45f1 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/19484 CVE: CVE-2026-90329 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- [ Upstream commit 207853d46f7ef2e28042344a1468da8754c3ddbf ] hid_device_io_start() allows reports to run concurrently with probe. If the probe subsequently fails, __hid_device_probe() releases driver resources and clears hdev->driver without first excluding those report callbacks. For example, a report may enter hidraw_report_event() while the failure path frees the associated hidraw object, leading to a use-after-free when the report takes the object's list lock. Stop input before performing failed-probe cleanup. This reacquires driver_input_lock and waits for any report callback already in progress. Fixes: c849a6143bec ("HID: Separate struct hid_device's driver_lock into two locks.") Reported-by: syzbot+9eebf5f6544c5e873858@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=9eebf5f6544c5e873858 Signed-off-by: Yousef Alhouseen <alhouseenyousef@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.com> Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Yao Yiqi <yaoyiqi3@huawei.com> --- drivers/hid/hid-core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 934d782b42b8..d97e3fb5d350 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2335,6 +2335,8 @@ static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv) */ if (ret) { + if (hdev->io_started) + hid_device_io_stop(hdev); devres_release_group(&hdev->dev, hdev->devres_group_id); hid_close_report(hdev); hdev->driver = NULL; -- 2.34.1
From: Dan Carpenter <dan.carpenter@linaro.org> stable inclusion from stable-v5.10.270 commit f83bc9e6d797c7a6dfd4dfa499bf1f633c1fd7df category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/19484 CVE: CVE-2026-90329 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- [ Upstream commit 89e756e3cc8d9c1ebc0f2b2f6912227073d93118 ] The hid_check_device_match() returns true if we find a match and false if we don't. But here it returns -ENODEV which becomes true instead of false. Fixes: 207733f92661 ("HID: split apart hid_device_probe to make logic more apparent") Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org> Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Reviewed-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz> Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Yao Yiqi <yaoyiqi3@huawei.com> --- drivers/hid/hid-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index d97e3fb5d350..33419823e548 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2289,7 +2289,7 @@ static bool hid_check_device_match(struct hid_device *hdev, { *id = hid_match_device(hdev, hdrv); if (!*id) - return -ENODEV; + return false; if (hdrv->match) return hdrv->match(hdev, hid_ignore_special_drivers); -- 2.34.1
From: Vitaly Kuznetsov <vkuznets@redhat.com> stable inclusion from stable-v6.6.64 commit b03e713a400aeb5f969bab4daf47a7402d0df814 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/19484 CVE: CVE-2026-90329 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- [ Upstream commit 66ef47faa90d838cda131fe1f7776456cc3b59f2 ] It was found that unloading 'hid_hyperv' module results in a devres complaint: ... hv_vmbus: unregistering driver hid_hyperv ------------[ cut here ]------------ WARNING: CPU: 2 PID: 3983 at drivers/base/devres.c:691 devres_release_group+0x1f2/0x2c0 ... Call Trace: <TASK> ? devres_release_group+0x1f2/0x2c0 ? __warn+0xd1/0x1c0 ? devres_release_group+0x1f2/0x2c0 ? report_bug+0x32a/0x3c0 ? handle_bug+0x53/0xa0 ? exc_invalid_op+0x18/0x50 ? asm_exc_invalid_op+0x1a/0x20 ? devres_release_group+0x1f2/0x2c0 ? devres_release_group+0x90/0x2c0 ? rcu_is_watching+0x15/0xb0 ? __pfx_devres_release_group+0x10/0x10 hid_device_remove+0xf5/0x220 device_release_driver_internal+0x371/0x540 ? klist_put+0xf3/0x170 bus_remove_device+0x1f1/0x3f0 device_del+0x33f/0x8c0 ? __pfx_device_del+0x10/0x10 ? cleanup_srcu_struct+0x337/0x500 hid_destroy_device+0xc8/0x130 mousevsc_remove+0xd2/0x1d0 [hid_hyperv] device_release_driver_internal+0x371/0x540 driver_detach+0xc5/0x180 bus_remove_driver+0x11e/0x2a0 ? __mutex_unlock_slowpath+0x160/0x5e0 vmbus_driver_unregister+0x62/0x2b0 [hv_vmbus] ... And the issue seems to be that the corresponding devres group is not allocated. Normally, devres_open_group() is called from __hid_device_probe() but Hyper-V HID driver overrides 'hid_dev->driver' with 'mousevsc_hid_driver' stub and basically re-implements __hid_device_probe() by calling hid_parse() and hid_hw_start() but not devres_open_group(). hid_device_probe() does not call __hid_device_probe() for it. Later, when the driver is removed, hid_device_remove() calls devres_release_group() as it doesn't check whether hdev->driver was initially overridden or not. The issue seems to be related to the commit 62c68e7cee33 ("HID: ensure timely release of driver-allocated resources") but the commit itself seems to be correct. Fix the issue by dropping the 'hid_dev->driver' override and using hid_register_driver()/hid_unregister_driver() instead. Alternatively, it would have been possible to rely on the default handling but HID_CONNECT_DEFAULT implies HID_CONNECT_HIDRAW and it doesn't seem to work for mousevsc as-is. Fixes: 62c68e7cee33 ("HID: ensure timely release of driver-allocated resources") Suggested-by: Michael Kelley <mhklinux@outlook.com> Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com> Reviewed-by: Michael Kelley <mhklinux@outlook.com> Tested-by: Saurabh Sengar <ssengar@linux.microsoft.com> Signed-off-by: Jiri Kosina <jkosina@suse.com> Signed-off-by: Sasha Levin <sashal@kernel.org> Conflicts: drivers/hid/hid-hyperv.c [ Context conflicts. ] Signed-off-by: Yao Yiqi <yaoyiqi3@huawei.com> --- drivers/hid/hid-hyperv.c | 58 ++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c index bf77cfb723d5..2d7619428f6b 100644 --- a/drivers/hid/hid-hyperv.c +++ b/drivers/hid/hid-hyperv.c @@ -435,6 +435,25 @@ static int mousevsc_hid_raw_request(struct hid_device *hid, return 0; } +static int mousevsc_hid_probe(struct hid_device *hid_dev, const struct hid_device_id *id) +{ + int ret; + + ret = hid_parse(hid_dev); + if (ret) { + hid_err(hid_dev, "parse failed\n"); + return ret; + } + + ret = hid_hw_start(hid_dev, HID_CONNECT_HIDINPUT | HID_CONNECT_HIDDEV); + if (ret) { + hid_err(hid_dev, "hw start failed\n"); + return ret; + } + + return 0; +} + static struct hid_ll_driver mousevsc_ll_driver = { .parse = mousevsc_hid_parse, .open = mousevsc_hid_open, @@ -444,7 +463,16 @@ static struct hid_ll_driver mousevsc_ll_driver = { .raw_request = mousevsc_hid_raw_request, }; -static struct hid_driver mousevsc_hid_driver; +static const struct hid_device_id mousevsc_devices[] = { + { HID_DEVICE(BUS_VIRTUAL, HID_GROUP_ANY, 0x045E, 0x0621) }, + { } +}; + +static struct hid_driver mousevsc_hid_driver = { + .name = "hid-hyperv", + .id_table = mousevsc_devices, + .probe = mousevsc_hid_probe, +}; static int mousevsc_probe(struct hv_device *device, const struct hv_vmbus_device_id *dev_id) @@ -486,7 +514,6 @@ static int mousevsc_probe(struct hv_device *device, } hid_dev->ll_driver = &mousevsc_ll_driver; - hid_dev->driver = &mousevsc_hid_driver; hid_dev->bus = BUS_VIRTUAL; hid_dev->vendor = input_dev->hid_dev_info.vendor; hid_dev->product = input_dev->hid_dev_info.product; @@ -501,20 +528,6 @@ static int mousevsc_probe(struct hv_device *device, if (ret) goto probe_err2; - - ret = hid_parse(hid_dev); - if (ret) { - hid_err(hid_dev, "parse failed\n"); - goto probe_err2; - } - - ret = hid_hw_start(hid_dev, HID_CONNECT_HIDINPUT | HID_CONNECT_HIDDEV); - - if (ret) { - hid_err(hid_dev, "hw start failed\n"); - goto probe_err2; - } - device_init_wakeup(&device->device, true); input_dev->connected = true; @@ -594,12 +607,23 @@ static struct hv_driver mousevsc_drv = { static int __init mousevsc_init(void) { - return vmbus_driver_register(&mousevsc_drv); + int ret; + + ret = hid_register_driver(&mousevsc_hid_driver); + if (ret) + return ret; + + ret = vmbus_driver_register(&mousevsc_drv); + if (ret) + hid_unregister_driver(&mousevsc_hid_driver); + + return ret; } static void __exit mousevsc_exit(void) { vmbus_driver_unregister(&mousevsc_drv); + hid_unregister_driver(&mousevsc_hid_driver); } MODULE_LICENSE("GPL"); -- 2.34.1
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://atomgit.com/openeuler/kernel/merge_requests/28630 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/OZU... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://atomgit.com/openeuler/kernel/merge_requests/28630 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/OZU...
participants (2)
-
patchwork bot -
Yao Yiqi