]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.15-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 20 Oct 2023 15:03:32 +0000 (17:03 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 20 Oct 2023 15:03:32 +0000 (17:03 +0200)
added patches:
driver-platform-add-helper-for-safer-setting-of-driver_override.patch
rpmsg-constify-local-variable-in-field-store-macro.patch
rpmsg-fix-kfree-of-static-memory-on-setting-driver_override.patch
xfs-don-t-expose-internal-symlink-metadata-buffers-to-the-vfs.patch

queue-5.15/driver-platform-add-helper-for-safer-setting-of-driver_override.patch [new file with mode: 0644]
queue-5.15/rpmsg-constify-local-variable-in-field-store-macro.patch [new file with mode: 0644]
queue-5.15/rpmsg-fix-kfree-of-static-memory-on-setting-driver_override.patch [new file with mode: 0644]
queue-5.15/series
queue-5.15/xfs-don-t-expose-internal-symlink-metadata-buffers-to-the-vfs.patch [new file with mode: 0644]

diff --git a/queue-5.15/driver-platform-add-helper-for-safer-setting-of-driver_override.patch b/queue-5.15/driver-platform-add-helper-for-safer-setting-of-driver_override.patch
new file mode 100644 (file)
index 0000000..3713037
--- /dev/null
@@ -0,0 +1,204 @@
+From stable-owner@vger.kernel.org Wed Oct 18 14:04:56 2023
+From: Lee Jones <lee@kernel.org>
+Date: Wed, 18 Oct 2023 13:04:32 +0100
+Subject: driver: platform: Add helper for safer setting of driver_override
+To: lee@kernel.org
+Cc: stable@vger.kernel.org, Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>, "Rafael J . Wysocki" <rafael.j.wysocki@intel.com>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Message-ID: <20231018120441.2110004-1-lee@kernel.org>
+
+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.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Lee Jones <lee@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/base/driver.c           |   69 ++++++++++++++++++++++++++++++++++++++++
+ drivers/base/platform.c         |   28 ++--------------
+ include/linux/device/driver.h   |    2 +
+ include/linux/platform_device.h |    6 ++-
+ 4 files changed, 80 insertions(+), 25 deletions(-)
+
+--- a/drivers/base/driver.c
++++ b/drivers/base/driver.c
+@@ -31,6 +31,75 @@ static struct device *next_device(struct
+ }
+ /**
++ * 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.
+  * @start: Device to begin with
+--- a/drivers/base/platform.c
++++ b/drivers/base/platform.c
+@@ -1270,31 +1270,11 @@ static ssize_t driver_override_store(str
+                                    const char *buf, size_t count)
+ {
+       struct platform_device *pdev = to_platform_device(dev);
+-      char *driver_override, *old, *cp;
++      int ret;
+-      /* 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);
++      ret = driver_set_override(dev, &pdev->driver_override, buf, count);
++      if (ret)
++              return ret;
+       return count;
+ }
+--- a/include/linux/device/driver.h
++++ b/include/linux/device/driver.h
+@@ -150,6 +150,8 @@ extern int __must_check driver_create_fi
+ 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,
+--- a/include/linux/platform_device.h
++++ b/include/linux/platform_device.h
+@@ -31,7 +31,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;
diff --git a/queue-5.15/rpmsg-constify-local-variable-in-field-store-macro.patch b/queue-5.15/rpmsg-constify-local-variable-in-field-store-macro.patch
new file mode 100644 (file)
index 0000000..21b5632
--- /dev/null
@@ -0,0 +1,36 @@
+From stable-owner@vger.kernel.org Wed Oct 18 14:04:56 2023
+From: Lee Jones <lee@kernel.org>
+Date: Wed, 18 Oct 2023 13:04:33 +0100
+Subject: rpmsg: Constify local variable in field store macro
+To: lee@kernel.org
+Cc: stable@vger.kernel.org, Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Message-ID: <20231018120441.2110004-2-lee@kernel.org>
+
+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@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Lee Jones <lee@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/rpmsg/rpmsg_core.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/rpmsg/rpmsg_core.c
++++ b/drivers/rpmsg/rpmsg_core.c
+@@ -376,7 +376,8 @@ field##_store(struct device *dev, struct
+             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)                                                       \
diff --git a/queue-5.15/rpmsg-fix-kfree-of-static-memory-on-setting-driver_override.patch b/queue-5.15/rpmsg-fix-kfree-of-static-memory-on-setting-driver_override.patch
new file mode 100644 (file)
index 0000000..d681c5b
--- /dev/null
@@ -0,0 +1,77 @@
+From stable-owner@vger.kernel.org Wed Oct 18 14:04:57 2023
+From: Lee Jones <lee@kernel.org>
+Date: Wed, 18 Oct 2023 13:04:34 +0100
+Subject: rpmsg: Fix kfree() of static memory on setting driver_override
+To: lee@kernel.org
+Cc: stable@vger.kernel.org, Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>, Bjorn Andersson <bjorn.andersson@linaro.org>, Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Message-ID: <20231018120441.2110004-3-lee@kernel.org>
+
+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@linaro.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Lee Jones <lee@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/rpmsg/rpmsg_internal.h |   13 +++++++++++--
+ include/linux/rpmsg.h          |    6 ++++--
+ 2 files changed, 15 insertions(+), 4 deletions(-)
+
+--- a/drivers/rpmsg/rpmsg_internal.h
++++ b/drivers/rpmsg/rpmsg_internal.h
+@@ -90,10 +90,19 @@ int rpmsg_release_channel(struct rpmsg_d
+  */
+ 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
+--- 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
+@@ -51,7 +53,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;
index 8d63cbd64cb429abdaec739d252a10467a57d09e..88af243e89d1f044a88a107ca3badb7ee0d24192 100644 (file)
@@ -1,2 +1,6 @@
 lib-kconfig.debug-do-not-enable-debug_preempt-by-default.patch
 documentation-sysctl-align-cells-in-second-content-column.patch
+xfs-don-t-expose-internal-symlink-metadata-buffers-to-the-vfs.patch
+driver-platform-add-helper-for-safer-setting-of-driver_override.patch
+rpmsg-constify-local-variable-in-field-store-macro.patch
+rpmsg-fix-kfree-of-static-memory-on-setting-driver_override.patch
diff --git a/queue-5.15/xfs-don-t-expose-internal-symlink-metadata-buffers-to-the-vfs.patch b/queue-5.15/xfs-don-t-expose-internal-symlink-metadata-buffers-to-the-vfs.patch
new file mode 100644 (file)
index 0000000..0fcb7a9
--- /dev/null
@@ -0,0 +1,155 @@
+From 7b7820b83f230036fc48c3e7fb280c48c58adebf Mon Sep 17 00:00:00 2001
+From: "Darrick J. Wong" <djwong@kernel.org>
+Date: Wed, 15 Dec 2021 12:07:41 -0800
+Subject: xfs: don't expose internal symlink metadata buffers to the vfs
+
+From: Darrick J. Wong <djwong@kernel.org>
+
+commit 7b7820b83f230036fc48c3e7fb280c48c58adebf upstream.
+
+Ian Kent reported that for inline symlinks, it's possible for
+vfs_readlink to hang on to the target buffer returned by
+_vn_get_link_inline long after it's been freed by xfs inode reclaim.
+This is a layering violation -- we should never expose XFS internals to
+the VFS.
+
+When the symlink has a remote target, we allocate a separate buffer,
+copy the internal information, and let the VFS manage the new buffer's
+lifetime.  Let's adapt the inline code paths to do this too.  It's
+less efficient, but fixes the layering violation and avoids the need to
+adapt the if_data lifetime to rcu rules.  Clearly I don't care about
+readlink benchmarks.
+
+As a side note, this fixes the minor locking violation where we can
+access the inode data fork without taking any locks; proper locking (and
+eliminating the possibility of having to switch inode_operations on a
+live inode) is essential to online repair coordinating repairs
+correctly.
+
+Reported-by: Ian Kent <raven@themaw.net>
+Signed-off-by: Darrick J. Wong <djwong@kernel.org>
+Reviewed-by: Dave Chinner <dchinner@redhat.com>
+Tested-by: Chandan Babu R <chandanbabu@kernel.org>
+Acked-by: Leah Rumancik <leah.rumancik@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/xfs/xfs_iops.c    |   34 +---------------------------------
+ fs/xfs/xfs_symlink.c |   29 +++++++++++++++++++----------
+ 2 files changed, 20 insertions(+), 43 deletions(-)
+
+--- a/fs/xfs/xfs_iops.c
++++ b/fs/xfs/xfs_iops.c
+@@ -511,27 +511,6 @@ xfs_vn_get_link(
+       return ERR_PTR(error);
+ }
+-STATIC const char *
+-xfs_vn_get_link_inline(
+-      struct dentry           *dentry,
+-      struct inode            *inode,
+-      struct delayed_call     *done)
+-{
+-      struct xfs_inode        *ip = XFS_I(inode);
+-      char                    *link;
+-
+-      ASSERT(ip->i_df.if_format == XFS_DINODE_FMT_LOCAL);
+-
+-      /*
+-       * The VFS crashes on a NULL pointer, so return -EFSCORRUPTED if
+-       * if_data is junk.
+-       */
+-      link = ip->i_df.if_u1.if_data;
+-      if (XFS_IS_CORRUPT(ip->i_mount, !link))
+-              return ERR_PTR(-EFSCORRUPTED);
+-      return link;
+-}
+-
+ static uint32_t
+ xfs_stat_blksize(
+       struct xfs_inode        *ip)
+@@ -1200,14 +1179,6 @@ static const struct inode_operations xfs
+       .update_time            = xfs_vn_update_time,
+ };
+-static const struct inode_operations xfs_inline_symlink_inode_operations = {
+-      .get_link               = xfs_vn_get_link_inline,
+-      .getattr                = xfs_vn_getattr,
+-      .setattr                = xfs_vn_setattr,
+-      .listxattr              = xfs_vn_listxattr,
+-      .update_time            = xfs_vn_update_time,
+-};
+-
+ /* Figure out if this file actually supports DAX. */
+ static bool
+ xfs_inode_supports_dax(
+@@ -1358,10 +1329,7 @@ xfs_setup_iops(
+               inode->i_fop = &xfs_dir_file_operations;
+               break;
+       case S_IFLNK:
+-              if (ip->i_df.if_format == XFS_DINODE_FMT_LOCAL)
+-                      inode->i_op = &xfs_inline_symlink_inode_operations;
+-              else
+-                      inode->i_op = &xfs_symlink_inode_operations;
++              inode->i_op = &xfs_symlink_inode_operations;
+               break;
+       default:
+               inode->i_op = &xfs_inode_operations;
+--- a/fs/xfs/xfs_symlink.c
++++ b/fs/xfs/xfs_symlink.c
+@@ -22,6 +22,7 @@
+ #include "xfs_trace.h"
+ #include "xfs_trans.h"
+ #include "xfs_ialloc.h"
++#include "xfs_error.h"
+ /* ----- Kernel only functions below ----- */
+ int
+@@ -96,17 +97,15 @@ xfs_readlink_bmap_ilocked(
+ int
+ xfs_readlink(
+-      struct xfs_inode *ip,
+-      char            *link)
++      struct xfs_inode        *ip,
++      char                    *link)
+ {
+-      struct xfs_mount *mp = ip->i_mount;
+-      xfs_fsize_t     pathlen;
+-      int             error = 0;
++      struct xfs_mount        *mp = ip->i_mount;
++      xfs_fsize_t             pathlen;
++      int                     error = -EFSCORRUPTED;
+       trace_xfs_readlink(ip);
+-      ASSERT(ip->i_df.if_format != XFS_DINODE_FMT_LOCAL);
+-
+       if (xfs_is_shutdown(mp))
+               return -EIO;
+@@ -121,12 +120,22 @@ xfs_readlink(
+                        __func__, (unsigned long long) ip->i_ino,
+                        (long long) pathlen);
+               ASSERT(0);
+-              error = -EFSCORRUPTED;
+               goto out;
+       }
+-
+-      error = xfs_readlink_bmap_ilocked(ip, link);
++      if (ip->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
++              /*
++               * The VFS crashes on a NULL pointer, so return -EFSCORRUPTED
++               * if if_data is junk.
++               */
++              if (XFS_IS_CORRUPT(ip->i_mount, !ip->i_df.if_u1.if_data))
++                      goto out;
++
++              memcpy(link, ip->i_df.if_u1.if_data, pathlen + 1);
++              error = 0;
++      } else {
++              error = xfs_readlink_bmap_ilocked(ip, link);
++      }
+  out:
+       xfs_iunlock(ip, XFS_ILOCK_SHARED);