From: Sasha Levin Date: Tue, 28 Jul 2026 16:09:36 +0000 (-0400) Subject: Fixes for all trees X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=ae93477d9ac0bca0ce84e01138202bc3ec884403;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for all trees Signed-off-by: Sasha Levin --- diff --git a/queue-5.10/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch b/queue-5.10/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch new file mode 100644 index 0000000000..9b526c7c39 --- /dev/null +++ b/queue-5.10/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch @@ -0,0 +1,73 @@ +From 29ae8286712519330c5689704acdd299b2ebaf62 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 17:54:34 +0800 +Subject: bpf: Fix ld_{abs,ind} failure path analysis in subprogs + +From: Daniel Borkmann + +commit ee861486e377edc55361c08dcbceab3f6b6577bd upstream. + +Usage of ld_{abs,ind} instructions got extended into subprogs some time +ago via commit 09b28d76eac4 ("bpf: Add abnormal return checks."). These +are only allowed in subprograms when the latter are BTF annotated and +have scalar return types. + +The code generator in bpf_gen_ld_abs() has an abnormal exit path (r0=0 + +exit) from legacy cBPF times. While the enforcement is on scalar return +types, the verifier must also simulate the path of abnormal exit if the +packet data load via ld_{abs,ind} failed. + +This is currently not the case. Fix it by having the verifier simulate +both success and failure paths, and extend it in similar ways as we do +for tail calls. The success path (r0=unknown, continue to next insn) is +pushed onto stack for later validation and the r0=0 and return to the +caller is done on the fall-through side. + +Fixes: 09b28d76eac4 ("bpf: Add abnormal return checks.") +Reported-by: STAR Labs SG +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260408191242.526279-2-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +[ Dropped visit_abnormal_return_insn changes: depends on 7.0 symbols from + e40f5a6bf88a ("bpf: correct stack liveness for tail calls"); + Hunk1: adapted IS_ERR/PTR_ERR to !branch/-EFAULT to match push_stack() + NULL-on-failure convention; + Dropped mark_reg_scratched(), which only affects log verbosity, introduced + by 0f55f9ed21f9 ("bpf: Only print scratched registers and stack slots to + verifier logs.").] +Signed-off-by: Philo Lu +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 19e1f7fff07a9c..058c05e7f144c7 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -8556,6 +8556,22 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn) + mark_reg_unknown(env, regs, BPF_REG_0); + /* ld_abs load up to 32-bit skb data. */ + regs[BPF_REG_0].subreg_def = env->insn_idx + 1; ++ /* ++ * See bpf_gen_ld_abs() which emits a hidden BPF_EXIT with r0=0 ++ * which must be explored by the verifier when in a subprog. ++ */ ++ if (env->cur_state->curframe) { ++ struct bpf_verifier_state *branch; ++ ++ branch = push_stack(env, env->insn_idx + 1, env->insn_idx, false); ++ if (!branch) ++ return -EFAULT; ++ mark_reg_known_zero(env, regs, BPF_REG_0); ++ err = prepare_func_exit(env, &env->insn_idx); ++ if (err) ++ return err; ++ env->insn_idx--; ++ } + return 0; + } + +-- +2.53.0 + diff --git a/queue-5.10/series b/queue-5.10/series index 10dd46bc18..4304ed3faa 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -57,3 +57,5 @@ usb-serial-io_edgeport-cap-received-transmit-credits.patch usb-serial-option-add-tdtech-mt5710-cn.patch posix-cpu-timers-prevent-uaf-caused-by-non-leader-ex.patch crypto-rsa-pkcs1pad-don-t-warn-on-an-empty-digest.patch +bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch +usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch diff --git a/queue-5.10/usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch b/queue-5.10/usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch new file mode 100644 index 0000000000..edec8e0861 --- /dev/null +++ b/queue-5.10/usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch @@ -0,0 +1,98 @@ +From 67de533bcda4a5bc79f7041ab651c6f09ec2fb32 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 09:50:00 +0800 +Subject: usb: xhci-pci: Limit VIA VL805 DMA addressing to 36 bits + +From: Xincheng Zhang + +commit 1fc50f1ecde39feb4fccdaf4bc71aa6c0eb25c49 upstream. + +The VIA VL805/806 xHCI controller advertises AC64, but fails to handle +DMA addresses at or above 0x1000000000. On systems with large amounts of +RAM, this can cause USB device failures when the controller is given DMA +addresses beyond its usable address width. + +Do not use XHCI_NO_64BIT_SUPPORT for this controller. That quirk clears +the cached AC64 capability and limits DMA to 32 bits, causing unnecessary +bouncing for addresses between 4GiB and 64GiB and hiding the controller's +real AC64 capability from code that may need to distinguish register +access width from usable DMA address width. + +Track the usable DMA address width separately from the AC64 capability. +Initialize the generic xhci->dma_mask_bits field to 64 and let PCI quirks +reduce it for controllers with narrower DMA support. Set VIA VL805/806 to +36 bits so the DMA API only hands it addresses in the range it can handle +while keeping HCCPARAMS1.AC64 visible. + +Cc: stable +Signed-off-by: Xincheng Zhang +Link: https://patch.msgid.link/20260630-xhci-via-dma-fix-v3-1-690dcb8cf75a@ultrarisc.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/host/xhci-pci.c | 1 + + drivers/usb/host/xhci.c | 15 ++++++++++----- + drivers/usb/host/xhci.h | 1 + + 3 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c +index 2be84d5e9261da..6e87f36afb49c4 100644 +--- a/drivers/usb/host/xhci-pci.c ++++ b/drivers/usb/host/xhci-pci.c +@@ -302,6 +302,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) + xhci->quirks |= XHCI_LPM_SUPPORT; + xhci->quirks |= XHCI_TRB_OVERFETCH; + xhci->quirks |= XHCI_EP_CTX_BROKEN_DCS; ++ xhci->dma_mask_bits = 36; + } + + if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && +diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c +index 03de77fbe3af34..2cc27dba08e2d6 100644 +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -5323,6 +5323,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) + if (xhci->hci_version > 0x100) + xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2); + ++ xhci->dma_mask_bits = 64; + xhci->quirks |= quirks; + + get_quirks(dev, xhci); +@@ -5358,12 +5359,16 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) + if (xhci->quirks & XHCI_NO_64BIT_SUPPORT) + xhci->hcc_params &= ~BIT(0); + +- /* Set dma_mask and coherent_dma_mask to 64-bits, +- * if xHC supports 64-bit addressing */ ++ /* ++ * Set dma_mask and coherent_dma_mask to 64-bits if xHC supports ++ * 64-bit addressing, unless a controller-specific quirk callback ++ * limits the usable address width. ++ */ + if (HCC_64BIT_ADDR(xhci->hcc_params) && +- !dma_set_mask(dev, DMA_BIT_MASK(64))) { +- xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n"); +- dma_set_coherent_mask(dev, DMA_BIT_MASK(64)); ++ !dma_set_mask(dev, DMA_BIT_MASK(xhci->dma_mask_bits))) { ++ xhci_dbg(xhci, "Enabling %u-bit DMA addresses.\n", ++ xhci->dma_mask_bits); ++ dma_set_coherent_mask(dev, DMA_BIT_MASK(xhci->dma_mask_bits)); + } else { + /* + * This is to avoid error in cases where a 32-bit USB +diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h +index 4d4ac8ec614b20..8d1c6c59e9e927 100644 +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1782,6 +1782,7 @@ struct xhci_hcd { + int event_ring_max; + /* 4KB min, 128MB max */ + int page_size; ++ unsigned int dma_mask_bits; + /* Valid values are 12 to 20, inclusive */ + int page_shift; + /* msi-x vectors */ +-- +2.53.0 + diff --git a/queue-5.15/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch b/queue-5.15/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch new file mode 100644 index 0000000000..7bd1202dcc --- /dev/null +++ b/queue-5.15/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch @@ -0,0 +1,73 @@ +From d0768ec9dbcb21527597bb22c39f5ff142e1b0db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 17:54:34 +0800 +Subject: bpf: Fix ld_{abs,ind} failure path analysis in subprogs + +From: Daniel Borkmann + +commit ee861486e377edc55361c08dcbceab3f6b6577bd upstream. + +Usage of ld_{abs,ind} instructions got extended into subprogs some time +ago via commit 09b28d76eac4 ("bpf: Add abnormal return checks."). These +are only allowed in subprograms when the latter are BTF annotated and +have scalar return types. + +The code generator in bpf_gen_ld_abs() has an abnormal exit path (r0=0 + +exit) from legacy cBPF times. While the enforcement is on scalar return +types, the verifier must also simulate the path of abnormal exit if the +packet data load via ld_{abs,ind} failed. + +This is currently not the case. Fix it by having the verifier simulate +both success and failure paths, and extend it in similar ways as we do +for tail calls. The success path (r0=unknown, continue to next insn) is +pushed onto stack for later validation and the r0=0 and return to the +caller is done on the fall-through side. + +Fixes: 09b28d76eac4 ("bpf: Add abnormal return checks.") +Reported-by: STAR Labs SG +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260408191242.526279-2-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +[ Dropped visit_abnormal_return_insn changes: depends on 7.0 symbols from + e40f5a6bf88a ("bpf: correct stack liveness for tail calls"); + Hunk1: adapted IS_ERR/PTR_ERR to !branch/-EFAULT to match push_stack() + NULL-on-failure convention; + Dropped mark_reg_scratched(), which only affects log verbosity, introduced + by 0f55f9ed21f9 ("bpf: Only print scratched registers and stack slots to + verifier logs.").] +Signed-off-by: Philo Lu +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index ec447854f53450..5e71d58e4a3006 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -9644,6 +9644,22 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn) + mark_reg_unknown(env, regs, BPF_REG_0); + /* ld_abs load up to 32-bit skb data. */ + regs[BPF_REG_0].subreg_def = env->insn_idx + 1; ++ /* ++ * See bpf_gen_ld_abs() which emits a hidden BPF_EXIT with r0=0 ++ * which must be explored by the verifier when in a subprog. ++ */ ++ if (env->cur_state->curframe) { ++ struct bpf_verifier_state *branch; ++ ++ branch = push_stack(env, env->insn_idx + 1, env->insn_idx, false); ++ if (!branch) ++ return -EFAULT; ++ mark_reg_known_zero(env, regs, BPF_REG_0); ++ err = prepare_func_exit(env, &env->insn_idx); ++ if (err) ++ return err; ++ env->insn_idx--; ++ } + return 0; + } + +-- +2.53.0 + diff --git a/queue-5.15/series b/queue-5.15/series index bbfea89b72..9b8c9fc633 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -74,3 +74,5 @@ usb-serial-option-add-tdtech-mt5710-cn.patch posix-cpu-timers-prevent-uaf-caused-by-non-leader-ex.patch crypto-rsa-pkcs1pad-don-t-warn-on-an-empty-digest.patch revert-drm-amd-display-add-missing-kdoc-for-allm-par.patch +bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch +usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch diff --git a/queue-5.15/usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch b/queue-5.15/usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch new file mode 100644 index 0000000000..dea0dc37d6 --- /dev/null +++ b/queue-5.15/usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch @@ -0,0 +1,98 @@ +From b5ca4f4659b7447dcf31b14b78743f87b73a8392 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 10:25:14 +0800 +Subject: usb: xhci-pci: Limit VIA VL805 DMA addressing to 36 bits + +From: Xincheng Zhang + +commit 1fc50f1ecde39feb4fccdaf4bc71aa6c0eb25c49 upstream. + +The VIA VL805/806 xHCI controller advertises AC64, but fails to handle +DMA addresses at or above 0x1000000000. On systems with large amounts of +RAM, this can cause USB device failures when the controller is given DMA +addresses beyond its usable address width. + +Do not use XHCI_NO_64BIT_SUPPORT for this controller. That quirk clears +the cached AC64 capability and limits DMA to 32 bits, causing unnecessary +bouncing for addresses between 4GiB and 64GiB and hiding the controller's +real AC64 capability from code that may need to distinguish register +access width from usable DMA address width. + +Track the usable DMA address width separately from the AC64 capability. +Initialize the generic xhci->dma_mask_bits field to 64 and let PCI quirks +reduce it for controllers with narrower DMA support. Set VIA VL805/806 to +36 bits so the DMA API only hands it addresses in the range it can handle +while keeping HCCPARAMS1.AC64 visible. + +Cc: stable@kernel.org +Signed-off-by: Xincheng Zhang +Link: https://patch.msgid.link/20260630-xhci-via-dma-fix-v3-1-690dcb8cf75a@ultrarisc.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/host/xhci-pci.c | 1 + + drivers/usb/host/xhci.c | 15 ++++++++++----- + drivers/usb/host/xhci.h | 1 + + 3 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c +index 9c7491ac28f2f3..f8988f110dcff5 100644 +--- a/drivers/usb/host/xhci-pci.c ++++ b/drivers/usb/host/xhci-pci.c +@@ -338,6 +338,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) + if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == PCI_DEVICE_ID_VIA_VL805) { + xhci->quirks |= XHCI_LPM_SUPPORT; + xhci->quirks |= XHCI_TRB_OVERFETCH; ++ xhci->dma_mask_bits = 36; + } + + if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && +diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c +index 0ac438392545dd..823fe397bfb105 100644 +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -5398,6 +5398,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) + if (xhci->hci_version > 0x100) + xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2); + ++ xhci->dma_mask_bits = 64; + /* xhci-plat or xhci-pci might have set max_interrupters already */ + if ((!xhci->max_interrupters) || + xhci->max_interrupters > HCS_MAX_INTRS(xhci->hcs_params1)) +@@ -5438,12 +5439,16 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) + if (xhci->quirks & XHCI_NO_64BIT_SUPPORT) + xhci->hcc_params &= ~BIT(0); + +- /* Set dma_mask and coherent_dma_mask to 64-bits, +- * if xHC supports 64-bit addressing */ ++ /* ++ * Set dma_mask and coherent_dma_mask to 64-bits if xHC supports ++ * 64-bit addressing, unless a controller-specific quirk callback ++ * limits the usable address width. ++ */ + if (HCC_64BIT_ADDR(xhci->hcc_params) && +- !dma_set_mask(dev, DMA_BIT_MASK(64))) { +- xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n"); +- dma_set_coherent_mask(dev, DMA_BIT_MASK(64)); ++ !dma_set_mask(dev, DMA_BIT_MASK(xhci->dma_mask_bits))) { ++ xhci_dbg(xhci, "Enabling %u-bit DMA addresses.\n", ++ xhci->dma_mask_bits); ++ dma_set_coherent_mask(dev, DMA_BIT_MASK(xhci->dma_mask_bits)); + } else { + /* + * This is to avoid error in cases where a 32-bit USB +diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h +index ac33baa2b0f82d..96519c446778d1 100644 +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1544,6 +1544,7 @@ struct xhci_hcd { + int event_ring_max; + /* 4KB min, 128MB max */ + int page_size; ++ unsigned int dma_mask_bits; + /* Valid values are 12 to 20, inclusive */ + int page_shift; + /* msi-x vectors */ +-- +2.53.0 + diff --git a/queue-6.1/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch b/queue-6.1/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch new file mode 100644 index 0000000000..c2138e6170 --- /dev/null +++ b/queue-6.1/bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch @@ -0,0 +1,71 @@ +From aa07a55e06f2ec3dfb56964de6666e3feb2290ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 17:49:37 +0800 +Subject: bpf: Fix ld_{abs,ind} failure path analysis in subprogs + +From: Daniel Borkmann + +commit ee861486e377edc55361c08dcbceab3f6b6577bd upstream. + +Usage of ld_{abs,ind} instructions got extended into subprogs some time +ago via commit 09b28d76eac4 ("bpf: Add abnormal return checks."). These +are only allowed in subprograms when the latter are BTF annotated and +have scalar return types. + +The code generator in bpf_gen_ld_abs() has an abnormal exit path (r0=0 + +exit) from legacy cBPF times. While the enforcement is on scalar return +types, the verifier must also simulate the path of abnormal exit if the +packet data load via ld_{abs,ind} failed. + +This is currently not the case. Fix it by having the verifier simulate +both success and failure paths, and extend it in similar ways as we do +for tail calls. The success path (r0=unknown, continue to next insn) is +pushed onto stack for later validation and the r0=0 and return to the +caller is done on the fall-through side. + +Fixes: 09b28d76eac4 ("bpf: Add abnormal return checks.") +Reported-by: STAR Labs SG +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260408191242.526279-2-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +[ Dropped visit_abnormal_return_insn changes: depends on 7.0 symbols from + e40f5a6bf88a ("bpf: correct stack liveness for tail calls"); + Hunk1: adapted IS_ERR/PTR_ERR to !branch/-EFAULT to match push_stack() + NULL-on-failure convention. ] +Signed-off-by: Philo Lu +Signed-off-by: Sasha Levin +--- + kernel/bpf/verifier.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c +index 4380082f321c7a..4ff1d5007a23e2 100644 +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -10751,6 +10751,23 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn) + mark_reg_unknown(env, regs, BPF_REG_0); + /* ld_abs load up to 32-bit skb data. */ + regs[BPF_REG_0].subreg_def = env->insn_idx + 1; ++ /* ++ * See bpf_gen_ld_abs() which emits a hidden BPF_EXIT with r0=0 ++ * which must be explored by the verifier when in a subprog. ++ */ ++ if (env->cur_state->curframe) { ++ struct bpf_verifier_state *branch; ++ ++ mark_reg_scratched(env, BPF_REG_0); ++ branch = push_stack(env, env->insn_idx + 1, env->insn_idx, false); ++ if (!branch) ++ return -EFAULT; ++ mark_reg_known_zero(env, regs, BPF_REG_0); ++ err = prepare_func_exit(env, &env->insn_idx); ++ if (err) ++ return err; ++ env->insn_idx--; ++ } + return 0; + } + +-- +2.53.0 + diff --git a/queue-6.1/bpf-prefer-dirty-packs-for-ebpf-allocations.patch b/queue-6.1/bpf-prefer-dirty-packs-for-ebpf-allocations.patch new file mode 100644 index 0000000000..a459dcd6d6 --- /dev/null +++ b/queue-6.1/bpf-prefer-dirty-packs-for-ebpf-allocations.patch @@ -0,0 +1,49 @@ +From 4674e7a68b938484143f0e5167d48bb2866dddf3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 15:56:57 -0700 +Subject: bpf: Prefer dirty packs for eBPF allocations + +From: Pawan Gupta + +commit b72e29e0f7ee329d89f86db8700c8ea99b4a370a upstream. + +The pack allocator only flushes predictors when reusing a dirty pack for +cBPF, eBPF allocations never trigger a flush. Currently, eBPF picks the +first free pack, which could be a clean pack. As an optimization, leaving +a clean pack for cBPF can avoid flushes. + +Prefer dirty packs for eBPF and keep clean packs free for cBPF. This +mirrors the existing cBPF preference for clean packs: each program kind +prefers the pack that avoids an extra flush, and falls back to the other +kind only when no preferred pack has room. eBPF reuse of a dirty pack is +harmless since eBPF being privileged does not flush. + +Signed-off-by: Pawan Gupta +Acked-by: Daniel Borkmann +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + kernel/bpf/core.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 926bf11aeaf21a..4ea21434bf78e6 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -946,10 +946,10 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool + goto found_free_area; + /* + * cBPF reuse of a dirty pack triggers a flush, so prefer a +- * clean pack for cBPF. eBPF never flushes, so pick the first +- * free pack, dirty or clean. ++ * clean pack for cBPF. eBPF never flushes, so steer it to a ++ * dirty pack and keep clean packs free for cBPF. + */ +- if (!was_classic || !pack->arch_flush_needed) ++ if (was_classic ^ pack->arch_flush_needed) + goto found_free_area; + if (!fallback_pack) { + fallback_pack = pack; +-- +2.53.0 + diff --git a/queue-6.1/bpf-prefer-packs-that-won-t-trigger-an-ibpb-flush-on.patch b/queue-6.1/bpf-prefer-packs-that-won-t-trigger-an-ibpb-flush-on.patch new file mode 100644 index 0000000000..320aa07025 --- /dev/null +++ b/queue-6.1/bpf-prefer-packs-that-won-t-trigger-an-ibpb-flush-on.patch @@ -0,0 +1,88 @@ +From b3af5f1c9afb58eeb3636a2aa0b39b79dffcbc93 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 15:56:42 -0700 +Subject: bpf: Prefer packs that won't trigger an IBPB flush on allocation + +From: Pawan Gupta + +commit a9b1f19a6a673ba06820898d0f1ad02883ea1639 upstream. + +Currently BPF pack allocator picks the chunks from the first available +pack. While this is okay, it naturally leads to more frequent flushes +when there are multiple packs in the system that weren't used since the +last flush. + +As an optimization prefer allocating the new programs from packs that +are unused since last flush. When all packs are dirty, allocation forces +a flush and marks all packs clean. + +Below are some future optimizations ideas: + + 1. Currently, the "dirty" tracking is only done at the pack-level. + Flush frequency can further be reduced with chunk-level tracking. + This requires a new bitmap per-pack to track the dirty state. + 2. IBPB flush is done on all CPUs, even if only a single CPU ran the + BPF program. On a system with hundreds of CPUs this could be a + major bottleneck forcing hundreds of IPIs to deliver the flush. + The solution is to track the CPUs where a BPF program ran, and + issue IBPB only on those CPUs. + 3. Avoid IBPB when flush is already done at other sources (e.g. + context switch). + +Signed-off-by: Pawan Gupta +Acked-by: Daniel Borkmann +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + kernel/bpf/core.c | 27 ++++++++++++++++++++++++--- + 1 file changed, 24 insertions(+), 3 deletions(-) + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 5a0f804ecdf404..926bf11aeaf21a 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -912,8 +912,8 @@ static struct bpf_prog_pack *alloc_new_pack(bpf_jit_fill_hole_t bpf_fill_ill_ins + void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool was_classic) + { + unsigned int nbits = BPF_PROG_SIZE_TO_NBITS(size); +- struct bpf_prog_pack *pack; +- unsigned long pos; ++ struct bpf_prog_pack *pack, *fallback_pack = NULL; ++ unsigned long pos, fallback_pos = 0; + void *ptr = NULL; + + mutex_lock(&pack_mutex); +@@ -939,8 +939,29 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool + list_for_each_entry(pack, &pack_list, list) { + pos = bitmap_find_next_zero_area(pack->bitmap, BPF_PROG_CHUNK_COUNT, 0, + nbits, 0); +- if (pos < BPF_PROG_CHUNK_COUNT) ++ if (pos >= BPF_PROG_CHUNK_COUNT) ++ continue; ++ /* Flush not enabled, use any pack */ ++ if (!static_branch_unlikely(&bpf_pred_flush_enabled)) + goto found_free_area; ++ /* ++ * cBPF reuse of a dirty pack triggers a flush, so prefer a ++ * clean pack for cBPF. eBPF never flushes, so pick the first ++ * free pack, dirty or clean. ++ */ ++ if (!was_classic || !pack->arch_flush_needed) ++ goto found_free_area; ++ if (!fallback_pack) { ++ fallback_pack = pack; ++ fallback_pos = pos; ++ } ++ } ++ ++ /* No preferred pack found */ ++ if (fallback_pack) { ++ pack = fallback_pack; ++ pos = fallback_pos; ++ goto found_free_area; + } + + pack = alloc_new_pack(bpf_fill_ill_insns); +-- +2.53.0 + diff --git a/queue-6.1/bpf-restrict-jit-predictor-flush-to-cbpf.patch b/queue-6.1/bpf-restrict-jit-predictor-flush-to-cbpf.patch new file mode 100644 index 0000000000..4737ff9bdb --- /dev/null +++ b/queue-6.1/bpf-restrict-jit-predictor-flush-to-cbpf.patch @@ -0,0 +1,137 @@ +From 513fdc68f0aa09190e09d7aa3505658f71f84441 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 15:56:11 -0700 +Subject: bpf: Restrict JIT predictor flush to cBPF + +From: Pawan Gupta + +commit 0bb99f2cfaae6822d734d69722de30af823efdf3 upstream. + +Currently predictor flush on memory reuse is done for all BPF JIT +allocations, but only cBPF programs can be loaded by an unprivileged user. +eBPF is privileged by default, and flushing predictors for all CPUs on +every eBPF reuse penalizes the common case for no security benefit. + +eBPF allocations can be frequent on busy systems, only flush predictors +for cBPF programs. Trampoline and dispatcher allocations also skip the +flush as they are eBPF-only. + + [pawan: backport dropped "was_classic" hunk for arches that do not + support pack allocator] + +Signed-off-by: Pawan Gupta +Acked-by: Daniel Borkmann +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + arch/x86/net/bpf_jit_comp.c | 3 ++- + include/linux/filter.h | 5 +++-- + kernel/bpf/core.c | 13 ++++++++----- + kernel/bpf/dispatcher.c | 2 +- + 4 files changed, 14 insertions(+), 9 deletions(-) + +diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c +index 095fec941bb739..30c6a021abcaf0 100644 +--- a/arch/x86/net/bpf_jit_comp.c ++++ b/arch/x86/net/bpf_jit_comp.c +@@ -2553,7 +2553,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) + /* allocate module memory for x86 insns and extable */ + header = bpf_jit_binary_pack_alloc(roundup(proglen, align) + extable_size, + &image, align, &rw_header, &rw_image, +- jit_fill_hole); ++ jit_fill_hole, ++ bpf_prog_was_classic(prog)); + if (!header) { + prog = orig_prog; + goto out_addrs; +diff --git a/include/linux/filter.h b/include/linux/filter.h +index fa7bb6f995989e..673aef4e1465af 100644 +--- a/include/linux/filter.h ++++ b/include/linux/filter.h +@@ -1082,7 +1082,7 @@ void bpf_jit_free(struct bpf_prog *fp); + struct bpf_binary_header * + bpf_jit_binary_pack_hdr(const struct bpf_prog *fp); + +-void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns); ++void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool was_classic); + void bpf_prog_pack_free(struct bpf_binary_header *hdr); + + static inline bool bpf_prog_kallsyms_verify_off(const struct bpf_prog *fp) +@@ -1096,7 +1096,8 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **ro_image, + unsigned int alignment, + struct bpf_binary_header **rw_hdr, + u8 **rw_image, +- bpf_jit_fill_hole_t bpf_fill_ill_insns); ++ bpf_jit_fill_hole_t bpf_fill_ill_insns, ++ bool was_classic); + int bpf_jit_binary_pack_finalize(struct bpf_prog *prog, + struct bpf_binary_header *ro_header, + struct bpf_binary_header *rw_header); +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 4643554c6e3a9c..f78ee18bab3b55 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -906,7 +906,7 @@ static struct bpf_prog_pack *alloc_new_pack(bpf_jit_fill_hole_t bpf_fill_ill_ins + return pack; + } + +-void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns) ++void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool was_classic) + { + unsigned int nbits = BPF_PROG_SIZE_TO_NBITS(size); + struct bpf_prog_pack *pack; +@@ -921,7 +921,7 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns) + * safe because cBPF programs (the unprivileged attack surface) + * are bounded well below a pack size. + */ +- if (static_branch_unlikely(&bpf_pred_flush_enabled)) ++ if (was_classic && static_branch_unlikely(&bpf_pred_flush_enabled)) + pr_warn_once("BPF: Predictors not flushed for allocations greater than BPF_PROG_PACK_SIZE\n"); + size = round_up(size, PAGE_SIZE); + ptr = module_alloc(size); +@@ -947,7 +947,9 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns) + pos = 0; + + found_free_area: +- static_call_cond(bpf_arch_pred_flush)(); ++ /* Flush only for cBPF as it may contain a crafted gadget */ ++ if (static_branch_unlikely(&bpf_pred_flush_enabled) && was_classic) ++ static_call_cond(bpf_arch_pred_flush)(); + bitmap_set(pack->bitmap, pos, nbits); + ptr = (void *)(pack->ptr) + (pos << BPF_PROG_CHUNK_SHIFT); + +@@ -1107,7 +1109,8 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **image_ptr, + unsigned int alignment, + struct bpf_binary_header **rw_header, + u8 **rw_image, +- bpf_jit_fill_hole_t bpf_fill_ill_insns) ++ bpf_jit_fill_hole_t bpf_fill_ill_insns, ++ bool was_classic) + { + struct bpf_binary_header *ro_header; + u32 size, hole, start; +@@ -1120,7 +1123,7 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **image_ptr, + + if (bpf_jit_charge_modmem(size)) + return NULL; +- ro_header = bpf_prog_pack_alloc(size, bpf_fill_ill_insns); ++ ro_header = bpf_prog_pack_alloc(size, bpf_fill_ill_insns, was_classic); + if (!ro_header) { + bpf_jit_uncharge_modmem(size); + return NULL; +diff --git a/kernel/bpf/dispatcher.c b/kernel/bpf/dispatcher.c +index fa3e9225aedc0a..b3f164e31c6bb4 100644 +--- a/kernel/bpf/dispatcher.c ++++ b/kernel/bpf/dispatcher.c +@@ -145,7 +145,7 @@ void bpf_dispatcher_change_prog(struct bpf_dispatcher *d, struct bpf_prog *from, + + mutex_lock(&d->mutex); + if (!d->image) { +- d->image = bpf_prog_pack_alloc(PAGE_SIZE, bpf_jit_fill_hole_with_zero); ++ d->image = bpf_prog_pack_alloc(PAGE_SIZE, bpf_jit_fill_hole_with_zero, false); + if (!d->image) + goto out; + d->rw_image = bpf_jit_alloc_exec(PAGE_SIZE); +-- +2.53.0 + diff --git a/queue-6.1/bpf-skip-redundant-ibpb-in-pack-allocator.patch b/queue-6.1/bpf-skip-redundant-ibpb-in-pack-allocator.patch new file mode 100644 index 0000000000..028e429efa --- /dev/null +++ b/queue-6.1/bpf-skip-redundant-ibpb-in-pack-allocator.patch @@ -0,0 +1,81 @@ +From 776f5af2ca01e7e054c700e868be0424ae786ee1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 15:56:26 -0700 +Subject: bpf: Skip redundant IBPB in pack allocator + +From: Pawan Gupta + +commit a23c1c5396a91680703360d1ee28a44657c503c4 upstream. + +bpf_prog_pack_alloc() issues IBPB on all CPUs on every cBPF allocation, +even when reusing chunks from an existing pack where no new memory was +touched since the last IBPB. + +Since IBPB on all CPUs is heavy, Dave Hansen suggested to track allocation +since last IBPB, and only issue IBPB at reuse for the chunks that have not +seen an IBPB since they were last freed. + +Track per-pack whether an IBPB is needed via arch_flush_needed. Set it when +allocating a chunk, reset on IBPB flush. On reuse, conditionally issue the +flush. Since IBPB invalidates all BTB entries, clear the flag on all packs +after flushing. + +Signed-off-by: Pawan Gupta +Acked-by: Daniel Borkmann +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + kernel/bpf/core.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index f78ee18bab3b55..5a0f804ecdf404 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -845,6 +845,7 @@ int bpf_jit_add_poke_descriptor(struct bpf_prog *prog, + struct bpf_prog_pack { + struct list_head list; + void *ptr; ++ bool arch_flush_needed; + unsigned long bitmap[]; + }; + +@@ -900,6 +901,8 @@ static struct bpf_prog_pack *alloc_new_pack(bpf_jit_fill_hole_t bpf_fill_ill_ins + bitmap_zero(pack->bitmap, BPF_PROG_PACK_SIZE / BPF_PROG_CHUNK_SIZE); + list_add_tail(&pack->list, &pack_list); + ++ if (static_branch_unlikely(&bpf_pred_flush_enabled)) ++ pack->arch_flush_needed = true; + set_vm_flush_reset_perms(pack->ptr); + set_memory_ro((unsigned long)pack->ptr, BPF_PROG_PACK_SIZE / PAGE_SIZE); + set_memory_x((unsigned long)pack->ptr, BPF_PROG_PACK_SIZE / PAGE_SIZE); +@@ -948,8 +951,15 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool + + found_free_area: + /* Flush only for cBPF as it may contain a crafted gadget */ +- if (static_branch_unlikely(&bpf_pred_flush_enabled) && was_classic) ++ if (static_branch_unlikely(&bpf_pred_flush_enabled) && ++ pack->arch_flush_needed && ++ was_classic) { ++ struct bpf_prog_pack *p; ++ + static_call_cond(bpf_arch_pred_flush)(); ++ list_for_each_entry(p, &pack_list, list) ++ p->arch_flush_needed = false; ++ } + bitmap_set(pack->bitmap, pos, nbits); + ptr = (void *)(pack->ptr) + (pos << BPF_PROG_CHUNK_SHIFT); + +@@ -987,6 +997,9 @@ void bpf_prog_pack_free(struct bpf_binary_header *hdr) + "bpf_prog_pack bug: missing bpf_arch_text_invalidate?\n"); + + bitmap_clear(pack->bitmap, pos, nbits); ++ ++ if (static_branch_unlikely(&bpf_pred_flush_enabled)) ++ pack->arch_flush_needed = true; + if (bitmap_find_next_zero_area(pack->bitmap, BPF_PROG_CHUNK_COUNT, 0, + BPF_PROG_CHUNK_COUNT, 0) == 0) { + list_del(&pack->list); +-- +2.53.0 + diff --git a/queue-6.1/bpf-support-for-hardening-against-jit-spraying.patch b/queue-6.1/bpf-support-for-hardening-against-jit-spraying.patch new file mode 100644 index 0000000000..9199d10ecf --- /dev/null +++ b/queue-6.1/bpf-support-for-hardening-against-jit-spraying.patch @@ -0,0 +1,120 @@ +From 324250cda67e8434bd5aec8c9ad706e2a68605cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 15:55:40 -0700 +Subject: bpf: Support for hardening against JIT spraying + +From: Pawan Gupta + +commit 96cce16e26dd02a8678f1e87f88a4b5cdb63b995 upstream. + +The BPF JIT allocator packs many small programs into larger executable +allocations and reuses space within those allocations as programs are +loaded and freed. When fresh code is written into space that a previous +program occupied, an indirect jump into the new program can reuse a branch +prediction left behind by the old one. + +Flush the indirect branch predictors before reusing JIT memory so that +indirect jumps into a newly written program don't reuse predictions from an +old program that occupied the same space. + +Introduce bpf_arch_pred_flush_enabled static key and bpf_arch_pred_flush +static call for flushing the branch predictors on JIT memory reuse. +Architectures that need a flush, can update it to a predictor flush +function. By default, its a NOP and does not emit any CALL. + +Allocations larger than a pack are not covered by this flush. That is safe +because cBPF programs (the unprivileged attack surface) are bounded well +below a pack size. Issue a warning if this assumption is ever violated +while the flush is active. + +Signed-off-by: Pawan Gupta +Acked-by: Daniel Borkmann +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + include/linux/filter.h | 10 ++++++++++ + kernel/bpf/core.c | 19 +++++++++++++++++++ + 2 files changed, 29 insertions(+) + +diff --git a/include/linux/filter.h b/include/linux/filter.h +index 37260c48fad495..fa7bb6f995989e 100644 +--- a/include/linux/filter.h ++++ b/include/linux/filter.h +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -1058,6 +1059,15 @@ extern long bpf_jit_limit_max; + + typedef void (*bpf_jit_fill_hole_t)(void *area, unsigned int size); + ++/* ++ * Flush the indirect branch predictors before reusing JIT memory, so that ++ * indirect jumps into a newly written program don't reuse predictions left ++ * behind by an old program that occupied the same space. ++ */ ++void bpf_arch_pred_flush(void); ++DECLARE_STATIC_CALL(bpf_arch_pred_flush, bpf_arch_pred_flush); ++DECLARE_STATIC_KEY_FALSE(bpf_pred_flush_enabled); ++ + void bpf_jit_fill_hole_with_zero(void *area, unsigned int size); + + struct bpf_binary_header * +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 77044d4a80cc16..4643554c6e3a9c 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -852,6 +853,15 @@ void bpf_jit_fill_hole_with_zero(void *area, unsigned int size) + memset(area, 0, size); + } + ++DEFINE_STATIC_CALL_NULL(bpf_arch_pred_flush, bpf_arch_pred_flush); ++ ++/* ++ * Enabled once bpf_arch_pred_flush points at a real flush routine. Lets the ++ * pack allocator test "is a predictor flush wired up at all" with a cheap ++ * static branch instead of repeatedly querying the static call target. ++ */ ++DEFINE_STATIC_KEY_FALSE(bpf_pred_flush_enabled); ++ + #define BPF_PROG_SIZE_TO_NBITS(size) (round_up(size, BPF_PROG_CHUNK_SIZE) / BPF_PROG_CHUNK_SIZE) + + static DEFINE_MUTEX(pack_mutex); +@@ -905,6 +915,14 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns) + + mutex_lock(&pack_mutex); + if (size > BPF_PROG_PACK_SIZE) { ++ /* ++ * Allocations larger than a pack get their own pages, and ++ * predictors are not flushed for such allocation. This is only ++ * safe because cBPF programs (the unprivileged attack surface) ++ * are bounded well below a pack size. ++ */ ++ if (static_branch_unlikely(&bpf_pred_flush_enabled)) ++ pr_warn_once("BPF: Predictors not flushed for allocations greater than BPF_PROG_PACK_SIZE\n"); + size = round_up(size, PAGE_SIZE); + ptr = module_alloc(size); + if (ptr) { +@@ -929,6 +947,7 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns) + pos = 0; + + found_free_area: ++ static_call_cond(bpf_arch_pred_flush)(); + bitmap_set(pack->bitmap, pos, nbits); + ptr = (void *)(pack->ptr) + (pos << BPF_PROG_CHUNK_SHIFT); + +-- +2.53.0 + diff --git a/queue-6.1/series b/queue-6.1/series index c486cc47b1..afd95acb76 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -89,3 +89,11 @@ usb-serial-option-add-tdtech-mt5710-cn.patch posix-cpu-timers-prevent-uaf-caused-by-non-leader-ex.patch crypto-rsa-pkcs1pad-don-t-warn-on-an-empty-digest.patch revert-drm-amd-display-add-missing-kdoc-for-allm-par.patch +bpf-support-for-hardening-against-jit-spraying.patch +x86-bugs-enable-ibpb-flush-on-bpf-jit-allocation.patch +bpf-restrict-jit-predictor-flush-to-cbpf.patch +bpf-skip-redundant-ibpb-in-pack-allocator.patch +bpf-prefer-packs-that-won-t-trigger-an-ibpb-flush-on.patch +bpf-prefer-dirty-packs-for-ebpf-allocations.patch +bpf-fix-ld_-abs-ind-failure-path-analysis-in-subprog.patch +usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch diff --git a/queue-6.1/usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch b/queue-6.1/usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch new file mode 100644 index 0000000000..82e8fd687e --- /dev/null +++ b/queue-6.1/usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch @@ -0,0 +1,98 @@ +From 7c6b5705648998527620b2584e33b95a44ed7dd5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 11:01:16 +0800 +Subject: usb: xhci-pci: Limit VIA VL805 DMA addressing to 36 bits + +From: Xincheng Zhang + +commit 1fc50f1ecde39feb4fccdaf4bc71aa6c0eb25c49 upstream. + +The VIA VL805/806 xHCI controller advertises AC64, but fails to handle +DMA addresses at or above 0x1000000000. On systems with large amounts of +RAM, this can cause USB device failures when the controller is given DMA +addresses beyond its usable address width. + +Do not use XHCI_NO_64BIT_SUPPORT for this controller. That quirk clears +the cached AC64 capability and limits DMA to 32 bits, causing unnecessary +bouncing for addresses between 4GiB and 64GiB and hiding the controller's +real AC64 capability from code that may need to distinguish register +access width from usable DMA address width. + +Track the usable DMA address width separately from the AC64 capability. +Initialize the generic xhci->dma_mask_bits field to 64 and let PCI quirks +reduce it for controllers with narrower DMA support. Set VIA VL805/806 to +36 bits so the DMA API only hands it addresses in the range it can handle +while keeping HCCPARAMS1.AC64 visible. + +Cc: stable@kernel.org +Signed-off-by: Xincheng Zhang +Link: https://patch.msgid.link/20260630-xhci-via-dma-fix-v3-1-690dcb8cf75a@ultrarisc.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/host/xhci-pci.c | 1 + + drivers/usb/host/xhci.c | 15 ++++++++++----- + drivers/usb/host/xhci.h | 1 + + 3 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c +index 7ad6d13d65ee94..8fffc84d014779 100644 +--- a/drivers/usb/host/xhci-pci.c ++++ b/drivers/usb/host/xhci-pci.c +@@ -337,6 +337,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) + if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == PCI_DEVICE_ID_VIA_VL805) { + xhci->quirks |= XHCI_LPM_SUPPORT; + xhci->quirks |= XHCI_TRB_OVERFETCH; ++ xhci->dma_mask_bits = 36; + } + + if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && +diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c +index e00baa3b7324cb..37fb2491d88f22 100644 +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -5394,6 +5394,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) + if (xhci->hci_version > 0x100) + xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2); + ++ xhci->dma_mask_bits = 64; + /* xhci-plat or xhci-pci might have set max_interrupters already */ + if ((!xhci->max_interrupters) || + xhci->max_interrupters > HCS_MAX_INTRS(xhci->hcs_params1)) +@@ -5434,12 +5435,16 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) + if (xhci->quirks & XHCI_NO_64BIT_SUPPORT) + xhci->hcc_params &= ~BIT(0); + +- /* Set dma_mask and coherent_dma_mask to 64-bits, +- * if xHC supports 64-bit addressing */ ++ /* ++ * Set dma_mask and coherent_dma_mask to 64-bits if xHC supports ++ * 64-bit addressing, unless a controller-specific quirk callback ++ * limits the usable address width. ++ */ + if (HCC_64BIT_ADDR(xhci->hcc_params) && +- !dma_set_mask(dev, DMA_BIT_MASK(64))) { +- xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n"); +- dma_set_coherent_mask(dev, DMA_BIT_MASK(64)); ++ !dma_set_mask(dev, DMA_BIT_MASK(xhci->dma_mask_bits))) { ++ xhci_dbg(xhci, "Enabling %u-bit DMA addresses.\n", ++ xhci->dma_mask_bits); ++ dma_set_coherent_mask(dev, DMA_BIT_MASK(xhci->dma_mask_bits)); + } else { + /* + * This is to avoid error in cases where a 32-bit USB +diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h +index b43e88102200e5..b446fa9eb8370b 100644 +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1543,6 +1543,7 @@ struct xhci_hcd { + int event_ring_max; + /* 4KB min, 128MB max */ + int page_size; ++ unsigned int dma_mask_bits; + /* Valid values are 12 to 20, inclusive */ + int page_shift; + /* msi-x vectors */ +-- +2.53.0 + diff --git a/queue-6.1/x86-bugs-enable-ibpb-flush-on-bpf-jit-allocation.patch b/queue-6.1/x86-bugs-enable-ibpb-flush-on-bpf-jit-allocation.patch new file mode 100644 index 0000000000..c82101acce --- /dev/null +++ b/queue-6.1/x86-bugs-enable-ibpb-flush-on-bpf-jit-allocation.patch @@ -0,0 +1,147 @@ +From 3c9eafeacf227f43739921c90ffec27fab8aa585 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 15:55:56 -0700 +Subject: x86/bugs: Enable IBPB flush on BPF JIT allocation + +From: Pawan Gupta + +commit a3af84b0fa00ead01fcd0e28b5d773ff25990a0d upstream. + +Enable hardening against JIT spraying when Spectre-v2 mitigations are in +use. Specifically, issue an IBPB flush on BPF JIT memory reuse. Skip +enabling the IBPB flush if the BPF dispatcher is already using a retpoline +sequence. + +This hardening applies only when BPF-JIT is in use. Guard the enabling +under CONFIG_BPF_JIT so that bugs.c still builds with CONFIG_BPF_JIT=n. + + [ pawan: Use entry_ibpb() instead of write_ibpb(). JIT hardening enable + moved to spectre_v2_select_mitigation() because there is no + spectre_v2_apply_mitigation()] + +Signed-off-by: Pawan Gupta +Acked-by: Daniel Borkmann +Acked-by: Dave Hansen +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + arch/x86/include/asm/nospec-branch.h | 4 +++ + arch/x86/kernel/cpu/bugs.c | 50 +++++++++++++++++++++++++--- + 2 files changed, 49 insertions(+), 5 deletions(-) + +diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h +index 818a5913f21950..40842aabd21783 100644 +--- a/arch/x86/include/asm/nospec-branch.h ++++ b/arch/x86/include/asm/nospec-branch.h +@@ -280,6 +280,10 @@ extern void srso_alias_untrain_ret(void); + extern void entry_untrain_ret(void); + extern void entry_ibpb(void); + ++#ifdef CONFIG_BPF_JIT ++extern void bpf_arch_ibpb(void); ++#endif ++ + #ifdef CONFIG_X86_64 + extern void clear_bhb_loop(void); + #endif +diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c +index a0b362ac50a1b3..662d13612ef4b2 100644 +--- a/arch/x86/kernel/cpu/bugs.c ++++ b/arch/x86/kernel/cpu/bugs.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1298,8 +1299,21 @@ static inline const char *spectre_v2_module_string(void) + { + return spectre_v2_bad_module ? " - vulnerable module loaded" : ""; + } ++ ++/* ++ * The "retpoline sequence" is the "call;mov;ret" sequence that ++ * replaces normal indirect branch instructions. Differentiate ++ * *the* retpoline sequence from the LFENCE-prefixed indirect ++ * branches that simply use the retpoline infrastructure. ++ */ ++static inline bool retpoline_seq_enabled(void) ++{ ++ return boot_cpu_has(X86_FEATURE_RETPOLINE) && !boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE); ++} ++ + #else + static inline const char *spectre_v2_module_string(void) { return ""; } ++static inline bool retpoline_seq_enabled(void) { return false; } + #endif + + #define SPECTRE_V2_LFENCE_MSG "WARNING: LFENCE mitigation is not recommended for this CPU, data leaks possible!\n" +@@ -1780,8 +1794,7 @@ static void __init bhi_select_mitigation(void) + return; + + /* Retpoline mitigates against BHI unless the CPU has RRSBA behavior */ +- if (boot_cpu_has(X86_FEATURE_RETPOLINE) && +- !boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE)) { ++ if (retpoline_seq_enabled()) { + spec_ctrl_disable_kernel_rrsba(); + if (rrsba_disabled) + return; +@@ -1803,6 +1816,27 @@ static void __init bhi_select_mitigation(void) + pr_info("Spectre BHI mitigation: SW BHB clearing on syscall\n"); + } + ++#ifdef CONFIG_BPF_JIT ++static void __bpf_arch_ibpb(void *unused) ++{ ++ entry_ibpb(); ++} ++ ++void bpf_arch_ibpb(void) ++{ ++ on_each_cpu(__bpf_arch_ibpb, NULL, 1); ++} ++ ++static bool __init cpu_wants_ibpb_bpf(void) ++{ ++ /* A genuine retpoline already neutralizes ring0 indirect predictions */ ++ if (retpoline_seq_enabled()) ++ return false; ++ ++ return boot_cpu_has(X86_FEATURE_IBPB); ++} ++#endif ++ + static void __init spectre_v2_select_mitigation(void) + { + enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline(); +@@ -1985,6 +2019,14 @@ static void __init spectre_v2_select_mitigation(void) + pr_info("Enabling Restricted Speculation for firmware calls\n"); + } + ++#ifdef CONFIG_BPF_JIT ++ if (cpu_wants_ibpb_bpf()) { ++ static_call_update(bpf_arch_pred_flush, bpf_arch_ibpb); ++ static_branch_enable(&bpf_pred_flush_enabled); ++ pr_info("Enabling IBPB for BPF\n"); ++ } ++#endif ++ + /* Set up IBPB and STIBP depending on the general spectre V2 command */ + spectre_v2_cmd = cmd; + } +@@ -3157,9 +3199,7 @@ static const char *spectre_bhi_state(void) + return "; BHI: BHI_DIS_S"; + else if (boot_cpu_has(X86_FEATURE_CLEAR_BHB_LOOP)) + return "; BHI: SW loop, KVM: SW loop"; +- else if (boot_cpu_has(X86_FEATURE_RETPOLINE) && +- !boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE) && +- rrsba_disabled) ++ else if (retpoline_seq_enabled() && rrsba_disabled) + return "; BHI: Retpoline"; + else if (boot_cpu_has(X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT)) + return "; BHI: Vulnerable, KVM: SW loop"; +-- +2.53.0 + diff --git a/queue-6.12/risc-v-kvm-serialize-virtual-interrupt-pending-state.patch b/queue-6.12/risc-v-kvm-serialize-virtual-interrupt-pending-state.patch new file mode 100644 index 0000000000..e1ba09a069 --- /dev/null +++ b/queue-6.12/risc-v-kvm-serialize-virtual-interrupt-pending-state.patch @@ -0,0 +1,396 @@ +From 1c14dcdc3dac9189363a11f91d5e1891807b921d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 09:35:51 +0800 +Subject: RISC-V: KVM: Serialize virtual interrupt pending state updates + +From: Xie Bo + +commit d024a0a7879e6f37c0152aacf6d8e37b214a1738 upstream. + +KVM RISC-V tracks guest local interrupt state with two bitmaps: + + - irqs_pending: interrupts that should be visible to the guest + - irqs_pending_mask: interrupts whose pending state changed + +The current code updates those bitmaps with independent atomic bitops +and assumes a multiple-producer, single-consumer protocol. That model +does not actually hold. + +kvm_riscv_vcpu_sync_interrupts() is not a pure consumer. When the guest +changes guest-visible HVIP state, sync_interrupts() writes both +irqs_pending and irqs_pending_mask to reflect the new guest state back +into KVM state. As a result, irqs_pending and irqs_pending_mask form a +single logical state transition, but they are not updated atomically as +a pair. + +This allows a race where a newly injected interrupt is lost. For +example: + + CPU0 CPU1 + ---- ---- + kvm_riscv_vcpu_set_interrupt(VS_SOFT) + set_bit(VS_SOFT, irqs_pending) + kvm_riscv_vcpu_sync_interrupts() + sees guest-cleared HVIP.VSSIP + sets irqs_pending_mask + clear_bit(IRQ_VS_SOFT, irqs_pending) + set_bit(VS_SOFT, irqs_pending_mask) + kvm_vcpu_kick() + +After that interleaving, a later flush can update HVIP without VSSIP +even though a new virtual interrupt was injected. In practice, the +guest can remain blocked in WFI with work pending. + +The same pending/mask protocol is shared by VS soft interrupts, PMU +overflow delivery, and AIA high interrupt synchronization, so the race +is not limited to one interrupt source. + +Fix this by serializing all updates to irqs_pending and irqs_pending_mask +with a per-vCPU raw spinlock. This keeps the pending bit and the dirty +mask as one state transition across: + + - set/unset interrupt + - guest HVIP sync + - interrupt flush to guest CSR state + - vCPU reset + - AIA CSR writes that clear dirty state + +Use non-atomic bitmap operations while holding the lock. Hold the lock +across the AIA sync, flush, and pending checks as well, so both bitmap +words share the same serialization domain. + +This intentionally replaces the existing lockless protocol instead of +trying to repair it with additional barriers. The problem is not memory +ordering on a single field; it is that two separate bitmaps encode one +shared state machine while both producers and sync paths can modify +them. A per-vCPU raw spinlock keeps the fix small, local, and suitable +for backporting. + +Fixes: cce69aff689e ("RISC-V: KVM: Implement VCPU interrupts and requests handling") +Cc: stable@vger.kernel.org +Signed-off-by: Xie Bo +Reviewed-by: Anup Patel +Link: https://lore.kernel.org/r/20260715020359.1521354-2-xb@ultrarisc.com +Signed-off-by: Anup Patel + +[ bo: Adapt the reset and CSR helpers to their older signatures. ] + +Signed-off-by: Sasha Levin +--- + arch/riscv/include/asm/kvm_host.h | 10 ++--- + arch/riscv/kvm/aia.c | 34 +++++++++++---- + arch/riscv/kvm/vcpu.c | 69 ++++++++++++++++++++++--------- + arch/riscv/kvm/vcpu_onereg.c | 8 +++- + 4 files changed, 87 insertions(+), 34 deletions(-) + +diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h +index 2e2254fd2a2aae..7beef600abad7c 100644 +--- a/arch/riscv/include/asm/kvm_host.h ++++ b/arch/riscv/include/asm/kvm_host.h +@@ -232,13 +232,13 @@ struct kvm_vcpu_arch { + /* + * VCPU interrupts + * +- * We have a lockless approach for tracking pending VCPU interrupts +- * implemented using atomic bitops. The irqs_pending bitmap represent +- * pending interrupts whereas irqs_pending_mask represent bits changed +- * in irqs_pending. Our approach is modeled around multiple producer +- * and single consumer problem where the consumer is the VCPU itself. ++ * The irqs_pending bitmap represents pending interrupts whereas ++ * irqs_pending_mask represents bits changed in irqs_pending. Updates ++ * to these bitmaps are serialized so vcpu interrupt sync/flush cannot ++ * drop a newly injected interrupt while syncing guest-visible HVIP. + */ + #define KVM_RISCV_VCPU_NR_IRQS 64 ++ raw_spinlock_t irqs_pending_lock; + DECLARE_BITMAP(irqs_pending, KVM_RISCV_VCPU_NR_IRQS); + DECLARE_BITMAP(irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS); + +diff --git a/arch/riscv/kvm/aia.c b/arch/riscv/kvm/aia.c +index 9f3b527596ded8..01319d8d75b0a4 100644 +--- a/arch/riscv/kvm/aia.c ++++ b/arch/riscv/kvm/aia.c +@@ -71,12 +71,15 @@ void kvm_riscv_vcpu_aia_flush_interrupts(struct kvm_vcpu *vcpu) + struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr; + unsigned long mask, val; + ++ lockdep_assert_held(&vcpu->arch.irqs_pending_lock); ++ + if (!kvm_riscv_aia_available()) + return; + +- if (READ_ONCE(vcpu->arch.irqs_pending_mask[1])) { +- mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[1], 0); +- val = READ_ONCE(vcpu->arch.irqs_pending[1]) & mask; ++ mask = vcpu->arch.irqs_pending_mask[1]; ++ if (mask) { ++ vcpu->arch.irqs_pending_mask[1] = 0; ++ val = vcpu->arch.irqs_pending[1] & mask; + + csr->hviph &= ~mask; + csr->hviph |= val; +@@ -87,6 +90,8 @@ void kvm_riscv_vcpu_aia_sync_interrupts(struct kvm_vcpu *vcpu) + { + struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr; + ++ lockdep_assert_held(&vcpu->arch.irqs_pending_lock); ++ + if (kvm_riscv_aia_available()) + csr->vsieh = csr_read(CSR_VSIEH); + } +@@ -96,13 +101,21 @@ bool kvm_riscv_vcpu_aia_has_interrupts(struct kvm_vcpu *vcpu, u64 mask) + { + int hgei; + unsigned long seip; ++#ifdef CONFIG_32BIT ++ unsigned long flags; ++ bool pending; ++#endif + + if (!kvm_riscv_aia_available()) + return false; + + #ifdef CONFIG_32BIT +- if (READ_ONCE(vcpu->arch.irqs_pending[1]) & +- (vcpu->arch.aia_context.guest_csr.vsieh & upper_32_bits(mask))) ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ pending = vcpu->arch.irqs_pending[1] & ++ (vcpu->arch.aia_context.guest_csr.vsieh & ++ upper_32_bits(mask)); ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); ++ if (pending) + return true; + #endif + +@@ -190,6 +203,9 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu, + unsigned long val) + { + struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr; ++#ifdef CONFIG_32BIT ++ unsigned long flags; ++#endif + + if (reg_num >= sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long)) + return -ENOENT; +@@ -198,8 +214,12 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu, + ((unsigned long *)csr)[reg_num] = val; + + #ifdef CONFIG_32BIT +- if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph)) +- WRITE_ONCE(vcpu->arch.irqs_pending_mask[1], 0); ++ if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph)) { ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ vcpu->arch.irqs_pending_mask[1] = 0; ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, ++ flags); ++ } + #endif + } + +diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c +index da01c81bf41676..ad519c9c31d05a 100644 +--- a/arch/riscv/kvm/vcpu.c ++++ b/arch/riscv/kvm/vcpu.c +@@ -52,6 +52,7 @@ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu) + struct kvm_vcpu_csr *reset_csr = &vcpu->arch.guest_reset_csr; + struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; + struct kvm_cpu_context *reset_cntx = &vcpu->arch.guest_reset_context; ++ unsigned long flags; + bool loaded; + + /** +@@ -80,8 +81,10 @@ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu) + + kvm_riscv_vcpu_aia_reset(vcpu); + ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); + bitmap_zero(vcpu->arch.irqs_pending, KVM_RISCV_VCPU_NR_IRQS); + bitmap_zero(vcpu->arch.irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS); ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); + + kvm_riscv_vcpu_pmu_reset(vcpu); + +@@ -126,6 +129,8 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) + /* Setup VCPU hfence queue */ + spin_lock_init(&vcpu->arch.hfence_lock); + ++ raw_spin_lock_init(&vcpu->arch.irqs_pending_lock); ++ + /* Setup reset state of shadow SSTATUS and HSTATUS CSRs */ + spin_lock_init(&vcpu->arch.reset_cntx_lock); + +@@ -341,10 +346,14 @@ void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu) + { + struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; + unsigned long mask, val; ++ unsigned long flags; ++ ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); + +- if (READ_ONCE(vcpu->arch.irqs_pending_mask[0])) { +- mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[0], 0); +- val = READ_ONCE(vcpu->arch.irqs_pending[0]) & mask; ++ mask = vcpu->arch.irqs_pending_mask[0]; ++ if (mask) { ++ vcpu->arch.irqs_pending_mask[0] = 0; ++ val = vcpu->arch.irqs_pending[0] & mask; + + csr->hvip &= ~mask; + csr->hvip |= val; +@@ -352,11 +361,14 @@ void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu) + + /* Flush AIA high interrupts */ + kvm_riscv_vcpu_aia_flush_interrupts(vcpu); ++ ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); + } + + void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu) + { + unsigned long hvip; ++ unsigned long flags; + struct kvm_vcpu_arch *v = &vcpu->arch; + struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; + +@@ -365,34 +377,41 @@ void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu) + + /* Sync-up HVIP.VSSIP bit changes does by Guest */ + hvip = csr_read(CSR_HVIP); ++ ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ + if ((csr->hvip ^ hvip) & (1UL << IRQ_VS_SOFT)) { + if (hvip & (1UL << IRQ_VS_SOFT)) { +- if (!test_and_set_bit(IRQ_VS_SOFT, +- v->irqs_pending_mask)) +- set_bit(IRQ_VS_SOFT, v->irqs_pending); ++ if (!__test_and_set_bit(IRQ_VS_SOFT, ++ v->irqs_pending_mask)) ++ __set_bit(IRQ_VS_SOFT, v->irqs_pending); + } else { +- if (!test_and_set_bit(IRQ_VS_SOFT, +- v->irqs_pending_mask)) +- clear_bit(IRQ_VS_SOFT, v->irqs_pending); ++ if (!__test_and_set_bit(IRQ_VS_SOFT, ++ v->irqs_pending_mask)) ++ __clear_bit(IRQ_VS_SOFT, v->irqs_pending); + } + } + + /* Sync up the HVIP.LCOFIP bit changes (only clear) by the guest */ + if ((csr->hvip ^ hvip) & (1UL << IRQ_PMU_OVF)) { + if (!(hvip & (1UL << IRQ_PMU_OVF)) && +- !test_and_set_bit(IRQ_PMU_OVF, v->irqs_pending_mask)) +- clear_bit(IRQ_PMU_OVF, v->irqs_pending); ++ !__test_and_set_bit(IRQ_PMU_OVF, v->irqs_pending_mask)) ++ __clear_bit(IRQ_PMU_OVF, v->irqs_pending); + } + + /* Sync-up AIA high interrupts */ + kvm_riscv_vcpu_aia_sync_interrupts(vcpu); + ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); ++ + /* Sync-up timer CSRs */ + kvm_riscv_vcpu_timer_sync(vcpu); + } + + int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq) + { ++ unsigned long flags; ++ + /* + * We only allow VS-mode software, timer, and external + * interrupts when irq is one of the local interrupts +@@ -405,9 +424,10 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq) + irq != IRQ_PMU_OVF) + return -EINVAL; + +- set_bit(irq, vcpu->arch.irqs_pending); +- smp_mb__before_atomic(); +- set_bit(irq, vcpu->arch.irqs_pending_mask); ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ __set_bit(irq, vcpu->arch.irqs_pending); ++ __set_bit(irq, vcpu->arch.irqs_pending_mask); ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); + + kvm_vcpu_kick(vcpu); + +@@ -416,6 +436,8 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq) + + int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq) + { ++ unsigned long flags; ++ + /* + * We only allow VS-mode software, timer, counter overflow and external + * interrupts when irq is one of the local interrupts +@@ -428,26 +450,33 @@ int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq) + irq != IRQ_PMU_OVF) + return -EINVAL; + +- clear_bit(irq, vcpu->arch.irqs_pending); +- smp_mb__before_atomic(); +- set_bit(irq, vcpu->arch.irqs_pending_mask); ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ __clear_bit(irq, vcpu->arch.irqs_pending); ++ __set_bit(irq, vcpu->arch.irqs_pending_mask); ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); + + return 0; + } + + bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask) + { ++ unsigned long flags; + unsigned long ie; ++ bool ret; + ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); + ie = ((vcpu->arch.guest_csr.vsie & VSIP_VALID_MASK) + << VSIP_TO_HVIP_SHIFT) & (unsigned long)mask; + ie |= vcpu->arch.guest_csr.vsie & ~IRQ_LOCAL_MASK & + (unsigned long)mask; +- if (READ_ONCE(vcpu->arch.irqs_pending[0]) & ie) +- return true; ++ ret = vcpu->arch.irqs_pending[0] & ie; ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); + + /* Check AIA high interrupts */ +- return kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask); ++ if (!ret) ++ ret = kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask); ++ ++ return ret; + } + + void __kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu) +diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c +index b319c4c13c54ce..6223806fcbc2ba 100644 +--- a/arch/riscv/kvm/vcpu_onereg.c ++++ b/arch/riscv/kvm/vcpu_onereg.c +@@ -445,6 +445,7 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu, + unsigned long reg_val) + { + struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; ++ unsigned long flags; + + if (reg_num >= sizeof(struct kvm_riscv_csr) / sizeof(unsigned long)) + return -ENOENT; +@@ -456,8 +457,11 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu, + + ((unsigned long *)csr)[reg_num] = reg_val; + +- if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) +- WRITE_ONCE(vcpu->arch.irqs_pending_mask[0], 0); ++ if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) { ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ vcpu->arch.irqs_pending_mask[0] = 0; ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); ++ } + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.12/series b/queue-6.12/series index 353924a5cf..db6b2dc0e5 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -131,3 +131,5 @@ usb-serial-keyspan_pda-fix-data-loss-on-receive-throttling.patch usb-serial-option-add-tdtech-mt5710-cn.patch crypto-rsa-pkcs1pad-don-t-warn-on-an-empty-digest.patch revert-drm-amd-display-add-missing-kdoc-for-allm-par.patch +risc-v-kvm-serialize-virtual-interrupt-pending-state.patch +usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch diff --git a/queue-6.12/usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch b/queue-6.12/usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch new file mode 100644 index 0000000000..21e26d14f1 --- /dev/null +++ b/queue-6.12/usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch @@ -0,0 +1,98 @@ +From 586bac10775ce3582f0022f995ab2c717680f3e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 13:42:10 +0800 +Subject: usb: xhci-pci: Limit VIA VL805 DMA addressing to 36 bits + +From: Xincheng Zhang + +commit 1fc50f1ecde39feb4fccdaf4bc71aa6c0eb25c49 upstream. + +The VIA VL805/806 xHCI controller advertises AC64, but fails to handle +DMA addresses at or above 0x1000000000. On systems with large amounts of +RAM, this can cause USB device failures when the controller is given DMA +addresses beyond its usable address width. + +Do not use XHCI_NO_64BIT_SUPPORT for this controller. That quirk clears +the cached AC64 capability and limits DMA to 32 bits, causing unnecessary +bouncing for addresses between 4GiB and 64GiB and hiding the controller's +real AC64 capability from code that may need to distinguish register +access width from usable DMA address width. + +Track the usable DMA address width separately from the AC64 capability. +Initialize the generic xhci->dma_mask_bits field to 64 and let PCI quirks +reduce it for controllers with narrower DMA support. Set VIA VL805/806 to +36 bits so the DMA API only hands it addresses in the range it can handle +while keeping HCCPARAMS1.AC64 visible. + +Cc: stable@kernel.org +Signed-off-by: Xincheng Zhang +Link: https://patch.msgid.link/20260630-xhci-via-dma-fix-v3-1-690dcb8cf75a@ultrarisc.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/host/xhci-pci.c | 1 + + drivers/usb/host/xhci.c | 15 ++++++++++----- + drivers/usb/host/xhci.h | 1 + + 3 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c +index 5f60528453e917..bd33cf6769cf6d 100644 +--- a/drivers/usb/host/xhci-pci.c ++++ b/drivers/usb/host/xhci-pci.c +@@ -454,6 +454,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) + if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == PCI_DEVICE_ID_VIA_VL805) { + xhci->quirks |= XHCI_LPM_SUPPORT; + xhci->quirks |= XHCI_TRB_OVERFETCH; ++ xhci->dma_mask_bits = 36; + } + + if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && +diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c +index aae3f1d1f11950..a50e813dda13a0 100644 +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -5259,6 +5259,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) + if (xhci->hci_version > 0x100) + xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2); + ++ xhci->dma_mask_bits = 64; + /* xhci-plat or xhci-pci might have set max_interrupters already */ + if ((!xhci->max_interrupters) || + xhci->max_interrupters > HCS_MAX_INTRS(xhci->hcs_params1)) +@@ -5300,12 +5301,16 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) + if (xhci->quirks & XHCI_NO_64BIT_SUPPORT) + xhci->hcc_params &= ~BIT(0); + +- /* Set dma_mask and coherent_dma_mask to 64-bits, +- * if xHC supports 64-bit addressing */ ++ /* ++ * Set dma_mask and coherent_dma_mask to 64-bits if xHC supports ++ * 64-bit addressing, unless a controller-specific quirk callback ++ * limits the usable address width. ++ */ + if (HCC_64BIT_ADDR(xhci->hcc_params) && +- !dma_set_mask(dev, DMA_BIT_MASK(64))) { +- xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n"); +- dma_set_coherent_mask(dev, DMA_BIT_MASK(64)); ++ !dma_set_mask(dev, DMA_BIT_MASK(xhci->dma_mask_bits))) { ++ xhci_dbg(xhci, "Enabling %u-bit DMA addresses.\n", ++ xhci->dma_mask_bits); ++ dma_set_coherent_mask(dev, DMA_BIT_MASK(xhci->dma_mask_bits)); + } else { + /* + * This is to avoid error in cases where a 32-bit USB +diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h +index b4fa8e7e437639..1a3f2dfd5a711d 100644 +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1510,6 +1510,7 @@ struct xhci_hcd { + /* imod_interval in ns (I * 250ns) */ + u32 imod_interval; + u32 page_size; ++ unsigned int dma_mask_bits; + /* MSI-X/MSI vectors */ + int nvecs; + /* optional clocks */ +-- +2.53.0 + diff --git a/queue-6.18/selftests-bpf-adjust-verifier_map_ptr-for-the-map-s-.patch b/queue-6.18/selftests-bpf-adjust-verifier_map_ptr-for-the-map-s-.patch new file mode 100644 index 0000000000..975af01bc6 --- /dev/null +++ b/queue-6.18/selftests-bpf-adjust-verifier_map_ptr-for-the-map-s-.patch @@ -0,0 +1,62 @@ +From aaec921dfddf4dbd9b4ec078512330f90e44219e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 15:25:08 +0800 +Subject: selftests/bpf: Adjust verifier_map_ptr for the map's excl field + +From: KP Singh + +commit 38498c0ebacd54dbaac3513a548a13f1a8455c4e upstream. + +Adding the u32 excl field at offset 32 of struct bpf_map right after the +sha[SHA256_DIGEST_SIZE] hash shifts the ops pointer from offset 32 to 40. +Therefore, fix up the test case. + + # LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t verifier_map_ptr + [...] + #637/1 verifier_map_ptr/bpf_map_ptr: read with negative offset rejected:OK + #637/2 verifier_map_ptr/bpf_map_ptr: read with negative offset rejected @unpriv:OK + #637/3 verifier_map_ptr/bpf_map_ptr: write rejected:OK + #637/4 verifier_map_ptr/bpf_map_ptr: write rejected @unpriv:OK + #637/5 verifier_map_ptr/bpf_map_ptr: read non-existent field rejected:OK + #637/6 verifier_map_ptr/bpf_map_ptr: read non-existent field rejected @unpriv:OK + #637/7 verifier_map_ptr/bpf_map_ptr: read ops field accepted:OK + #637/8 verifier_map_ptr/bpf_map_ptr: read ops field accepted @unpriv:OK + [...] + Summary: 2/18 PASSED, 0 SKIPPED, 0 FAILED + +Signed-off-by: KP Singh +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260601150248.394863-7-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Shung-Hsi Yu +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/bpf/progs/verifier_map_ptr.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/tools/testing/selftests/bpf/progs/verifier_map_ptr.c b/tools/testing/selftests/bpf/progs/verifier_map_ptr.c +index e2767d27d8aaf8..d8e822d1a8bab6 100644 +--- a/tools/testing/selftests/bpf/progs/verifier_map_ptr.c ++++ b/tools/testing/selftests/bpf/progs/verifier_map_ptr.c +@@ -70,13 +70,15 @@ __naked void bpf_map_ptr_write_rejected(void) + : __clobber_all); + } + +-/* The first element of struct bpf_map is a SHA256 hash of 32 bytes, accessing +- * into this array is valid. The opts field is now at offset 33. ++/* ++ * struct bpf_map starts with the SHA256 hash sha[32] at offset 0 (a readable ++ * byte array), followed by the u32 excl field at offset 32. Reading a u32 at ++ * offset 33 runs past the end of excl and is rejected. + */ + SEC("socket") + __description("bpf_map_ptr: read non-existent field rejected") + __failure +-__msg("cannot access ptr member ops with moff 32 in struct bpf_map with off 33 size 4") ++__msg("access beyond the end of member excl (mend:36) in struct bpf_map with off 33 size 4") + __failure_unpriv + __msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN") + __flag(BPF_F_ANY_ALIGNMENT) +-- +2.53.0 + diff --git a/queue-6.18/selftests-bpf-keep-verifier_map_ptr-exercising-ops-p.patch b/queue-6.18/selftests-bpf-keep-verifier_map_ptr-exercising-ops-p.patch new file mode 100644 index 0000000000..589680497b --- /dev/null +++ b/queue-6.18/selftests-bpf-keep-verifier_map_ptr-exercising-ops-p.patch @@ -0,0 +1,107 @@ +From 49dc6cace7c840b60fe16b4b29d76b82d01ea7dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 15:25:09 +0800 +Subject: selftests/bpf: Keep verifier_map_ptr exercising ops pointer access + +From: Daniel Borkmann + +commit 082c412097716b93ff1365689fc4ddcd1ce8296f upstream. + +sashiko complained that 38498c0ebacd ("selftests/bpf: Adjust verifier_map_ptr +for the map's excl field") would slightly decrease the test coverage given +before the test was against the verifier rejecting the ops pointer. Recover +the old test with the right offsets and add the existing one as an additional +test case. + + # LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t verifier_map_ptr + [ 1.672932] bpf_testmod: module verification failed: signature and/or required key missing - tainting kernel + #637/1 verifier_map_ptr/bpf_map_ptr: read with negative offset rejected:OK + #637/2 verifier_map_ptr/bpf_map_ptr: read with negative offset rejected @unpriv:OK + #637/3 verifier_map_ptr/bpf_map_ptr: write rejected:OK + #637/4 verifier_map_ptr/bpf_map_ptr: write rejected @unpriv:OK + #637/5 verifier_map_ptr/bpf_map_ptr: read non-existent field rejected:OK + #637/6 verifier_map_ptr/bpf_map_ptr: read non-existent field rejected @unpriv:OK + #637/7 verifier_map_ptr/bpf_map_ptr: read beyond excl field rejected:OK + #637/8 verifier_map_ptr/bpf_map_ptr: read beyond excl field rejected @unpriv:OK + #637/9 verifier_map_ptr/bpf_map_ptr: read ops field accepted:OK + #637/10 verifier_map_ptr/bpf_map_ptr: read ops field accepted @unpriv:OK + #637/11 verifier_map_ptr/bpf_map_ptr: r = 0, map_ptr = map_ptr + r:OK + #637/12 verifier_map_ptr/bpf_map_ptr: r = 0, map_ptr = map_ptr + r @unpriv:OK + #637/13 verifier_map_ptr/bpf_map_ptr: r = 0, r = r + map_ptr:OK + #637/14 verifier_map_ptr/bpf_map_ptr: r = 0, r = r + map_ptr @unpriv:OK + #637 verifier_map_ptr:OK + [...] + Summary: 2/20 PASSED, 0 SKIPPED, 0 FAILED + +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260602133052.423725-4-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Shung-Hsi Yu +Signed-off-by: Sasha Levin +--- + .../selftests/bpf/progs/verifier_map_ptr.c | 34 ++++++++++++++++--- + 1 file changed, 30 insertions(+), 4 deletions(-) + +diff --git a/tools/testing/selftests/bpf/progs/verifier_map_ptr.c b/tools/testing/selftests/bpf/progs/verifier_map_ptr.c +index d8e822d1a8bab6..1661936598703c 100644 +--- a/tools/testing/selftests/bpf/progs/verifier_map_ptr.c ++++ b/tools/testing/selftests/bpf/progs/verifier_map_ptr.c +@@ -72,17 +72,43 @@ __naked void bpf_map_ptr_write_rejected(void) + + /* + * struct bpf_map starts with the SHA256 hash sha[32] at offset 0 (a readable +- * byte array), followed by the u32 excl field at offset 32. Reading a u32 at +- * offset 33 runs past the end of excl and is rejected. ++ * byte array), the u32 excl field at offset 32, and the ops pointer at offset ++ * 40. Reading a u32 at offset 41 reaches into the middle of the ops pointer, ++ * i.e. a partial pointer access, which is rejected. + */ + SEC("socket") + __description("bpf_map_ptr: read non-existent field rejected") + __failure +-__msg("access beyond the end of member excl (mend:36) in struct bpf_map with off 33 size 4") ++__msg("cannot access ptr member ops with moff 40 in struct bpf_map with off 41 size 4") + __failure_unpriv + __msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN") + __flag(BPF_F_ANY_ALIGNMENT) + __naked void read_non_existent_field_rejected(void) ++{ ++ asm volatile (" \ ++ r6 = 0; \ ++ r1 = %[map_array_48b] ll; \ ++ r6 = *(u32*)(r1 + 41); \ ++ r0 = 1; \ ++ exit; \ ++" : ++ : __imm_addr(map_array_48b) ++ : __clobber_all); ++} ++ ++/* ++ * The u32 excl field spans offsets 32..35 (mend 36). Reading a u32 at offset ++ * 33 starts inside excl but extends past its end, which the verifier rejects ++ * as an out-of-bounds scalar access. ++ */ ++SEC("socket") ++__description("bpf_map_ptr: read beyond excl field rejected") ++__failure ++__msg("access beyond the end of member excl (mend:36) in struct bpf_map with off 33 size 4") ++__failure_unpriv ++__msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN") ++__flag(BPF_F_ANY_ALIGNMENT) ++__naked void read_beyond_excl_field_rejected(void) + { + asm volatile (" \ + r6 = 0; \ +@@ -105,7 +131,7 @@ __naked void ptr_read_ops_field_accepted(void) + asm volatile (" \ + r6 = 0; \ + r1 = %[map_array_48b] ll; \ +- r6 = *(u64*)(r1 + 0); \ ++ r6 = *(u64*)(r1 + 40); \ + r0 = 1; \ + exit; \ + " : +-- +2.53.0 + diff --git a/queue-6.18/series b/queue-6.18/series index 6577cefe1a..4b83dd9083 100644 --- a/queue-6.18/series +++ b/queue-6.18/series @@ -166,3 +166,6 @@ usb-typec-ucsi-add-duplicate-detection-to-nvidia-registration-path.patch wifi-mwifiex-fix-freeze-for-60-seconds-caused-by-req.patch risc-v-kvm-serialize-virtual-interrupt-pending-state.patch revert-drm-amd-display-add-missing-kdoc-for-allm-par.patch +usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch +selftests-bpf-adjust-verifier_map_ptr-for-the-map-s-.patch +selftests-bpf-keep-verifier_map_ptr-exercising-ops-p.patch diff --git a/queue-6.18/usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch b/queue-6.18/usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch new file mode 100644 index 0000000000..e367d705c8 --- /dev/null +++ b/queue-6.18/usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch @@ -0,0 +1,98 @@ +From ef549d84c970722249b8f90d768fdf5f8376ef2a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 13:43:41 +0800 +Subject: usb: xhci-pci: Limit VIA VL805 DMA addressing to 36 bits + +From: Xincheng Zhang + +commit 1fc50f1ecde39feb4fccdaf4bc71aa6c0eb25c49 upstream. + +The VIA VL805/806 xHCI controller advertises AC64, but fails to handle +DMA addresses at or above 0x1000000000. On systems with large amounts of +RAM, this can cause USB device failures when the controller is given DMA +addresses beyond its usable address width. + +Do not use XHCI_NO_64BIT_SUPPORT for this controller. That quirk clears +the cached AC64 capability and limits DMA to 32 bits, causing unnecessary +bouncing for addresses between 4GiB and 64GiB and hiding the controller's +real AC64 capability from code that may need to distinguish register +access width from usable DMA address width. + +Track the usable DMA address width separately from the AC64 capability. +Initialize the generic xhci->dma_mask_bits field to 64 and let PCI quirks +reduce it for controllers with narrower DMA support. Set VIA VL805/806 to +36 bits so the DMA API only hands it addresses in the range it can handle +while keeping HCCPARAMS1.AC64 visible. + +Cc: stable@kernel.org +Signed-off-by: Xincheng Zhang +Link: https://patch.msgid.link/20260630-xhci-via-dma-fix-v3-1-690dcb8cf75a@ultrarisc.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/host/xhci-pci.c | 1 + + drivers/usb/host/xhci.c | 15 ++++++++++----- + drivers/usb/host/xhci.h | 1 + + 3 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c +index f67a4d9562046f..734f7e74158354 100644 +--- a/drivers/usb/host/xhci-pci.c ++++ b/drivers/usb/host/xhci-pci.c +@@ -448,6 +448,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) + if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == PCI_DEVICE_ID_VIA_VL805) { + xhci->quirks |= XHCI_LPM_SUPPORT; + xhci->quirks |= XHCI_TRB_OVERFETCH; ++ xhci->dma_mask_bits = 36; + } + + if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && +diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c +index a06758addbf823..23b104c2956c7c 100644 +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -5459,6 +5459,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) + if (xhci->hci_version > 0x100) + xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2); + ++ xhci->dma_mask_bits = 64; + /* xhci-plat or xhci-pci might have set max_interrupters already */ + if ((!xhci->max_interrupters) || + xhci->max_interrupters > HCS_MAX_INTRS(xhci->hcs_params1)) +@@ -5505,12 +5506,16 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) + if (xhci->quirks & XHCI_NO_64BIT_SUPPORT) + xhci->hcc_params &= ~BIT(0); + +- /* Set dma_mask and coherent_dma_mask to 64-bits, +- * if xHC supports 64-bit addressing */ ++ /* ++ * Set dma_mask and coherent_dma_mask to 64-bits if xHC supports ++ * 64-bit addressing, unless a controller-specific quirk callback ++ * limits the usable address width. ++ */ + if (HCC_64BIT_ADDR(xhci->hcc_params) && +- !dma_set_mask(dev, DMA_BIT_MASK(64))) { +- xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n"); +- dma_set_coherent_mask(dev, DMA_BIT_MASK(64)); ++ !dma_set_mask(dev, DMA_BIT_MASK(xhci->dma_mask_bits))) { ++ xhci_dbg(xhci, "Enabling %u-bit DMA addresses.\n", ++ xhci->dma_mask_bits); ++ dma_set_coherent_mask(dev, DMA_BIT_MASK(xhci->dma_mask_bits)); + } else { + /* + * This is to avoid error in cases where a 32-bit USB +diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h +index 58a51f09cceb8f..4cd4cb0e431d17 100644 +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1524,6 +1524,7 @@ struct xhci_hcd { + /* imod_interval in ns (I * 250ns) */ + u32 imod_interval; + u32 page_size; ++ unsigned int dma_mask_bits; + /* MSI-X/MSI vectors */ + int nvecs; + /* optional clocks */ +-- +2.53.0 + diff --git a/queue-6.6/risc-v-kvm-serialize-virtual-interrupt-pending-state.patch b/queue-6.6/risc-v-kvm-serialize-virtual-interrupt-pending-state.patch new file mode 100644 index 0000000000..98f8628f70 --- /dev/null +++ b/queue-6.6/risc-v-kvm-serialize-virtual-interrupt-pending-state.patch @@ -0,0 +1,386 @@ +From 1e5d7c82565e45d8fd6613921135040edc514141 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jul 2026 10:06:19 +0800 +Subject: RISC-V: KVM: Serialize virtual interrupt pending state updates + +From: Xie Bo + +commit d024a0a7879e6f37c0152aacf6d8e37b214a1738 upstream. + +KVM RISC-V tracks guest local interrupt state with two bitmaps: + + - irqs_pending: interrupts that should be visible to the guest + - irqs_pending_mask: interrupts whose pending state changed + +The current code updates those bitmaps with independent atomic bitops +and assumes a multiple-producer, single-consumer protocol. That model +does not actually hold. + +kvm_riscv_vcpu_sync_interrupts() is not a pure consumer. When the guest +changes guest-visible HVIP state, sync_interrupts() writes both +irqs_pending and irqs_pending_mask to reflect the new guest state back +into KVM state. As a result, irqs_pending and irqs_pending_mask form a +single logical state transition, but they are not updated atomically as +a pair. + +This allows a race where a newly injected interrupt is lost. For +example: + + CPU0 CPU1 + ---- ---- + kvm_riscv_vcpu_set_interrupt(VS_SOFT) + set_bit(VS_SOFT, irqs_pending) + kvm_riscv_vcpu_sync_interrupts() + sees guest-cleared HVIP.VSSIP + sets irqs_pending_mask + clear_bit(IRQ_VS_SOFT, irqs_pending) + set_bit(VS_SOFT, irqs_pending_mask) + kvm_vcpu_kick() + +After that interleaving, a later flush can update HVIP without VSSIP +even though a new virtual interrupt was injected. In practice, the +guest can remain blocked in WFI with work pending. + +The same pending/mask protocol is shared by VS soft interrupts, PMU +overflow delivery, and AIA high interrupt synchronization, so the race +is not limited to one interrupt source. + +Fix this by serializing all updates to irqs_pending and irqs_pending_mask +with a per-vCPU raw spinlock. This keeps the pending bit and the dirty +mask as one state transition across: + + - set/unset interrupt + - guest HVIP sync + - interrupt flush to guest CSR state + - vCPU reset + - AIA CSR writes that clear dirty state + +Use non-atomic bitmap operations while holding the lock. Hold the lock +across the AIA sync, flush, and pending checks as well, so both bitmap +words share the same serialization domain. + +This intentionally replaces the existing lockless protocol instead of +trying to repair it with additional barriers. The problem is not memory +ordering on a single field; it is that two separate bitmaps encode one +shared state machine while both producers and sync paths can modify +them. A per-vCPU raw spinlock keeps the fix small, local, and suitable +for backporting. + +Fixes: cce69aff689e ("RISC-V: KVM: Implement VCPU interrupts and requests handling") +Cc: stable@vger.kernel.org +Signed-off-by: Xie Bo +Reviewed-by: Anup Patel +Link: https://lore.kernel.org/r/20260715020359.1521354-2-xb@ultrarisc.com +Signed-off-by: Anup Patel +[ bo: Drop IRQ_PMU_OVF handling, which is not present in 6.6.y, and + adapt the reset and CSR helpers to their older signatures. ] +Signed-off-by: Sasha Levin +--- + arch/riscv/include/asm/kvm_host.h | 10 ++--- + arch/riscv/kvm/aia.c | 35 +++++++++++++---- + arch/riscv/kvm/vcpu.c | 64 ++++++++++++++++++++++--------- + arch/riscv/kvm/vcpu_onereg.c | 8 +++- + 4 files changed, 85 insertions(+), 32 deletions(-) + +diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h +index 459e61ad7d2b68..d2d7f9b4f7c043 100644 +--- a/arch/riscv/include/asm/kvm_host.h ++++ b/arch/riscv/include/asm/kvm_host.h +@@ -202,13 +202,13 @@ struct kvm_vcpu_arch { + /* + * VCPU interrupts + * +- * We have a lockless approach for tracking pending VCPU interrupts +- * implemented using atomic bitops. The irqs_pending bitmap represent +- * pending interrupts whereas irqs_pending_mask represent bits changed +- * in irqs_pending. Our approach is modeled around multiple producer +- * and single consumer problem where the consumer is the VCPU itself. ++ * The irqs_pending bitmap represents pending interrupts whereas ++ * irqs_pending_mask represents bits changed in irqs_pending. Updates ++ * to these bitmaps are serialized so vcpu interrupt sync/flush cannot ++ * drop a newly injected interrupt while syncing guest-visible HVIP. + */ + #define KVM_RISCV_VCPU_NR_IRQS 64 ++ raw_spinlock_t irqs_pending_lock; + DECLARE_BITMAP(irqs_pending, KVM_RISCV_VCPU_NR_IRQS); + DECLARE_BITMAP(irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS); + +diff --git a/arch/riscv/kvm/aia.c b/arch/riscv/kvm/aia.c +index 74bb27440527b3..be133090306455 100644 +--- a/arch/riscv/kvm/aia.c ++++ b/arch/riscv/kvm/aia.c +@@ -71,12 +71,15 @@ void kvm_riscv_vcpu_aia_flush_interrupts(struct kvm_vcpu *vcpu) + struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr; + unsigned long mask, val; + ++ lockdep_assert_held(&vcpu->arch.irqs_pending_lock); ++ + if (!kvm_riscv_aia_available()) + return; + +- if (READ_ONCE(vcpu->arch.irqs_pending_mask[1])) { +- mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[1], 0); +- val = READ_ONCE(vcpu->arch.irqs_pending[1]) & mask; ++ mask = vcpu->arch.irqs_pending_mask[1]; ++ if (mask) { ++ vcpu->arch.irqs_pending_mask[1] = 0; ++ val = vcpu->arch.irqs_pending[1] & mask; + + csr->hviph &= ~mask; + csr->hviph |= val; +@@ -87,6 +90,8 @@ void kvm_riscv_vcpu_aia_sync_interrupts(struct kvm_vcpu *vcpu) + { + struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr; + ++ lockdep_assert_held(&vcpu->arch.irqs_pending_lock); ++ + if (kvm_riscv_aia_available()) + csr->vsieh = csr_read(CSR_VSIEH); + } +@@ -96,13 +101,22 @@ bool kvm_riscv_vcpu_aia_has_interrupts(struct kvm_vcpu *vcpu, u64 mask) + { + int hgei; + unsigned long seip; ++#ifdef CONFIG_32BIT ++ unsigned long flags; ++ bool pending; ++#endif + + if (!kvm_riscv_aia_available()) + return false; + + #ifdef CONFIG_32BIT +- if (READ_ONCE(vcpu->arch.irqs_pending[1]) & +- (vcpu->arch.aia_context.guest_csr.vsieh & upper_32_bits(mask))) ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ pending = vcpu->arch.irqs_pending[1] & ++ (vcpu->arch.aia_context.guest_csr.vsieh & ++ upper_32_bits(mask)); ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); ++ ++ if (pending) + return true; + #endif + +@@ -190,6 +204,9 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu, + unsigned long val) + { + struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr; ++#ifdef CONFIG_32BIT ++ unsigned long flags; ++#endif + + if (reg_num >= sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long)) + return -ENOENT; +@@ -198,8 +215,12 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu, + ((unsigned long *)csr)[reg_num] = val; + + #ifdef CONFIG_32BIT +- if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph)) +- WRITE_ONCE(vcpu->arch.irqs_pending_mask[1], 0); ++ if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph)) { ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ vcpu->arch.irqs_pending_mask[1] = 0; ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, ++ flags); ++ } + #endif + } + +diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c +index 9584d62c96ee74..da769ecfdd1083 100644 +--- a/arch/riscv/kvm/vcpu.c ++++ b/arch/riscv/kvm/vcpu.c +@@ -44,6 +44,7 @@ const struct kvm_stats_header kvm_vcpu_stats_header = { + + static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu) + { ++ unsigned long flags; + struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; + struct kvm_vcpu_csr *reset_csr = &vcpu->arch.guest_reset_csr; + struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; +@@ -74,8 +75,10 @@ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu) + + kvm_riscv_vcpu_aia_reset(vcpu); + ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); + bitmap_zero(vcpu->arch.irqs_pending, KVM_RISCV_VCPU_NR_IRQS); + bitmap_zero(vcpu->arch.irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS); ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); + + kvm_riscv_vcpu_pmu_reset(vcpu); + +@@ -117,6 +120,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) + + /* Setup VCPU hfence queue */ + spin_lock_init(&vcpu->arch.hfence_lock); ++ raw_spin_lock_init(&vcpu->arch.irqs_pending_lock); + + /* Setup reset state of shadow SSTATUS and HSTATUS CSRs */ + cntx = &vcpu->arch.guest_reset_context; +@@ -323,10 +327,14 @@ void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu) + { + struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; + unsigned long mask, val; ++ unsigned long flags; + +- if (READ_ONCE(vcpu->arch.irqs_pending_mask[0])) { +- mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[0], 0); +- val = READ_ONCE(vcpu->arch.irqs_pending[0]) & mask; ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ ++ mask = vcpu->arch.irqs_pending_mask[0]; ++ if (mask) { ++ vcpu->arch.irqs_pending_mask[0] = 0; ++ val = vcpu->arch.irqs_pending[0] & mask; + + csr->hvip &= ~mask; + csr->hvip |= val; +@@ -334,11 +342,14 @@ void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu) + + /* Flush AIA high interrupts */ + kvm_riscv_vcpu_aia_flush_interrupts(vcpu); ++ ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); + } + + void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu) + { + unsigned long hvip; ++ unsigned long flags; + struct kvm_vcpu_arch *v = &vcpu->arch; + struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; + +@@ -347,27 +358,34 @@ void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu) + + /* Sync-up HVIP.VSSIP bit changes does by Guest */ + hvip = csr_read(CSR_HVIP); ++ ++ raw_spin_lock_irqsave(&v->irqs_pending_lock, flags); ++ + if ((csr->hvip ^ hvip) & (1UL << IRQ_VS_SOFT)) { + if (hvip & (1UL << IRQ_VS_SOFT)) { +- if (!test_and_set_bit(IRQ_VS_SOFT, +- v->irqs_pending_mask)) +- set_bit(IRQ_VS_SOFT, v->irqs_pending); ++ if (!__test_and_set_bit(IRQ_VS_SOFT, ++ v->irqs_pending_mask)) ++ __set_bit(IRQ_VS_SOFT, v->irqs_pending); + } else { +- if (!test_and_set_bit(IRQ_VS_SOFT, +- v->irqs_pending_mask)) +- clear_bit(IRQ_VS_SOFT, v->irqs_pending); ++ if (!__test_and_set_bit(IRQ_VS_SOFT, ++ v->irqs_pending_mask)) ++ __clear_bit(IRQ_VS_SOFT, v->irqs_pending); + } + } + + /* Sync-up AIA high interrupts */ + kvm_riscv_vcpu_aia_sync_interrupts(vcpu); + ++ raw_spin_unlock_irqrestore(&v->irqs_pending_lock, flags); ++ + /* Sync-up timer CSRs */ + kvm_riscv_vcpu_timer_sync(vcpu); + } + + int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq) + { ++ unsigned long flags; ++ + /* + * We only allow VS-mode software, timer, and external + * interrupts when irq is one of the local interrupts +@@ -379,9 +397,10 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq) + irq != IRQ_VS_EXT) + return -EINVAL; + +- set_bit(irq, vcpu->arch.irqs_pending); +- smp_mb__before_atomic(); +- set_bit(irq, vcpu->arch.irqs_pending_mask); ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ __set_bit(irq, vcpu->arch.irqs_pending); ++ __set_bit(irq, vcpu->arch.irqs_pending_mask); ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); + + kvm_vcpu_kick(vcpu); + +@@ -390,6 +409,8 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq) + + int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq) + { ++ unsigned long flags; ++ + /* + * We only allow VS-mode software, timer, and external + * interrupts when irq is one of the local interrupts +@@ -401,26 +422,33 @@ int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq) + irq != IRQ_VS_EXT) + return -EINVAL; + +- clear_bit(irq, vcpu->arch.irqs_pending); +- smp_mb__before_atomic(); +- set_bit(irq, vcpu->arch.irqs_pending_mask); ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ __clear_bit(irq, vcpu->arch.irqs_pending); ++ __set_bit(irq, vcpu->arch.irqs_pending_mask); ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); + + return 0; + } + + bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask) + { ++ unsigned long flags; + unsigned long ie; ++ bool ret; + ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); + ie = ((vcpu->arch.guest_csr.vsie & VSIP_VALID_MASK) + << VSIP_TO_HVIP_SHIFT) & (unsigned long)mask; + ie |= vcpu->arch.guest_csr.vsie & ~IRQ_LOCAL_MASK & + (unsigned long)mask; +- if (READ_ONCE(vcpu->arch.irqs_pending[0]) & ie) +- return true; ++ ret = vcpu->arch.irqs_pending[0] & ie; ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); + + /* Check AIA high interrupts */ +- return kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask); ++ if (!ret) ++ ret = kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask); ++ ++ return ret; + } + + void __kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu) +diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c +index d520b25d856167..0e5853186365e2 100644 +--- a/arch/riscv/kvm/vcpu_onereg.c ++++ b/arch/riscv/kvm/vcpu_onereg.c +@@ -361,6 +361,7 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu, + unsigned long reg_val) + { + struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; ++ unsigned long flags; + + if (reg_num >= sizeof(struct kvm_riscv_csr) / sizeof(unsigned long)) + return -ENOENT; +@@ -372,8 +373,11 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu, + + ((unsigned long *)csr)[reg_num] = reg_val; + +- if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) +- WRITE_ONCE(vcpu->arch.irqs_pending_mask[0], 0); ++ if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) { ++ raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags); ++ vcpu->arch.irqs_pending_mask[0] = 0; ++ raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags); ++ } + + return 0; + } +-- +2.53.0 + diff --git a/queue-6.6/series b/queue-6.6/series index 39f8e62246..e9d9d6b586 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -112,3 +112,5 @@ usb-serial-option-add-tdtech-mt5710-cn.patch posix-cpu-timers-prevent-uaf-caused-by-non-leader-ex.patch crypto-rsa-pkcs1pad-don-t-warn-on-an-empty-digest.patch revert-drm-amd-display-add-missing-kdoc-for-allm-par.patch +risc-v-kvm-serialize-virtual-interrupt-pending-state.patch +usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch diff --git a/queue-6.6/usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch b/queue-6.6/usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch new file mode 100644 index 0000000000..3dd9fa767b --- /dev/null +++ b/queue-6.6/usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch @@ -0,0 +1,98 @@ +From e60692a6513e848eb3fa0456ff17e22702785c0a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 13:41:00 +0800 +Subject: usb: xhci-pci: Limit VIA VL805 DMA addressing to 36 bits + +From: Xincheng Zhang + +commit 1fc50f1ecde39feb4fccdaf4bc71aa6c0eb25c49 upstream. + +The VIA VL805/806 xHCI controller advertises AC64, but fails to handle +DMA addresses at or above 0x1000000000. On systems with large amounts of +RAM, this can cause USB device failures when the controller is given DMA +addresses beyond its usable address width. + +Do not use XHCI_NO_64BIT_SUPPORT for this controller. That quirk clears +the cached AC64 capability and limits DMA to 32 bits, causing unnecessary +bouncing for addresses between 4GiB and 64GiB and hiding the controller's +real AC64 capability from code that may need to distinguish register +access width from usable DMA address width. + +Track the usable DMA address width separately from the AC64 capability. +Initialize the generic xhci->dma_mask_bits field to 64 and let PCI quirks +reduce it for controllers with narrower DMA support. Set VIA VL805/806 to +36 bits so the DMA API only hands it addresses in the range it can handle +while keeping HCCPARAMS1.AC64 visible. + +Cc: stable@kernel.org +Signed-off-by: Xincheng Zhang +Link: https://patch.msgid.link/20260630-xhci-via-dma-fix-v3-1-690dcb8cf75a@ultrarisc.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/host/xhci-pci.c | 1 + + drivers/usb/host/xhci.c | 15 ++++++++++----- + drivers/usb/host/xhci.h | 1 + + 3 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c +index 5abc48f148dcbc..d5ba5a34625bef 100644 +--- a/drivers/usb/host/xhci-pci.c ++++ b/drivers/usb/host/xhci-pci.c +@@ -510,6 +510,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) + if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == PCI_DEVICE_ID_VIA_VL805) { + xhci->quirks |= XHCI_LPM_SUPPORT; + xhci->quirks |= XHCI_TRB_OVERFETCH; ++ xhci->dma_mask_bits = 36; + } + + if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && +diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c +index 31509845594e9f..210b5727d1a632 100644 +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -5267,6 +5267,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) + if (xhci->hci_version > 0x100) + xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2); + ++ xhci->dma_mask_bits = 64; + /* xhci-plat or xhci-pci might have set max_interrupters already */ + if ((!xhci->max_interrupters) || + xhci->max_interrupters > HCS_MAX_INTRS(xhci->hcs_params1)) +@@ -5308,12 +5309,16 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) + if (xhci->quirks & XHCI_NO_64BIT_SUPPORT) + xhci->hcc_params &= ~BIT(0); + +- /* Set dma_mask and coherent_dma_mask to 64-bits, +- * if xHC supports 64-bit addressing */ ++ /* ++ * Set dma_mask and coherent_dma_mask to 64-bits if xHC supports ++ * 64-bit addressing, unless a controller-specific quirk callback ++ * limits the usable address width. ++ */ + if (HCC_64BIT_ADDR(xhci->hcc_params) && +- !dma_set_mask(dev, DMA_BIT_MASK(64))) { +- xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n"); +- dma_set_coherent_mask(dev, DMA_BIT_MASK(64)); ++ !dma_set_mask(dev, DMA_BIT_MASK(xhci->dma_mask_bits))) { ++ xhci_dbg(xhci, "Enabling %u-bit DMA addresses.\n", ++ xhci->dma_mask_bits); ++ dma_set_coherent_mask(dev, DMA_BIT_MASK(xhci->dma_mask_bits)); + } else { + /* + * This is to avoid error in cases where a 32-bit USB +diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h +index 849a83e4013cca..bb7e73df297abc 100644 +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1538,6 +1538,7 @@ struct xhci_hcd { + int event_ring_max; + /* 4KB min, 128MB max */ + int page_size; ++ unsigned int dma_mask_bits; + /* Valid values are 12 to 20, inclusive */ + int page_shift; + /* msi-x vectors */ +-- +2.53.0 + diff --git a/queue-7.1/selftests-bpf-adjust-verifier_map_ptr-for-the-map-s-.patch b/queue-7.1/selftests-bpf-adjust-verifier_map_ptr-for-the-map-s-.patch new file mode 100644 index 0000000000..ee89b0f685 --- /dev/null +++ b/queue-7.1/selftests-bpf-adjust-verifier_map_ptr-for-the-map-s-.patch @@ -0,0 +1,62 @@ +From 4d619b836061cd599df1425eb32e052bbb841260 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 15:25:08 +0800 +Subject: selftests/bpf: Adjust verifier_map_ptr for the map's excl field + +From: KP Singh + +commit 38498c0ebacd54dbaac3513a548a13f1a8455c4e upstream. + +Adding the u32 excl field at offset 32 of struct bpf_map right after the +sha[SHA256_DIGEST_SIZE] hash shifts the ops pointer from offset 32 to 40. +Therefore, fix up the test case. + + # LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t verifier_map_ptr + [...] + #637/1 verifier_map_ptr/bpf_map_ptr: read with negative offset rejected:OK + #637/2 verifier_map_ptr/bpf_map_ptr: read with negative offset rejected @unpriv:OK + #637/3 verifier_map_ptr/bpf_map_ptr: write rejected:OK + #637/4 verifier_map_ptr/bpf_map_ptr: write rejected @unpriv:OK + #637/5 verifier_map_ptr/bpf_map_ptr: read non-existent field rejected:OK + #637/6 verifier_map_ptr/bpf_map_ptr: read non-existent field rejected @unpriv:OK + #637/7 verifier_map_ptr/bpf_map_ptr: read ops field accepted:OK + #637/8 verifier_map_ptr/bpf_map_ptr: read ops field accepted @unpriv:OK + [...] + Summary: 2/18 PASSED, 0 SKIPPED, 0 FAILED + +Signed-off-by: KP Singh +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260601150248.394863-7-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Shung-Hsi Yu +Signed-off-by: Sasha Levin +--- + tools/testing/selftests/bpf/progs/verifier_map_ptr.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/tools/testing/selftests/bpf/progs/verifier_map_ptr.c b/tools/testing/selftests/bpf/progs/verifier_map_ptr.c +index e2767d27d8aaf8..d8e822d1a8bab6 100644 +--- a/tools/testing/selftests/bpf/progs/verifier_map_ptr.c ++++ b/tools/testing/selftests/bpf/progs/verifier_map_ptr.c +@@ -70,13 +70,15 @@ __naked void bpf_map_ptr_write_rejected(void) + : __clobber_all); + } + +-/* The first element of struct bpf_map is a SHA256 hash of 32 bytes, accessing +- * into this array is valid. The opts field is now at offset 33. ++/* ++ * struct bpf_map starts with the SHA256 hash sha[32] at offset 0 (a readable ++ * byte array), followed by the u32 excl field at offset 32. Reading a u32 at ++ * offset 33 runs past the end of excl and is rejected. + */ + SEC("socket") + __description("bpf_map_ptr: read non-existent field rejected") + __failure +-__msg("cannot access ptr member ops with moff 32 in struct bpf_map with off 33 size 4") ++__msg("access beyond the end of member excl (mend:36) in struct bpf_map with off 33 size 4") + __failure_unpriv + __msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN") + __flag(BPF_F_ANY_ALIGNMENT) +-- +2.53.0 + diff --git a/queue-7.1/selftests-bpf-keep-verifier_map_ptr-exercising-ops-p.patch b/queue-7.1/selftests-bpf-keep-verifier_map_ptr-exercising-ops-p.patch new file mode 100644 index 0000000000..697cf23212 --- /dev/null +++ b/queue-7.1/selftests-bpf-keep-verifier_map_ptr-exercising-ops-p.patch @@ -0,0 +1,107 @@ +From 60d662120c20ca34fd253b72d836e781f29ff287 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 15:25:09 +0800 +Subject: selftests/bpf: Keep verifier_map_ptr exercising ops pointer access + +From: Daniel Borkmann + +commit 082c412097716b93ff1365689fc4ddcd1ce8296f upstream. + +sashiko complained that 38498c0ebacd ("selftests/bpf: Adjust verifier_map_ptr +for the map's excl field") would slightly decrease the test coverage given +before the test was against the verifier rejecting the ops pointer. Recover +the old test with the right offsets and add the existing one as an additional +test case. + + # LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t verifier_map_ptr + [ 1.672932] bpf_testmod: module verification failed: signature and/or required key missing - tainting kernel + #637/1 verifier_map_ptr/bpf_map_ptr: read with negative offset rejected:OK + #637/2 verifier_map_ptr/bpf_map_ptr: read with negative offset rejected @unpriv:OK + #637/3 verifier_map_ptr/bpf_map_ptr: write rejected:OK + #637/4 verifier_map_ptr/bpf_map_ptr: write rejected @unpriv:OK + #637/5 verifier_map_ptr/bpf_map_ptr: read non-existent field rejected:OK + #637/6 verifier_map_ptr/bpf_map_ptr: read non-existent field rejected @unpriv:OK + #637/7 verifier_map_ptr/bpf_map_ptr: read beyond excl field rejected:OK + #637/8 verifier_map_ptr/bpf_map_ptr: read beyond excl field rejected @unpriv:OK + #637/9 verifier_map_ptr/bpf_map_ptr: read ops field accepted:OK + #637/10 verifier_map_ptr/bpf_map_ptr: read ops field accepted @unpriv:OK + #637/11 verifier_map_ptr/bpf_map_ptr: r = 0, map_ptr = map_ptr + r:OK + #637/12 verifier_map_ptr/bpf_map_ptr: r = 0, map_ptr = map_ptr + r @unpriv:OK + #637/13 verifier_map_ptr/bpf_map_ptr: r = 0, r = r + map_ptr:OK + #637/14 verifier_map_ptr/bpf_map_ptr: r = 0, r = r + map_ptr @unpriv:OK + #637 verifier_map_ptr:OK + [...] + Summary: 2/20 PASSED, 0 SKIPPED, 0 FAILED + +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/r/20260602133052.423725-4-daniel@iogearbox.net +Signed-off-by: Alexei Starovoitov +Signed-off-by: Shung-Hsi Yu +Signed-off-by: Sasha Levin +--- + .../selftests/bpf/progs/verifier_map_ptr.c | 34 ++++++++++++++++--- + 1 file changed, 30 insertions(+), 4 deletions(-) + +diff --git a/tools/testing/selftests/bpf/progs/verifier_map_ptr.c b/tools/testing/selftests/bpf/progs/verifier_map_ptr.c +index d8e822d1a8bab6..1661936598703c 100644 +--- a/tools/testing/selftests/bpf/progs/verifier_map_ptr.c ++++ b/tools/testing/selftests/bpf/progs/verifier_map_ptr.c +@@ -72,17 +72,43 @@ __naked void bpf_map_ptr_write_rejected(void) + + /* + * struct bpf_map starts with the SHA256 hash sha[32] at offset 0 (a readable +- * byte array), followed by the u32 excl field at offset 32. Reading a u32 at +- * offset 33 runs past the end of excl and is rejected. ++ * byte array), the u32 excl field at offset 32, and the ops pointer at offset ++ * 40. Reading a u32 at offset 41 reaches into the middle of the ops pointer, ++ * i.e. a partial pointer access, which is rejected. + */ + SEC("socket") + __description("bpf_map_ptr: read non-existent field rejected") + __failure +-__msg("access beyond the end of member excl (mend:36) in struct bpf_map with off 33 size 4") ++__msg("cannot access ptr member ops with moff 40 in struct bpf_map with off 41 size 4") + __failure_unpriv + __msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN") + __flag(BPF_F_ANY_ALIGNMENT) + __naked void read_non_existent_field_rejected(void) ++{ ++ asm volatile (" \ ++ r6 = 0; \ ++ r1 = %[map_array_48b] ll; \ ++ r6 = *(u32*)(r1 + 41); \ ++ r0 = 1; \ ++ exit; \ ++" : ++ : __imm_addr(map_array_48b) ++ : __clobber_all); ++} ++ ++/* ++ * The u32 excl field spans offsets 32..35 (mend 36). Reading a u32 at offset ++ * 33 starts inside excl but extends past its end, which the verifier rejects ++ * as an out-of-bounds scalar access. ++ */ ++SEC("socket") ++__description("bpf_map_ptr: read beyond excl field rejected") ++__failure ++__msg("access beyond the end of member excl (mend:36) in struct bpf_map with off 33 size 4") ++__failure_unpriv ++__msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN") ++__flag(BPF_F_ANY_ALIGNMENT) ++__naked void read_beyond_excl_field_rejected(void) + { + asm volatile (" \ + r6 = 0; \ +@@ -105,7 +131,7 @@ __naked void ptr_read_ops_field_accepted(void) + asm volatile (" \ + r6 = 0; \ + r1 = %[map_array_48b] ll; \ +- r6 = *(u64*)(r1 + 0); \ ++ r6 = *(u64*)(r1 + 40); \ + r0 = 1; \ + exit; \ + " : +-- +2.53.0 + diff --git a/queue-7.1/series b/queue-7.1/series index ab5db8cdbe..bca54f6338 100644 --- a/queue-7.1/series +++ b/queue-7.1/series @@ -162,3 +162,6 @@ drm-amd-display-add-dp_skip_rbr-flag-for-nutmeg.patch wifi-mwifiex-fix-freeze-for-60-seconds-caused-by-req.patch risc-v-kvm-serialize-virtual-interrupt-pending-state.patch revert-drm-amd-display-add-missing-kdoc-for-allm-par.patch +usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch +selftests-bpf-adjust-verifier_map_ptr-for-the-map-s-.patch +selftests-bpf-keep-verifier_map_ptr-exercising-ops-p.patch diff --git a/queue-7.1/usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch b/queue-7.1/usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch new file mode 100644 index 0000000000..479c7d465a --- /dev/null +++ b/queue-7.1/usb-xhci-pci-limit-via-vl805-dma-addressing-to-36-bi.patch @@ -0,0 +1,98 @@ +From 6bfa2043f130d971f495789fce705e684c9e004f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jul 2026 13:46:07 +0800 +Subject: usb: xhci-pci: Limit VIA VL805 DMA addressing to 36 bits + +From: Xincheng Zhang + +commit 1fc50f1ecde39feb4fccdaf4bc71aa6c0eb25c49 upstream. + +The VIA VL805/806 xHCI controller advertises AC64, but fails to handle +DMA addresses at or above 0x1000000000. On systems with large amounts of +RAM, this can cause USB device failures when the controller is given DMA +addresses beyond its usable address width. + +Do not use XHCI_NO_64BIT_SUPPORT for this controller. That quirk clears +the cached AC64 capability and limits DMA to 32 bits, causing unnecessary +bouncing for addresses between 4GiB and 64GiB and hiding the controller's +real AC64 capability from code that may need to distinguish register +access width from usable DMA address width. + +Track the usable DMA address width separately from the AC64 capability. +Initialize the generic xhci->dma_mask_bits field to 64 and let PCI quirks +reduce it for controllers with narrower DMA support. Set VIA VL805/806 to +36 bits so the DMA API only hands it addresses in the range it can handle +while keeping HCCPARAMS1.AC64 visible. + +Cc: stable@kernel.org +Signed-off-by: Xincheng Zhang +Link: https://patch.msgid.link/20260630-xhci-via-dma-fix-v3-1-690dcb8cf75a@ultrarisc.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/host/xhci-pci.c | 1 + + drivers/usb/host/xhci.c | 15 ++++++++++----- + drivers/usb/host/xhci.h | 1 + + 3 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c +index 585b2f3117b08a..b0377701a94042 100644 +--- a/drivers/usb/host/xhci-pci.c ++++ b/drivers/usb/host/xhci-pci.c +@@ -448,6 +448,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) + if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == PCI_DEVICE_ID_VIA_VL805) { + xhci->quirks |= XHCI_LPM_SUPPORT; + xhci->quirks |= XHCI_TRB_OVERFETCH; ++ xhci->dma_mask_bits = 36; + } + + if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && +diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c +index 15346fdd66bc43..5b15eae233d3f6 100644 +--- a/drivers/usb/host/xhci.c ++++ b/drivers/usb/host/xhci.c +@@ -5469,6 +5469,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) + if (xhci->hci_version > 0x100) + xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2); + ++ xhci->dma_mask_bits = 64; + xhci->max_slots = HCS_MAX_SLOTS(hcs_params1); + xhci->max_ports = min(HCS_MAX_PORTS(hcs_params1), MAX_HC_PORTS); + /* xhci-plat or xhci-pci might have set max_interrupters already */ +@@ -5518,12 +5519,16 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) + if (xhci->quirks & XHCI_NO_64BIT_SUPPORT) + xhci->hcc_params &= ~BIT(0); + +- /* Set dma_mask and coherent_dma_mask to 64-bits, +- * if xHC supports 64-bit addressing */ ++ /* ++ * Set dma_mask and coherent_dma_mask to 64-bits if xHC supports ++ * 64-bit addressing, unless a controller-specific quirk callback ++ * limits the usable address width. ++ */ + if ((xhci->hcc_params & HCC_64BIT_ADDR) && +- !dma_set_mask(dev, DMA_BIT_MASK(64))) { +- xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n"); +- dma_set_coherent_mask(dev, DMA_BIT_MASK(64)); ++ !dma_set_mask(dev, DMA_BIT_MASK(xhci->dma_mask_bits))) { ++ xhci_dbg(xhci, "Enabling %u-bit DMA addresses.\n", ++ xhci->dma_mask_bits); ++ dma_set_coherent_mask(dev, DMA_BIT_MASK(xhci->dma_mask_bits)); + } else { + /* + * This is to avoid error in cases where a 32-bit USB +diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h +index aeecd301f20707..d0f14fc2324572 100644 +--- a/drivers/usb/host/xhci.h ++++ b/drivers/usb/host/xhci.h +@@ -1524,6 +1524,7 @@ struct xhci_hcd { + /* imod_interval in ns (I * 250ns) */ + u32 imod_interval; + u32 page_size; ++ unsigned int dma_mask_bits; + /* MSI-X/MSI vectors */ + int nvecs; + /* optional clocks */ +-- +2.53.0 +