mailweb.openeuler.org
Manage this list

Keyboard Shortcuts

Thread View

  • j: Next unread message
  • k: Previous unread message
  • j a: Jump to all threads
  • j l: Jump to MailingList overview

Kernel

Threads by month
  • ----- 2026 -----
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2025 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2024 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2023 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2022 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2021 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2020 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2019 -----
  • December
kernel@openeuler.org

  • 24 participants
  • 24639 discussions
[PATCH OLK-6.6] KVM: arm64: vgic-v3: Restrict ICH_AP1Rn_EL2 accesses to 64-bit only with vNMI
by Jinqian Yang 01 Sep '26

01 Sep '26
ICH_AP1Rn_EL2 is 64-bit only when vNMI is in use, with the NMI priority in ICH_AP1R0_EL2[63:32]; otherwise the upper bits are RES0. Gate the save/restore access width on vgic_v3_vcpu_has_vnmi() which checks both vgic.has_nmi and ID_AA64PFR1_EL1.NMI, so that the NMI priority is preserved across context switch only when vNMI is actually enabled for the guest. Also drop the early assignment of kvm->arch.pfr1_nmi in kvm_arch_init_vm(). Without it vNMI is no longer enabled by default at VM creation on hosts with FEAT_NMI; instead the VMM must explicitly set ID_AA64PFR1_EL1.NMI via SET_ONE_REG to enable vNMI for the guest. Signed-off-by: Jinqian Yang <yangjinqian1(a)huawei.com> --- arch/arm64/include/asm/kvm_hyp.h | 1 + arch/arm64/kvm/arm.c | 3 -- arch/arm64/kvm/hyp/vgic-v3-sr.c | 55 +++++++++++++++++++++++++++----- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h index 127ad280e68b..c4121bf0aadc 100644 --- a/arch/arm64/include/asm/kvm_hyp.h +++ b/arch/arm64/include/asm/kvm_hyp.h @@ -82,6 +82,7 @@ void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if); void __vgic_v3_deactivate_traps(struct vgic_v3_cpu_if *cpu_if); void __vgic_v3_save_aprs(struct vgic_v3_cpu_if *cpu_if); void __vgic_v3_restore_aprs(struct vgic_v3_cpu_if *cpu_if); +bool vgic_v3_vcpu_has_vnmi(struct kvm_vcpu *vcpu); int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu); #ifdef __KVM_NVHE_HYPERVISOR__ diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 2b560eba3e0b..9a4be08730da 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -381,9 +381,6 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) /* The maximum number of VCPUs is limited by the host's GIC model */ kvm->max_vcpus = kvm_arm_default_max_vcpus(); - if (cpus_have_const_cap(ARM64_HAS_NMI) && !static_branch_unlikely(&vgic_v3_cpuif_trap)) - kvm->arch.pfr1_nmi = ID_AA64PFR1_EL1_NMI_IMP; - kvm_arm_init_hypercalls(kvm); if (!kvm_is_realm(kvm)) diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c index 7a9e132f68db..ab406332762e 100644 --- a/arch/arm64/kvm/hyp/vgic-v3-sr.c +++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c @@ -335,10 +335,40 @@ void __vgic_v3_deactivate_traps(struct vgic_v3_cpu_if *cpu_if) write_gicreg(0, ICH_HCR_EL2); } +static struct kvm_vcpu *vgic_v3_cpu_if_to_vcpu(struct vgic_v3_cpu_if *cpu_if) +{ + struct vgic_cpu *vgic_cpu = container_of(cpu_if, struct vgic_cpu, vgic_v3); + + return container_of(vgic_cpu, struct kvm_vcpu, arch.vgic_cpu); +} + +/* + * vNMI is only usable if the guest has selected NMI support + * (vgic.has_nmi) and the vcpu has FEAT_NMI (pfr1_nmi). + * + * This drives the width of the ICH_AP1Rn_EL2 accesses: with vNMI the + * registers are 64bit (the NMI priority lives in ICH_AP1R0_EL2[63]), + * without it only the low 32 bits are valid. + */ +bool vgic_v3_vcpu_has_vnmi(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm = kern_hyp_va(vcpu->kvm); + + return kvm->arch.vgic.has_nmi && + kvm->arch.pfr1_nmi == ID_AA64PFR1_EL1_NMI_IMP; +} + void __vgic_v3_save_aprs(struct vgic_v3_cpu_if *cpu_if) { u64 val; u32 nr_pre_bits; + /* + * ICH_AP1Rn_EL2 are only 64bit when the vcpu has vNMI: the NMI + * priority is encoded in ICH_AP1R0_EL2[63]. Without vNMI, the + * upper bits are RES0 and only the low 32 bits must be + * preserved. + */ + bool vnmi = vgic_v3_vcpu_has_vnmi(vgic_v3_cpu_if_to_vcpu(cpu_if)); val = read_gicreg(ICH_VTR_EL2); nr_pre_bits = vtr_to_nr_pre_bits(val); @@ -357,14 +387,18 @@ void __vgic_v3_save_aprs(struct vgic_v3_cpu_if *cpu_if) switch (nr_pre_bits) { case 7: - cpu_if->vgic_ap1r[3] = __vgic_v3_read_ap1rn(3); - cpu_if->vgic_ap1r[2] = __vgic_v3_read_ap1rn(2); + cpu_if->vgic_ap1r[3] = vnmi ? __vgic_v3_read_ap1rn(3) + : (u32)__vgic_v3_read_ap1rn(3); + cpu_if->vgic_ap1r[2] = vnmi ? __vgic_v3_read_ap1rn(2) + : (u32)__vgic_v3_read_ap1rn(2); fallthrough; case 6: - cpu_if->vgic_ap1r[1] = __vgic_v3_read_ap1rn(1); + cpu_if->vgic_ap1r[1] = vnmi ? __vgic_v3_read_ap1rn(1) + : (u32)__vgic_v3_read_ap1rn(1); fallthrough; default: - cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0); + cpu_if->vgic_ap1r[0] = vnmi ? __vgic_v3_read_ap1rn(0) + : (u32)__vgic_v3_read_ap1rn(0); } } @@ -372,6 +406,7 @@ void __vgic_v3_restore_aprs(struct vgic_v3_cpu_if *cpu_if) { u64 val; u32 nr_pre_bits; + bool vnmi = vgic_v3_vcpu_has_vnmi(vgic_v3_cpu_if_to_vcpu(cpu_if)); val = read_gicreg(ICH_VTR_EL2); nr_pre_bits = vtr_to_nr_pre_bits(val); @@ -390,14 +425,18 @@ void __vgic_v3_restore_aprs(struct vgic_v3_cpu_if *cpu_if) switch (nr_pre_bits) { case 7: - __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[3], 3); - __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[2], 2); + __vgic_v3_write_ap1rn(vnmi ? cpu_if->vgic_ap1r[3] + : (u32)cpu_if->vgic_ap1r[3], 3); + __vgic_v3_write_ap1rn(vnmi ? cpu_if->vgic_ap1r[2] + : (u32)cpu_if->vgic_ap1r[2], 2); fallthrough; case 6: - __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[1], 1); + __vgic_v3_write_ap1rn(vnmi ? cpu_if->vgic_ap1r[1] + : (u32)cpu_if->vgic_ap1r[1], 1); fallthrough; default: - __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[0], 0); + __vgic_v3_write_ap1rn(vnmi ? cpu_if->vgic_ap1r[0] + : (u32)cpu_if->vgic_ap1r[0], 0); } } -- 2.33.0
2 1
0 0
[PATCH OLK-6.6] vhost_iotlb: bound map allocation in add_range
by Lin Ruifeng 01 Sep '26

01 Sep '26
From: Linfeng Sun  <linfeng.sun.dev(a)gamil.com> stable inclusion from stable-v7.1.9 commit ae128dd19040ee06a4f8143c7ced4d18080d7a9a category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18250 CVE: CVE-2026-74713 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- [ Upstream commit 1ed35ac7f3fe2b4396bdd29ac3a7f0ebc0829e94 ] vhost_iotlb_add_range_ctx() only retires an old entry when the table has a non-zero limit, has exactly reached that limit and has VHOST_IOTLB_FLAG_RETIRE set. Non-retiring tables can keep allocating entries after reaching their configured limit. Existing vhost devices allocate their IOTLB with max_iotlb_entries from vhost.c, which defaults to 2048 and is tunable by module parameter. Use the caller-provided limit at the allocation point instead of adding a separate default in the common IOTLB helper, and reject non-positive values in vhost paths that can report an error. Other vhost IOTLB users should not create zero-limit tables when entries can be populated from userspace or guest-controlled requests. Add caller-side max_iotlb_entries parameters for mlx5 vDPA, VDUSE and vhost-vDPA. Reject non-positive VDUSE and vhost-vDPA values, and require at least two entries for vdpa_sim and mlx5 vDPA paths that install full-range mappings, since those mappings are split into two IOTLB entries. Handle full-range mappings in the common helper by checking that the IOTLB can hold both split entries before inserting the first half. This avoids returning an error after leaving a half mapping behind. When the table is full, keep the existing retire behavior for retiring tables and return -ENOSPC for non-retiring tables. Reuse the retired map node instead of freeing it and allocating a replacement, so a stream of IOTLB updates cannot keep forcing GFP_ATOMIC allocations after the table has reached its limit. If a zero-limit IOTLB still reaches the common helper, treat it as a configuration error and return -EINVAL. I found this bug myself, though the patch was written with AI assistance. Fixes: 0bbe30668d89 ("vhost: factor out IOTLB") Assisted-by: OpenAI-Codex:GPT-5 Signed-off-by: Linfeng Sun <linfeng.sun.dev(a)gamil.com> Message-ID: <AMYAtgAiKmgYcSQT5ukl-4qq.3.1781960405943.Hmail.241270009(a)hdu.edu.cn> Signed-off-by: Michael S. Tsirkin <mst(a)redhat.com> Signed-off-by: Sasha Levin <sashal(a)kernel.org> Conflicts: drivers/vdpa/mlx5/core/mr.c drivers/vdpa/vdpa_sim/vdpa_sim.c drivers/vdpa/vdpa_user/iova_domain.c drivers/vhost/iotlb.c drivers/vhost/vdpa.c drivers/vhost/vhost.c [Context Conflicts] Signed-off-by: Lin Ruifeng <linruifeng4(a)huawei.com> --- drivers/vdpa/mlx5/core/mlx5_vdpa.h | 2 ++ drivers/vdpa/mlx5/core/mr.c | 3 ++ drivers/vdpa/mlx5/core/resources.c | 11 ++++++- drivers/vdpa/vdpa_sim/vdpa_sim.c | 4 ++- drivers/vdpa/vdpa_user/iova_domain.c | 11 ++++++- drivers/vhost/iotlb.c | 47 +++++++++++++++++++--------- drivers/vhost/vdpa.c | 11 +++++-- drivers/vhost/vhost.c | 8 +++++ 8 files changed, 78 insertions(+), 19 deletions(-) diff --git a/drivers/vdpa/mlx5/core/mlx5_vdpa.h b/drivers/vdpa/mlx5/core/mlx5_vdpa.h index ca56242972b3..869219529ff1 100644 --- a/drivers/vdpa/mlx5/core/mlx5_vdpa.h +++ b/drivers/vdpa/mlx5/core/mlx5_vdpa.h @@ -11,6 +11,8 @@ #define MLX5V_ETH_HARD_MTU (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN) +extern int mlx5_vdpa_max_iotlb_entries; + struct mlx5_vdpa_direct_mr { u64 start; u64 end; diff --git a/drivers/vdpa/mlx5/core/mr.c b/drivers/vdpa/mlx5/core/mr.c index 165730656934..b7c1d532ccbc 100644 --- a/drivers/vdpa/mlx5/core/mr.c +++ b/drivers/vdpa/mlx5/core/mr.c @@ -577,6 +577,9 @@ static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, { int err; + if (mlx5_vdpa_max_iotlb_entries < 2) + return -EINVAL; + err = _mlx5_vdpa_create_dvq_mr(mvdev, iotlb, asid); if (err) return err; diff --git a/drivers/vdpa/mlx5/core/resources.c b/drivers/vdpa/mlx5/core/resources.c index d5a59c9035fb..00b66438ab53 100644 --- a/drivers/vdpa/mlx5/core/resources.c +++ b/drivers/vdpa/mlx5/core/resources.c @@ -3,8 +3,14 @@ #include <linux/iova.h> #include <linux/mlx5/driver.h> +#include <linux/moduleparam.h> #include "mlx5_vdpa.h" +int mlx5_vdpa_max_iotlb_entries = 2048; +module_param_named(max_iotlb_entries, mlx5_vdpa_max_iotlb_entries, int, 0444); +MODULE_PARM_DESC(max_iotlb_entries, + "Maximum number of iotlb entries. (default: 2048)"); + static int alloc_pd(struct mlx5_vdpa_dev *dev, u32 *pdn, u16 uid) { struct mlx5_core_dev *mdev = dev->mdev; @@ -229,7 +235,10 @@ int mlx5_vdpa_destroy_mkey(struct mlx5_vdpa_dev *mvdev, u32 mkey) static int init_ctrl_vq(struct mlx5_vdpa_dev *mvdev) { - mvdev->cvq.iotlb = vhost_iotlb_alloc(0, 0); + if (mlx5_vdpa_max_iotlb_entries < 2) + return -EINVAL; + + mvdev->cvq.iotlb = vhost_iotlb_alloc(mlx5_vdpa_max_iotlb_entries, 0); if (!mvdev->cvq.iotlb) return -ENOMEM; diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c index af59d90ba9a8..36b7c12e2a73 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c @@ -34,7 +34,7 @@ MODULE_PARM_DESC(batch_mapping, "Batched mapping 1 -Enable; 0 - Disable"); static int max_iotlb_entries = 2048; module_param(max_iotlb_entries, int, 0444); MODULE_PARM_DESC(max_iotlb_entries, - "Maximum number of iotlb entries for each address space. 0 means unlimited. (default: 2048)"); + "Maximum number of iotlb entries for each address space. (default: 2048)"); static bool use_va = true; module_param(use_va, bool, 0444); @@ -199,6 +199,8 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr, if (!dev_attr->alloc_size) return ERR_PTR(-EINVAL); + if (max_iotlb_entries < 2) + return ERR_PTR(-EINVAL); if (config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) { if (config->device_features & diff --git a/drivers/vdpa/vdpa_user/iova_domain.c b/drivers/vdpa/vdpa_user/iova_domain.c index cc8d26b97187..0a7791803132 100644 --- a/drivers/vdpa/vdpa_user/iova_domain.c +++ b/drivers/vdpa/vdpa_user/iova_domain.c @@ -12,11 +12,17 @@ #include <linux/file.h> #include <linux/anon_inodes.h> #include <linux/highmem.h> +#include <linux/moduleparam.h> #include <linux/vmalloc.h> #include <linux/vdpa.h> #include "iova_domain.h" +static int max_iotlb_entries = 2048; +module_param(max_iotlb_entries, int, 0444); +MODULE_PARM_DESC(max_iotlb_entries, + "Maximum number of iotlb entries. (default: 2048)"); + static int vduse_iotlb_add_range(struct vduse_iova_domain *domain, u64 start, u64 last, u64 addr, unsigned int perm, @@ -607,12 +613,15 @@ vduse_domain_create(unsigned long iova_limit, size_t bounce_size) bounce_pfns = PAGE_ALIGN(bounce_size) >> BOUNCE_MAP_SHIFT; if (iova_limit <= bounce_size) return NULL; + + if (max_iotlb_entries <= 0) + return NULL; domain = kzalloc(sizeof(*domain), GFP_KERNEL); if (!domain) return NULL; - domain->iotlb = vhost_iotlb_alloc(0, 0); + domain->iotlb = vhost_iotlb_alloc(max_iotlb_entries, 0); if (!domain->iotlb) goto err_iotlb; diff --git a/drivers/vhost/iotlb.c b/drivers/vhost/iotlb.c index ea61330a3431..a6228dd24931 100644 --- a/drivers/vhost/iotlb.c +++ b/drivers/vhost/iotlb.c @@ -20,6 +20,14 @@ INTERVAL_TREE_DEFINE(struct vhost_iotlb_map, rb, __u64, __subtree_last, START, LAST, static inline, vhost_iotlb_itree); +static void vhost_iotlb_map_unlink(struct vhost_iotlb *iotlb, + struct vhost_iotlb_map *map) +{ + vhost_iotlb_itree_remove(map, &iotlb->root); + list_del(&map->link); + iotlb->nmaps--; +} + /** * vhost_iotlb_map_free - remove a map node and free it * @iotlb: the IOTLB @@ -28,10 +36,8 @@ INTERVAL_TREE_DEFINE(struct vhost_iotlb_map, void vhost_iotlb_map_free(struct vhost_iotlb *iotlb, struct vhost_iotlb_map *map) { - vhost_iotlb_itree_remove(map, &iotlb->root); - list_del(&map->link); + vhost_iotlb_map_unlink(iotlb, map); kfree(map); - iotlb->nmaps--; } EXPORT_SYMBOL_GPL(vhost_iotlb_map_free); @@ -57,14 +63,25 @@ int vhost_iotlb_add_range_ctx(struct vhost_iotlb *iotlb, if (last < start) return -EFAULT; + if (!iotlb->limit) + return -EINVAL; + /* If the range being mapped is [0, ULONG_MAX], split it into two entries * otherwise its size would overflow u64. */ if (start == 0 && last == ULONG_MAX) { u64 mid = last / 2; - int err = vhost_iotlb_add_range_ctx(iotlb, start, mid, addr, - perm, opaque); + int err; + + if (iotlb->limit < 2) + return -ENOSPC; + if (!(iotlb->flags & VHOST_IOTLB_FLAG_RETIRE) && + iotlb->nmaps > iotlb->limit - 2) + return -ENOSPC; + + err = vhost_iotlb_add_range_ctx(iotlb, start, mid, addr, + perm, opaque); if (err) return err; @@ -72,17 +89,19 @@ int vhost_iotlb_add_range_ctx(struct vhost_iotlb *iotlb, start = mid + 1; } - if (iotlb->limit && - iotlb->nmaps == iotlb->limit && - iotlb->flags & VHOST_IOTLB_FLAG_RETIRE) { - map = list_first_entry(&iotlb->list, typeof(*map), link); - vhost_iotlb_map_free(iotlb, map); + if (iotlb->nmaps >= iotlb->limit) { + if (iotlb->flags & VHOST_IOTLB_FLAG_RETIRE) { + map = list_first_entry(&iotlb->list, typeof(*map), link); + vhost_iotlb_map_unlink(iotlb, map); + } else { + return -ENOSPC; + } + } else { + map = kmalloc(sizeof(*map), GFP_ATOMIC); + if (!map) + return -ENOMEM; } - map = kmalloc(sizeof(*map), GFP_ATOMIC); - if (!map) - return -ENOMEM; - map->start = start; map->size = last - start + 1; map->last = last; diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c index 0583374602f8..72c71b2fb198 100644 --- a/drivers/vhost/vdpa.c +++ b/drivers/vhost/vdpa.c @@ -37,6 +37,11 @@ enum { #define VHOST_VDPA_DEV_MAX (1U << MINORBITS) +static int max_iotlb_entries = 2048; +module_param(max_iotlb_entries, int, 0444); +MODULE_PARM_DESC(max_iotlb_entries, + "Maximum number of iotlb entries. (default: 2048)"); + #define VHOST_VDPA_IOTLB_BUCKETS 16 struct vhost_vdpa_as { @@ -114,12 +119,14 @@ static struct vhost_vdpa_as *vhost_vdpa_alloc_as(struct vhost_vdpa *v, u32 asid) if (asid >= v->vdpa->nas) return NULL; + if (max_iotlb_entries <= 0) + return NULL; as = kmalloc(sizeof(*as), GFP_KERNEL); if (!as) return NULL; - vhost_iotlb_init(&as->iotlb, 0, 0); + vhost_iotlb_init(&as->iotlb, max_iotlb_entries, 0); as->id = asid; hlist_add_head(&as->hash_link, head); @@ -1833,7 +1840,7 @@ static int vhost_vdpa_probe(struct vdpa_device *vdpa) goto err; } - vhost_iotlb_init(&v->resv_iotlb, 0, 0); + vhost_iotlb_init(&v->resv_iotlb, max_iotlb_entries, 0); r = dev_set_name(&v->dev, "vhost-vdpa-%u", minor); if (r) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index a58be2369fdc..2b410ddffac2 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -977,6 +977,9 @@ EXPORT_SYMBOL_GPL(vhost_dev_set_owner); static struct vhost_iotlb *iotlb_alloc(void) { + if (max_iotlb_entries <= 0) + return NULL; + return vhost_iotlb_alloc(max_iotlb_entries, VHOST_IOTLB_FLAG_RETIRE); } @@ -1817,6 +1820,8 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m) return -EOPNOTSUPP; if (mem.nregions > max_mem_regions) return -E2BIG; + if (max_iotlb_entries <= 0) + return -EINVAL; newmem = kvzalloc(struct_size(newmem, regions, mem.nregions), GFP_KERNEL); if (!newmem) @@ -2111,6 +2116,9 @@ int vhost_init_device_iotlb(struct vhost_dev *d) struct vhost_iotlb *niotlb, *oiotlb; int i; + if (max_iotlb_entries <= 0) + return -EINVAL; + niotlb = iotlb_alloc(); if (!niotlb) return -ENOMEM; -- 2.34.1
2 1
0 0
[PATCH OLK-6.6] bpf: Simplify sanitize_err() signature
by Pu Lehui 01 Sep '26

01 Sep '26
From: Eduard Zingerman <eddyz87(a)gmail.com> mainline inclusion from mainline-v7.2-rc7 commit a15970d916b39acc7c60a0a99c27a6e378690aa9 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18233 CVE: CVE-2026-74720 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?… -------------------------------- The sanitize_err() function is called when: - ptr += scalar - scalar += ptr - scalar += scalar ALU operations are processed. This commit drops offset and pointer registers parameters from its signature to simplify the follow-up changes for 'scalar += ptr' case. regs[src].type is safe to access, as it is not mutated by the callers. Signed-off-by: Yiyang Chen <chenyy23(a)mails.tsinghua.edu.cn> Acked-by: Shung-Hsi Yu <shung-hsi.yu(a)suse.com> Link: https://patch.msgid.link/20260729-c3-035-public-bpf-v4-v4-1-8ee297e2346b@ma… Signed-off-by: Eduard Zingerman <eddyz87(a)gmail.com> Conflicts: kernel/bpf/verifier.c [ctx conflicts] Signed-off-by: Pu Lehui <pulehui(a)huawei.com> --- kernel/bpf/verifier.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index ee8c00981cea..b59ee8344873 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -12725,23 +12725,21 @@ static void sanitize_mark_insn_seen(struct bpf_verifier_env *env) env->insn_aux_data[env->insn_idx].seen = env->pass_cnt; } -static int sanitize_err(struct bpf_verifier_env *env, - const struct bpf_insn *insn, int reason, - const struct bpf_reg_state *off_reg, - const struct bpf_reg_state *dst_reg) +static int sanitize_err(struct bpf_verifier_env *env, const struct bpf_insn *insn, int reason) { static const char *err = "pointer arithmetic with it prohibited for !root"; const char *op = BPF_OP(insn->code) == BPF_ADD ? "add" : "sub"; u32 dst = insn->dst_reg, src = insn->src_reg; + struct bpf_reg_state *regs = cur_regs(env); switch (reason) { case REASON_BOUNDS: verbose(env, "R%d has unknown scalar with mixed signed bounds, %s\n", - off_reg == dst_reg ? dst : src, err); + regs[src].type == SCALAR_VALUE ? src : dst, err); break; case REASON_TYPE: verbose(env, "R%d has pointer with unsupported alu operation, %s\n", - off_reg == dst_reg ? src : dst, err); + regs[src].type == SCALAR_VALUE ? dst : src, err); break; case REASON_PATHS: verbose(env, "R%d tried to %s from different maps, paths or scalars, %s\n", @@ -12923,7 +12921,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, ret = sanitize_ptr_alu(env, insn, ptr_reg, off_reg, dst_reg, &info, false); if (ret < 0) - return sanitize_err(env, insn, ret, off_reg, dst_reg); + return sanitize_err(env, insn, ret); } switch (opcode) { @@ -13087,7 +13085,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, ret = sanitize_ptr_alu(env, insn, dst_reg, off_reg, dst_reg, &info, true); if (ret < 0) - return sanitize_err(env, insn, ret, off_reg, dst_reg); + return sanitize_err(env, insn, ret); } return 0; @@ -13719,7 +13717,7 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, if (sanitize_needed(opcode)) { ret = sanitize_val_alu(env, insn); if (ret < 0) - return sanitize_err(env, insn, ret, NULL, NULL); + return sanitize_err(env, insn, ret); } /* Calculate sign/unsigned bounds and tnum for alu32 and alu64 bit ops. -- 2.34.1
2 1
0 0
[PATCH OLK-5.10] vhost/vdpa: validate virtqueue index in mmap and fault paths
by Fanhua Li 01 Sep '26

01 Sep '26
From: Qihang Tang <q.h.hack.winter(a)gmail.com> stable inclusion from stable-v5.10.261 commit 0f310bac6db9bd3bb1655707d692d9d2a86eeb17 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18146 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- [ Upstream commit 929e4f044621c8cc30b612fb74e1410bef09e41b ] vhost_vdpa_mmap() and vhost_vdpa_fault() use vma->vm_pgoff as a virtqueue index for get_vq_notification(), but they do not validate that the index is smaller than v->nvqs. The ioctl path already performs both a bounds check and array_index_nospec(), but the mmap/fault path only checks that the index fits in u16. This allows an out-of-range queue index to reach driver-specific get_vq_notification() callbacks. Fix this by extracting a unified vhost_vdpa_get_vq_notification() helper that validates the queue index against v->nvqs and applies array_index_nospec() before calling the driver callback. Both the mmap and fault paths use this helper, and the bounds checking is consolidated into a single location. From source inspection, the most defensible impact is out-of-bounds access in the callback path, potentially leading to invalid PFN remaps and crash/DoS. Fixes: ddd89d0a059d ("vhost_vdpa: support doorbell mapping via mmap") Acked-by: Eugenio Pérez <eperezma(a)redhat.com> Acked-by: Michael S. Tsirkin <mst(a)redhat.com> Signed-off-by: Qihang Tang <q.h.hack.winter(a)gmail.com> Signed-off-by: Michael S. Tsirkin <mst(a)redhat.com> Message-ID: <20260508075821.92656-1-q.h.hack.winter(a)gmail.com> Signed-off-by: Sasha Levin <sashal(a)kernel.org> Conflicts: drivers/vhost/vdpa.c [Fanhua Li: context conflict] Signed-off-by: Fanhua Li <lifanhua5(a)huawei.com> --- drivers/vhost/vdpa.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c index 88c9d7665cedb..56d99c3d0a389 100644 --- a/drivers/vhost/vdpa.c +++ b/drivers/vhost/vdpa.c @@ -1567,16 +1567,32 @@ static int vhost_vdpa_release(struct inode *inode, struct file *filep) } #ifdef CONFIG_MMU -static vm_fault_t vhost_vdpa_fault(struct vm_fault *vmf) +static int +vhost_vdpa_get_vq_notification(struct vhost_vdpa *v, unsigned long index, + struct vdpa_notification_area *notify) { - struct vhost_vdpa *v = vmf->vma->vm_file->private_data; struct vdpa_device *vdpa = v->vdpa; const struct vdpa_config_ops *ops = vdpa->config; + + if (index > 65535 || index >= v->nvqs) + return -EINVAL; + + index = array_index_nospec(index, v->nvqs); + + *notify = ops->get_vq_notification(vdpa, index); + + return 0; +} + +static vm_fault_t vhost_vdpa_fault(struct vm_fault *vmf) +{ + struct vhost_vdpa *v = vmf->vma->vm_file->private_data; struct vdpa_notification_area notify; struct vm_area_struct *vma = vmf->vma; - u16 index = vma->vm_pgoff; + unsigned long index = vma->vm_pgoff; - notify = ops->get_vq_notification(vdpa, index); + if (vhost_vdpa_get_vq_notification(v, index, &notify)) + return VM_FAULT_SIGBUS; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); if (remap_pfn_range(vma, vmf->address & PAGE_MASK, @@ -1605,8 +1621,6 @@ static int vhost_vdpa_mmap(struct file *file, struct vm_area_struct *vma) return -EINVAL; if (vma->vm_flags & VM_READ) return -EINVAL; - if (index > 65535) - return -EINVAL; if (!ops->get_vq_notification) return -ENOTSUPP; @@ -1614,7 +1628,8 @@ static int vhost_vdpa_mmap(struct file *file, struct vm_area_struct *vma) * support the doorbell which sits on the page boundary and * does not share the page with other registers. */ - notify = ops->get_vq_notification(vdpa, index); + if (vhost_vdpa_get_vq_notification(v, index, &notify)) + return -EINVAL; if (notify.addr & (PAGE_SIZE - 1)) return -EINVAL; if (vma->vm_end - vma->vm_start != notify.size) -- 2.43.0
2 1
0 0
[PATCH OLK-6.6 1/1] KVM: arm64: vgic-v3: Restrict ICH_AP1Rn_EL2 accesses to 64-bit only with vNMI
by Jinqian Yang 31 Aug '26

31 Aug '26
ICH_AP1Rn_EL2 is 64-bit only when vNMI is in use, with the NMI priority in ICH_AP1R0_EL2[63:32]; otherwise the upper bits are RES0. Gate the save/restore access width on vgic_v3_vcpu_has_vnmi() which checks both vgic.has_nmi and ID_AA64PFR1_EL1.NMI, so that the NMI priority is preserved across context switch only when vNMI is actually enabled for the guest. Also drop the early assignment of kvm->arch.pfr1_nmi in kvm_arch_init_vm(). Without it vNMI is no longer enabled by default at VM creation on hosts with FEAT_NMI; instead the VMM must explicitly set ID_AA64PFR1_EL1.NMI via SET_ONE_REG to enable vNMI for the guest. Signed-off-by: Jinqian Yang <yangjinqian1(a)huawei.com> --- arch/arm64/include/asm/kvm_hyp.h | 1 + arch/arm64/kvm/arm.c | 3 -- arch/arm64/kvm/hyp/vgic-v3-sr.c | 55 +++++++++++++++++++++++++++----- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h index 127ad280e68b..c4121bf0aadc 100644 --- a/arch/arm64/include/asm/kvm_hyp.h +++ b/arch/arm64/include/asm/kvm_hyp.h @@ -82,6 +82,7 @@ void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if); void __vgic_v3_deactivate_traps(struct vgic_v3_cpu_if *cpu_if); void __vgic_v3_save_aprs(struct vgic_v3_cpu_if *cpu_if); void __vgic_v3_restore_aprs(struct vgic_v3_cpu_if *cpu_if); +bool vgic_v3_vcpu_has_vnmi(struct kvm_vcpu *vcpu); int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu); #ifdef __KVM_NVHE_HYPERVISOR__ diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 2b560eba3e0b..9a4be08730da 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -381,9 +381,6 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) /* The maximum number of VCPUs is limited by the host's GIC model */ kvm->max_vcpus = kvm_arm_default_max_vcpus(); - if (cpus_have_const_cap(ARM64_HAS_NMI) && !static_branch_unlikely(&vgic_v3_cpuif_trap)) - kvm->arch.pfr1_nmi = ID_AA64PFR1_EL1_NMI_IMP; - kvm_arm_init_hypercalls(kvm); if (!kvm_is_realm(kvm)) diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c index 7a9e132f68db..ab406332762e 100644 --- a/arch/arm64/kvm/hyp/vgic-v3-sr.c +++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c @@ -335,10 +335,40 @@ void __vgic_v3_deactivate_traps(struct vgic_v3_cpu_if *cpu_if) write_gicreg(0, ICH_HCR_EL2); } +static struct kvm_vcpu *vgic_v3_cpu_if_to_vcpu(struct vgic_v3_cpu_if *cpu_if) +{ + struct vgic_cpu *vgic_cpu = container_of(cpu_if, struct vgic_cpu, vgic_v3); + + return container_of(vgic_cpu, struct kvm_vcpu, arch.vgic_cpu); +} + +/* + * vNMI is only usable if the guest has selected NMI support + * (vgic.has_nmi) and the vcpu has FEAT_NMI (pfr1_nmi). + * + * This drives the width of the ICH_AP1Rn_EL2 accesses: with vNMI the + * registers are 64bit (the NMI priority lives in ICH_AP1R0_EL2[63]), + * without it only the low 32 bits are valid. + */ +bool vgic_v3_vcpu_has_vnmi(struct kvm_vcpu *vcpu) +{ + struct kvm *kvm = kern_hyp_va(vcpu->kvm); + + return kvm->arch.vgic.has_nmi && + kvm->arch.pfr1_nmi == ID_AA64PFR1_EL1_NMI_IMP; +} + void __vgic_v3_save_aprs(struct vgic_v3_cpu_if *cpu_if) { u64 val; u32 nr_pre_bits; + /* + * ICH_AP1Rn_EL2 are only 64bit when the vcpu has vNMI: the NMI + * priority is encoded in ICH_AP1R0_EL2[63]. Without vNMI, the + * upper bits are RES0 and only the low 32 bits must be + * preserved. + */ + bool vnmi = vgic_v3_vcpu_has_vnmi(vgic_v3_cpu_if_to_vcpu(cpu_if)); val = read_gicreg(ICH_VTR_EL2); nr_pre_bits = vtr_to_nr_pre_bits(val); @@ -357,14 +387,18 @@ void __vgic_v3_save_aprs(struct vgic_v3_cpu_if *cpu_if) switch (nr_pre_bits) { case 7: - cpu_if->vgic_ap1r[3] = __vgic_v3_read_ap1rn(3); - cpu_if->vgic_ap1r[2] = __vgic_v3_read_ap1rn(2); + cpu_if->vgic_ap1r[3] = vnmi ? __vgic_v3_read_ap1rn(3) + : (u32)__vgic_v3_read_ap1rn(3); + cpu_if->vgic_ap1r[2] = vnmi ? __vgic_v3_read_ap1rn(2) + : (u32)__vgic_v3_read_ap1rn(2); fallthrough; case 6: - cpu_if->vgic_ap1r[1] = __vgic_v3_read_ap1rn(1); + cpu_if->vgic_ap1r[1] = vnmi ? __vgic_v3_read_ap1rn(1) + : (u32)__vgic_v3_read_ap1rn(1); fallthrough; default: - cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0); + cpu_if->vgic_ap1r[0] = vnmi ? __vgic_v3_read_ap1rn(0) + : (u32)__vgic_v3_read_ap1rn(0); } } @@ -372,6 +406,7 @@ void __vgic_v3_restore_aprs(struct vgic_v3_cpu_if *cpu_if) { u64 val; u32 nr_pre_bits; + bool vnmi = vgic_v3_vcpu_has_vnmi(vgic_v3_cpu_if_to_vcpu(cpu_if)); val = read_gicreg(ICH_VTR_EL2); nr_pre_bits = vtr_to_nr_pre_bits(val); @@ -390,14 +425,18 @@ void __vgic_v3_restore_aprs(struct vgic_v3_cpu_if *cpu_if) switch (nr_pre_bits) { case 7: - __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[3], 3); - __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[2], 2); + __vgic_v3_write_ap1rn(vnmi ? cpu_if->vgic_ap1r[3] + : (u32)cpu_if->vgic_ap1r[3], 3); + __vgic_v3_write_ap1rn(vnmi ? cpu_if->vgic_ap1r[2] + : (u32)cpu_if->vgic_ap1r[2], 2); fallthrough; case 6: - __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[1], 1); + __vgic_v3_write_ap1rn(vnmi ? cpu_if->vgic_ap1r[1] + : (u32)cpu_if->vgic_ap1r[1], 1); fallthrough; default: - __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[0], 0); + __vgic_v3_write_ap1rn(vnmi ? cpu_if->vgic_ap1r[0] + : (u32)cpu_if->vgic_ap1r[0], 0); } } -- 2.33.0
2 1
0 0
[PATCH OLK-6.6] net: pktgen: fix proc entry use-after-free
by JiangJieHua 31 Aug '26

31 Aug '26
From: Chengfeng Ye <nicoyip.dev(a)gmail.com> stable inclusion from stable-v6.6.153 commit 577443530cb592d5782a1f79847411a9363a65c8 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/17690 CVE: CVE-2026-74479 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- [ Upstream commit 817ff6efdb7f484ea547218e11e17d8e43daa3b4 ] pktgen_change_name() replaces pkt_dev->entry while holding t->if_lock. pktgen_remove_device() removes the same entry before _rem_dev_from_if_list() takes that lock. This allows the following interleaving: CPU 0 (NETDEV_CHANGENAME) CPU 1 (kpktgend) if_lock(t) proc_remove(pkt_dev->entry) proc_remove(pkt_dev->entry) pkt_dev->entry = proc_create_data(...) if_unlock(t) The kthread can pass the stale proc_dir_entry to proc_remove() after the rename path has freed it. A reproducer with a widened race window reports: BUG: KASAN: slab-use-after-free in proc_remove+0x78/0x80 Read of size 8 at addr ffff8881478fea70 by task kpktgend_0/67 Call Trace: proc_remove+0x78/0x80 pktgen_remove_device.isra.0+0x11c/0x4c0 pktgen_thread_worker+0x1214/0x6bc0 kthread+0x2c6/0x3b0 Allocated by task 95: __proc_create+0x204/0x790 proc_create_data+0x72/0xe0 pktgen_thread_write+0xd61/0x1510 Freed by task 28: kmem_cache_free+0xcb/0x3d0 proc_free_inode+0x5b/0x80 rcu_core+0x50a/0x1850 The buggy address belongs to the object at ffff8881478fea00 which belongs to the cache proc_dir_entry of size 192 Move proc_remove() into the if_lock-protected list removal helper. Keep it before list_del_rcu() to preserve the ordering required by add_device(). The rename path must then finish replacing the entry before removal, or it observes that the device is no longer on the list. Fixes: 39df232f1a9b ("[PKTGEN]: fix device name handling") Cc: stable(a)vger.kernel.org Signed-off-by: Chengfeng Ye <nicoyip.dev(a)gmail.com> Reviewed-by: Simon Horman <horms(a)kernel.org> Link: https://patch.msgid.link/20260719145740.2888967-1-nicoyip.dev@gmail.com Signed-off-by: Jakub Kicinski <kuba(a)kernel.org> Signed-off-by: Sasha Levin <sashal(a)kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org> Conflicts: net/core/pktgen.c [577443530cb5 moves proc_remove() into the if_lock-protected _rem_dev_from_if_list() helper to close a proc entry use-after-free race between pktgen_change_name() and pktgen_remove_device(). In the downstream tree the comment above pktgen_remove_device()'s proc_remove() call still used the single-line '*/' closing style, so the hunk was adjusted to drop the now-redundant proc_remove(pkt_dev->entry) call and the 'And update the thread if_list' comment, while keeping the proc_remove() addition inside _rem_dev_from_if_list() intact. Semantically equivalent to the upstream fix.] Signed-off-by: JiangJieHua <jiangjiehua1(a)huawei.com> --- net/core/pktgen.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 32a60c8195d5f..906cf7f8179af 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -3881,6 +3881,7 @@ static void _rem_dev_from_if_list(struct pktgen_thread *t, struct pktgen_dev *p; if_lock(t); + proc_remove(pkt_dev->entry); list_for_each_safe(q, n, &t->if_list) { p = list_entry(q, struct pktgen_dev, list); if (p == pkt_dev) @@ -3908,10 +3909,8 @@ static int pktgen_remove_device(struct pktgen_thread *t, /* Remove proc before if_list entry, because add_device uses * list to determine if interface already exist, avoid race - * with proc_create_data() */ - proc_remove(pkt_dev->entry); - - /* And update the thread if_list */ + * with proc_create_data() + */ _rem_dev_from_if_list(t, pkt_dev); #ifdef CONFIG_XFRM -- 2.33.8
2 1
0 0
[PATCH OLK-6.6] net: pktgen: fix proc entry use-after-free
by JiangJieHua 31 Aug '26

31 Aug '26
From: Chengfeng Ye <nicoyip.dev(a)gmail.com> stable inclusion from stable-v6.6.153 commit 577443530cb592d5782a1f79847411a9363a65c8 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/17690 CVE: CVE-2026-74479 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- [ Upstream commit 817ff6efdb7f484ea547218e11e17d8e43daa3b4 ] pktgen_change_name() replaces pkt_dev->entry while holding t->if_lock. pktgen_remove_device() removes the same entry before _rem_dev_from_if_list() takes that lock. This allows the following interleaving: CPU 0 (NETDEV_CHANGENAME) CPU 1 (kpktgend) if_lock(t) proc_remove(pkt_dev->entry) proc_remove(pkt_dev->entry) pkt_dev->entry = proc_create_data(...) if_unlock(t) The kthread can pass the stale proc_dir_entry to proc_remove() after the rename path has freed it. A reproducer with a widened race window reports: BUG: KASAN: slab-use-after-free in proc_remove+0x78/0x80 Read of size 8 at addr ffff8881478fea70 by task kpktgend_0/67 Call Trace: proc_remove+0x78/0x80 pktgen_remove_device.isra.0+0x11c/0x4c0 pktgen_thread_worker+0x1214/0x6bc0 kthread+0x2c6/0x3b0 Allocated by task 95: __proc_create+0x204/0x790 proc_create_data+0x72/0xe0 pktgen_thread_write+0xd61/0x1510 Freed by task 28: kmem_cache_free+0xcb/0x3d0 proc_free_inode+0x5b/0x80 rcu_core+0x50a/0x1850 The buggy address belongs to the object at ffff8881478fea00 which belongs to the cache proc_dir_entry of size 192 Move proc_remove() into the if_lock-protected list removal helper. Keep it before list_del_rcu() to preserve the ordering required by add_device(). The rename path must then finish replacing the entry before removal, or it observes that the device is no longer on the list. Fixes: 39df232f1a9b ("[PKTGEN]: fix device name handling") Cc: stable(a)vger.kernel.org Signed-off-by: Chengfeng Ye <nicoyip.dev(a)gmail.com> Reviewed-by: Simon Horman <horms(a)kernel.org> Link: https://patch.msgid.link/20260719145740.2888967-1-nicoyip.dev@gmail.com Signed-off-by: Jakub Kicinski <kuba(a)kernel.org> Signed-off-by: Sasha Levin <sashal(a)kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org> Conflicts: net/core/pktgen.c [577443530cb5 moves proc_remove() into the if_lock-protected _rem_dev_from_if_list() helper to close a proc entry use-after-free race between pktgen_change_name() and pktgen_remove_device(). In the downstream tree the comment above pktgen_remove_device()'s proc_remove() call still used the single-line '*/' closing style, so the hunk was adjusted to drop the now-redundant proc_remove(pkt_dev->entry) call and the 'And update the thread if_list' comment, while keeping the proc_remove() addition inside _rem_dev_from_if_list() intact. Semantically equivalent to the upstream fix.] Signed-off-by: JiangJieHua <jiangjiehua1(a)huawei.com> --- net/core/pktgen.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 32a60c8195d5f..83efb7be323eb 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -3881,6 +3881,7 @@ static void _rem_dev_from_if_list(struct pktgen_thread *t, struct pktgen_dev *p; if_lock(t); + proc_remove(pkt_dev->entry); list_for_each_safe(q, n, &t->if_list) { p = list_entry(q, struct pktgen_dev, list); if (p == pkt_dev) @@ -3909,9 +3910,6 @@ static int pktgen_remove_device(struct pktgen_thread *t, /* Remove proc before if_list entry, because add_device uses * list to determine if interface already exist, avoid race * with proc_create_data() */ - proc_remove(pkt_dev->entry); - - /* And update the thread if_list */ _rem_dev_from_if_list(t, pkt_dev); #ifdef CONFIG_XFRM -- 2.33.8
2 1
0 0
[PATCH OLK-6.6] tcp: challenge ACK for non-exact RST in SYN-RECEIVED
by JiangJieHua 31 Aug '26

31 Aug '26
From: Yuxiang Yang <yangyx22(a)mails.tsinghua.edu.cn> stable inclusion from stable-v6.6.153 commit 8b0a3a094f4cae2fb92e4d08d4eef7246a9d9c49 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/16927 CVE: CVE-2026-68118 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- [ Upstream commit a28c4fcbf774e23b4779cae468e3497a5ad1f4a1 ] The SYN-RECEIVED request-socket path in tcp_check_req() accepts an in-window RST without requiring SEG.SEQ to exactly match RCV.NXT. A non-exact RST therefore removes the request instead of eliciting a challenge ACK. RFC 9293 section 3.10.7.4 applies the RFC 5961 reset check in SYN-RECEIVED: an exact RST resets the connection, while a non-exact in-window RST must trigger a challenge ACK and be dropped. Apply that check before the ACK-field validation, following the RFC sequence-number, RST, then ACK processing order. Factor the per-netns challenge ACK quota out of tcp_send_challenge_ack() so request sockets can share it. Use the request socket's send_ack() callback and its own out-of-window ACK timestamp to send and rate-limit the response. Reported-by: Yuxiang Yang <yangyx22(a)mails.tsinghua.edu.cn> Reported-by: Yizhou Zhao <zhaoyz24(a)mails.tsinghua.edu.cn> Reported-by: Ao Wang <wangao(a)seu.edu.cn> Reported-by: Xuewei Feng <fengxw06(a)126.com> Reported-by: Qi Li <qli01(a)tsinghua.edu.cn> Reported-by: Ke Xu <xuke(a)tsinghua.edu.cn> Fixes: 282f23c6ee34 ("tcp: implement RFC 5961 3.2") Cc: stable(a)vger.kernel.org Signed-off-by: Yuxiang Yang <yangyx22(a)mails.tsinghua.edu.cn> Reviewed-by: Eric Dumazet <edumazet(a)google.com> Link: https://patch.msgid.link/20260717081443.809393-2-yangyx22@mails.tsinghua.ed… Signed-off-by: Jakub Kicinski <kuba(a)kernel.org> Signed-off-by: Sasha Levin <sashal(a)kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org> Conflicts: include/net/tcp.h Signed-off-by: JiangJieHua <jiangjiehua1(a)huawei.com> --- include/net/tcp.h | 2 ++ net/ipv4/tcp_input.c | 56 ++++++++++++++++++++++++++++++---------- net/ipv4/tcp_minisocks.c | 12 ++++++++- 3 files changed, 56 insertions(+), 14 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 8674996bd39c6..a40864c5f2803 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1685,6 +1685,8 @@ static inline bool tcp_paws_reject(const struct tcp_options_received *rx_opt, bool tcp_oow_rate_limited(struct net *net, const struct sk_buff *skb, int mib_idx, u32 *last_oow_ack_time); +void tcp_reqsk_send_challenge_ack(struct sock *sk, struct sk_buff *skb, + struct request_sock *req); static inline void tcp_mib_init(struct net *net) { diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index e6499904caf56..6af54c18f55ca 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3744,24 +3744,17 @@ bool tcp_oow_rate_limited(struct net *net, const struct sk_buff *skb, return __tcp_oow_rate_limited(net, mib_idx, last_oow_ack_time); } -/* RFC 5961 7 [ACK Throttling] */ -static void tcp_send_challenge_ack(struct sock *sk) +/* Consume one slot from the per-netns RFC 5961 challenge ACK quota. + * Returns true if a challenge ACK may be sent. + */ +static bool tcp_challenge_ack_allowed(struct net *net) { - struct tcp_sock *tp = tcp_sk(sk); - struct net *net = sock_net(sk); u32 count, now, ack_limit; - /* First check our per-socket dupack rate limit. */ - if (__tcp_oow_rate_limited(net, - LINUX_MIB_TCPACKSKIPPEDCHALLENGE, - &tp->last_oow_ack_time)) - return; - ack_limit = READ_ONCE(net->ipv4.sysctl_tcp_challenge_ack_limit); if (ack_limit == INT_MAX) - goto send_ack; + return true; - /* Then check host-wide RFC 5961 rate limit. */ now = jiffies / HZ; if (now != READ_ONCE(net->ipv4.tcp_challenge_timestamp)) { u32 half = (ack_limit + 1) >> 1; @@ -3773,12 +3766,49 @@ static void tcp_send_challenge_ack(struct sock *sk) count = READ_ONCE(net->ipv4.tcp_challenge_count); if (count > 0) { WRITE_ONCE(net->ipv4.tcp_challenge_count, count - 1); -send_ack: + return true; + } + return false; +} + +/* RFC 5961 7 [ACK Throttling] */ +static void tcp_send_challenge_ack(struct sock *sk) +{ + struct tcp_sock *tp = tcp_sk(sk); + struct net *net = sock_net(sk); + + /* First check our per-socket dupack rate limit. */ + if (__tcp_oow_rate_limited(net, + LINUX_MIB_TCPACKSKIPPEDCHALLENGE, + &tp->last_oow_ack_time)) + return; + + /* Then check the per-netns RFC 5961 rate limit. */ + if (tcp_challenge_ack_allowed(net)) { NET_INC_STATS(net, LINUX_MIB_TCPCHALLENGEACK); tcp_send_ack(sk); } } +/* Send a challenge ACK from a SYN-RECEIVED request socket. Uses + * __tcp_oow_rate_limited() directly so that an RST carrying payload + * cannot bypass the per-request rate limit. + */ +void tcp_reqsk_send_challenge_ack(struct sock *sk, struct sk_buff *skb, + struct request_sock *req) +{ + struct net *net = sock_net(sk); + + if (__tcp_oow_rate_limited(net, LINUX_MIB_TCPACKSKIPPEDCHALLENGE, + &tcp_rsk(req)->last_oow_ack_time)) + return; + + if (tcp_challenge_ack_allowed(net)) { + NET_INC_STATS(net, LINUX_MIB_TCPCHALLENGEACK); + req->rsk_ops->send_ack(sk, skb, req); + } +} + static void tcp_store_ts_recent(struct tcp_sock *tp) { tp->rx_opt.ts_recent = tp->rx_opt.rcv_tsval; diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 8099563937e38..6138f546e90df 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -763,7 +763,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, * elsewhere and is checked directly against the child socket rather * than req because user data may have been sent out. */ - if ((flg & TCP_FLAG_ACK) && !fastopen && + if ((flg & TCP_FLAG_ACK) && !(flg & TCP_FLAG_RST) && !fastopen && (TCP_SKB_CB(skb)->ack_seq != tcp_rsk(req)->snt_isn + 1)) return sk; @@ -802,6 +802,16 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, flg &= ~TCP_FLAG_SYN; } + /* RFC 5961 section 3.2, as clarified by RFC 9293 section + * 3.10.7.4, requires a challenge ACK for a non-exact + * in-window RST in SYN-RECEIVED. + */ + if ((flg & TCP_FLAG_RST) && + TCP_SKB_CB(skb)->seq != tcp_rsk(req)->rcv_nxt) { + tcp_reqsk_send_challenge_ack(sk, skb, req); + return NULL; + } + /* RFC793: "second check the RST bit" and * "fourth, check the SYN bit" */ -- 2.33.8
2 1
0 0
[PATCH OLK-6.6 0/3] net: fix hard_header_len races in packet send paths Qihang
by JiangJieHua 31 Aug '26

31 Aug '26
Qihang Tang (3): net: remove CAP_SYS_RAWIO zero-padding in dev_validate_header packet: use consistent hard_header_len in non-ring send paths packet: use consistent hard_header_len in TX_RING send path include/linux/netdevice.h | 11 ++++------ net/packet/af_packet.c | 45 +++++++++++++++++++++++---------------- 2 files changed, 31 insertions(+), 25 deletions(-) -- 2.33.8
2 4
0 0
[PATCH OLK-6.6 0/3] net: fix hard_header_len races in packet send paths
by JiangJieHua 31 Aug '26

31 Aug '26
Qihang Tang (3): net: remove CAP_SYS_RAWIO zero-padding in dev_validate_header packet: use consistent hard_header_len in non-ring send paths packet: use consistent hard_header_len in TX_RING send path include/linux/netdevice.h | 11 ++++------ net/packet/af_packet.c | 45 +++++++++++++++++++++++---------------- 2 files changed, 31 insertions(+), 25 deletions(-) -- 2.33.8
2 4
0 0
  • ← Newer
  • 1
  • ...
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • ...
  • 2464
  • Older →

HyperKitty Powered by HyperKitty