From: Greg Kroah-Hartman Date: Tue, 17 Jun 2025 13:20:30 +0000 (+0200) Subject: 6.6-stable patches X-Git-Tag: v6.6.94~42 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=24d2751df829c4d6e28df5d49f27f8b85dacb1d4;p=thirdparty%2Fkernel%2Fstable-queue.git 6.6-stable patches 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 --- 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 index 0000000000..a1ae71e90c --- /dev/null +++ b/queue-6.6/hid-usbhid-eliminate-recurrent-out-of-bounds-bug-in-usbhid_parse.patch @@ -0,0 +1,165 @@ +From fe7f7ac8e0c708446ff017453add769ffc15deed Mon Sep 17 00:00:00 2001 +From: Terry Junge +Date: Wed, 12 Mar 2025 15:23:31 -0700 +Subject: HID: usbhid: Eliminate recurrent out-of-bounds bug in usbhid_parse() + +From: Terry Junge + +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 +Reviewed-by: Michael Kelley +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..f38e43b45c --- /dev/null +++ b/queue-6.6/io_uring-add-io_file_can_poll-helper.patch @@ -0,0 +1,125 @@ +From bf48072fe1ca2006b620292d1909748a30565c7d Mon Sep 17 00:00:00 2001 +From: Jens Axboe +Date: Sun, 28 Jan 2024 20:08:24 -0700 +Subject: io_uring: add io_file_can_poll() helper + +From: Jens Axboe + +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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include + #include ++#include + #include + #include + #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 index 0000000000..845fe0d251 --- /dev/null +++ b/queue-6.6/io_uring-rw-allow-pollable-non-blocking-attempts-for-fmode_nowait.patch @@ -0,0 +1,83 @@ +From 759b078e8395322668d9a0023df25ae32f2e356f Mon Sep 17 00:00:00 2001 +From: Jens Axboe +Date: Sun, 6 Oct 2024 10:40:36 -0600 +Subject: io_uring/rw: allow pollable non-blocking attempts for !FMODE_NOWAIT + +From: Jens Axboe + +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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 0000000000..de92e3852d --- /dev/null +++ b/queue-6.6/io_uring-rw-fix-wrong-nowait-check-in-io_rw_init_file.patch @@ -0,0 +1,34 @@ +From 3390df92ec38f364e7d770988cf116ed7b426489 Mon Sep 17 00:00:00 2001 +From: Jens Axboe +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 + +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 +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 +Signed-off-by: Greg Kroah-Hartman +--- + 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) { diff --git a/queue-6.6/series b/queue-6.6/series index 1f56bdce33..245837d936 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -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