From: Greg Kroah-Hartman Date: Thu, 12 Dec 2024 08:42:39 +0000 (+0100) Subject: 5.10-stable patches X-Git-Tag: v5.4.287~43 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2c759ce473f1e3f529dbf854c82f60a3ae90524b;p=thirdparty%2Fkernel%2Fstable-queue.git 5.10-stable patches added patches: jffs2-fix-rtime-decompressor.patch jffs2-prevent-rtime-decompress-memory-corruption.patch xhci-dbc-fix-stall-transfer-event-handling.patch --- diff --git a/queue-5.10/jffs2-fix-rtime-decompressor.patch b/queue-5.10/jffs2-fix-rtime-decompressor.patch new file mode 100644 index 00000000000..f1410bcceb0 --- /dev/null +++ b/queue-5.10/jffs2-fix-rtime-decompressor.patch @@ -0,0 +1,32 @@ +From b29bf7119d6bbfd04aabb8d82b060fe2a33ef890 Mon Sep 17 00:00:00 2001 +From: Richard Weinberger +Date: Tue, 3 Dec 2024 12:27:15 +0100 +Subject: jffs2: Fix rtime decompressor + +From: Richard Weinberger + +commit b29bf7119d6bbfd04aabb8d82b060fe2a33ef890 upstream. + +The fix for a memory corruption contained a off-by-one error and +caused the compressor to fail in legit cases. + +Cc: Kinsey Moore +Cc: stable@vger.kernel.org +Fixes: fe051552f5078 ("jffs2: Prevent rtime decompress memory corruption") +Signed-off-by: Richard Weinberger +Signed-off-by: Greg Kroah-Hartman +--- + fs/jffs2/compr_rtime.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/jffs2/compr_rtime.c ++++ b/fs/jffs2/compr_rtime.c +@@ -95,7 +95,7 @@ static int jffs2_rtime_decompress(unsign + + positions[value]=outpos; + if (repeat) { +- if ((outpos + repeat) >= destlen) { ++ if ((outpos + repeat) > destlen) { + return 1; + } + if (backoffs + repeat >= outpos) { diff --git a/queue-5.10/jffs2-prevent-rtime-decompress-memory-corruption.patch b/queue-5.10/jffs2-prevent-rtime-decompress-memory-corruption.patch new file mode 100644 index 00000000000..078df2a6d66 --- /dev/null +++ b/queue-5.10/jffs2-prevent-rtime-decompress-memory-corruption.patch @@ -0,0 +1,34 @@ +From fe051552f5078fa02d593847529a3884305a6ffe Mon Sep 17 00:00:00 2001 +From: Kinsey Moore +Date: Tue, 23 Jul 2024 15:58:05 -0500 +Subject: jffs2: Prevent rtime decompress memory corruption + +From: Kinsey Moore + +commit fe051552f5078fa02d593847529a3884305a6ffe upstream. + +The rtime decompression routine does not fully check bounds during the +entirety of the decompression pass and can corrupt memory outside the +decompression buffer if the compressed data is corrupted. This adds the +required check to prevent this failure mode. + +Cc: stable@vger.kernel.org +Signed-off-by: Kinsey Moore +Signed-off-by: Richard Weinberger +Signed-off-by: Greg Kroah-Hartman +--- + fs/jffs2/compr_rtime.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/fs/jffs2/compr_rtime.c ++++ b/fs/jffs2/compr_rtime.c +@@ -95,6 +95,9 @@ static int jffs2_rtime_decompress(unsign + + positions[value]=outpos; + if (repeat) { ++ if ((outpos + repeat) >= destlen) { ++ return 1; ++ } + if (backoffs + repeat >= outpos) { + while(repeat) { + cpage_out[outpos++] = cpage_out[backoffs++]; diff --git a/queue-5.10/series b/queue-5.10/series index e9ef1ae93a3..55ac1b884bb 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -445,3 +445,6 @@ revert-unicode-don-t-special-case-ignorable-code-points.patch kvm-arm64-vgic-its-add-a-data-length-check-in-vgic_its_save_.patch kvm-arm64-vgic-its-clear-dte-when-mapd-unmaps-a-device.patch kvm-arm64-vgic-its-clear-ite-when-discard-frees-an-ite.patch +jffs2-prevent-rtime-decompress-memory-corruption.patch +jffs2-fix-rtime-decompressor.patch +xhci-dbc-fix-stall-transfer-event-handling.patch diff --git a/queue-5.10/xhci-dbc-fix-stall-transfer-event-handling.patch b/queue-5.10/xhci-dbc-fix-stall-transfer-event-handling.patch new file mode 100644 index 00000000000..5f0e5f545db --- /dev/null +++ b/queue-5.10/xhci-dbc-fix-stall-transfer-event-handling.patch @@ -0,0 +1,294 @@ +From 9044ad57b60b0556d42b6f8aa218a68865e810a4 Mon Sep 17 00:00:00 2001 +From: Mathias Nyman +Date: Thu, 5 Sep 2024 17:32:49 +0300 +Subject: xhci: dbc: Fix STALL transfer event handling +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Mathias Nyman + +commit 9044ad57b60b0556d42b6f8aa218a68865e810a4 upstream. + +Don't flush all pending DbC data requests when an endpoint halts. + +An endpoint may halt and xHC DbC triggers a STALL error event if there's +an issue with a bulk data transfer. The transfer should restart once xHC +DbC receives a ClearFeature(ENDPOINT_HALT) request from the host. + +Once xHC DbC restarts it will start from the TRB pointed to by dequeue +field in the endpoint context, which might be the same TRB we got the +STALL event for. Turn the TRB to a no-op in this case to make sure xHC +DbC doesn't reuse and tries to retransmit this same TRB after we already +handled it, and gave its corresponding data request back. + +Other STALL events might be completely bogus. +Lukasz Bartosik discovered that xHC DbC might issue spurious STALL events +if hosts sends a ClearFeature(ENDPOINT_HALT) request to non-halted +endpoints even without any active bulk transfers. + +Assume STALL event is spurious if it reports 0 bytes transferred, and +the endpoint stopped on the STALLED TRB. +Don't give back the data request corresponding to the TRB in this case. + +The halted status is per endpoint. Track it with a per endpoint flag +instead of the driver invented DbC wide DS_STALLED state. +DbC remains in DbC-Configured state even if endpoints halt. There is no +Stalled state in the DbC Port state Machine (xhci section 7.6.6) + +Reported-by: Łukasz Bartosik +Closes: https://lore.kernel.org/linux-usb/20240725074857.623299-1-ukaszb@chromium.org/ +Tested-by: Łukasz Bartosik +Signed-off-by: Mathias Nyman +Link: https://lore.kernel.org/r/20240905143300.1959279-2-mathias.nyman@linux.intel.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/host/xhci-dbgcap.c | 135 ++++++++++++++++++++++++----------------- + drivers/usb/host/xhci-dbgcap.h | 2 + 2 files changed, 83 insertions(+), 54 deletions(-) + +--- a/drivers/usb/host/xhci-dbgcap.c ++++ b/drivers/usb/host/xhci-dbgcap.c +@@ -158,16 +158,18 @@ static void xhci_dbc_giveback(struct dbc + spin_lock(&dbc->lock); + } + +-static void xhci_dbc_flush_single_request(struct dbc_request *req) ++static void trb_to_noop(union xhci_trb *trb) + { +- union xhci_trb *trb = req->trb; +- + trb->generic.field[0] = 0; + trb->generic.field[1] = 0; + trb->generic.field[2] = 0; + trb->generic.field[3] &= cpu_to_le32(TRB_CYCLE); + trb->generic.field[3] |= cpu_to_le32(TRB_TYPE(TRB_TR_NOOP)); ++} + ++static void xhci_dbc_flush_single_request(struct dbc_request *req) ++{ ++ trb_to_noop(req->trb); + xhci_dbc_giveback(req, -ESHUTDOWN); + } + +@@ -637,7 +639,6 @@ static void xhci_dbc_stop(struct xhci_db + case DS_DISABLED: + return; + case DS_CONFIGURED: +- case DS_STALLED: + if (dbc->driver->disconnect) + dbc->driver->disconnect(dbc); + break; +@@ -658,6 +659,23 @@ static void xhci_dbc_stop(struct xhci_db + } + + static void ++handle_ep_halt_changes(struct xhci_dbc *dbc, struct dbc_ep *dep, bool halted) ++{ ++ if (halted) { ++ dev_info(dbc->dev, "DbC Endpoint halted\n"); ++ dep->halted = 1; ++ ++ } else if (dep->halted) { ++ dev_info(dbc->dev, "DbC Endpoint halt cleared\n"); ++ dep->halted = 0; ++ ++ if (!list_empty(&dep->list_pending)) ++ writel(DBC_DOOR_BELL_TARGET(dep->direction), ++ &dbc->regs->doorbell); ++ } ++} ++ ++static void + dbc_handle_port_status(struct xhci_dbc *dbc, union xhci_trb *event) + { + u32 portsc; +@@ -685,6 +703,7 @@ static void dbc_handle_xfer_event(struct + struct xhci_ring *ring; + int ep_id; + int status; ++ struct xhci_ep_ctx *ep_ctx; + u32 comp_code; + size_t remain_length; + struct dbc_request *req = NULL, *r; +@@ -694,8 +713,30 @@ static void dbc_handle_xfer_event(struct + ep_id = TRB_TO_EP_ID(le32_to_cpu(event->generic.field[3])); + dep = (ep_id == EPID_OUT) ? + get_out_ep(dbc) : get_in_ep(dbc); ++ ep_ctx = (ep_id == EPID_OUT) ? ++ dbc_bulkout_ctx(dbc) : dbc_bulkin_ctx(dbc); + ring = dep->ring; + ++ /* Match the pending request: */ ++ list_for_each_entry(r, &dep->list_pending, list_pending) { ++ if (r->trb_dma == event->trans_event.buffer) { ++ req = r; ++ break; ++ } ++ if (r->status == -COMP_STALL_ERROR) { ++ dev_warn(dbc->dev, "Give back stale stalled req\n"); ++ ring->num_trbs_free++; ++ xhci_dbc_giveback(r, 0); ++ } ++ } ++ ++ if (!req) { ++ dev_warn(dbc->dev, "no matched request\n"); ++ return; ++ } ++ ++ trace_xhci_dbc_handle_transfer(ring, &req->trb->generic); ++ + switch (comp_code) { + case COMP_SUCCESS: + remain_length = 0; +@@ -706,31 +747,49 @@ static void dbc_handle_xfer_event(struct + case COMP_TRB_ERROR: + case COMP_BABBLE_DETECTED_ERROR: + case COMP_USB_TRANSACTION_ERROR: +- case COMP_STALL_ERROR: + dev_warn(dbc->dev, "tx error %d detected\n", comp_code); + status = -comp_code; + break; ++ case COMP_STALL_ERROR: ++ dev_warn(dbc->dev, "Stall error at bulk TRB %llx, remaining %zu, ep deq %llx\n", ++ event->trans_event.buffer, remain_length, ep_ctx->deq); ++ status = 0; ++ dep->halted = 1; ++ ++ /* ++ * xHC DbC may trigger a STALL bulk xfer event when host sends a ++ * ClearFeature(ENDPOINT_HALT) request even if there wasn't an ++ * active bulk transfer. ++ * ++ * Don't give back this transfer request as hardware will later ++ * start processing TRBs starting from this 'STALLED' TRB, ++ * causing TRBs and requests to be out of sync. ++ * ++ * If STALL event shows some bytes were transferred then assume ++ * it's an actual transfer issue and give back the request. ++ * In this case mark the TRB as No-Op to avoid hw from using the ++ * TRB again. ++ */ ++ ++ if ((ep_ctx->deq & ~TRB_CYCLE) == event->trans_event.buffer) { ++ dev_dbg(dbc->dev, "Ep stopped on Stalled TRB\n"); ++ if (remain_length == req->length) { ++ dev_dbg(dbc->dev, "Spurious stall event, keep req\n"); ++ req->status = -COMP_STALL_ERROR; ++ req->actual = 0; ++ return; ++ } ++ dev_dbg(dbc->dev, "Give back stalled req, but turn TRB to No-op\n"); ++ trb_to_noop(req->trb); ++ } ++ break; ++ + default: + dev_err(dbc->dev, "unknown tx error %d\n", comp_code); + status = -comp_code; + break; + } + +- /* Match the pending request: */ +- list_for_each_entry(r, &dep->list_pending, list_pending) { +- if (r->trb_dma == event->trans_event.buffer) { +- req = r; +- break; +- } +- } +- +- if (!req) { +- dev_warn(dbc->dev, "no matched request\n"); +- return; +- } +- +- trace_xhci_dbc_handle_transfer(ring, &req->trb->generic); +- + ring->num_trbs_free++; + req->actual = req->length - remain_length; + xhci_dbc_giveback(req, status); +@@ -750,7 +809,6 @@ static void inc_evt_deq(struct xhci_ring + static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc) + { + dma_addr_t deq; +- struct dbc_ep *dep; + union xhci_trb *evt; + u32 ctrl, portsc; + bool update_erdp = false; +@@ -802,43 +860,17 @@ static enum evtreturn xhci_dbc_do_handle + return EVT_DISC; + } + +- /* Handle endpoint stall event: */ ++ /* Check and handle changes in endpoint halt status */ + ctrl = readl(&dbc->regs->control); +- if ((ctrl & DBC_CTRL_HALT_IN_TR) || +- (ctrl & DBC_CTRL_HALT_OUT_TR)) { +- dev_info(dbc->dev, "DbC Endpoint stall\n"); +- dbc->state = DS_STALLED; +- +- if (ctrl & DBC_CTRL_HALT_IN_TR) { +- dep = get_in_ep(dbc); +- xhci_dbc_flush_endpoint_requests(dep); +- } +- +- if (ctrl & DBC_CTRL_HALT_OUT_TR) { +- dep = get_out_ep(dbc); +- xhci_dbc_flush_endpoint_requests(dep); +- } +- +- return EVT_DONE; +- } ++ handle_ep_halt_changes(dbc, get_in_ep(dbc), ctrl & DBC_CTRL_HALT_IN_TR); ++ handle_ep_halt_changes(dbc, get_out_ep(dbc), ctrl & DBC_CTRL_HALT_OUT_TR); + + /* Clear DbC run change bit: */ + if (ctrl & DBC_CTRL_DBC_RUN_CHANGE) { + writel(ctrl, &dbc->regs->control); + ctrl = readl(&dbc->regs->control); + } +- + break; +- case DS_STALLED: +- ctrl = readl(&dbc->regs->control); +- if (!(ctrl & DBC_CTRL_HALT_IN_TR) && +- !(ctrl & DBC_CTRL_HALT_OUT_TR) && +- (ctrl & DBC_CTRL_DBC_RUN)) { +- dbc->state = DS_CONFIGURED; +- break; +- } +- +- return EVT_DONE; + default: + dev_err(dbc->dev, "Unknown DbC state %d\n", dbc->state); + break; +@@ -994,9 +1026,6 @@ static ssize_t dbc_show(struct device *d + case DS_CONFIGURED: + p = "configured"; + break; +- case DS_STALLED: +- p = "stalled"; +- break; + default: + p = "unknown"; + } +--- a/drivers/usb/host/xhci-dbgcap.h ++++ b/drivers/usb/host/xhci-dbgcap.h +@@ -81,7 +81,6 @@ enum dbc_state { + DS_ENABLED, + DS_CONNECTED, + DS_CONFIGURED, +- DS_STALLED, + }; + + struct dbc_ep { +@@ -89,6 +88,7 @@ struct dbc_ep { + struct list_head list_pending; + struct xhci_ring *ring; + unsigned int direction:1; ++ unsigned int halted:1; + }; + + #define DBC_QUEUE_SIZE 16