]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.6-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 12 Jul 2025 14:45:16 +0000 (16:45 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 12 Jul 2025 14:45:16 +0000 (16:45 +0200)
added patches:
drm-framebuffer-acquire-internal-references-on-gem-handles.patch
revert-usb-gadget-u_serial-add-null-pointer-check-in-gs_start_io.patch
usb-gadget-u_serial-fix-race-condition-in-tty-wakeup.patch

queue-6.6/drm-framebuffer-acquire-internal-references-on-gem-handles.patch [new file with mode: 0644]
queue-6.6/revert-usb-gadget-u_serial-add-null-pointer-check-in-gs_start_io.patch [new file with mode: 0644]
queue-6.6/series
queue-6.6/usb-gadget-u_serial-fix-race-condition-in-tty-wakeup.patch [new file with mode: 0644]

diff --git a/queue-6.6/drm-framebuffer-acquire-internal-references-on-gem-handles.patch b/queue-6.6/drm-framebuffer-acquire-internal-references-on-gem-handles.patch
new file mode 100644 (file)
index 0000000..2ded45d
--- /dev/null
@@ -0,0 +1,303 @@
+From f6bfc9afc7510cb5e6fbe0a17c507917b0120280 Mon Sep 17 00:00:00 2001
+From: Thomas Zimmermann <tzimmermann@suse.de>
+Date: Mon, 7 Jul 2025 15:11:55 +0200
+Subject: drm/framebuffer: Acquire internal references on GEM handles
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Thomas Zimmermann <tzimmermann@suse.de>
+
+commit f6bfc9afc7510cb5e6fbe0a17c507917b0120280 upstream.
+
+Acquire GEM handles in drm_framebuffer_init() and release them in
+the corresponding drm_framebuffer_cleanup(). Ties the handle's
+lifetime to the framebuffer. Not all GEM buffer objects have GEM
+handles. If not set, no refcounting takes place. This is the case
+for some fbdev emulation. This is not a problem as these GEM objects
+do not use dma-bufs and drivers will not release them while fbdev
+emulation is running. Framebuffer flags keep a bit per color plane
+of which the framebuffer holds a GEM handle reference.
+
+As all drivers use drm_framebuffer_init(), they will now all hold
+dma-buf references as fixed in commit 5307dce878d4 ("drm/gem: Acquire
+references on GEM handles for framebuffers").
+
+In the GEM framebuffer helpers, restore the original ref counting
+on buffer objects. As the helpers for handle refcounting are now
+no longer called from outside the DRM core, unexport the symbols.
+
+v3:
+- don't mix internal flags with mode flags (Christian)
+v2:
+- track framebuffer handle refs by flag
+- drop gma500 cleanup (Christian)
+
+Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
+Fixes: 5307dce878d4 ("drm/gem: Acquire references on GEM handles for framebuffers")
+Reported-by: Bert Karwatzki <spasswolf@web.de>
+Closes: https://lore.kernel.org/dri-devel/20250703115915.3096-1-spasswolf@web.de/
+Tested-by: Bert Karwatzki <spasswolf@web.de>
+Tested-by: Mario Limonciello <superm1@kernel.org>
+Tested-by: Borislav Petkov (AMD) <bp@alien8.de>
+Cc: Thomas Zimmermann <tzimmermann@suse.de>
+Cc: Anusha Srivatsa <asrivats@redhat.com>
+Cc: Christian König <christian.koenig@amd.com>
+Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
+Cc: Maxime Ripard <mripard@kernel.org>
+Cc: Sumit Semwal <sumit.semwal@linaro.org>
+Cc: "Christian König" <christian.koenig@amd.com>
+Cc: linux-media@vger.kernel.org
+Cc: dri-devel@lists.freedesktop.org
+Cc: linaro-mm-sig@lists.linaro.org
+Cc: <stable@vger.kernel.org>
+Reviewed-by: Christian König <christian.koenig@amd.com>
+Link: https://lore.kernel.org/r/20250707131224.249496-1-tzimmermann@suse.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/drm_framebuffer.c            |   31 ++++++++++++++++++++--
+ drivers/gpu/drm/drm_gem.c                    |   38 +++++++++++++++++----------
+ drivers/gpu/drm/drm_gem_framebuffer_helper.c |   16 ++++-------
+ drivers/gpu/drm/drm_internal.h               |    2 -
+ include/drm/drm_framebuffer.h                |    7 ++++
+ 5 files changed, 68 insertions(+), 26 deletions(-)
+
+--- a/drivers/gpu/drm/drm_framebuffer.c
++++ b/drivers/gpu/drm/drm_framebuffer.c
+@@ -844,11 +844,23 @@ void drm_framebuffer_free(struct kref *k
+ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
+                        const struct drm_framebuffer_funcs *funcs)
+ {
++      unsigned int i;
+       int ret;
++      bool exists;
+       if (WARN_ON_ONCE(fb->dev != dev || !fb->format))
+               return -EINVAL;
++      for (i = 0; i < fb->format->num_planes; i++) {
++              if (drm_WARN_ON_ONCE(dev, fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i)))
++                      fb->internal_flags &= ~DRM_FRAMEBUFFER_HAS_HANDLE_REF(i);
++              if (fb->obj[i]) {
++                      exists = drm_gem_object_handle_get_if_exists_unlocked(fb->obj[i]);
++                      if (exists)
++                              fb->internal_flags |= DRM_FRAMEBUFFER_HAS_HANDLE_REF(i);
++              }
++      }
++
+       INIT_LIST_HEAD(&fb->filp_head);
+       fb->funcs = funcs;
+@@ -857,7 +869,7 @@ int drm_framebuffer_init(struct drm_devi
+       ret = __drm_mode_object_add(dev, &fb->base, DRM_MODE_OBJECT_FB,
+                                   false, drm_framebuffer_free);
+       if (ret)
+-              goto out;
++              goto err;
+       mutex_lock(&dev->mode_config.fb_lock);
+       dev->mode_config.num_fb++;
+@@ -865,7 +877,16 @@ int drm_framebuffer_init(struct drm_devi
+       mutex_unlock(&dev->mode_config.fb_lock);
+       drm_mode_object_register(dev, &fb->base);
+-out:
++
++      return 0;
++
++err:
++      for (i = 0; i < fb->format->num_planes; i++) {
++              if (fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i)) {
++                      drm_gem_object_handle_put_unlocked(fb->obj[i]);
++                      fb->internal_flags &= ~DRM_FRAMEBUFFER_HAS_HANDLE_REF(i);
++              }
++      }
+       return ret;
+ }
+ EXPORT_SYMBOL(drm_framebuffer_init);
+@@ -942,6 +963,12 @@ EXPORT_SYMBOL(drm_framebuffer_unregister
+ void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
+ {
+       struct drm_device *dev = fb->dev;
++      unsigned int i;
++
++      for (i = 0; i < fb->format->num_planes; i++) {
++              if (fb->internal_flags & DRM_FRAMEBUFFER_HAS_HANDLE_REF(i))
++                      drm_gem_object_handle_put_unlocked(fb->obj[i]);
++      }
+       mutex_lock(&dev->mode_config.fb_lock);
+       list_del(&fb->head);
+--- a/drivers/gpu/drm/drm_gem.c
++++ b/drivers/gpu/drm/drm_gem.c
+@@ -197,23 +197,34 @@ static void drm_gem_object_handle_get(st
+ }
+ /**
+- * drm_gem_object_handle_get_unlocked - acquire reference on user-space handles
++ * drm_gem_object_handle_get_if_exists_unlocked - acquire reference on user-space handle, if any
+  * @obj: GEM object
+  *
+- * Acquires a reference on the GEM buffer object's handle. Required
+- * to keep the GEM object alive. Call drm_gem_object_handle_put_unlocked()
+- * to release the reference.
++ * Acquires a reference on the GEM buffer object's handle. Required to keep
++ * the GEM object alive. Call drm_gem_object_handle_put_if_exists_unlocked()
++ * to release the reference. Does nothing if the buffer object has no handle.
++ *
++ * Returns:
++ * True if a handle exists, or false otherwise
+  */
+-void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj)
++bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj)
+ {
+       struct drm_device *dev = obj->dev;
+       guard(mutex)(&dev->object_name_lock);
+-      drm_WARN_ON(dev, !obj->handle_count); /* first ref taken in create-tail helper */
++      /*
++       * First ref taken during GEM object creation, if any. Some
++       * drivers set up internal framebuffers with GEM objects that
++       * do not have a GEM handle. Hence, this counter can be zero.
++       */
++      if (!obj->handle_count)
++              return false;
++
+       drm_gem_object_handle_get(obj);
++
++      return true;
+ }
+-EXPORT_SYMBOL(drm_gem_object_handle_get_unlocked);
+ /**
+  * drm_gem_object_handle_free - release resources bound to userspace handles
+@@ -246,7 +257,7 @@ static void drm_gem_object_exported_dma_
+ }
+ /**
+- * drm_gem_object_handle_put_unlocked - releases reference on user-space handles
++ * drm_gem_object_handle_put_unlocked - releases reference on user-space handle
+  * @obj: GEM object
+  *
+  * Releases a reference on the GEM buffer object's handle. Possibly releases
+@@ -257,14 +268,14 @@ void drm_gem_object_handle_put_unlocked(
+       struct drm_device *dev = obj->dev;
+       bool final = false;
+-      if (WARN_ON(READ_ONCE(obj->handle_count) == 0))
++      if (drm_WARN_ON(dev, READ_ONCE(obj->handle_count) == 0))
+               return;
+       /*
+-      * Must bump handle count first as this may be the last
+-      * ref, in which case the object would disappear before we
+-      * checked for a name
+-      */
++       * Must bump handle count first as this may be the last
++       * ref, in which case the object would disappear before
++       * we checked for a name.
++       */
+       mutex_lock(&dev->object_name_lock);
+       if (--obj->handle_count == 0) {
+@@ -277,7 +288,6 @@ void drm_gem_object_handle_put_unlocked(
+       if (final)
+               drm_gem_object_put(obj);
+ }
+-EXPORT_SYMBOL(drm_gem_object_handle_put_unlocked);
+ /*
+  * Called at device or object close to release the file's
+--- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c
++++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c
+@@ -99,7 +99,7 @@ void drm_gem_fb_destroy(struct drm_frame
+       unsigned int i;
+       for (i = 0; i < fb->format->num_planes; i++)
+-              drm_gem_object_handle_put_unlocked(fb->obj[i]);
++              drm_gem_object_put(fb->obj[i]);
+       drm_framebuffer_cleanup(fb);
+       kfree(fb);
+@@ -182,10 +182,8 @@ int drm_gem_fb_init_with_funcs(struct dr
+               if (!objs[i]) {
+                       drm_dbg_kms(dev, "Failed to lookup GEM object\n");
+                       ret = -ENOENT;
+-                      goto err_gem_object_handle_put_unlocked;
++                      goto err_gem_object_put;
+               }
+-              drm_gem_object_handle_get_unlocked(objs[i]);
+-              drm_gem_object_put(objs[i]);
+               min_size = (height - 1) * mode_cmd->pitches[i]
+                        + drm_format_info_min_pitch(info, i, width)
+@@ -195,22 +193,22 @@ int drm_gem_fb_init_with_funcs(struct dr
+                       drm_dbg_kms(dev,
+                                   "GEM object size (%zu) smaller than minimum size (%u) for plane %d\n",
+                                   objs[i]->size, min_size, i);
+-                      drm_gem_object_handle_put_unlocked(objs[i]);
++                      drm_gem_object_put(objs[i]);
+                       ret = -EINVAL;
+-                      goto err_gem_object_handle_put_unlocked;
++                      goto err_gem_object_put;
+               }
+       }
+       ret = drm_gem_fb_init(dev, fb, mode_cmd, objs, i, funcs);
+       if (ret)
+-              goto err_gem_object_handle_put_unlocked;
++              goto err_gem_object_put;
+       return 0;
+-err_gem_object_handle_put_unlocked:
++err_gem_object_put:
+       while (i > 0) {
+               --i;
+-              drm_gem_object_handle_put_unlocked(objs[i]);
++              drm_gem_object_put(objs[i]);
+       }
+       return ret;
+ }
+--- a/drivers/gpu/drm/drm_internal.h
++++ b/drivers/gpu/drm/drm_internal.h
+@@ -155,7 +155,7 @@ void drm_sysfs_lease_event(struct drm_de
+ /* drm_gem.c */
+ int drm_gem_init(struct drm_device *dev);
+-void drm_gem_object_handle_get_unlocked(struct drm_gem_object *obj);
++bool drm_gem_object_handle_get_if_exists_unlocked(struct drm_gem_object *obj);
+ void drm_gem_object_handle_put_unlocked(struct drm_gem_object *obj);
+ int drm_gem_handle_create_tail(struct drm_file *file_priv,
+                              struct drm_gem_object *obj,
+--- a/include/drm/drm_framebuffer.h
++++ b/include/drm/drm_framebuffer.h
+@@ -23,6 +23,7 @@
+ #ifndef __DRM_FRAMEBUFFER_H__
+ #define __DRM_FRAMEBUFFER_H__
++#include <linux/bits.h>
+ #include <linux/ctype.h>
+ #include <linux/list.h>
+ #include <linux/sched.h>
+@@ -100,6 +101,8 @@ struct drm_framebuffer_funcs {
+                    unsigned num_clips);
+ };
++#define DRM_FRAMEBUFFER_HAS_HANDLE_REF(_i)    BIT(0u + (_i))
++
+ /**
+  * struct drm_framebuffer - frame buffer object
+  *
+@@ -189,6 +192,10 @@ struct drm_framebuffer {
+        */
+       int flags;
+       /**
++       * @internal_flags: Framebuffer flags like DRM_FRAMEBUFFER_HAS_HANDLE_REF.
++       */
++      unsigned int internal_flags;
++      /**
+        * @hot_x: X coordinate of the cursor hotspot. Used by the legacy cursor
+        * IOCTL when the driver supports cursor through a DRM_PLANE_TYPE_CURSOR
+        * universal plane.
diff --git a/queue-6.6/revert-usb-gadget-u_serial-add-null-pointer-check-in-gs_start_io.patch b/queue-6.6/revert-usb-gadget-u_serial-add-null-pointer-check-in-gs_start_io.patch
new file mode 100644 (file)
index 0000000..2e47118
--- /dev/null
@@ -0,0 +1,57 @@
+From f6c7bc4a6823a0a959f40866a1efe99bd03c2c5b Mon Sep 17 00:00:00 2001
+From: Kuen-Han Tsai <khtsai@google.com>
+Date: Tue, 17 Jun 2025 13:07:11 +0800
+Subject: Revert "usb: gadget: u_serial: Add null pointer check in gs_start_io"
+
+From: Kuen-Han Tsai <khtsai@google.com>
+
+commit f6c7bc4a6823a0a959f40866a1efe99bd03c2c5b upstream.
+
+This reverts commit ffd603f214237e250271162a5b325c6199a65382.
+
+Commit ffd603f21423 ("usb: gadget: u_serial: Add null pointer check in
+gs_start_io") adds null pointer checks at the beginning of the
+gs_start_io() function to prevent a null pointer dereference. However,
+these checks are redundant because the function's comment already
+requires callers to hold the port_lock and ensure port.tty and port_usb
+are not null. All existing callers already follow these rules.
+
+The true cause of the null pointer dereference is a race condition. When
+gs_start_io() calls either gs_start_rx() or gs_start_tx(), the port_lock
+is temporarily released for usb_ep_queue(). This allows port.tty and
+port_usb to be cleared.
+
+Fixes: ffd603f21423 ("usb: gadget: u_serial: Add null pointer check in gs_start_io")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Kuen-Han Tsai <khtsai@google.com>
+Reviewed-by: Prashanth K <prashanth.k@oss.qualcomm.com>
+Link: https://lore.kernel.org/r/20250617050844.1848232-1-khtsai@google.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/function/u_serial.c |    6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+--- a/drivers/usb/gadget/function/u_serial.c
++++ b/drivers/usb/gadget/function/u_serial.c
+@@ -539,20 +539,16 @@ static int gs_alloc_requests(struct usb_
+ static int gs_start_io(struct gs_port *port)
+ {
+       struct list_head        *head = &port->read_pool;
+-      struct usb_ep           *ep;
++      struct usb_ep           *ep = port->port_usb->out;
+       int                     status;
+       unsigned                started;
+-      if (!port->port_usb || !port->port.tty)
+-              return -EIO;
+-
+       /* Allocate RX and TX I/O buffers.  We can't easily do this much
+        * earlier (with GFP_KERNEL) because the requests are coupled to
+        * endpoints, as are the packet sizes we'll be using.  Different
+        * configurations may use different endpoints with a given port;
+        * and high speed vs full speed changes packet sizes too.
+        */
+-      ep = port->port_usb->out;
+       status = gs_alloc_requests(ep, head, gs_read_complete,
+               &port->read_allocated);
+       if (status)
index afb2d810fee1378ab6bfdb91717f8016125f581c..03f91ae13a7548c3624a35e157714ac3ff39169d 100644 (file)
@@ -45,3 +45,6 @@ drm-gem-acquire-references-on-gem-handles-for-framebuffers.patch
 drm-sched-increment-job-count-before-swapping-tail-spsc-queue.patch
 drm-ttm-fix-error-handling-in-ttm_buffer_object_transfer.patch
 drm-gem-fix-race-in-drm_gem_handle_create_tail.patch
+usb-gadget-u_serial-fix-race-condition-in-tty-wakeup.patch
+revert-usb-gadget-u_serial-add-null-pointer-check-in-gs_start_io.patch
+drm-framebuffer-acquire-internal-references-on-gem-handles.patch
diff --git a/queue-6.6/usb-gadget-u_serial-fix-race-condition-in-tty-wakeup.patch b/queue-6.6/usb-gadget-u_serial-fix-race-condition-in-tty-wakeup.patch
new file mode 100644 (file)
index 0000000..8a232a5
--- /dev/null
@@ -0,0 +1,59 @@
+From c529c3730bd09115684644e26bf01ecbd7e2c2c9 Mon Sep 17 00:00:00 2001
+From: Kuen-Han Tsai <khtsai@google.com>
+Date: Tue, 17 Jun 2025 13:07:12 +0800
+Subject: usb: gadget: u_serial: Fix race condition in TTY wakeup
+
+From: Kuen-Han Tsai <khtsai@google.com>
+
+commit c529c3730bd09115684644e26bf01ecbd7e2c2c9 upstream.
+
+A race condition occurs when gs_start_io() calls either gs_start_rx() or
+gs_start_tx(), as those functions briefly drop the port_lock for
+usb_ep_queue(). This allows gs_close() and gserial_disconnect() to clear
+port.tty and port_usb, respectively.
+
+Use the null-safe TTY Port helper function to wake up TTY.
+
+Example
+  CPU1:                              CPU2:
+  gserial_connect() // lock
+                             gs_close() // await lock
+  gs_start_rx()     // unlock
+  usb_ep_queue()
+                             gs_close() // lock, reset port.tty and unlock
+  gs_start_rx()     // lock
+  tty_wakeup()      // NPE
+
+Fixes: 35f95fd7f234 ("TTY: usb/u_serial, use tty from tty_port")
+Cc: stable <stable@kernel.org>
+Signed-off-by: Kuen-Han Tsai <khtsai@google.com>
+Reviewed-by: Prashanth K <prashanth.k@oss.qualcomm.com>
+Link: https://lore.kernel.org/linux-usb/20240116141801.396398-1-khtsai@google.com/
+Link: https://lore.kernel.org/r/20250617050844.1848232-2-khtsai@google.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/function/u_serial.c |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/gadget/function/u_serial.c
++++ b/drivers/usb/gadget/function/u_serial.c
+@@ -291,8 +291,8 @@ __acquires(&port->port_lock)
+                       break;
+       }
+-      if (do_tty_wake && port->port.tty)
+-              tty_wakeup(port->port.tty);
++      if (do_tty_wake)
++              tty_port_tty_wakeup(&port->port);
+       return status;
+ }
+@@ -573,7 +573,7 @@ static int gs_start_io(struct gs_port *p
+               gs_start_tx(port);
+               /* Unblock any pending writes into our circular buffer, in case
+                * we didn't in gs_start_tx() */
+-              tty_wakeup(port->port.tty);
++              tty_port_tty_wakeup(&port->port);
+       } else {
+               /* Free reqs only if we are still connected */
+               if (port->port_usb) {