From: Krzysztof Kozlowski krzysztof.kozlowski@linaro.org
commit 6c2f421174273de8f83cde4286d1c076d43a2d35 upstream.
Several core drivers and buses expect that driver_override is a dynamically allocated memory thus later they can kfree() it.
However such assumption is not documented, there were in the past and there are already users setting it to a string literal. This leads to kfree() of static memory during device release (e.g. in error paths or during unbind):
kernel BUG at ../mm/slub.c:3960! Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM ... (kfree) from [<c058da50>] (platform_device_release+0x88/0xb4) (platform_device_release) from [<c0585be0>] (device_release+0x2c/0x90) (device_release) from [<c0a69050>] (kobject_put+0xec/0x20c) (kobject_put) from [<c0f2f120>] (exynos5_clk_probe+0x154/0x18c) (exynos5_clk_probe) from [<c058de70>] (platform_drv_probe+0x6c/0xa4) (platform_drv_probe) from [<c058b7ac>] (really_probe+0x280/0x414) (really_probe) from [<c058baf4>] (driver_probe_device+0x78/0x1c4) (driver_probe_device) from [<c0589854>] (bus_for_each_drv+0x74/0xb8) (bus_for_each_drv) from [<c058b48c>] (__device_attach+0xd4/0x16c) (__device_attach) from [<c058a638>] (bus_probe_device+0x88/0x90) (bus_probe_device) from [<c05871fc>] (device_add+0x3dc/0x62c) (device_add) from [<c075ff10>] (of_platform_device_create_pdata+0x94/0xbc) (of_platform_device_create_pdata) from [<c07600ec>] (of_platform_bus_create+0x1a8/0x4fc) (of_platform_bus_create) from [<c0760150>] (of_platform_bus_create+0x20c/0x4fc) (of_platform_bus_create) from [<c07605f0>] (of_platform_populate+0x84/0x118) (of_platform_populate) from [<c0f3c964>] (of_platform_default_populate_init+0xa0/0xb8) (of_platform_default_populate_init) from [<c01031f8>] (do_one_initcall+0x8c/0x404)
Provide a helper which clearly documents the usage of driver_override. This will allow later to reuse the helper and reduce the amount of duplicated code.
Convert the platform driver to use a new helper and make the driver_override field const char (it is not modified by the core).
Reviewed-by: Rafael J. Wysocki rafael.j.wysocki@intel.com Acked-by: Rafael J. Wysocki rafael.j.wysocki@intel.com Signed-off-by: Krzysztof Kozlowski krzysztof.kozlowski@linaro.org Link: https://lore.kernel.org/r/20220419113435.246203-2-krzysztof.kozlowski@linaro... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Lee Jones lee@kernel.org --- drivers/base/driver.c | 69 +++++++++++++++++++++++++++++++++ drivers/base/platform.c | 28 ++----------- include/linux/device.h | 2 + include/linux/platform_device.h | 6 ++- 4 files changed, 80 insertions(+), 25 deletions(-)
diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 4e5ca632f35e8..ef14566a49710 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -29,6 +29,75 @@ static struct device *next_device(struct klist_iter *i) return dev; }
+/** + * driver_set_override() - Helper to set or clear driver override. + * @dev: Device to change + * @override: Address of string to change (e.g. &device->driver_override); + * The contents will be freed and hold newly allocated override. + * @s: NUL-terminated string, new driver name to force a match, pass empty + * string to clear it ("" or "\n", where the latter is only for sysfs + * interface). + * @len: length of @s + * + * Helper to set or clear driver override in a device, intended for the cases + * when the driver_override field is allocated by driver/bus code. + * + * Returns: 0 on success or a negative error code on failure. + */ +int driver_set_override(struct device *dev, const char **override, + const char *s, size_t len) +{ + const char *new, *old; + char *cp; + + if (!override || !s) + return -EINVAL; + + /* + * The stored value will be used in sysfs show callback (sysfs_emit()), + * which has a length limit of PAGE_SIZE and adds a trailing newline. + * Thus we can store one character less to avoid truncation during sysfs + * show. + */ + if (len >= (PAGE_SIZE - 1)) + return -EINVAL; + + if (!len) { + /* Empty string passed - clear override */ + device_lock(dev); + old = *override; + *override = NULL; + device_unlock(dev); + kfree(old); + + return 0; + } + + cp = strnchr(s, len, '\n'); + if (cp) + len = cp - s; + + new = kstrndup(s, len, GFP_KERNEL); + if (!new) + return -ENOMEM; + + device_lock(dev); + old = *override; + if (cp != s) { + *override = new; + } else { + /* "\n" passed - clear override */ + kfree(new); + *override = NULL; + } + device_unlock(dev); + + kfree(old); + + return 0; +} +EXPORT_SYMBOL_GPL(driver_set_override); + /** * driver_for_each_device - Iterator for devices bound to a driver. * @drv: Driver we're iterating. diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 75623b914b8c2..0ed43d185a900 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -973,31 +973,11 @@ static ssize_t driver_override_store(struct device *dev, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(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); + int ret;
- kfree(old); + ret = driver_set_override(dev, &pdev->driver_override, buf, count); + if (ret) + return ret;
return count; } diff --git a/include/linux/device.h b/include/linux/device.h index c7be3a8073ec3..af4ecbf889107 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -422,6 +422,8 @@ extern int __must_check driver_create_file(struct device_driver *driver, extern void driver_remove_file(struct device_driver *driver, const struct driver_attribute *attr);
+int driver_set_override(struct device *dev, const char **override, + const char *s, size_t len); extern int __must_check driver_for_each_device(struct device_driver *drv, struct device *start, void *data, diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index 569f446502bed..c7bd8a1a60976 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -29,7 +29,11 @@ struct platform_device { struct resource *resource;
const struct platform_device_id *id_entry; - char *driver_override; /* Driver name to force a match */ + /* + * Driver name to force a match. Do not set directly, because core + * frees it. Use driver_set_override() to set or clear it. + */ + const char *driver_override;
/* MFD cell pointer */ struct mfd_cell *mfd_cell;
From: Krzysztof Kozlowski krzysztof.kozlowski@linaro.org
commit e5f89131a06142e91073b6959d91cea73861d40e upstream.
Memory pointed by variable 'old' in field store macro is not modified, so it can be made a pointer to const.
Signed-off-by: Krzysztof Kozlowski krzysztof.kozlowski@linaro.org Link: https://lore.kernel.org/r/20220419113435.246203-12-krzysztof.kozlowski@linar... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Lee Jones lee@kernel.org --- drivers/rpmsg/rpmsg_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index c1d4990beab02..458ddfc09120b 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -332,7 +332,8 @@ field##_store(struct device *dev, struct device_attribute *attr, \ const char *buf, size_t sz) \ { \ struct rpmsg_device *rpdev = to_rpmsg_device(dev); \ - char *new, *old; \ + const char *old; \ + char *new; \ \ new = kstrndup(buf, sz, GFP_KERNEL); \ if (!new) \
From: Krzysztof Kozlowski krzysztof.kozlowski@linaro.org
commit e5f89131a06142e91073b6959d91cea73861d40e upstream.
Memory pointed by variable 'old' in field store macro is not modified, so it can be made a pointer to const.
Signed-off-by: Krzysztof Kozlowski krzysztof.kozlowski@linaro.org Link: https://lore.kernel.org/r/20220419113435.246203-12-krzysztof.kozlowski@linar... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Lee Jones lee@kernel.org --- drivers/rpmsg/rpmsg_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index c1d4990beab02..458ddfc09120b 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -332,7 +332,8 @@ field##_store(struct device *dev, struct device_attribute *attr, \ const char *buf, size_t sz) \ { \ struct rpmsg_device *rpdev = to_rpmsg_device(dev); \ - char *new, *old; \ + const char *old; \ + char *new; \ \ new = kstrndup(buf, sz, GFP_KERNEL); \ if (!new) \
From: Krzysztof Kozlowski krzysztof.kozlowski@linaro.org
commit 42cd402b8fd4672b692400fe5f9eecd55d2794ac upstream.
The driver_override field from platform driver should not be initialized from static memory (string literal) because the core later kfree() it, for example when driver_override is set via sysfs.
Use dedicated helper to set driver_override properly.
Fixes: 950a7388f02b ("rpmsg: Turn name service into a stand alone driver") Fixes: c0cdc19f84a4 ("rpmsg: Driver for user space endpoint interface") Reviewed-by: Bjorn Andersson bjorn.andersson@linaro.org Signed-off-by: Krzysztof Kozlowski krzysztof.kozlowski@linaro.org Link: https://lore.kernel.org/r/20220419113435.246203-13-krzysztof.kozlowski@linar... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Lee Jones lee@kernel.org --- drivers/rpmsg/rpmsg_internal.h | 13 +++++++++++-- include/linux/rpmsg.h | 6 ++++-- 2 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h index 3fc83cd50e98f..9165e3c811be4 100644 --- a/drivers/rpmsg/rpmsg_internal.h +++ b/drivers/rpmsg/rpmsg_internal.h @@ -84,10 +84,19 @@ struct device *rpmsg_find_device(struct device *parent, */ static inline int rpmsg_chrdev_register_device(struct rpmsg_device *rpdev) { + int ret; + strcpy(rpdev->id.name, "rpmsg_chrdev"); - rpdev->driver_override = "rpmsg_chrdev"; + ret = driver_set_override(&rpdev->dev, &rpdev->driver_override, + rpdev->id.name, strlen(rpdev->id.name)); + if (ret) + return ret; + + ret = rpmsg_register_device(rpdev); + if (ret) + kfree(rpdev->driver_override);
- return rpmsg_register_device(rpdev); + return ret; }
#endif diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h index a68972b097b72..6e7690e20dc51 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h @@ -41,7 +41,9 @@ struct rpmsg_channel_info { * rpmsg_device - device that belong to the rpmsg bus * @dev: the device struct * @id: device id (used to match between rpmsg drivers and devices) - * @driver_override: driver name to force a match + * @driver_override: driver name to force a match; do not set directly, + * because core frees it; use driver_set_override() to + * set or clear it. * @src: local address * @dst: destination address * @ept: the rpmsg endpoint of this channel @@ -50,7 +52,7 @@ struct rpmsg_channel_info { struct rpmsg_device { struct device dev; struct rpmsg_device_id id; - char *driver_override; + const char *driver_override; u32 src; u32 dst; struct rpmsg_endpoint *ept;
From: Krzysztof Kozlowski krzysztof.kozlowski@linaro.org
commit 42cd402b8fd4672b692400fe5f9eecd55d2794ac upstream.
The driver_override field from platform driver should not be initialized from static memory (string literal) because the core later kfree() it, for example when driver_override is set via sysfs.
Use dedicated helper to set driver_override properly.
Fixes: 950a7388f02b ("rpmsg: Turn name service into a stand alone driver") Fixes: c0cdc19f84a4 ("rpmsg: Driver for user space endpoint interface") Reviewed-by: Bjorn Andersson bjorn.andersson@linaro.org Signed-off-by: Krzysztof Kozlowski krzysztof.kozlowski@linaro.org Link: https://lore.kernel.org/r/20220419113435.246203-13-krzysztof.kozlowski@linar... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Lee Jones lee@kernel.org --- drivers/rpmsg/rpmsg_internal.h | 13 +++++++++++-- include/linux/rpmsg.h | 6 ++++-- 2 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h index 3fc83cd50e98f..9165e3c811be4 100644 --- a/drivers/rpmsg/rpmsg_internal.h +++ b/drivers/rpmsg/rpmsg_internal.h @@ -84,10 +84,19 @@ struct device *rpmsg_find_device(struct device *parent, */ static inline int rpmsg_chrdev_register_device(struct rpmsg_device *rpdev) { + int ret; + strcpy(rpdev->id.name, "rpmsg_chrdev"); - rpdev->driver_override = "rpmsg_chrdev"; + ret = driver_set_override(&rpdev->dev, &rpdev->driver_override, + rpdev->id.name, strlen(rpdev->id.name)); + if (ret) + return ret; + + ret = rpmsg_register_device(rpdev); + if (ret) + kfree(rpdev->driver_override);
- return rpmsg_register_device(rpdev); + return ret; }
#endif diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h index a68972b097b72..6e7690e20dc51 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h @@ -41,7 +41,9 @@ struct rpmsg_channel_info { * rpmsg_device - device that belong to the rpmsg bus * @dev: the device struct * @id: device id (used to match between rpmsg drivers and devices) - * @driver_override: driver name to force a match + * @driver_override: driver name to force a match; do not set directly, + * because core frees it; use driver_set_override() to + * set or clear it. * @src: local address * @dst: destination address * @ept: the rpmsg endpoint of this channel @@ -50,7 +52,7 @@ struct rpmsg_channel_info { struct rpmsg_device { struct device dev; struct rpmsg_device_id id; - char *driver_override; + const char *driver_override; u32 src; u32 dst; struct rpmsg_endpoint *ept;
<snip>
Something went wrong with this 5.4 series you sent, I got the following emails which look like 2 different versions of this series?:
11 C Oct 18 Lee Jones (7.0K) [PATCH v5.4.y 1/3] driver: platform: Add helper for safer setting of driver_override 12 C Oct 18 Lee Jones (2.6K) ├─>[PATCH v5.4.y 3/3] rpmsg: Fix kfree() of static memory on setting driver_override 13 C Oct 18 Lee Jones (1.1K) ├─>[PATCH v5.4.y 2/3] rpmsg: Constify local variable in field store macro 14 C Oct 18 Lee Jones (2.6K) ├─>[PATCH v5.4.y 2/2] rpmsg: Fix kfree() of static memory on setting driver_override 15 C Oct 18 Lee Jones (1.1K) └─>[PATCH v5.4.y 1/2] rpmsg: Constify local variable in field store macro
And you can see it here: https://lore.kernel.org/all/20231018120527.2110438-1-lee@kernel.org/#r
So I don't know what patches to take for 5.4, sorry. Can you please resend the properly ones?
thanks,
greg k-h
On Fri, 20 Oct 2023, Greg Kroah-Hartman wrote:
<snip>
Something went wrong with this 5.4 series you sent, I got the following emails which look like 2 different versions of this series?:
11 C Oct 18 Lee Jones (7.0K) [PATCH v5.4.y 1/3] driver: platform: Add helper for safer setting of driver_override 12 C Oct 18 Lee Jones (2.6K) ├─>[PATCH v5.4.y 3/3] rpmsg: Fix kfree() of static memory on setting driver_override 13 C Oct 18 Lee Jones (1.1K) ├─>[PATCH v5.4.y 2/3] rpmsg: Constify local variable in field store macro 14 C Oct 18 Lee Jones (2.6K) ├─>[PATCH v5.4.y 2/2] rpmsg: Fix kfree() of static memory on setting driver_override 15 C Oct 18 Lee Jones (1.1K) └─>[PATCH v5.4.y 1/2] rpmsg: Constify local variable in field store macro
And you can see it here: https://lore.kernel.org/all/20231018120527.2110438-1-lee@kernel.org/#r
So I don't know what patches to take for 5.4, sorry. Can you please resend the properly ones?
You're right. They're in my inbox too.
One set was sent 1s after the other, so must be a tooling error.
The 2 sets are identical.
1/3 == 1/3 2/3 == 2/3 3/3 == 3/3
On Mon, Oct 23, 2023 at 10:48:15AM +0100, Lee Jones wrote:
On Fri, 20 Oct 2023, Greg Kroah-Hartman wrote:
<snip>
Something went wrong with this 5.4 series you sent, I got the following emails which look like 2 different versions of this series?:
11 C Oct 18 Lee Jones (7.0K) [PATCH v5.4.y 1/3] driver: platform: Add helper for safer setting of driver_override 12 C Oct 18 Lee Jones (2.6K) ├─>[PATCH v5.4.y 3/3] rpmsg: Fix kfree() of static memory on setting driver_override 13 C Oct 18 Lee Jones (1.1K) ├─>[PATCH v5.4.y 2/3] rpmsg: Constify local variable in field store macro 14 C Oct 18 Lee Jones (2.6K) ├─>[PATCH v5.4.y 2/2] rpmsg: Fix kfree() of static memory on setting driver_override 15 C Oct 18 Lee Jones (1.1K) └─>[PATCH v5.4.y 1/2] rpmsg: Constify local variable in field store macro
And you can see it here: https://lore.kernel.org/all/20231018120527.2110438-1-lee@kernel.org/#r
So I don't know what patches to take for 5.4, sorry. Can you please resend the properly ones?
You're right. They're in my inbox too.
One set was sent 1s after the other, so must be a tooling error.
The 2 sets are identical.
1/3 == 1/3 2/3 == 2/3 3/3 == 3/3
You have 1/2 and 2/2 here, so hence my confusion :(
All of these need to be resent anyway, let's talk off-list...
thanks,
greg k-h
linux-stable-mirror@lists.linaro.org