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

  • 13 participants
  • 24592 discussions
[PATCH OLK-5.10] [Backport] driver core: use READ_ONCE() for dev->driver in dev_has_sync_state()
by Lin Ruifeng 01 Sep '26

01 Sep '26
From: Danilo Krummrich <dakr(a)kernel.org> stable inclusion from stable-v5.10.261 commit 89789e4c141904506163dcb91c7289a074573931 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18448 CVE: CVE-2026-80677 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- [ Upstream commit e9506871a8ea304cde48ff4a57226df2aadddae3 ] dev_has_sync_state() reads dev->driver twice without holding device_lock() -- once for the NULL check and once to dereference ->sync_state. Some callers only hold device_links_write_lock, which doesn't prevent a concurrent unbind from clearing dev->driver via device_unbind_cleanup(). Fix it by reading dev->driver exactly once with READ_ONCE(), pairing with the WRITE_ONCE() in device_set_driver(). Link: https://lore.kernel.org/driver-core/DHW8QPU1VU1F.3P6PH69HLFBYC@kernel.org/ Fixes: ac338acf514e ("driver core: Add dev_has_sync_state()") Reviewed-by: Rafael J. Wysocki (Intel) <rafael(a)kernel.org> Acked-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org> Reviewed-by: Saravana Kannan <saravanak(a)kernel.org> Link: https://patch.msgid.link/20260418162221.1121873-1-dakr@kernel.org Signed-off-by: Danilo Krummrich <dakr(a)kernel.org> Signed-off-by: Sasha Levin <sashal(a)kernel.org> Signed-off-by: Lin Ruifeng <linruifeng4(a)huawei.com> --- include/linux/device.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/linux/device.h b/include/linux/device.h index 65dac0c81e47..863d943715cc 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -894,9 +894,12 @@ static inline struct device_node *dev_of_node(struct device *dev) static inline bool dev_has_sync_state(struct device *dev) { + struct device_driver *drv; + if (!dev) return false; - if (dev->driver && dev->driver->sync_state) + drv = READ_ONCE(dev->driver); + if (drv && drv->sync_state) return true; if (dev->bus && dev->bus->sync_state) return true; -- 2.34.1
2 1
0 0
[PATCH OLK-6.6] dmaengine: idxd: fix double free of wq, engine, and group structs
by Lin Ruifeng 01 Sep '26

01 Sep '26
From: Yuho Choi <dbgh9129(a)gmail.com> stable inclusion from stable-v7.1.8 commit c93a9f652b7373ac8ee5bfcc18a9af76959b6c6c category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18548 CVE: CVE-2026-80698 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- [ Upstream commit ec2d428b2e32dd157de8f86a86dd85c5b2c8f45c ] The release callbacks for wq, engine, and group devices (idxd_conf_wq_release, idxd_conf_engine_release, idxd_conf_group_release) each call kfree() on the enclosing struct. The setup error paths and cleanup functions also call kfree() explicitly after put_device(), producing a double free whenever put_device() drops the reference count to zero and fires the release. In the setup functions, device_initialize() is called before device_add(), so the reference count is exactly 1 at the error sites. put_device() unconditionally fires the release, which frees the struct; the subsequent explicit kfree() then operates on freed memory. For idxd_setup_wqs(), the wq release callback also owns opcap_bmap and wqcfg. The error unwind additionally freed those fields explicitly before calling put_device(), causing further double frees on both. Remove the redundant explicit kfree() calls from all setup error paths and cleanup functions for wq, engine, and group structs, delegating sole ownership of those allocations to the release callbacks. Fixes: 7c5dd23e57c1 ("dmaengine: idxd: fix wq conf_dev 'struct device' lifetime") Fixes: 75b911309060 ("dmaengine: idxd: fix engine conf_dev lifetime") Fixes: defe49f96012 ("dmaengine: idxd: fix group conf_dev lifetime") Signed-off-by: Yuho Choi <dbgh9129(a)gmail.com> Acked-by: Vinicius Costa Gomes <vinicius.gomes(a)intel.com> Reviewed-by: Frank Li <Frank.Li(a)nxp.com> Link: https://patch.msgid.link/20260415205452.67155-1-dbgh9129@gmail.com Signed-off-by: Vinod Koul <vkoul(a)kernel.org> Signed-off-by: Sasha Levin <sashal(a)kernel.org> Signed-off-by: Lin Ruifeng <linruifeng4(a)huawei.com> --- drivers/dma/idxd/init.c | 36 +++++------------------------------- 1 file changed, 5 insertions(+), 31 deletions(-) diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index 624a47b64bb4..eaa0523a41ed 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -150,18 +150,12 @@ static void idxd_cleanup_interrupts(struct idxd_device *idxd) static void idxd_clean_wqs(struct idxd_device *idxd) { - struct idxd_wq *wq; struct device *conf_dev; int i; for (i = 0; i < idxd->max_wqs; i++) { - wq = idxd->wqs[i]; - if (idxd->hw.wq_cap.op_config) - bitmap_free(wq->opcap_bmap); - kfree(wq->wqcfg); - conf_dev = wq_confdev(wq); + conf_dev = wq_confdev(idxd->wqs[i]); put_device(conf_dev); - kfree(wq); } bitmap_free(idxd->wq_enable_map); kfree(idxd->wqs); @@ -203,7 +197,6 @@ static int idxd_setup_wqs(struct idxd_device *idxd) rc = dev_set_name(conf_dev, "wq%d.%d", idxd->id, wq->id); if (rc < 0) { put_device(conf_dev); - kfree(wq); goto err_unwind; } @@ -217,7 +210,6 @@ static int idxd_setup_wqs(struct idxd_device *idxd) wq->wqcfg = kzalloc_node(idxd->wqcfg_size, GFP_KERNEL, dev_to_node(dev)); if (!wq->wqcfg) { put_device(conf_dev); - kfree(wq); rc = -ENOMEM; goto err_unwind; } @@ -225,9 +217,7 @@ static int idxd_setup_wqs(struct idxd_device *idxd) if (idxd->hw.wq_cap.op_config) { wq->opcap_bmap = bitmap_zalloc(IDXD_MAX_OPCAP_BITS, GFP_KERNEL); if (!wq->opcap_bmap) { - kfree(wq->wqcfg); put_device(conf_dev); - kfree(wq); rc = -ENOMEM; goto err_unwind; } @@ -242,13 +232,8 @@ static int idxd_setup_wqs(struct idxd_device *idxd) err_unwind: while (--i >= 0) { - wq = idxd->wqs[i]; - if (idxd->hw.wq_cap.op_config) - bitmap_free(wq->opcap_bmap); - kfree(wq->wqcfg); - conf_dev = wq_confdev(wq); + conf_dev = wq_confdev(idxd->wqs[i]); put_device(conf_dev); - kfree(wq); } bitmap_free(idxd->wq_enable_map); @@ -260,15 +245,12 @@ static int idxd_setup_wqs(struct idxd_device *idxd) static void idxd_clean_engines(struct idxd_device *idxd) { - struct idxd_engine *engine; struct device *conf_dev; int i; for (i = 0; i < idxd->max_engines; i++) { - engine = idxd->engines[i]; - conf_dev = engine_confdev(engine); + conf_dev = engine_confdev(idxd->engines[i]); put_device(conf_dev); - kfree(engine); } kfree(idxd->engines); } @@ -303,7 +285,6 @@ static int idxd_setup_engines(struct idxd_device *idxd) rc = dev_set_name(conf_dev, "engine%d.%d", idxd->id, engine->id); if (rc < 0) { put_device(conf_dev); - kfree(engine); goto err; } @@ -314,10 +295,8 @@ static int idxd_setup_engines(struct idxd_device *idxd) err: while (--i >= 0) { - engine = idxd->engines[i]; - conf_dev = engine_confdev(engine); + conf_dev = engine_confdev(idxd->engines[i]); put_device(conf_dev); - kfree(engine); } kfree(idxd->engines); @@ -326,13 +305,10 @@ static int idxd_setup_engines(struct idxd_device *idxd) static void idxd_clean_groups(struct idxd_device *idxd) { - struct idxd_group *group; int i; for (i = 0; i < idxd->max_groups; i++) { - group = idxd->groups[i]; - put_device(group_confdev(group)); - kfree(group); + put_device(group_confdev(idxd->groups[i])); } kfree(idxd->groups); } @@ -367,7 +343,6 @@ static int idxd_setup_groups(struct idxd_device *idxd) rc = dev_set_name(conf_dev, "group%d.%d", idxd->id, group->id); if (rc < 0) { put_device(conf_dev); - kfree(group); goto err; } @@ -392,7 +367,6 @@ static int idxd_setup_groups(struct idxd_device *idxd) while (--i >= 0) { group = idxd->groups[i]; put_device(group_confdev(group)); - kfree(group); } kfree(idxd->groups); -- 2.34.1
2 1
0 0
[PATCH OLK-5.10] entry: Fix seccomp bypass after ptrace with TSYNC
by Jinjie Ruan 01 Sep '26

01 Sep '26
mainline inclusion from mainline-v7.3-rc1 commit 4a3591287fb7f808e209b4974ed337f609a2006b category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18562 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- Sashiko review pointed out the following issue. If a thread is stopped in syscall_trace_enter() for ptrace, another thread can install a seccomp filter with SECCOMP_FILTER_FLAG_TSYNC (e.g., via seccomp_attach_filter()). This will successfully set SYSCALL_WORK_SECCOMP on the stopped thread, but syscall_trace_enter() evaluates a cached 'work' variable sampled on entry. Consequently, the subsequent check for SYSCALL_WORK_SECCOMP misses the newly assigned flag, and the filter is silently bypassed. This race condition could allow an unprivileged process to execute a prohibited system call (e.g., execve) that the newly installed filter was intended to block, especially since the tracer might have modified the system call number during the ptrace stop. Fix this by re-reading the syscall_work flags after ptrace handling, so that any new SYSCALL_WORK_SECCOMP flag set by another thread via TSYNC during the ptrace stop is observed before the subsequent seccomp check. Fixes: 142781e108b1 ("entry: Provide generic syscall entry functionality") Signed-off-by: Jinjie Ruan <ruanjinjie(a)huawei.com> Signed-off-by: Thomas Gleixner <tglx(a)kernel.org> Cc: stable(a)vger.kernel.org Link: https://lore.kernel.org/all/20260629132914.1135C1F000E9@smtp.kernel.org/ Link: https://patch.msgid.link/20260713025712.416366-1-ruanjinjie@huawei.com Conflicts: include/linux/entry-common.h [Context and rework conflict. ] Signed-off-by: Jinjie Ruan <ruanjinjie(a)huawei.com> --- kernel/entry/common.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/entry/common.c b/kernel/entry/common.c index b3690d7ea3cb..5706a8f2e90c 100644 --- a/kernel/entry/common.c +++ b/kernel/entry/common.c @@ -51,6 +51,9 @@ static long syscall_trace_enter(struct pt_regs *regs, long syscall, ret = arch_syscall_enter_tracehook(regs); if (ret || (ti_work & _TIF_SYSCALL_EMU)) return -1L; + + /* ptrace might have changed work flags */ + ti_work = READ_ONCE(current_thread_info()->flags); } /* Do seccomp after ptrace, to catch any tracer changes. */ -- 2.34.1
2 1
0 0
[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
  • ← Newer
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • ...
  • 2460
  • Older →

HyperKitty Powered by HyperKitty