From: Greg Kroah-Hartman Date: Tue, 29 Apr 2025 07:30:30 +0000 (+0200) Subject: 6.6-stable patches X-Git-Tag: v5.4.293~43 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4c7d1c1d45b72e8e605dd60c4d84250028bae9a1;p=thirdparty%2Fkernel%2Fstable-queue.git 6.6-stable patches added patches: driver-core-fix-potential-null-pointer-dereference-in-dev_uevent.patch driver-core-introduce-device_set_driver-helper.patch revert-drivers-core-synchronize-really_probe-and-dev_uevent.patch x86-pvh-call-c-code-via-the-kernel-virtual-mapping.patch --- diff --git a/queue-6.6/driver-core-fix-potential-null-pointer-dereference-in-dev_uevent.patch b/queue-6.6/driver-core-fix-potential-null-pointer-dereference-in-dev_uevent.patch new file mode 100644 index 0000000000..5b8f6b8833 --- /dev/null +++ b/queue-6.6/driver-core-fix-potential-null-pointer-dereference-in-dev_uevent.patch @@ -0,0 +1,118 @@ +From 18daa52418e7e4629ed1703b64777294209d2622 Mon Sep 17 00:00:00 2001 +From: Dmitry Torokhov +Date: Mon, 10 Mar 2025 22:24:16 -0700 +Subject: driver core: fix potential NULL pointer dereference in dev_uevent() + +From: Dmitry Torokhov + +commit 18daa52418e7e4629ed1703b64777294209d2622 upstream. + +If userspace reads "uevent" device attribute at the same time as another +threads unbinds the device from its driver, change to dev->driver from a +valid pointer to NULL may result in crash. Fix this by using READ_ONCE() +when fetching the pointer, and take bus' drivers klist lock to make sure +driver instance will not disappear while we access it. + +Use WRITE_ONCE() when setting the driver pointer to ensure there is no +tearing. + +Signed-off-by: Dmitry Torokhov +Reviewed-by: Masami Hiramatsu (Google) +Link: https://lore.kernel.org/r/20250311052417.1846985-3-dmitry.torokhov@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/base/base.h | 13 ++++++++++++- + drivers/base/bus.c | 2 +- + drivers/base/core.c | 33 +++++++++++++++++++++++++++++++-- + 3 files changed, 44 insertions(+), 4 deletions(-) + +--- a/drivers/base/base.h ++++ b/drivers/base/base.h +@@ -73,6 +73,7 @@ static inline void subsys_put(struct sub + kset_put(&sp->subsys); + } + ++struct subsys_private *bus_to_subsys(const struct bus_type *bus); + struct subsys_private *class_to_subsys(const struct class *class); + + struct driver_private { +@@ -181,8 +182,18 @@ void device_driver_detach(struct device + + static inline void device_set_driver(struct device *dev, const struct device_driver *drv) + { ++ /* ++ * Majority (all?) read accesses to dev->driver happens either ++ * while holding device lock or in bus/driver code that is only ++ * invoked when the device is bound to a driver and there is no ++ * concern of the pointer being changed while it is being read. ++ * However when reading device's uevent file we read driver pointer ++ * without taking device lock (so we do not block there for ++ * arbitrary amount of time). We use WRITE_ONCE() here to prevent ++ * tearing so that READ_ONCE() can safely be used in uevent code. ++ */ + // FIXME - this cast should not be needed "soon" +- dev->driver = (struct device_driver *)drv; ++ WRITE_ONCE(dev->driver, (struct device_driver *)drv); + } + + int devres_release_all(struct device *dev); +--- a/drivers/base/bus.c ++++ b/drivers/base/bus.c +@@ -57,7 +57,7 @@ static int __must_check bus_rescan_devic + * NULL. A call to subsys_put() must be done when finished with the pointer in + * order for it to be properly freed. + */ +-static struct subsys_private *bus_to_subsys(const struct bus_type *bus) ++struct subsys_private *bus_to_subsys(const struct bus_type *bus) + { + struct subsys_private *sp = NULL; + struct kobject *kobj; +--- a/drivers/base/core.c ++++ b/drivers/base/core.c +@@ -2570,6 +2570,35 @@ static const char *dev_uevent_name(const + return NULL; + } + ++/* ++ * Try filling "DRIVER=" uevent variable for a device. Because this ++ * function may race with binding and unbinding the device from a driver, ++ * we need to be careful. Binding is generally safe, at worst we miss the ++ * fact that the device is already bound to a driver (but the driver ++ * information that is delivered through uevents is best-effort, it may ++ * become obsolete as soon as it is generated anyways). Unbinding is more ++ * risky as driver pointer is transitioning to NULL, so READ_ONCE() should ++ * be used to make sure we are dealing with the same pointer, and to ++ * ensure that driver structure is not going to disappear from under us ++ * we take bus' drivers klist lock. The assumption that only registered ++ * driver can be bound to a device, and to unregister a driver bus code ++ * will take the same lock. ++ */ ++static void dev_driver_uevent(const struct device *dev, struct kobj_uevent_env *env) ++{ ++ struct subsys_private *sp = bus_to_subsys(dev->bus); ++ ++ if (sp) { ++ scoped_guard(spinlock, &sp->klist_drivers.k_lock) { ++ struct device_driver *drv = READ_ONCE(dev->driver); ++ if (drv) ++ add_uevent_var(env, "DRIVER=%s", drv->name); ++ } ++ ++ subsys_put(sp); ++ } ++} ++ + static int dev_uevent(const struct kobject *kobj, struct kobj_uevent_env *env) + { + const struct device *dev = kobj_to_dev(kobj); +@@ -2601,8 +2630,8 @@ static int dev_uevent(const struct kobje + if (dev->type && dev->type->name) + add_uevent_var(env, "DEVTYPE=%s", dev->type->name); + +- if (dev->driver) +- add_uevent_var(env, "DRIVER=%s", dev->driver->name); ++ /* Add "DRIVER=%s" variable if the device is bound to a driver */ ++ dev_driver_uevent(dev, env); + + /* Add common DT information about the device */ + of_device_uevent(dev, env); diff --git a/queue-6.6/driver-core-introduce-device_set_driver-helper.patch b/queue-6.6/driver-core-introduce-device_set_driver-helper.patch new file mode 100644 index 0000000000..48f58b1c7a --- /dev/null +++ b/queue-6.6/driver-core-introduce-device_set_driver-helper.patch @@ -0,0 +1,78 @@ +From 04d3e5461c1f5cf8eec964ab64948ebed826e95e Mon Sep 17 00:00:00 2001 +From: Dmitry Torokhov +Date: Mon, 10 Mar 2025 22:24:15 -0700 +Subject: driver core: introduce device_set_driver() helper + +From: Dmitry Torokhov + +commit 04d3e5461c1f5cf8eec964ab64948ebed826e95e upstream. + +In preparation to closing a race when reading driver pointer in +dev_uevent() code, instead of setting device->driver pointer directly +introduce device_set_driver() helper. + +Signed-off-by: Dmitry Torokhov +Reviewed-by: Masami Hiramatsu (Google) +Link: https://lore.kernel.org/r/20250311052417.1846985-2-dmitry.torokhov@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/base/base.h | 6 ++++++ + drivers/base/core.c | 2 +- + drivers/base/dd.c | 6 +++--- + 3 files changed, 10 insertions(+), 4 deletions(-) + +--- a/drivers/base/base.h ++++ b/drivers/base/base.h +@@ -179,6 +179,12 @@ int driver_add_groups(struct device_driv + void driver_remove_groups(struct device_driver *drv, const struct attribute_group **groups); + void device_driver_detach(struct device *dev); + ++static inline void device_set_driver(struct device *dev, const struct device_driver *drv) ++{ ++ // FIXME - this cast should not be needed "soon" ++ dev->driver = (struct device_driver *)drv; ++} ++ + int devres_release_all(struct device *dev); + void device_block_probing(void); + void device_unblock_probing(void); +--- a/drivers/base/core.c ++++ b/drivers/base/core.c +@@ -3688,7 +3688,7 @@ done: + device_pm_remove(dev); + dpm_sysfs_remove(dev); + DPMError: +- dev->driver = NULL; ++ device_set_driver(dev, NULL); + bus_remove_device(dev); + BusError: + device_remove_attrs(dev); +--- a/drivers/base/dd.c ++++ b/drivers/base/dd.c +@@ -550,7 +550,7 @@ static void device_unbind_cleanup(struct + arch_teardown_dma_ops(dev); + kfree(dev->dma_range_map); + dev->dma_range_map = NULL; +- dev->driver = NULL; ++ device_set_driver(dev, NULL); + dev_set_drvdata(dev, NULL); + if (dev->pm_domain && dev->pm_domain->dismiss) + dev->pm_domain->dismiss(dev); +@@ -629,7 +629,7 @@ static int really_probe(struct device *d + } + + re_probe: +- dev->driver = drv; ++ device_set_driver(dev, drv); + + /* If using pinctrl, bind pins now before probing */ + ret = pinctrl_bind_pins(dev); +@@ -1014,7 +1014,7 @@ static int __device_attach(struct device + if (ret == 0) + ret = 1; + else { +- dev->driver = NULL; ++ device_set_driver(dev, NULL); + ret = 0; + } + } else { diff --git a/queue-6.6/revert-drivers-core-synchronize-really_probe-and-dev_uevent.patch b/queue-6.6/revert-drivers-core-synchronize-really_probe-and-dev_uevent.patch new file mode 100644 index 0000000000..4ae9db510c --- /dev/null +++ b/queue-6.6/revert-drivers-core-synchronize-really_probe-and-dev_uevent.patch @@ -0,0 +1,53 @@ +From dc1771f718548f7d4b93991b174c6e7b5e1ba410 Mon Sep 17 00:00:00 2001 +From: Dmitry Torokhov +Date: Mon, 10 Mar 2025 22:24:14 -0700 +Subject: Revert "drivers: core: synchronize really_probe() and dev_uevent()" + +From: Dmitry Torokhov + +commit dc1771f718548f7d4b93991b174c6e7b5e1ba410 upstream. + +This reverts commit c0a40097f0bc81deafc15f9195d1fb54595cd6d0. + +Probing a device can take arbitrary long time. In the field we observed +that, for example, probing a bad micro-SD cards in an external USB card +reader (or maybe cards were good but cables were flaky) sometimes takes +longer than 2 minutes due to multiple retries at various levels of the +stack. We can not block uevent_show() method for that long because udev +is reading that attribute very often and that blocks udev and interferes +with booting of the system. + +The change that introduced locking was concerned with dev_uevent() +racing with unbinding the driver. However we can handle it without +locking (which will be done in subsequent patch). + +There was also claim that synchronization with probe() is needed to +properly load USB drivers, however this is a red herring: the change +adding the lock was introduced in May of last year and USB loading and +probing worked properly for many years before that. + +Revert the harmful locking. + +Cc: stable@vger.kernel.org +Signed-off-by: Dmitry Torokhov +Reviewed-by: Masami Hiramatsu (Google) +Link: https://lore.kernel.org/r/20250311052417.1846985-1-dmitry.torokhov@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/base/core.c | 3 --- + 1 file changed, 3 deletions(-) + +--- a/drivers/base/core.c ++++ b/drivers/base/core.c +@@ -2672,11 +2672,8 @@ static ssize_t uevent_show(struct device + if (!env) + return -ENOMEM; + +- /* Synchronize with really_probe() */ +- device_lock(dev); + /* let the kset specific function add its keys */ + retval = kset->uevent_ops->uevent(&dev->kobj, env); +- device_unlock(dev); + if (retval) + goto out; + diff --git a/queue-6.6/series b/queue-6.6/series index d52b8bf5f6..44dcf91475 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -186,3 +186,7 @@ ubsan-fix-panic-from-test_ubsan_out_of_bounds.patch x86-cpu-add-cpu-model-number-for-bartlett-lake-cpus-.patch md-raid1-add-check-for-missing-source-disk-in-proces.patch spi-spi-imx-add-check-for-spi_imx_setupxfer.patch +x86-pvh-call-c-code-via-the-kernel-virtual-mapping.patch +revert-drivers-core-synchronize-really_probe-and-dev_uevent.patch +driver-core-introduce-device_set_driver-helper.patch +driver-core-fix-potential-null-pointer-dereference-in-dev_uevent.patch diff --git a/queue-6.6/x86-pvh-call-c-code-via-the-kernel-virtual-mapping.patch b/queue-6.6/x86-pvh-call-c-code-via-the-kernel-virtual-mapping.patch new file mode 100644 index 0000000000..3cb11a91c7 --- /dev/null +++ b/queue-6.6/x86-pvh-call-c-code-via-the-kernel-virtual-mapping.patch @@ -0,0 +1,49 @@ +From e8fbc0d9cab6c1ee6403f42c0991b0c1d5dbc092 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Wed, 9 Oct 2024 18:04:40 +0200 +Subject: x86/pvh: Call C code via the kernel virtual mapping + +From: Ard Biesheuvel + +commit e8fbc0d9cab6c1ee6403f42c0991b0c1d5dbc092 upstream. + +Calling C code via a different mapping than it was linked at is +problematic, because the compiler assumes that RIP-relative and absolute +symbol references are interchangeable. GCC in particular may use +RIP-relative per-CPU variable references even when not using -fpic. + +So call xen_prepare_pvh() via its kernel virtual mapping on x86_64, so +that those RIP-relative references produce the correct values. This +matches the pre-existing behavior for i386, which also invokes +xen_prepare_pvh() via the kernel virtual mapping before invoking +startup_32 with paging disabled again. + +Fixes: 7243b93345f7 ("xen/pvh: Bootstrap PVH guest") +Tested-by: Jason Andryuk +Reviewed-by: Jason Andryuk +Signed-off-by: Ard Biesheuvel +Message-ID: <20241009160438.3884381-8-ardb+git@google.com> +Signed-off-by: Juergen Gross +[ Stable context update ] +Signed-off-by: Jason Andryuk +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/platform/pvh/head.S | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/arch/x86/platform/pvh/head.S ++++ b/arch/x86/platform/pvh/head.S +@@ -100,7 +100,12 @@ SYM_CODE_START_LOCAL(pvh_start_xen) + xor %edx, %edx + wrmsr + +- call xen_prepare_pvh ++ /* Call xen_prepare_pvh() via the kernel virtual mapping */ ++ leaq xen_prepare_pvh(%rip), %rax ++ subq phys_base(%rip), %rax ++ addq $__START_KERNEL_map, %rax ++ ANNOTATE_RETPOLINE_SAFE ++ call *%rax + + /* startup_64 expects boot_params in %rsi. */ + mov $_pa(pvh_bootparams), %rsi