]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.6-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 17 Jun 2025 13:20:30 +0000 (15:20 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 17 Jun 2025 13:20:30 +0000 (15:20 +0200)
added patches:
hid-usbhid-eliminate-recurrent-out-of-bounds-bug-in-usbhid_parse.patch
io_uring-add-io_file_can_poll-helper.patch
io_uring-rw-allow-pollable-non-blocking-attempts-for-fmode_nowait.patch
io_uring-rw-fix-wrong-nowait-check-in-io_rw_init_file.patch

queue-6.6/hid-usbhid-eliminate-recurrent-out-of-bounds-bug-in-usbhid_parse.patch [new file with mode: 0644]
queue-6.6/io_uring-add-io_file_can_poll-helper.patch [new file with mode: 0644]
queue-6.6/io_uring-rw-allow-pollable-non-blocking-attempts-for-fmode_nowait.patch [new file with mode: 0644]
queue-6.6/io_uring-rw-fix-wrong-nowait-check-in-io_rw_init_file.patch [new file with mode: 0644]
queue-6.6/series

diff --git a/queue-6.6/hid-usbhid-eliminate-recurrent-out-of-bounds-bug-in-usbhid_parse.patch b/queue-6.6/hid-usbhid-eliminate-recurrent-out-of-bounds-bug-in-usbhid_parse.patch
new file mode 100644 (file)
index 0000000..a1ae71e
--- /dev/null
@@ -0,0 +1,165 @@
+From fe7f7ac8e0c708446ff017453add769ffc15deed Mon Sep 17 00:00:00 2001
+From: Terry Junge <linuxhid@cosmicgizmosystems.com>
+Date: Wed, 12 Mar 2025 15:23:31 -0700
+Subject: HID: usbhid: Eliminate recurrent out-of-bounds bug in usbhid_parse()
+
+From: Terry Junge <linuxhid@cosmicgizmosystems.com>
+
+commit fe7f7ac8e0c708446ff017453add769ffc15deed upstream.
+
+Update struct hid_descriptor to better reflect the mandatory and
+optional parts of the HID Descriptor as per USB HID 1.11 specification.
+Note: the kernel currently does not parse any optional HID class
+descriptors, only the mandatory report descriptor.
+
+Update all references to member element desc[0] to rpt_desc.
+
+Add test to verify bLength and bNumDescriptors values are valid.
+
+Replace the for loop with direct access to the mandatory HID class
+descriptor member for the report descriptor. This eliminates the
+possibility of getting an out-of-bounds fault.
+
+Add a warning message if the HID descriptor contains any unsupported
+optional HID class descriptors.
+
+Reported-by: syzbot+c52569baf0c843f35495@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=c52569baf0c843f35495
+Fixes: f043bfc98c19 ("HID: usbhid: fix out-of-bounds bug")
+Cc: stable@vger.kernel.org
+Signed-off-by: Terry Junge <linuxhid@cosmicgizmosystems.com>
+Reviewed-by: Michael Kelley <mhklinux@outlook.com>
+Signed-off-by: Jiri Kosina <jkosina@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/hid/hid-hyperv.c            |    4 ++--
+ drivers/hid/usbhid/hid-core.c       |   25 ++++++++++++++-----------
+ drivers/usb/gadget/function/f_hid.c |   12 ++++++------
+ include/linux/hid.h                 |    3 ++-
+ 4 files changed, 24 insertions(+), 20 deletions(-)
+
+--- a/drivers/hid/hid-hyperv.c
++++ b/drivers/hid/hid-hyperv.c
+@@ -192,7 +192,7 @@ static void mousevsc_on_receive_device_i
+               goto cleanup;
+       input_device->report_desc_size = le16_to_cpu(
+-                                      desc->desc[0].wDescriptorLength);
++                                      desc->rpt_desc.wDescriptorLength);
+       if (input_device->report_desc_size == 0) {
+               input_device->dev_info_status = -EINVAL;
+               goto cleanup;
+@@ -210,7 +210,7 @@ static void mousevsc_on_receive_device_i
+       memcpy(input_device->report_desc,
+              ((unsigned char *)desc) + desc->bLength,
+-             le16_to_cpu(desc->desc[0].wDescriptorLength));
++             le16_to_cpu(desc->rpt_desc.wDescriptorLength));
+       /* Send the ack */
+       memset(&ack, 0, sizeof(struct mousevsc_prt_msg));
+--- a/drivers/hid/usbhid/hid-core.c
++++ b/drivers/hid/usbhid/hid-core.c
+@@ -982,12 +982,11 @@ static int usbhid_parse(struct hid_devic
+       struct usb_host_interface *interface = intf->cur_altsetting;
+       struct usb_device *dev = interface_to_usbdev (intf);
+       struct hid_descriptor *hdesc;
++      struct hid_class_descriptor *hcdesc;
+       u32 quirks = 0;
+       unsigned int rsize = 0;
+       char *rdesc;
+-      int ret, n;
+-      int num_descriptors;
+-      size_t offset = offsetof(struct hid_descriptor, desc);
++      int ret;
+       quirks = hid_lookup_quirk(hid);
+@@ -1009,20 +1008,19 @@ static int usbhid_parse(struct hid_devic
+               return -ENODEV;
+       }
+-      if (hdesc->bLength < sizeof(struct hid_descriptor)) {
+-              dbg_hid("hid descriptor is too short\n");
++      if (!hdesc->bNumDescriptors ||
++          hdesc->bLength != sizeof(*hdesc) +
++                            (hdesc->bNumDescriptors - 1) * sizeof(*hcdesc)) {
++              dbg_hid("hid descriptor invalid, bLen=%hhu bNum=%hhu\n",
++                      hdesc->bLength, hdesc->bNumDescriptors);
+               return -EINVAL;
+       }
+       hid->version = le16_to_cpu(hdesc->bcdHID);
+       hid->country = hdesc->bCountryCode;
+-      num_descriptors = min_t(int, hdesc->bNumDescriptors,
+-             (hdesc->bLength - offset) / sizeof(struct hid_class_descriptor));
+-
+-      for (n = 0; n < num_descriptors; n++)
+-              if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT)
+-                      rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
++      if (hdesc->rpt_desc.bDescriptorType == HID_DT_REPORT)
++              rsize = le16_to_cpu(hdesc->rpt_desc.wDescriptorLength);
+       if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
+               dbg_hid("weird size of report descriptor (%u)\n", rsize);
+@@ -1050,6 +1048,11 @@ static int usbhid_parse(struct hid_devic
+               goto err;
+       }
++      if (hdesc->bNumDescriptors > 1)
++              hid_warn(intf,
++                      "%u unsupported optional hid class descriptors\n",
++                      (int)(hdesc->bNumDescriptors - 1));
++
+       hid->quirks |= quirks;
+       return 0;
+--- a/drivers/usb/gadget/function/f_hid.c
++++ b/drivers/usb/gadget/function/f_hid.c
+@@ -118,8 +118,8 @@ static struct hid_descriptor hidg_desc =
+       .bcdHID                         = cpu_to_le16(0x0101),
+       .bCountryCode                   = 0x00,
+       .bNumDescriptors                = 0x1,
+-      /*.desc[0].bDescriptorType      = DYNAMIC */
+-      /*.desc[0].wDescriptorLenght    = DYNAMIC */
++      /*.rpt_desc.bDescriptorType     = DYNAMIC */
++      /*.rpt_desc.wDescriptorLength   = DYNAMIC */
+ };
+ /* Super-Speed Support */
+@@ -728,8 +728,8 @@ static int hidg_setup(struct usb_functio
+                       struct hid_descriptor hidg_desc_copy = hidg_desc;
+                       VDBG(cdev, "USB_REQ_GET_DESCRIPTOR: HID\n");
+-                      hidg_desc_copy.desc[0].bDescriptorType = HID_DT_REPORT;
+-                      hidg_desc_copy.desc[0].wDescriptorLength =
++                      hidg_desc_copy.rpt_desc.bDescriptorType = HID_DT_REPORT;
++                      hidg_desc_copy.rpt_desc.wDescriptorLength =
+                               cpu_to_le16(hidg->report_desc_length);
+                       length = min_t(unsigned short, length,
+@@ -970,8 +970,8 @@ static int hidg_bind(struct usb_configur
+        * We can use hidg_desc struct here but we should not relay
+        * that its content won't change after returning from this function.
+        */
+-      hidg_desc.desc[0].bDescriptorType = HID_DT_REPORT;
+-      hidg_desc.desc[0].wDescriptorLength =
++      hidg_desc.rpt_desc.bDescriptorType = HID_DT_REPORT;
++      hidg_desc.rpt_desc.wDescriptorLength =
+               cpu_to_le16(hidg->report_desc_length);
+       hidg_hs_in_ep_desc.bEndpointAddress =
+--- a/include/linux/hid.h
++++ b/include/linux/hid.h
+@@ -736,8 +736,9 @@ struct hid_descriptor {
+       __le16 bcdHID;
+       __u8  bCountryCode;
+       __u8  bNumDescriptors;
++      struct hid_class_descriptor rpt_desc;
+-      struct hid_class_descriptor desc[1];
++      struct hid_class_descriptor opt_descs[];
+ } __attribute__ ((packed));
+ #define HID_DEVICE(b, g, ven, prod)                                   \
diff --git a/queue-6.6/io_uring-add-io_file_can_poll-helper.patch b/queue-6.6/io_uring-add-io_file_can_poll-helper.patch
new file mode 100644 (file)
index 0000000..f38e43b
--- /dev/null
@@ -0,0 +1,125 @@
+From bf48072fe1ca2006b620292d1909748a30565c7d Mon Sep 17 00:00:00 2001
+From: Jens Axboe <axboe@kernel.dk>
+Date: Sun, 28 Jan 2024 20:08:24 -0700
+Subject: io_uring: add io_file_can_poll() helper
+
+From: Jens Axboe <axboe@kernel.dk>
+
+Commit 95041b93e90a06bb613ec4bef9cd4d61570f68e4 upstream.
+
+This adds a flag to avoid dipping dereferencing file and then f_op to
+figure out if the file has a poll handler defined or not. We generally
+call this at least twice for networked workloads, and if using ring
+provided buffers, we do it on every buffer selection. Particularly the
+latter is troublesome, as it's otherwise a very fast operation.
+
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/io_uring_types.h |    3 +++
+ io_uring/io_uring.c            |    2 +-
+ io_uring/io_uring.h            |   12 ++++++++++++
+ io_uring/kbuf.c                |    3 +--
+ io_uring/poll.c                |    2 +-
+ io_uring/rw.c                  |    4 ++--
+ 6 files changed, 20 insertions(+), 6 deletions(-)
+
+--- a/include/linux/io_uring_types.h
++++ b/include/linux/io_uring_types.h
+@@ -416,6 +416,7 @@ enum {
+       /* keep async read/write and isreg together and in order */
+       REQ_F_SUPPORT_NOWAIT_BIT,
+       REQ_F_ISREG_BIT,
++      REQ_F_CAN_POLL_BIT,
+       /* not a real bit, just to check we're not overflowing the space */
+       __REQ_F_LAST_BIT,
+@@ -483,6 +484,8 @@ enum {
+       REQ_F_CLEAR_POLLIN      = BIT(REQ_F_CLEAR_POLLIN_BIT),
+       /* hashed into ->cancel_hash_locked, protected by ->uring_lock */
+       REQ_F_HASH_LOCKED       = BIT(REQ_F_HASH_LOCKED_BIT),
++      /* file is pollable */
++      REQ_F_CAN_POLL          = BIT(REQ_F_CAN_POLL_BIT),
+ };
+ typedef void (*io_req_tw_func_t)(struct io_kiocb *req, struct io_tw_state *ts);
+--- a/io_uring/io_uring.c
++++ b/io_uring/io_uring.c
+@@ -1953,7 +1953,7 @@ fail:
+       if (req->flags & REQ_F_FORCE_ASYNC) {
+               bool opcode_poll = def->pollin || def->pollout;
+-              if (opcode_poll && file_can_poll(req->file)) {
++              if (opcode_poll && io_file_can_poll(req)) {
+                       needs_poll = true;
+                       issue_flags |= IO_URING_F_NONBLOCK;
+               }
+--- a/io_uring/io_uring.h
++++ b/io_uring/io_uring.h
+@@ -5,6 +5,7 @@
+ #include <linux/lockdep.h>
+ #include <linux/resume_user_mode.h>
+ #include <linux/kasan.h>
++#include <linux/poll.h>
+ #include <linux/io_uring_types.h>
+ #include <uapi/linux/eventpoll.h>
+ #include "io-wq.h"
+@@ -410,4 +411,15 @@ static inline size_t uring_sqe_size(stru
+               return 2 * sizeof(struct io_uring_sqe);
+       return sizeof(struct io_uring_sqe);
+ }
++
++static inline bool io_file_can_poll(struct io_kiocb *req)
++{
++      if (req->flags & REQ_F_CAN_POLL)
++              return true;
++      if (file_can_poll(req->file)) {
++              req->flags |= REQ_F_CAN_POLL;
++              return true;
++      }
++      return false;
++}
+ #endif
+--- a/io_uring/kbuf.c
++++ b/io_uring/kbuf.c
+@@ -148,8 +148,7 @@ static void __user *io_ring_buffer_selec
+       req->buf_list = bl;
+       req->buf_index = buf->bid;
+-      if (issue_flags & IO_URING_F_UNLOCKED ||
+-          (req->file && !file_can_poll(req->file))) {
++      if (issue_flags & IO_URING_F_UNLOCKED || !io_file_can_poll(req)) {
+               /*
+                * If we came in unlocked, we have no choice but to consume the
+                * buffer here, otherwise nothing ensures that the buffer won't
+--- a/io_uring/poll.c
++++ b/io_uring/poll.c
+@@ -717,7 +717,7 @@ int io_arm_poll_handler(struct io_kiocb
+       if (!def->pollin && !def->pollout)
+               return IO_APOLL_ABORTED;
+-      if (!file_can_poll(req->file))
++      if (!io_file_can_poll(req))
+               return IO_APOLL_ABORTED;
+       if (!(req->flags & REQ_F_APOLL_MULTISHOT))
+               mask |= EPOLLONESHOT;
+--- a/io_uring/rw.c
++++ b/io_uring/rw.c
+@@ -629,7 +629,7 @@ static bool io_rw_should_retry(struct io
+        * just use poll if we can, and don't attempt if the fs doesn't
+        * support callback based unlocks
+        */
+-      if (file_can_poll(req->file) || !(req->file->f_mode & FMODE_BUF_RASYNC))
++      if (io_file_can_poll(req) || !(req->file->f_mode & FMODE_BUF_RASYNC))
+               return false;
+       wait->wait.func = io_async_buf_func;
+@@ -783,7 +783,7 @@ static int __io_read(struct io_kiocb *re
+       if (ret == -EAGAIN || (req->flags & REQ_F_REISSUE)) {
+               req->flags &= ~REQ_F_REISSUE;
+               /* if we can poll, just do that */
+-              if (req->opcode == IORING_OP_READ && file_can_poll(req->file))
++              if (req->opcode == IORING_OP_READ && io_file_can_poll(req))
+                       return -EAGAIN;
+               /* IOPOLL retry should happen for io-wq threads */
+               if (!force_nonblock && !(req->ctx->flags & IORING_SETUP_IOPOLL))
diff --git a/queue-6.6/io_uring-rw-allow-pollable-non-blocking-attempts-for-fmode_nowait.patch b/queue-6.6/io_uring-rw-allow-pollable-non-blocking-attempts-for-fmode_nowait.patch
new file mode 100644 (file)
index 0000000..845fe0d
--- /dev/null
@@ -0,0 +1,83 @@
+From 759b078e8395322668d9a0023df25ae32f2e356f Mon Sep 17 00:00:00 2001
+From: Jens Axboe <axboe@kernel.dk>
+Date: Sun, 6 Oct 2024 10:40:36 -0600
+Subject: io_uring/rw: allow pollable non-blocking attempts for !FMODE_NOWAIT
+
+From: Jens Axboe <axboe@kernel.dk>
+
+Commit f7c9134385331c5ef36252895130aa01a92de907 upstream.
+
+The checking for whether or not io_uring can do a non-blocking read or
+write attempt is gated on FMODE_NOWAIT. However, if the file is
+pollable, it's feasible to just check if it's currently in a state in
+which it can sanely receive or send _some_ data.
+
+This avoids unnecessary io-wq punts, and repeated worthless retries
+before doing that punt, by assuming that some data can get delivered
+or received if poll tells us that is true. It also allows multishot
+reads to properly work with these types of files, enabling a bit of
+a cleanup of the logic that:
+
+c9d952b9103b ("io_uring/rw: fix cflags posting for single issue multishot read")
+
+had to put in place.
+
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ io_uring/rw.c |   22 ++++++++++++++++------
+ 1 file changed, 16 insertions(+), 6 deletions(-)
+
+--- a/io_uring/rw.c
++++ b/io_uring/rw.c
+@@ -28,9 +28,19 @@ struct io_rw {
+       rwf_t                           flags;
+ };
+-static inline bool io_file_supports_nowait(struct io_kiocb *req)
++static bool io_file_supports_nowait(struct io_kiocb *req, __poll_t mask)
+ {
+-      return req->flags & REQ_F_SUPPORT_NOWAIT;
++      /* If FMODE_NOWAIT is set for a file, we're golden */
++      if (req->flags & REQ_F_SUPPORT_NOWAIT)
++              return true;
++      /* No FMODE_NOWAIT, if we can poll, check the status */
++      if (io_file_can_poll(req)) {
++              struct poll_table_struct pt = { ._key = mask };
++
++              return vfs_poll(req->file, &pt) & mask;
++      }
++      /* No FMODE_NOWAIT support, and file isn't pollable. Tough luck. */
++      return false;
+ }
+ #ifdef CONFIG_COMPAT
+@@ -685,8 +695,8 @@ static int io_rw_init_file(struct io_kio
+        * supports async. Otherwise it's impossible to use O_NONBLOCK files
+        * reliably. If not, or it IOCB_NOWAIT is set, don't retry.
+        */
+-      if ((kiocb->ki_flags & IOCB_NOWAIT) ||
+-          ((file->f_flags & O_NONBLOCK) && !io_file_supports_nowait(req)))
++      if (kiocb->ki_flags & IOCB_NOWAIT ||
++          ((file->f_flags & O_NONBLOCK && (req->flags & REQ_F_SUPPORT_NOWAIT))))
+               req->flags |= REQ_F_NOWAIT;
+       if (ctx->flags & IORING_SETUP_IOPOLL) {
+@@ -752,7 +762,7 @@ static int __io_read(struct io_kiocb *re
+       if (force_nonblock) {
+               /* If the file doesn't support async, just async punt */
+-              if (unlikely(!io_file_supports_nowait(req))) {
++              if (unlikely(!io_file_supports_nowait(req, EPOLLIN))) {
+                       ret = io_setup_async_rw(req, iovec, s, true);
+                       return ret ?: -EAGAIN;
+               }
+@@ -927,7 +937,7 @@ int io_write(struct io_kiocb *req, unsig
+       if (force_nonblock) {
+               /* If the file doesn't support async, just async punt */
+-              if (unlikely(!io_file_supports_nowait(req)))
++              if (unlikely(!io_file_supports_nowait(req, EPOLLOUT)))
+                       goto copy_iov;
+               /* File path supports NOWAIT for non-direct_IO only for block devices. */
diff --git a/queue-6.6/io_uring-rw-fix-wrong-nowait-check-in-io_rw_init_file.patch b/queue-6.6/io_uring-rw-fix-wrong-nowait-check-in-io_rw_init_file.patch
new file mode 100644 (file)
index 0000000..de92e38
--- /dev/null
@@ -0,0 +1,34 @@
+From 3390df92ec38f364e7d770988cf116ed7b426489 Mon Sep 17 00:00:00 2001
+From: Jens Axboe <axboe@kernel.dk>
+Date: Sat, 19 Oct 2024 09:16:51 -0600
+Subject: io_uring/rw: fix wrong NOWAIT check in io_rw_init_file()
+
+From: Jens Axboe <axboe@kernel.dk>
+
+Commit ae6a888a4357131c01d85f4c91fb32552dd0bf70 upstream.
+
+A previous commit improved how !FMODE_NOWAIT is dealt with, but
+inadvertently negated a check whilst doing so. This caused -EAGAIN to be
+returned from reading files with O_NONBLOCK set. Fix up the check for
+REQ_F_SUPPORT_NOWAIT.
+
+Reported-by: Julian Orth <ju.orth@gmail.com>
+Link: https://github.com/axboe/liburing/issues/1270
+Fixes: f7c913438533 ("io_uring/rw: allow pollable non-blocking attempts for !FMODE_NOWAIT")
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ io_uring/rw.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/io_uring/rw.c
++++ b/io_uring/rw.c
+@@ -696,7 +696,7 @@ static int io_rw_init_file(struct io_kio
+        * reliably. If not, or it IOCB_NOWAIT is set, don't retry.
+        */
+       if (kiocb->ki_flags & IOCB_NOWAIT ||
+-          ((file->f_flags & O_NONBLOCK && (req->flags & REQ_F_SUPPORT_NOWAIT))))
++          ((file->f_flags & O_NONBLOCK && !(req->flags & REQ_F_SUPPORT_NOWAIT))))
+               req->flags |= REQ_F_NOWAIT;
+       if (ctx->flags & IORING_SETUP_IOPOLL) {
index 1f56bdce33eee4fe618237f12140b648d82c8e70..245837d936b17fb8dcac378d49d6f189f49a0c55 100644 (file)
@@ -336,3 +336,7 @@ bio-fix-bio_first_folio-for-sparsemem-without-vmemma.patch
 block-fix-bvec_set_folio-for-very-large-folios.patch
 tools-resolve_btfids-fix-build-when-cross-compiling-kernel-with-clang.patch
 alsa-usb-audio-add-implicit-feedback-quirk-for-rode-ai-1.patch
+hid-usbhid-eliminate-recurrent-out-of-bounds-bug-in-usbhid_parse.patch
+io_uring-add-io_file_can_poll-helper.patch
+io_uring-rw-allow-pollable-non-blocking-attempts-for-fmode_nowait.patch
+io_uring-rw-fix-wrong-nowait-check-in-io_rw_init_file.patch