]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 12 Dec 2024 08:42:39 +0000 (09:42 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 12 Dec 2024 08:42:39 +0000 (09:42 +0100)
added patches:
jffs2-fix-rtime-decompressor.patch
jffs2-prevent-rtime-decompress-memory-corruption.patch
xhci-dbc-fix-stall-transfer-event-handling.patch

queue-5.10/jffs2-fix-rtime-decompressor.patch [new file with mode: 0644]
queue-5.10/jffs2-prevent-rtime-decompress-memory-corruption.patch [new file with mode: 0644]
queue-5.10/series
queue-5.10/xhci-dbc-fix-stall-transfer-event-handling.patch [new file with mode: 0644]

diff --git a/queue-5.10/jffs2-fix-rtime-decompressor.patch b/queue-5.10/jffs2-fix-rtime-decompressor.patch
new file mode 100644 (file)
index 0000000..f1410bc
--- /dev/null
@@ -0,0 +1,32 @@
+From b29bf7119d6bbfd04aabb8d82b060fe2a33ef890 Mon Sep 17 00:00:00 2001
+From: Richard Weinberger <richard@nod.at>
+Date: Tue, 3 Dec 2024 12:27:15 +0100
+Subject: jffs2: Fix rtime decompressor
+
+From: Richard Weinberger <richard@nod.at>
+
+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 <kinsey.moore@oarcorp.com>
+Cc: stable@vger.kernel.org
+Fixes: fe051552f5078 ("jffs2: Prevent rtime decompress memory corruption")
+Signed-off-by: Richard Weinberger <richard@nod.at>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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 (file)
index 0000000..078df2a
--- /dev/null
@@ -0,0 +1,34 @@
+From fe051552f5078fa02d593847529a3884305a6ffe Mon Sep 17 00:00:00 2001
+From: Kinsey Moore <kinsey.moore@oarcorp.com>
+Date: Tue, 23 Jul 2024 15:58:05 -0500
+Subject: jffs2: Prevent rtime decompress memory corruption
+
+From: Kinsey Moore <kinsey.moore@oarcorp.com>
+
+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 <kinsey.moore@oarcorp.com>
+Signed-off-by: Richard Weinberger <richard@nod.at>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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++];
index e9ef1ae93a3a885aeea5a50ff7d779e222c98902..55ac1b884bbd63cbb76865267bf93d0055f58ec6 100644 (file)
@@ -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 (file)
index 0000000..5f0e5f5
--- /dev/null
@@ -0,0 +1,294 @@
+From 9044ad57b60b0556d42b6f8aa218a68865e810a4 Mon Sep 17 00:00:00 2001
+From: Mathias Nyman <mathias.nyman@linux.intel.com>
+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 <mathias.nyman@linux.intel.com>
+
+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 <ukaszb@chromium.org>
+Closes: https://lore.kernel.org/linux-usb/20240725074857.623299-1-ukaszb@chromium.org/
+Tested-by: Łukasz Bartosik <ukaszb@chromium.org>
+Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
+Link: https://lore.kernel.org/r/20240905143300.1959279-2-mathias.nyman@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ 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