[PATCH OLK-5.10 0/5] CVE-2026-53120
patches for CVE-2026-53120 Danilo Krummrich (1): PCI: use generic driver_override infrastructure Samiullah Khawaja (1): PCI: Initialize temporary device in new_id_store() Zhenzhong Duan (2): PCI: Move pci_match_device() ahead of new_id_store() PCI: Avoid duplicate IDs in driver dynamic IDs list Ziming Du (1): [Huawei] PCI: fix kabi breakage due to driver_override removal drivers/pci/pci-driver.c | 161 +++++++++++++++-------------- drivers/pci/pci-sysfs.c | 48 --------- drivers/pci/probe.c | 1 - drivers/vfio/pci/vfio_pci.c | 4 +- drivers/xen/xen-pciback/pci_stub.c | 6 +- include/linux/pci.h | 2 +- 6 files changed, 93 insertions(+), 129 deletions(-) -- 2.43.0
From: Zhenzhong Duan <zhenzhong.duan@gmail.com> mainline inclusion from mainline-v5.11-rc1 commit 1f40704bb01b9fba9925006662a37373d514f26b category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/15817 CVE: CVE-2026-53120 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- Move pci_match_device() and its dependencies (pci_match_id() and pci_device_id_any) ahead of new_id_store(). This is preparation work for calling pci_match_device() in new_id_store(). No functional changes. [bhelgaas: update function comments] Link: https://lore.kernel.org/r/20201117054409.3428-2-zhenzhong.duan@gmail.com Signed-off-by: Zhenzhong Duan <zhenzhong.duan@gmail.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Signed-off-by: Ziming Du <duziming2@huawei.com> --- drivers/pci/pci-driver.c | 145 ++++++++++++++++++++------------------- 1 file changed, 73 insertions(+), 72 deletions(-) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 986bb53b60c9d..172ae44f164b2 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -89,6 +89,79 @@ static void pci_free_dynids(struct pci_driver *drv) spin_unlock(&drv->dynids.lock); } +/** + * pci_match_id - See if a PCI device matches a given pci_id table + * @ids: array of PCI device ID structures to search in + * @dev: the PCI device structure to match against. + * + * Used by a driver to check whether a PCI device is in its list of + * supported devices. Returns the matching pci_device_id structure or + * %NULL if there is no match. + * + * Deprecated; don't use this as it will not catch any dynamic IDs + * that a driver might want to check for. + */ +const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, + struct pci_dev *dev) +{ + if (ids) { + while (ids->vendor || ids->subvendor || ids->class_mask) { + if (pci_match_one_device(ids, dev)) + return ids; + ids++; + } + } + return NULL; +} +EXPORT_SYMBOL(pci_match_id); + +static const struct pci_device_id pci_device_id_any = { + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, +}; + +/** + * pci_match_device - See if a device matches a driver's list of IDs + * @drv: the PCI driver to match against + * @dev: the PCI device structure to match against + * + * Used by a driver to check whether a PCI device is in its list of + * supported devices or in the dynids list, which may have been augmented + * via the sysfs "new_id" file. Returns the matching pci_device_id + * structure or %NULL if there is no match. + */ +static const struct pci_device_id *pci_match_device(struct pci_driver *drv, + struct pci_dev *dev) +{ + struct pci_dynid *dynid; + const struct pci_device_id *found_id = NULL; + + /* When driver_override is set, only bind to the matching driver */ + if (dev->driver_override && strcmp(dev->driver_override, drv->name)) + return NULL; + + /* Look at the dynamic ids first, before the static ones */ + spin_lock(&drv->dynids.lock); + list_for_each_entry(dynid, &drv->dynids.list, node) { + if (pci_match_one_device(&dynid->id, dev)) { + found_id = &dynid->id; + break; + } + } + spin_unlock(&drv->dynids.lock); + + if (!found_id) + found_id = pci_match_id(drv->id_table, dev); + + /* driver_override will always match, send a dummy id */ + if (!found_id && dev->driver_override) + found_id = &pci_device_id_any; + + return found_id; +} + /** * store_new_id - sysfs frontend to pci_add_dynid() * @driver: target device driver @@ -208,78 +281,6 @@ static struct attribute *pci_drv_attrs[] = { }; ATTRIBUTE_GROUPS(pci_drv); -/** - * pci_match_id - See if a pci device matches a given pci_id table - * @ids: array of PCI device id structures to search in - * @dev: the PCI device structure to match against. - * - * Used by a driver to check whether a PCI device present in the - * system is in its list of supported devices. Returns the matching - * pci_device_id structure or %NULL if there is no match. - * - * Deprecated, don't use this as it will not catch any dynamic ids - * that a driver might want to check for. - */ -const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, - struct pci_dev *dev) -{ - if (ids) { - while (ids->vendor || ids->subvendor || ids->class_mask) { - if (pci_match_one_device(ids, dev)) - return ids; - ids++; - } - } - return NULL; -} -EXPORT_SYMBOL(pci_match_id); - -static const struct pci_device_id pci_device_id_any = { - .vendor = PCI_ANY_ID, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, -}; - -/** - * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure - * @drv: the PCI driver to match against - * @dev: the PCI device structure to match against - * - * Used by a driver to check whether a PCI device present in the - * system is in its list of supported devices. Returns the matching - * pci_device_id structure or %NULL if there is no match. - */ -static const struct pci_device_id *pci_match_device(struct pci_driver *drv, - struct pci_dev *dev) -{ - struct pci_dynid *dynid; - const struct pci_device_id *found_id = NULL; - - /* When driver_override is set, only bind to the matching driver */ - if (dev->driver_override && strcmp(dev->driver_override, drv->name)) - return NULL; - - /* Look at the dynamic ids first, before the static ones */ - spin_lock(&drv->dynids.lock); - list_for_each_entry(dynid, &drv->dynids.list, node) { - if (pci_match_one_device(&dynid->id, dev)) { - found_id = &dynid->id; - break; - } - } - spin_unlock(&drv->dynids.lock); - - if (!found_id) - found_id = pci_match_id(drv->id_table, dev); - - /* driver_override will always match, send a dummy id */ - if (!found_id && dev->driver_override) - found_id = &pci_device_id_any; - - return found_id; -} - struct drv_dev_and_id { struct pci_driver *drv; struct pci_dev *dev; -- 2.43.0
From: Danilo Krummrich <dakr@kernel.org> mainline inclusion from mainline-v7.1-rc1 commit 10a4206a24013be4d558d476010cbf2eb4c9fa64 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/15817 CVE: CVE-2026-53120 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- When a driver is probed through __driver_attach(), the bus' match() callback is called without the device lock held, thus accessing the driver_override field without a lock, which can cause a UAF. Fix this by using the driver-core driver_override infrastructure taking care of proper locking internally. Note that calling match() from __driver_attach() without the device lock held is intentional. [1] Link: https://lore.kernel.org/driver-core/DGRGTIRHA62X.3RY09D9SOK77P@kernel.org/ [1] Reported-by: Gui-Dong Han <hanguidong02@gmail.com> Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220789 Fixes: 782a985d7af2 ("PCI: Introduce new device binding path using pci_dev.driver_override") Acked-by: Bjorn Helgaas <bhelgaas@google.com> Acked-by: Alex Williamson <alex@shazbot.org> Tested-by: Gui-Dong Han <hanguidong02@gmail.com> Reviewed-by: Gui-Dong Han <hanguidong02@gmail.com> Link: https://patch.msgid.link/20260324005919.2408620-6-dakr@kernel.org Signed-off-by: Danilo Krummrich <dakr@kernel.org> Conflicts: drivers/pci/pci-driver.c drivers/pci/pci-sysfs.c drivers/vfio/pci/vfio_pci_core.c include/linux/pci.h drivers/pci/probe.c drivers/vfio/pci/vfio_pci.c [Ziming Du: context conflict due to 343b7258687ecfbb363bfda8833a7cf641aac524/23d99baf9d729ca30b2fb6798a7b403a37bfb800 and reconstruction of VFIO] Signed-off-by: Ziming Du <duziming2@huawei.com> --- drivers/pci/pci-driver.c | 9 ++++-- drivers/pci/pci-sysfs.c | 48 ------------------------------ drivers/pci/probe.c | 1 - drivers/vfio/pci/vfio_pci.c | 4 +-- drivers/xen/xen-pciback/pci_stub.c | 6 ++-- include/linux/pci.h | 1 - 6 files changed, 12 insertions(+), 57 deletions(-) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 172ae44f164b2..65e9543403589 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -137,9 +137,11 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv, { struct pci_dynid *dynid; const struct pci_device_id *found_id = NULL; + int ret; /* When driver_override is set, only bind to the matching driver */ - if (dev->driver_override && strcmp(dev->driver_override, drv->name)) + ret = device_match_driver_override(&dev->dev, &drv->driver); + if (ret == 0) return NULL; /* Look at the dynamic ids first, before the static ones */ @@ -156,7 +158,7 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv, found_id = pci_match_id(drv->id_table, dev); /* driver_override will always match, send a dummy id */ - if (!found_id && dev->driver_override) + if (!found_id && ret > 0) found_id = &pci_device_id_any; return found_id; @@ -406,7 +408,7 @@ void __weak pcibios_free_irq(struct pci_dev *dev) static inline bool pci_device_can_probe(struct pci_dev *pdev) { return (!pdev->is_virtfn || pdev->physfn->sriov->drivers_autoprobe || - pdev->driver_override); + device_has_driver_override(&pdev->dev)); } #else static inline bool pci_device_can_probe(struct pci_dev *pdev) @@ -1605,6 +1607,7 @@ static int pci_dma_configure(struct device *dev) struct bus_type pci_bus_type = { .name = "pci", + .driver_override = true, .match = pci_bus_match, .uevent = pci_uevent, .probe = pci_device_probe, diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 2140c483cc475..6a8e997689f95 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -557,53 +557,6 @@ static ssize_t devspec_show(struct device *dev, static DEVICE_ATTR_RO(devspec); #endif -static ssize_t driver_override_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct pci_dev *pdev = to_pci_dev(dev); - char *driver_override, *old, *cp; - - /* We need to keep extra room for a newline */ - if (count >= (PAGE_SIZE - 1)) - return -EINVAL; - - driver_override = kstrndup(buf, count, GFP_KERNEL); - if (!driver_override) - return -ENOMEM; - - cp = strchr(driver_override, '\n'); - if (cp) - *cp = '\0'; - - device_lock(dev); - old = pdev->driver_override; - if (strlen(driver_override)) { - pdev->driver_override = driver_override; - } else { - kfree(driver_override); - pdev->driver_override = NULL; - } - device_unlock(dev); - - kfree(old); - - return count; -} - -static ssize_t driver_override_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct pci_dev *pdev = to_pci_dev(dev); - ssize_t len; - - device_lock(dev); - len = scnprintf(buf, PAGE_SIZE, "%s\n", pdev->driver_override); - device_unlock(dev); - return len; -} -static DEVICE_ATTR_RW(driver_override); - static struct attribute *pci_dev_attrs[] = { &dev_attr_resource.attr, &dev_attr_vendor.attr, @@ -630,7 +583,6 @@ static struct attribute *pci_dev_attrs[] = { #ifdef CONFIG_OF &dev_attr_devspec.attr, #endif - &dev_attr_driver_override.attr, &dev_attr_ari_enabled.attr, NULL, }; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 77772e6f4e357..d660c06f6615c 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2245,7 +2245,6 @@ static void pci_release_dev(struct device *dev) pci_release_of_node(pci_dev); pcibios_release_device(pci_dev); pci_bus_put(pci_dev->bus); - kfree(pci_dev->driver_override); bitmap_free(pci_dev->dma_alias_mask); kfree(pci_dev); } diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 4c593554f6a08..9be7e0ea844dd 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -1990,8 +1990,8 @@ static int vfio_pci_bus_notifier(struct notifier_block *nb, pdev->is_virtfn && physfn == vdev->pdev) { pci_info(vdev->pdev, "Captured SR-IOV VF %s driver_override\n", pci_name(pdev)); - pdev->driver_override = kasprintf(GFP_KERNEL, "%s", - vfio_pci_ops.name); + device_set_driver_override(&pdev->dev, + vfio_pci_ops.name); } else if (action == BUS_NOTIFY_BOUND_DRIVER && pdev->is_virtfn && physfn == vdev->pdev) { struct pci_driver *drv = pci_dev_driver(pdev); diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c index cb904ac830064..c4f57d72d4608 100644 --- a/drivers/xen/xen-pciback/pci_stub.c +++ b/drivers/xen/xen-pciback/pci_stub.c @@ -556,6 +556,8 @@ static int pcistub_seize(struct pci_dev *dev, return err; } +static struct pci_driver xen_pcibk_pci_driver; + /* Called when 'bind'. This means we must _NOT_ call pci_reset_function or * other functions that take the sysfs lock. */ static int pcistub_probe(struct pci_dev *dev, const struct pci_device_id *id) @@ -567,8 +569,8 @@ static int pcistub_probe(struct pci_dev *dev, const struct pci_device_id *id) match = pcistub_match(dev); - if ((dev->driver_override && - !strcmp(dev->driver_override, PCISTUB_DRIVER_NAME)) || + if (device_match_driver_override(&dev->dev, + &xen_pcibk_pci_driver.driver) > 0 || match) { if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL diff --git a/include/linux/pci.h b/include/linux/pci.h index 6417b5229c602..874fc8cafa98f 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -502,7 +502,6 @@ struct pci_dev { u16 acs_cap; /* ACS Capability offset */ phys_addr_t rom; /* Physical address if not from BAR */ size_t romlen; /* Length if not from BAR */ - char *driver_override; /* Driver name to force a match */ unsigned long priv_flags; /* Private flags for the PCI driver */ /* -- 2.43.0
Offering: HULK hulk inclusion category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/15817 CVE: CVE-2026-53120 -------------------------------- Add driver_override back to fix kabi broken. Fixes: 10a4206a2401 ("PCI: use generic driver_override infrastructure") Signed-off-by: Ziming Du <duziming2@huawei.com> --- include/linux/pci.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/pci.h b/include/linux/pci.h index 874fc8cafa98f..3a576673cfe12 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -503,6 +503,7 @@ struct pci_dev { phys_addr_t rom; /* Physical address if not from BAR */ size_t romlen; /* Length if not from BAR */ + KABI_DEPRECATE(char *, driver_override) unsigned long priv_flags; /* Private flags for the PCI driver */ /* * This flag is only set on root ports. When a slot below a root port -- 2.43.0
From: Zhenzhong Duan <zhenzhong.duan@gmail.com> mainline inclusion from mainline-v5.11-rc1 commit 3853f9123c185eb4018f5ccd3cdda5968efb5e10 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/15817 CVE: CVE-2026-53120 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- When a device ID is written to /sys/bus/pci/drivers/.../new_id, we previously only checked the driver's static ID table for duplicates. Writing the same ID several times added it to the dynamic IDs list several times. This doesn't cause user-visible broken behavior, but remove_id_store() only removes one of the duplicate IDs, so if we add an ID several times, we would have to remove it the same number of times before it's completely gone. Fix it by calling pci_match_device(), which checks both dynamic and static IDs to avoid inserting duplicate IDs in dynamic IDs list. After fix, attempts to add an ID more than once cause an error: # echo "1af4 1041" > /sys/bus/pci/drivers/vfio-pci/new_id # echo "1af4 1041" > /sys/bus/pci/drivers/vfio-pci/new_id bash: echo: write error: File exists Link: https://lore.kernel.org/r/20201117054409.3428-3-zhenzhong.duan@gmail.com Signed-off-by: Zhenzhong Duan <zhenzhong.duan@gmail.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Signed-off-by: Ziming Du <duziming2@huawei.com> --- drivers/pci/pci-driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 65e9543403589..337ea5883e7a5 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -200,7 +200,7 @@ static ssize_t new_id_store(struct device_driver *driver, const char *buf, pdev->subsystem_device = subdevice; pdev->class = class; - if (pci_match_id(pdrv->id_table, pdev)) + if (pci_match_device(pdrv, pdev)) retval = -EEXIST; kfree(pdev); -- 2.43.0
From: Samiullah Khawaja <skhawaja@google.com> mainline inclusion from mainline-v7.1-rc3 commit f45a49a2380a47332817b7248c61a0ebbc6f0d00 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/15817 CVE: CVE-2026-53120 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- When setting new_id of a PCI device driver using sysfs a lockdep splat occurs. This is because new_id_store() builds a temporary pci_dev for pci_match_device(), which calls device_match_driver_override(). That depends on the driver_override.lock added by cb3d1049f4ea ("driver core: generalize driver_override in struct device"). The new driver_override.lock was not initialized in the temporary pci_dev, resulting in this lockdep splat. Initialize the temporary pci_dev to fix this. Repro: Build with CONFIG_LOCKDEP=y, boot with QEMU, and add a new ID: # echo "8086 10f5" > /sys/bus/pci/drivers/e1000e/new_id INFO: trying to register non-static key. The code is fine but needs lockdep annotation, or maybe you didn't initialize this object before use? turning off the locking correctness validator. CPU: 2 UID: 0 PID: 177 Comm: liveupdate-iomm Not tainted 7.0.0+ #9 PREEMPT(full) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014 Call Trace: <TASK> dump_stack_lvl+0x5d/0x80 register_lock_class+0x77e/0x790 lock_acquire+0xbf/0x2e0 pci_match_device+0x24/0x180 new_id_store+0x189/0x1d0 kernfs_fop_write_iter+0x14f/0x210 vfs_write+0x263/0x5e0 ksys_write+0x79/0xf0 do_syscall_64+0x117/0xf80 Fixes: 10a4206a2401 ("PCI: use generic driver_override infrastructure") Fixes: 8895d3bcb8ba ("PCI: Fail new_id for vendor/device values already built into driver") Signed-off-by: Samiullah Khawaja <skhawaja@google.com> [bhelgaas: add commit log details and repro, trim backtrace] Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Danilo Krummrich <dakr@kernel.org> Link: https://patch.msgid.link/20260505234327.716630-1-skhawaja@google.com Conflicts: drivers/pci/pci-driver.c [Ziming Du: context conflict] Signed-off-by: Ziming Du <duziming2@huawei.com> --- drivers/pci/pci-driver.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 337ea5883e7a5..0d9b725e6d4d1 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -164,6 +164,11 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv, return found_id; } +static void _pci_free_device(struct device *dev) +{ + kfree(to_pci_dev(dev)); +} + /** * store_new_id - sysfs frontend to pci_add_dynid() * @driver: target device driver @@ -199,11 +204,13 @@ static ssize_t new_id_store(struct device_driver *driver, const char *buf, pdev->subsystem_vendor = subvendor; pdev->subsystem_device = subdevice; pdev->class = class; + pdev->dev.release = _pci_free_device; + device_initialize(&pdev->dev); if (pci_match_device(pdrv, pdev)) retval = -EEXIST; - kfree(pdev); + put_device(&pdev->dev); if (retval) return retval; -- 2.43.0
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://atomgit.com/openeuler/kernel/merge_requests/25779 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/2O2... 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/25779 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/2O2...
participants (2)
-
patchwork bot -
Ziming Du