* [PATCH v3 0/3] LoongArch: KVM: Harden interrupt injection
@ 2026-06-29 2:32 Bibo Mao
2026-06-29 2:32 ` [PATCH v3 1/3] LoongArch: KVM: Set default MAILBOX access size with 8 Bibo Mao
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Bibo Mao @ 2026-06-29 2:32 UTC (permalink / raw)
To: Huacai Chen; +Cc: kvm, loongarch, linux-kernel
API kvm_vcpu_ioctl_interrupt() is mainly to used to deliver interrupt
from user mode, and internal APIs kvm_queue_irq() and kvm_dequeue_irq()
are used in kernel mode, also moves IPI interrupt handling within lock
protection.
Also this patch replaces kvm_err() with WARN_ONCE() to avoid noise
kernel log.
---
v2 ... v3:
1. Split the patches into three smaller ones, the first patch removes
old default case and kvm_err() since it is impossible to happen.
And the second patch replaces kvm_err() with WARN_ONCE().
v1 ... v2:
1. Add border check with ipnum in eiointc_set_sw_coreisr() and
eiointc_update_irq(), so that injected interrupt vector is valid.
2. Move IPI inject and ack within lock to avoid contention in
ipi_set() and ipi_clear().
3. Add kvm_arch_irqchip_in_kernel() check in user mode irq injection
in function kvm_vcpu_ioctl_interrupt(), contention of user mode irq
injection is assured from user mode VMM.
---
Bibo Mao (3):
LoongArch: KVM: Set default MAILBOX access size with 8
LoongArch: KVM: Replace kvm_err() with WARN_ONCE()
LoongArch: KVM: Use internal API to deliver interrupt in kernel mode
arch/loongarch/kvm/exit.c | 15 ++++-----
arch/loongarch/kvm/intc/dmsintc.c | 15 +++++----
arch/loongarch/kvm/intc/eiointc.c | 32 ++++++++++--------
arch/loongarch/kvm/intc/ipi.c | 55 ++++++++++++++-----------------
arch/loongarch/kvm/intc/pch_pic.c | 12 +++----
arch/loongarch/kvm/vcpu.c | 5 ++-
6 files changed, 67 insertions(+), 67 deletions(-)
base-commit: dc59e4fea9d83f03bad6bddf3fa2e52491777482
--
2.39.3
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH v3 1/3] LoongArch: KVM: Set default MAILBOX access size with 8 2026-06-29 2:32 [PATCH v3 0/3] LoongArch: KVM: Harden interrupt injection Bibo Mao @ 2026-06-29 2:32 ` Bibo Mao 2026-06-29 2:45 ` sashiko-bot 2026-06-29 2:32 ` [PATCH v3 2/3] LoongArch: KVM: Replace kvm_err() with WARN_ONCE() Bibo Mao 2026-06-29 2:32 ` [PATCH v3 3/3] LoongArch: KVM: Use internal API to deliver interrupt in kernel mode Bibo Mao 2 siblings, 1 reply; 8+ messages in thread From: Bibo Mao @ 2026-06-29 2:32 UTC (permalink / raw) To: Huacai Chen; +Cc: kvm, loongarch, linux-kernel With IOCSR instruction emulation in function kvm_emu_iocsr(), the possible size combination is 1/2/4/8 and no other combinations. Here remove the old default case and replace the default case with 8 in read_mailbox() and write_mailbox(). Signed-off-by: Bibo Mao <maobibo@loongson.cn> --- arch/loongarch/kvm/intc/ipi.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/arch/loongarch/kvm/intc/ipi.c b/arch/loongarch/kvm/intc/ipi.c index 4fa0897d7bdb..d70bf415c7fc 100644 --- a/arch/loongarch/kvm/intc/ipi.c +++ b/arch/loongarch/kvm/intc/ipi.c @@ -67,11 +67,8 @@ static uint64_t read_mailbox(struct kvm_vcpu *vcpu, int offset, int len) return data & 0xffff; case 4: return data & 0xffffffff; - case 8: - return data; default: - kvm_err("%s: unknown data len: %d\n", __func__, len); - return 0; + return data; } } @@ -92,11 +89,9 @@ static void write_mailbox(struct kvm_vcpu *vcpu, int offset, uint64_t data, int case 4: *(unsigned int *)pbuf = (unsigned int)data; break; - case 8: + default: *(unsigned long *)pbuf = (unsigned long)data; break; - default: - kvm_err("%s: unknown data len: %d\n", __func__, len); } spin_unlock(&vcpu->arch.ipi_state.lock); } -- 2.39.3 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v3 1/3] LoongArch: KVM: Set default MAILBOX access size with 8 2026-06-29 2:32 ` [PATCH v3 1/3] LoongArch: KVM: Set default MAILBOX access size with 8 Bibo Mao @ 2026-06-29 2:45 ` sashiko-bot 0 siblings, 0 replies; 8+ messages in thread From: sashiko-bot @ 2026-06-29 2:45 UTC (permalink / raw) To: Bibo Mao; +Cc: kvm Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: New issues: - [High] Guest-triggerable Host Denial of Service via WARN_ONCE assertions. Pre-existing issues: - [High] Guest-triggerable Host Denial of Service via WARN_ON_ONCE on unaligned IOCSR access. - [High] Slab-Out-Of-Bounds memory read in `read_mailbox()` causes KASAN panic. -- commit cd8b88f78bdc2b7a47541c3fb91dfaf558c8c761 Author: Bibo Mao <maobibo@loongson.cn> Date: Mon Jun 29 02:32:11 2026 +0000 LoongArch: KVM: Set default MAILBOX access size with 8 With IOCSR instruction emulation in function kvm_emu_iocsr(), the possible size combination is 1/2/4/8 and no other combinations. Here remove the old default case and replace the default case with 8 in read_mailbox() and write_mailbox(). Signed-off-by: Bibo Mao <maobibo@loongson.cn> > diff --git a/arch/loongarch/kvm/intc/ipi.c b/arch/loongarch/kvm/intc/ipi.c > index 4fa0897d7bdb0..d70bf415c7fc6 100644 > --- a/arch/loongarch/kvm/intc/ipi.c > +++ b/arch/loongarch/kvm/intc/ipi.c > @@ -67,11 +67,8 @@ static uint64_t read_mailbox(struct kvm_vcpu *vcpu, int offset, int len) > return data & 0xffff; > case 4: > return data & 0xffffffff; > - case 8: > - return data; > default: > - kvm_err("%s: unknown data len: %d\n", __func__, len); > - return 0; > + return data; > } > } [Severity: High] This is a pre-existing issue, but does read_mailbox() unconditionally read 8 bytes from the buffer, exceeding the 32-byte bounds if the requested offset and length approach the end of the allowed range (e.g., offset 0x3c with length 4)? Looking at read_mailbox(): arch/loongarch/kvm/intc/ipi.c:read_mailbox() { ... spin_lock(&vcpu->arch.ipi_state.lock); data = *(ulong *)((void *)vcpu->arch.ipi_state.buf + (offset - 0x20)); spin_unlock(&vcpu->arch.ipi_state.lock); ... A guest performing a valid 4-byte IOCSR read at offset 0x3c causes read_mailbox() to calculate the array index as 0x1c (28). Dereferencing an 8-byte ulong pointer from this index within the 32-byte vcpu->arch.ipi_state.buf array reads bytes 28 through 35, where bytes 32-35 fall outside the bounds of the array into adjacent fields in struct kvm_vcpu_arch. Could this out-of-bounds memory read trigger a KASAN panic, causing a host denial of service? [Severity: High] This is a pre-existing issue, but can an unprivileged guest trigger a host denial of service via WARN_ON_ONCE on unaligned IOCSR access? Looking at loongarch_ipi_readl() and loongarch_ipi_writel(): arch/loongarch/kvm/intc/ipi.c:loongarch_ipi_readl() { ... offset = (uint32_t)(addr & 0x1ff); WARN_ON_ONCE(offset & (len - 1)); ... If a guest executes an IOCSR instruction with an unaligned address (e.g., iocsrrd.w at address 0x1001), the hardware/emulated offset is calculated as addr & 0x1ff, which will be unaligned. This causes the WARN_ON_ONCE(offset & (len - 1)) assertion to fire, which can panic the host kernel if panic_on_warn is enabled. [Severity: High] While the intention may have been to reduce log spam by replacing kvm_err() with WARN_ONCE(), does this inadvertently create a denial of service vector? Looking at mail_send() in arch/loongarch/kvm/intc/ipi.c: arch/loongarch/kvm/intc/ipi.c:mail_send() { ... if (unlikely(vcpu == NULL)) { WARN_ONCE(1, "%s: invalid target cpu: %d\n", __func__, cpu); return 0; } ... And in kvm_complete_iocsr_read() in arch/loongarch/kvm/exit.c: arch/loongarch/kvm/exit.c:kvm_complete_iocsr_read() { ... default: WARN_ONCE(1, "Bad IOCSR length: %d, addr is 0x%lx\n", run->iocsr_io.len, vcpu->arch.badv); er = EMULATE_FAIL; ... An unprivileged guest can deliberately provide invalid inputs (e.g., an unknown IOCSR address, an invalid target CPU ID for a mailbox send, or an unsupported MMIO length). This causes the emulation handlers to hit these WARN_ONCE() macros. Could this allow a malicious guest to trigger a kernel panic if panic_on_warn is enabled? -- Sashiko AI review · https://sashiko.dev/#/patchset/20260629023213.597030-1-maobibo@loongson.cn?part=1 ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v3 2/3] LoongArch: KVM: Replace kvm_err() with WARN_ONCE() 2026-06-29 2:32 [PATCH v3 0/3] LoongArch: KVM: Harden interrupt injection Bibo Mao 2026-06-29 2:32 ` [PATCH v3 1/3] LoongArch: KVM: Set default MAILBOX access size with 8 Bibo Mao @ 2026-06-29 2:32 ` Bibo Mao 2026-06-29 2:37 ` sashiko-bot 2026-06-30 4:27 ` Huacai Chen 2026-06-29 2:32 ` [PATCH v3 3/3] LoongArch: KVM: Use internal API to deliver interrupt in kernel mode Bibo Mao 2 siblings, 2 replies; 8+ messages in thread From: Bibo Mao @ 2026-06-29 2:32 UTC (permalink / raw) To: Huacai Chen; +Cc: kvm, loongarch, linux-kernel Since guest kernel and ioctl parameter from user mode is untrusted, there may be noise kernel log output in host hypervisor with abnormal state. Here replace kvm_err() with WARN_ONCE() to reduce this kind of noise kernel log, and there is no function change. Signed-off-by: Bibo Mao <maobibo@loongson.cn> --- arch/loongarch/kvm/exit.c | 15 +++++++-------- arch/loongarch/kvm/intc/dmsintc.c | 8 ++++---- arch/loongarch/kvm/intc/eiointc.c | 18 ++++++++--------- arch/loongarch/kvm/intc/ipi.c | 32 +++++++++++++++---------------- arch/loongarch/kvm/intc/pch_pic.c | 12 ++++++------ arch/loongarch/kvm/vcpu.c | 2 +- 6 files changed, 43 insertions(+), 44 deletions(-) diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c index 8572b63478bb..4ad006e27a4d 100644 --- a/arch/loongarch/kvm/exit.c +++ b/arch/loongarch/kvm/exit.c @@ -252,7 +252,7 @@ int kvm_complete_iocsr_read(struct kvm_vcpu *vcpu, struct kvm_run *run) *gpr = *(s64 *)run->iocsr_io.data; break; default: - kvm_err("Bad IOCSR length: %d, addr is 0x%lx\n", + WARN_ONCE(1, "Bad IOCSR length: %d, addr is 0x%lx\n", run->iocsr_io.len, vcpu->arch.badv); er = EMULATE_FAIL; break; @@ -326,7 +326,7 @@ static int kvm_trap_handle_gspr(struct kvm_vcpu *vcpu) /* Rollback PC only if emulation was unsuccessful */ if (er == EMULATE_FAIL) { - kvm_err("[%#lx]%s: unsupported gspr instruction 0x%08x\n", + WARN_ONCE(1, "[%#lx]%s: unsupported gspr instruction 0x%08x\n", curr_pc, __func__, inst.word); kvm_arch_vcpu_dump_regs(vcpu); @@ -491,7 +491,7 @@ int kvm_emu_mmio_read(struct kvm_vcpu *vcpu, larch_inst inst) return EMULATE_DO_MMIO; } - kvm_err("Read not supported Inst=0x%08x @%lx BadVaddr:%#lx\n", + WARN_ONCE(1, "Read not supported Inst=0x%08x @%lx BadVaddr:%#lx\n", inst.word, vcpu->arch.pc, vcpu->arch.badv); kvm_arch_vcpu_dump_regs(vcpu); vcpu->mmio_needed = 0; @@ -529,7 +529,7 @@ int kvm_complete_mmio_read(struct kvm_vcpu *vcpu, struct kvm_run *run) *gpr = *(s64 *)run->mmio.data; break; default: - kvm_err("Bad MMIO length: %d, addr is 0x%lx\n", + WARN_ONCE(1, "Bad MMIO length: %d, addr is 0x%lx\n", run->mmio.len, vcpu->arch.badv); er = EMULATE_FAIL; break; @@ -656,7 +656,7 @@ int kvm_emu_mmio_write(struct kvm_vcpu *vcpu, larch_inst inst) } vcpu->arch.pc = curr_pc; - kvm_err("Write not supported Inst=0x%08x @%lx BadVaddr:%#lx\n", + WARN_ONCE(1, "Write not supported Inst=0x%08x @%lx BadVaddr:%#lx\n", inst.word, vcpu->arch.pc, vcpu->arch.badv); kvm_arch_vcpu_dump_regs(vcpu); /* Rollback PC if emulation was unsuccessful */ @@ -748,8 +748,7 @@ static int kvm_handle_fpu_disabled(struct kvm_vcpu *vcpu, int ecode) * treated as a reserved instruction! * If FPU already in use, we shouldn't get this at all. */ - if (WARN_ON(vcpu->arch.aux_inuse & KVM_LARCH_FPU)) { - kvm_err("%s internal error\n", __func__); + if (WARN_ON_ONCE(vcpu->arch.aux_inuse & KVM_LARCH_FPU)) { run->exit_reason = KVM_EXIT_INTERNAL_ERROR; return RESUME_HOST; } @@ -943,7 +942,7 @@ static int kvm_fault_ni(struct kvm_vcpu *vcpu, int ecode) /* Fetch the instruction */ inst = vcpu->arch.badi; badv = vcpu->arch.badv; - kvm_err("ECode: %d PC=%#lx Inst=0x%08x BadVaddr=%#lx ESTAT=%#lx\n", + WARN_ONCE(1, "ECode: %d PC=%#lx Inst=0x%08x BadVaddr=%#lx ESTAT=%#lx\n", ecode, vcpu->arch.pc, inst, badv, read_gcsr_estat()); kvm_arch_vcpu_dump_regs(vcpu); kvm_queue_exception(vcpu, EXCCODE_INE, 0); diff --git a/arch/loongarch/kvm/intc/dmsintc.c b/arch/loongarch/kvm/intc/dmsintc.c index de25735ce039..708abbcd55bf 100644 --- a/arch/loongarch/kvm/intc/dmsintc.c +++ b/arch/loongarch/kvm/intc/dmsintc.c @@ -114,7 +114,7 @@ static int kvm_dmsintc_ctrl_access(struct kvm_device *dev, } break; default: - kvm_err("%s: unknown dmsintc register, addr = %d\n", __func__, addr); + WARN_ONCE(1, "%s: unknown dmsintc register, addr = %d\n", __func__, addr); return -ENXIO; } @@ -128,7 +128,7 @@ static int kvm_dmsintc_set_attr(struct kvm_device *dev, case KVM_DEV_LOONGARCH_DMSINTC_GRP_CTRL: return kvm_dmsintc_ctrl_access(dev, attr, true); default: - kvm_err("%s: unknown group (%d)\n", __func__, attr->group); + WARN_ONCE(1, "%s: unknown group (%d)\n", __func__, attr->group); return -EINVAL; } } @@ -139,13 +139,13 @@ static int kvm_dmsintc_create(struct kvm_device *dev, u32 type) struct loongarch_dmsintc *s; if (!dev) { - kvm_err("%s: kvm_device ptr is invalid!\n", __func__); + WARN_ONCE(1, "%s: kvm_device ptr is invalid!\n", __func__); return -EINVAL; } kvm = dev->kvm; if (kvm->arch.dmsintc) { - kvm_err("%s: LoongArch DMSINTC has already been created!\n", __func__); + WARN_ONCE(1, "%s: LoongArch DMSINTC has already been created!\n", __func__); return -EINVAL; } diff --git a/arch/loongarch/kvm/intc/eiointc.c b/arch/loongarch/kvm/intc/eiointc.c index 2b14485d14a7..555e55246f0c 100644 --- a/arch/loongarch/kvm/intc/eiointc.c +++ b/arch/loongarch/kvm/intc/eiointc.c @@ -47,7 +47,7 @@ static void eiointc_update_irq(struct loongarch_eiointc *s, int irq, int level) cpu = s->sw_coremap[irq]; vcpu = kvm_get_vcpu_by_id(s->kvm, cpu); if (unlikely(vcpu == NULL)) { - kvm_err("%s: invalid target cpu: %d\n", __func__, cpu); + WARN_ONCE(1, "%s: invalid target cpu: %d\n", __func__, cpu); return; } @@ -165,12 +165,12 @@ static int kvm_eiointc_read(struct kvm_vcpu *vcpu, struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc; if (!eiointc) { - kvm_err("%s: eiointc irqchip not valid!\n", __func__); + WARN_ONCE(1, "%s: eiointc irqchip not valid!\n", __func__); return 0; } if (addr & (len - 1)) { - kvm_err("%s: eiointc not aligned addr %llx len %d\n", __func__, addr, len); + WARN_ONCE(1, "%s: eiointc not aligned addr %llx len %d\n", __func__, addr, len); return 0; } @@ -297,12 +297,12 @@ static int kvm_eiointc_write(struct kvm_vcpu *vcpu, struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc; if (!eiointc) { - kvm_err("%s: eiointc irqchip not valid!\n", __func__); + WARN_ONCE(1, "%s: eiointc irqchip not valid!\n", __func__); return 0; } if (addr & (len - 1)) { - kvm_err("%s: eiointc not aligned addr %llx len %d\n", __func__, addr, len); + WARN_ONCE(1, "%s: eiointc not aligned addr %llx len %d\n", __func__, addr, len); return 0; } @@ -345,7 +345,7 @@ static int kvm_eiointc_virt_read(struct kvm_vcpu *vcpu, struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc; if (!eiointc) { - kvm_err("%s: eiointc irqchip not valid!\n", __func__); + WARN_ONCE(1, "%s: eiointc irqchip not valid!\n", __func__); return 0; } @@ -375,7 +375,7 @@ static int kvm_eiointc_virt_write(struct kvm_vcpu *vcpu, struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc; if (!eiointc) { - kvm_err("%s: eiointc irqchip not valid!\n", __func__); + WARN_ONCE(1, "%s: eiointc irqchip not valid!\n", __func__); return 0; } @@ -502,7 +502,7 @@ static int kvm_eiointc_regs_access(struct kvm_device *dev, p = (void *)s->coremap + offset * 4; break; default: - kvm_err("%s: unknown eiointc register, addr = %d\n", __func__, addr); + WARN_ONCE(1, "%s: unknown eiointc register, addr = %d\n", __func__, addr); return -EINVAL; } @@ -546,7 +546,7 @@ static int kvm_eiointc_sw_status_access(struct kvm_device *dev, p = &s->status; break; default: - kvm_err("%s: unknown eiointc register, addr = %d\n", __func__, addr); + WARN_ONCE(1, "%s: unknown eiointc register, addr = %d\n", __func__, addr); return -EINVAL; } spin_lock_irqsave(&s->lock, flags); diff --git a/arch/loongarch/kvm/intc/ipi.c b/arch/loongarch/kvm/intc/ipi.c index d70bf415c7fc..8d9dacfc1b15 100644 --- a/arch/loongarch/kvm/intc/ipi.c +++ b/arch/loongarch/kvm/intc/ipi.c @@ -30,7 +30,7 @@ static void ipi_send(struct kvm *kvm, uint64_t data) cpu = ((data & 0xffffffff) >> 16) & 0x3ff; vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu); if (unlikely(vcpu == NULL)) { - kvm_err("%s: invalid target cpu: %d\n", __func__, cpu); + WARN_ONCE(1, "%s: invalid target cpu: %d\n", __func__, cpu); return; } @@ -105,7 +105,7 @@ static int mail_send(struct kvm *kvm, uint64_t data) cpu = ((data & 0xffffffff) >> 16) & 0x3ff; vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu); if (unlikely(vcpu == NULL)) { - kvm_err("%s: invalid target cpu: %d\n", __func__, cpu); + WARN_ONCE(1, "%s: invalid target cpu: %d\n", __func__, cpu); return 0; } mailbox = ((data & 0xffffffff) >> 2) & 0x7; @@ -139,7 +139,7 @@ static int send_ipi_data(struct kvm_vcpu *vcpu, gpa_t addr, uint64_t data) ret = kvm_io_bus_read(vcpu, KVM_IOCSR_BUS, addr, 4, &val); srcu_read_unlock(&vcpu->kvm->srcu, idx); if (unlikely(ret)) { - kvm_err("%s: : read data from addr %llx failed\n", __func__, addr); + WARN_ONCE(1, "%s: : read data from addr %llx failed\n", __func__, addr); return 0; } /* Construct the mask by scanning the bit 27-30 */ @@ -155,7 +155,7 @@ static int send_ipi_data(struct kvm_vcpu *vcpu, gpa_t addr, uint64_t data) ret = kvm_io_bus_write(vcpu, KVM_IOCSR_BUS, addr, 4, &val); srcu_read_unlock(&vcpu->kvm->srcu, idx); if (unlikely(ret)) - kvm_err("%s: : write data to addr %llx failed\n", __func__, addr); + WARN_ONCE(1, "%s: : write data to addr %llx failed\n", __func__, addr); return 0; } @@ -168,7 +168,7 @@ static int any_send(struct kvm *kvm, uint64_t data) cpu = ((data & 0xffffffff) >> 16) & 0x3ff; vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu); if (unlikely(vcpu == NULL)) { - kvm_err("%s: invalid target cpu: %d\n", __func__, cpu); + WARN_ONCE(1, "%s: invalid target cpu: %d\n", __func__, cpu); return 0; } offset = data & 0xffff; @@ -200,14 +200,14 @@ static int loongarch_ipi_readl(struct kvm_vcpu *vcpu, gpa_t addr, int len, void break; case IOCSR_IPI_BUF_20 ... IOCSR_IPI_BUF_38 + 7: if (offset + len > IOCSR_IPI_BUF_38 + 8) { - kvm_err("%s: invalid offset or len: offset = %d, len = %d\n", + WARN_ONCE(1, "%s: invalid offset or len: offset = %d, len = %d\n", __func__, offset, len); break; } res = read_mailbox(vcpu, offset, len); break; default: - kvm_err("%s: unknown addr: %llx\n", __func__, addr); + WARN_ONCE(1, "%s: unknown addr: %llx\n", __func__, addr); break; } *(uint64_t *)val = res; @@ -242,7 +242,7 @@ static int loongarch_ipi_writel(struct kvm_vcpu *vcpu, gpa_t addr, int len, cons break; case IOCSR_IPI_BUF_20 ... IOCSR_IPI_BUF_38 + 7: if (offset + len > IOCSR_IPI_BUF_38 + 8) { - kvm_err("%s: invalid offset or len: offset = %d, len = %d\n", + WARN_ONCE(1, "%s: invalid offset or len: offset = %d, len = %d\n", __func__, offset, len); break; } @@ -258,7 +258,7 @@ static int loongarch_ipi_writel(struct kvm_vcpu *vcpu, gpa_t addr, int len, cons any_send(vcpu->kvm, data); break; default: - kvm_err("%s: unknown addr: %llx\n", __func__, addr); + WARN_ONCE(1, "%s: unknown addr: %llx\n", __func__, addr); break; } @@ -301,7 +301,7 @@ static int kvm_ipi_regs_access(struct kvm_device *dev, vcpu = kvm_get_vcpu_by_id(dev->kvm, cpu); if (unlikely(vcpu == NULL)) { - kvm_err("%s: invalid target cpu: %d\n", __func__, cpu); + WARN_ONCE(1, "%s: invalid target cpu: %d\n", __func__, cpu); return -EINVAL; } @@ -335,7 +335,7 @@ static int kvm_ipi_regs_access(struct kvm_device *dev, len = 8; break; default: - kvm_err("%s: unknown ipi register, addr = %d\n", __func__, addr); + WARN_ONCE(1, "%s: unknown ipi register, addr = %d\n", __func__, addr); return -EINVAL; } @@ -369,7 +369,7 @@ static int kvm_ipi_get_attr(struct kvm_device *dev, case KVM_DEV_LOONGARCH_IPI_GRP_REGS: return kvm_ipi_regs_access(dev, attr, false); default: - kvm_err("%s: unknown group (%d)\n", __func__, attr->group); + WARN_ONCE(1, "%s: unknown group (%d)\n", __func__, attr->group); return -EINVAL; } } @@ -381,7 +381,7 @@ static int kvm_ipi_set_attr(struct kvm_device *dev, case KVM_DEV_LOONGARCH_IPI_GRP_REGS: return kvm_ipi_regs_access(dev, attr, true); default: - kvm_err("%s: unknown group (%d)\n", __func__, attr->group); + WARN_ONCE(1, "%s: unknown group (%d)\n", __func__, attr->group); return -EINVAL; } } @@ -394,13 +394,13 @@ static int kvm_ipi_create(struct kvm_device *dev, u32 type) struct loongarch_ipi *s; if (!dev) { - kvm_err("%s: kvm_device ptr is invalid!\n", __func__); + WARN_ONCE(1, "%s: kvm_device ptr is invalid!\n", __func__); return -EINVAL; } kvm = dev->kvm; if (kvm->arch.ipi) { - kvm_err("%s: LoongArch IPI has already been created!\n", __func__); + WARN_ONCE(1, "%s: LoongArch IPI has already been created!\n", __func__); return -EINVAL; } @@ -420,7 +420,7 @@ static int kvm_ipi_create(struct kvm_device *dev, u32 type) ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS, IOCSR_IPI_BASE, IOCSR_IPI_SIZE, device); mutex_unlock(&kvm->slots_lock); if (ret < 0) { - kvm_err("%s: Initialize IOCSR dev failed, ret = %d\n", __func__, ret); + WARN_ONCE(1, "%s: Initialize IOCSR dev failed, ret = %d\n", __func__, ret); goto err; } diff --git a/arch/loongarch/kvm/intc/pch_pic.c b/arch/loongarch/kvm/intc/pch_pic.c index 175a630aceb4..299b4db26833 100644 --- a/arch/loongarch/kvm/intc/pch_pic.c +++ b/arch/loongarch/kvm/intc/pch_pic.c @@ -151,12 +151,12 @@ static int kvm_pch_pic_read(struct kvm_vcpu *vcpu, struct loongarch_pch_pic *s = vcpu->kvm->arch.pch_pic; if (!s) { - kvm_err("%s: pch pic irqchip not valid!\n", __func__); + WARN_ONCE(1, "%s: pch pic irqchip not valid!\n", __func__); return ret; } if (addr & (len - 1)) { - kvm_err("%s: pch pic not aligned addr %llx len %d\n", __func__, addr, len); + WARN_ONCE(1, "%s: pch pic not aligned addr %llx len %d\n", __func__, addr, len); return ret; } @@ -250,12 +250,12 @@ static int kvm_pch_pic_write(struct kvm_vcpu *vcpu, struct loongarch_pch_pic *s = vcpu->kvm->arch.pch_pic; if (!s) { - kvm_err("%s: pch pic irqchip not valid!\n", __func__); + WARN_ONCE(1, "%s: pch pic irqchip not valid!\n", __func__); return ret; } if (addr & (len - 1)) { - kvm_err("%s: pch pic not aligned addr %llx len %d\n", __func__, addr, len); + WARN_ONCE(1, "%s: pch pic not aligned addr %llx len %d\n", __func__, addr, len); return ret; } @@ -390,13 +390,13 @@ static int kvm_pch_pic_set_attr(struct kvm_device *dev, return -EFAULT; if (!dev->kvm->arch.pch_pic) { - kvm_err("%s: please create pch_pic irqchip first!\n", __func__); + WARN_ONCE(1, "%s: please create pch_pic irqchip first\n", __func__); return -ENODEV; } return kvm_pch_pic_init(dev, addr); default: - kvm_err("%s: unknown group (%d) attr (%lld)\n", __func__, attr->group, + WARN_ONCE(1, "%s: unknown group (%d) attr (%lld)\n", __func__, attr->group, attr->attr); return -EINVAL; } diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c index 20c207d80e31..361fca46e2b3 100644 --- a/arch/loongarch/kvm/vcpu.c +++ b/arch/loongarch/kvm/vcpu.c @@ -1473,7 +1473,7 @@ int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) else if (intr < 0) kvm_dequeue_irq(vcpu, -intr); else { - kvm_err("%s: invalid interrupt ioctl %d\n", __func__, irq->irq); + WARN_ONCE(1, "%s: invalid interrupt ioctl %d\n", __func__, irq->irq); return -EINVAL; } -- 2.39.3 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v3 2/3] LoongArch: KVM: Replace kvm_err() with WARN_ONCE() 2026-06-29 2:32 ` [PATCH v3 2/3] LoongArch: KVM: Replace kvm_err() with WARN_ONCE() Bibo Mao @ 2026-06-29 2:37 ` sashiko-bot 2026-06-30 4:27 ` Huacai Chen 1 sibling, 0 replies; 8+ messages in thread From: sashiko-bot @ 2026-06-29 2:37 UTC (permalink / raw) To: Bibo Mao; +Cc: kvm Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Critical] Replacing `kvm_err()` with `WARN_ONCE()` on user- and guest-controllable error paths introduces a host Denial of Service (DoS) vulnerability. -- commit 2fb4171bf923d0f32f53ed0ef52aee506acd81c3 Author: Bibo Mao <maobibo@loongson.cn> LoongArch: KVM: Replace kvm_err() with WARN_ONCE() Since guest kernel and ioctl parameter from user mode is untrusted, there may be noise kernel log output in host hypervisor with abnormal state. Here replace kvm_err() with WARN_ONCE() to reduce this kind of noise kernel log, and there is no function change. > diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c > --- a/arch/loongarch/kvm/exit.c > +++ b/arch/loongarch/kvm/exit.c > @@ -252,7 +252,7 @@ int kvm_complete_iocsr_read(struct kvm_vcpu *vcpu, struct kvm_run *run) > *gpr = *(s64 *)run->iocsr_io.data; > break; > default: > - kvm_err("Bad IOCSR length: %d, addr is 0x%lx\n", > + WARN_ONCE(1, "Bad IOCSR length: %d, addr is 0x%lx\n", > run->iocsr_io.len, vcpu->arch.badv); [Severity: Critical] Does changing this to a WARN_ONCE() introduce a host denial of service vector? A malicious guest executing an operation with a bad IOCSR length can trigger this path in kvm_complete_iocsr_read(). If the host system is configured with panic_on_warn=1, this allows an untrusted guest to crash the host. Could this be changed to pr_warn_once() or pr_err_ratelimited() instead to reduce the log spam without the risk of a kernel panic? [ ... ] > diff --git a/arch/loongarch/kvm/intc/dmsintc.c b/arch/loongarch/kvm/intc/dmsintc.c > --- a/arch/loongarch/kvm/intc/dmsintc.c > +++ b/arch/loongarch/kvm/intc/dmsintc.c > @@ -114,7 +114,7 @@ static int kvm_dmsintc_ctrl_access(struct kvm_device *dev, > } > break; > default: > - kvm_err("%s: unknown dmsintc register, addr = %d\n", __func__, addr); > + WARN_ONCE(1, "%s: unknown dmsintc register, addr = %d\n", __func__, addr); [Severity: Critical] Similarly here, can a host userspace process trigger this WARN_ONCE by passing an invalid address to KVM_SET_DEVICE_ATTR for the dmsintc device? This would allow an unprivileged host userspace process to crash the host if panic_on_warn=1 is set. [ ... ] > diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c > --- a/arch/loongarch/kvm/vcpu.c > +++ b/arch/loongarch/kvm/vcpu.c > @@ -1473,7 +1473,7 @@ int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) > else if (intr < 0) > kvm_dequeue_irq(vcpu, -intr); > else { > - kvm_err("%s: invalid interrupt ioctl %d\n", __func__, irq->irq); > + WARN_ONCE(1, "%s: invalid interrupt ioctl %d\n", __func__, irq->irq); [Severity: Critical] Does this also allow unprivileged userspace to trigger a warning via a bad interrupt ioctl parameter? -- Sashiko AI review · https://sashiko.dev/#/patchset/20260629023213.597030-1-maobibo@loongson.cn?part=2 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v3 2/3] LoongArch: KVM: Replace kvm_err() with WARN_ONCE() 2026-06-29 2:32 ` [PATCH v3 2/3] LoongArch: KVM: Replace kvm_err() with WARN_ONCE() Bibo Mao 2026-06-29 2:37 ` sashiko-bot @ 2026-06-30 4:27 ` Huacai Chen 1 sibling, 0 replies; 8+ messages in thread From: Huacai Chen @ 2026-06-30 4:27 UTC (permalink / raw) To: Bibo Mao; +Cc: kvm, loongarch, linux-kernel Hi, Bibo, On Mon, Jun 29, 2026 at 10:32 AM Bibo Mao <maobibo@loongson.cn> wrote: > > Since guest kernel and ioctl parameter from user mode is untrusted, > there may be noise kernel log output in host hypervisor with abnormal > state. Here replace kvm_err() with WARN_ONCE() to reduce this kind > of noise kernel log, and there is no function change. Maybe kvm_pr_unimpl() is a little better than WARN_ONCE()? At least it is a KVM API. Huacai > > Signed-off-by: Bibo Mao <maobibo@loongson.cn> > --- > arch/loongarch/kvm/exit.c | 15 +++++++-------- > arch/loongarch/kvm/intc/dmsintc.c | 8 ++++---- > arch/loongarch/kvm/intc/eiointc.c | 18 ++++++++--------- > arch/loongarch/kvm/intc/ipi.c | 32 +++++++++++++++---------------- > arch/loongarch/kvm/intc/pch_pic.c | 12 ++++++------ > arch/loongarch/kvm/vcpu.c | 2 +- > 6 files changed, 43 insertions(+), 44 deletions(-) > > diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c > index 8572b63478bb..4ad006e27a4d 100644 > --- a/arch/loongarch/kvm/exit.c > +++ b/arch/loongarch/kvm/exit.c > @@ -252,7 +252,7 @@ int kvm_complete_iocsr_read(struct kvm_vcpu *vcpu, struct kvm_run *run) > *gpr = *(s64 *)run->iocsr_io.data; > break; > default: > - kvm_err("Bad IOCSR length: %d, addr is 0x%lx\n", > + WARN_ONCE(1, "Bad IOCSR length: %d, addr is 0x%lx\n", > run->iocsr_io.len, vcpu->arch.badv); > er = EMULATE_FAIL; > break; > @@ -326,7 +326,7 @@ static int kvm_trap_handle_gspr(struct kvm_vcpu *vcpu) > > /* Rollback PC only if emulation was unsuccessful */ > if (er == EMULATE_FAIL) { > - kvm_err("[%#lx]%s: unsupported gspr instruction 0x%08x\n", > + WARN_ONCE(1, "[%#lx]%s: unsupported gspr instruction 0x%08x\n", > curr_pc, __func__, inst.word); > > kvm_arch_vcpu_dump_regs(vcpu); > @@ -491,7 +491,7 @@ int kvm_emu_mmio_read(struct kvm_vcpu *vcpu, larch_inst inst) > return EMULATE_DO_MMIO; > } > > - kvm_err("Read not supported Inst=0x%08x @%lx BadVaddr:%#lx\n", > + WARN_ONCE(1, "Read not supported Inst=0x%08x @%lx BadVaddr:%#lx\n", > inst.word, vcpu->arch.pc, vcpu->arch.badv); > kvm_arch_vcpu_dump_regs(vcpu); > vcpu->mmio_needed = 0; > @@ -529,7 +529,7 @@ int kvm_complete_mmio_read(struct kvm_vcpu *vcpu, struct kvm_run *run) > *gpr = *(s64 *)run->mmio.data; > break; > default: > - kvm_err("Bad MMIO length: %d, addr is 0x%lx\n", > + WARN_ONCE(1, "Bad MMIO length: %d, addr is 0x%lx\n", > run->mmio.len, vcpu->arch.badv); > er = EMULATE_FAIL; > break; > @@ -656,7 +656,7 @@ int kvm_emu_mmio_write(struct kvm_vcpu *vcpu, larch_inst inst) > } > > vcpu->arch.pc = curr_pc; > - kvm_err("Write not supported Inst=0x%08x @%lx BadVaddr:%#lx\n", > + WARN_ONCE(1, "Write not supported Inst=0x%08x @%lx BadVaddr:%#lx\n", > inst.word, vcpu->arch.pc, vcpu->arch.badv); > kvm_arch_vcpu_dump_regs(vcpu); > /* Rollback PC if emulation was unsuccessful */ > @@ -748,8 +748,7 @@ static int kvm_handle_fpu_disabled(struct kvm_vcpu *vcpu, int ecode) > * treated as a reserved instruction! > * If FPU already in use, we shouldn't get this at all. > */ > - if (WARN_ON(vcpu->arch.aux_inuse & KVM_LARCH_FPU)) { > - kvm_err("%s internal error\n", __func__); > + if (WARN_ON_ONCE(vcpu->arch.aux_inuse & KVM_LARCH_FPU)) { > run->exit_reason = KVM_EXIT_INTERNAL_ERROR; > return RESUME_HOST; > } > @@ -943,7 +942,7 @@ static int kvm_fault_ni(struct kvm_vcpu *vcpu, int ecode) > /* Fetch the instruction */ > inst = vcpu->arch.badi; > badv = vcpu->arch.badv; > - kvm_err("ECode: %d PC=%#lx Inst=0x%08x BadVaddr=%#lx ESTAT=%#lx\n", > + WARN_ONCE(1, "ECode: %d PC=%#lx Inst=0x%08x BadVaddr=%#lx ESTAT=%#lx\n", > ecode, vcpu->arch.pc, inst, badv, read_gcsr_estat()); > kvm_arch_vcpu_dump_regs(vcpu); > kvm_queue_exception(vcpu, EXCCODE_INE, 0); > diff --git a/arch/loongarch/kvm/intc/dmsintc.c b/arch/loongarch/kvm/intc/dmsintc.c > index de25735ce039..708abbcd55bf 100644 > --- a/arch/loongarch/kvm/intc/dmsintc.c > +++ b/arch/loongarch/kvm/intc/dmsintc.c > @@ -114,7 +114,7 @@ static int kvm_dmsintc_ctrl_access(struct kvm_device *dev, > } > break; > default: > - kvm_err("%s: unknown dmsintc register, addr = %d\n", __func__, addr); > + WARN_ONCE(1, "%s: unknown dmsintc register, addr = %d\n", __func__, addr); > return -ENXIO; > } > > @@ -128,7 +128,7 @@ static int kvm_dmsintc_set_attr(struct kvm_device *dev, > case KVM_DEV_LOONGARCH_DMSINTC_GRP_CTRL: > return kvm_dmsintc_ctrl_access(dev, attr, true); > default: > - kvm_err("%s: unknown group (%d)\n", __func__, attr->group); > + WARN_ONCE(1, "%s: unknown group (%d)\n", __func__, attr->group); > return -EINVAL; > } > } > @@ -139,13 +139,13 @@ static int kvm_dmsintc_create(struct kvm_device *dev, u32 type) > struct loongarch_dmsintc *s; > > if (!dev) { > - kvm_err("%s: kvm_device ptr is invalid!\n", __func__); > + WARN_ONCE(1, "%s: kvm_device ptr is invalid!\n", __func__); > return -EINVAL; > } > > kvm = dev->kvm; > if (kvm->arch.dmsintc) { > - kvm_err("%s: LoongArch DMSINTC has already been created!\n", __func__); > + WARN_ONCE(1, "%s: LoongArch DMSINTC has already been created!\n", __func__); > return -EINVAL; > } > > diff --git a/arch/loongarch/kvm/intc/eiointc.c b/arch/loongarch/kvm/intc/eiointc.c > index 2b14485d14a7..555e55246f0c 100644 > --- a/arch/loongarch/kvm/intc/eiointc.c > +++ b/arch/loongarch/kvm/intc/eiointc.c > @@ -47,7 +47,7 @@ static void eiointc_update_irq(struct loongarch_eiointc *s, int irq, int level) > cpu = s->sw_coremap[irq]; > vcpu = kvm_get_vcpu_by_id(s->kvm, cpu); > if (unlikely(vcpu == NULL)) { > - kvm_err("%s: invalid target cpu: %d\n", __func__, cpu); > + WARN_ONCE(1, "%s: invalid target cpu: %d\n", __func__, cpu); > return; > } > > @@ -165,12 +165,12 @@ static int kvm_eiointc_read(struct kvm_vcpu *vcpu, > struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc; > > if (!eiointc) { > - kvm_err("%s: eiointc irqchip not valid!\n", __func__); > + WARN_ONCE(1, "%s: eiointc irqchip not valid!\n", __func__); > return 0; > } > > if (addr & (len - 1)) { > - kvm_err("%s: eiointc not aligned addr %llx len %d\n", __func__, addr, len); > + WARN_ONCE(1, "%s: eiointc not aligned addr %llx len %d\n", __func__, addr, len); > return 0; > } > > @@ -297,12 +297,12 @@ static int kvm_eiointc_write(struct kvm_vcpu *vcpu, > struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc; > > if (!eiointc) { > - kvm_err("%s: eiointc irqchip not valid!\n", __func__); > + WARN_ONCE(1, "%s: eiointc irqchip not valid!\n", __func__); > return 0; > } > > if (addr & (len - 1)) { > - kvm_err("%s: eiointc not aligned addr %llx len %d\n", __func__, addr, len); > + WARN_ONCE(1, "%s: eiointc not aligned addr %llx len %d\n", __func__, addr, len); > return 0; > } > > @@ -345,7 +345,7 @@ static int kvm_eiointc_virt_read(struct kvm_vcpu *vcpu, > struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc; > > if (!eiointc) { > - kvm_err("%s: eiointc irqchip not valid!\n", __func__); > + WARN_ONCE(1, "%s: eiointc irqchip not valid!\n", __func__); > return 0; > } > > @@ -375,7 +375,7 @@ static int kvm_eiointc_virt_write(struct kvm_vcpu *vcpu, > struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc; > > if (!eiointc) { > - kvm_err("%s: eiointc irqchip not valid!\n", __func__); > + WARN_ONCE(1, "%s: eiointc irqchip not valid!\n", __func__); > return 0; > } > > @@ -502,7 +502,7 @@ static int kvm_eiointc_regs_access(struct kvm_device *dev, > p = (void *)s->coremap + offset * 4; > break; > default: > - kvm_err("%s: unknown eiointc register, addr = %d\n", __func__, addr); > + WARN_ONCE(1, "%s: unknown eiointc register, addr = %d\n", __func__, addr); > return -EINVAL; > } > > @@ -546,7 +546,7 @@ static int kvm_eiointc_sw_status_access(struct kvm_device *dev, > p = &s->status; > break; > default: > - kvm_err("%s: unknown eiointc register, addr = %d\n", __func__, addr); > + WARN_ONCE(1, "%s: unknown eiointc register, addr = %d\n", __func__, addr); > return -EINVAL; > } > spin_lock_irqsave(&s->lock, flags); > diff --git a/arch/loongarch/kvm/intc/ipi.c b/arch/loongarch/kvm/intc/ipi.c > index d70bf415c7fc..8d9dacfc1b15 100644 > --- a/arch/loongarch/kvm/intc/ipi.c > +++ b/arch/loongarch/kvm/intc/ipi.c > @@ -30,7 +30,7 @@ static void ipi_send(struct kvm *kvm, uint64_t data) > cpu = ((data & 0xffffffff) >> 16) & 0x3ff; > vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu); > if (unlikely(vcpu == NULL)) { > - kvm_err("%s: invalid target cpu: %d\n", __func__, cpu); > + WARN_ONCE(1, "%s: invalid target cpu: %d\n", __func__, cpu); > return; > } > > @@ -105,7 +105,7 @@ static int mail_send(struct kvm *kvm, uint64_t data) > cpu = ((data & 0xffffffff) >> 16) & 0x3ff; > vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu); > if (unlikely(vcpu == NULL)) { > - kvm_err("%s: invalid target cpu: %d\n", __func__, cpu); > + WARN_ONCE(1, "%s: invalid target cpu: %d\n", __func__, cpu); > return 0; > } > mailbox = ((data & 0xffffffff) >> 2) & 0x7; > @@ -139,7 +139,7 @@ static int send_ipi_data(struct kvm_vcpu *vcpu, gpa_t addr, uint64_t data) > ret = kvm_io_bus_read(vcpu, KVM_IOCSR_BUS, addr, 4, &val); > srcu_read_unlock(&vcpu->kvm->srcu, idx); > if (unlikely(ret)) { > - kvm_err("%s: : read data from addr %llx failed\n", __func__, addr); > + WARN_ONCE(1, "%s: : read data from addr %llx failed\n", __func__, addr); > return 0; > } > /* Construct the mask by scanning the bit 27-30 */ > @@ -155,7 +155,7 @@ static int send_ipi_data(struct kvm_vcpu *vcpu, gpa_t addr, uint64_t data) > ret = kvm_io_bus_write(vcpu, KVM_IOCSR_BUS, addr, 4, &val); > srcu_read_unlock(&vcpu->kvm->srcu, idx); > if (unlikely(ret)) > - kvm_err("%s: : write data to addr %llx failed\n", __func__, addr); > + WARN_ONCE(1, "%s: : write data to addr %llx failed\n", __func__, addr); > > return 0; > } > @@ -168,7 +168,7 @@ static int any_send(struct kvm *kvm, uint64_t data) > cpu = ((data & 0xffffffff) >> 16) & 0x3ff; > vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu); > if (unlikely(vcpu == NULL)) { > - kvm_err("%s: invalid target cpu: %d\n", __func__, cpu); > + WARN_ONCE(1, "%s: invalid target cpu: %d\n", __func__, cpu); > return 0; > } > offset = data & 0xffff; > @@ -200,14 +200,14 @@ static int loongarch_ipi_readl(struct kvm_vcpu *vcpu, gpa_t addr, int len, void > break; > case IOCSR_IPI_BUF_20 ... IOCSR_IPI_BUF_38 + 7: > if (offset + len > IOCSR_IPI_BUF_38 + 8) { > - kvm_err("%s: invalid offset or len: offset = %d, len = %d\n", > + WARN_ONCE(1, "%s: invalid offset or len: offset = %d, len = %d\n", > __func__, offset, len); > break; > } > res = read_mailbox(vcpu, offset, len); > break; > default: > - kvm_err("%s: unknown addr: %llx\n", __func__, addr); > + WARN_ONCE(1, "%s: unknown addr: %llx\n", __func__, addr); > break; > } > *(uint64_t *)val = res; > @@ -242,7 +242,7 @@ static int loongarch_ipi_writel(struct kvm_vcpu *vcpu, gpa_t addr, int len, cons > break; > case IOCSR_IPI_BUF_20 ... IOCSR_IPI_BUF_38 + 7: > if (offset + len > IOCSR_IPI_BUF_38 + 8) { > - kvm_err("%s: invalid offset or len: offset = %d, len = %d\n", > + WARN_ONCE(1, "%s: invalid offset or len: offset = %d, len = %d\n", > __func__, offset, len); > break; > } > @@ -258,7 +258,7 @@ static int loongarch_ipi_writel(struct kvm_vcpu *vcpu, gpa_t addr, int len, cons > any_send(vcpu->kvm, data); > break; > default: > - kvm_err("%s: unknown addr: %llx\n", __func__, addr); > + WARN_ONCE(1, "%s: unknown addr: %llx\n", __func__, addr); > break; > } > > @@ -301,7 +301,7 @@ static int kvm_ipi_regs_access(struct kvm_device *dev, > > vcpu = kvm_get_vcpu_by_id(dev->kvm, cpu); > if (unlikely(vcpu == NULL)) { > - kvm_err("%s: invalid target cpu: %d\n", __func__, cpu); > + WARN_ONCE(1, "%s: invalid target cpu: %d\n", __func__, cpu); > return -EINVAL; > } > > @@ -335,7 +335,7 @@ static int kvm_ipi_regs_access(struct kvm_device *dev, > len = 8; > break; > default: > - kvm_err("%s: unknown ipi register, addr = %d\n", __func__, addr); > + WARN_ONCE(1, "%s: unknown ipi register, addr = %d\n", __func__, addr); > return -EINVAL; > } > > @@ -369,7 +369,7 @@ static int kvm_ipi_get_attr(struct kvm_device *dev, > case KVM_DEV_LOONGARCH_IPI_GRP_REGS: > return kvm_ipi_regs_access(dev, attr, false); > default: > - kvm_err("%s: unknown group (%d)\n", __func__, attr->group); > + WARN_ONCE(1, "%s: unknown group (%d)\n", __func__, attr->group); > return -EINVAL; > } > } > @@ -381,7 +381,7 @@ static int kvm_ipi_set_attr(struct kvm_device *dev, > case KVM_DEV_LOONGARCH_IPI_GRP_REGS: > return kvm_ipi_regs_access(dev, attr, true); > default: > - kvm_err("%s: unknown group (%d)\n", __func__, attr->group); > + WARN_ONCE(1, "%s: unknown group (%d)\n", __func__, attr->group); > return -EINVAL; > } > } > @@ -394,13 +394,13 @@ static int kvm_ipi_create(struct kvm_device *dev, u32 type) > struct loongarch_ipi *s; > > if (!dev) { > - kvm_err("%s: kvm_device ptr is invalid!\n", __func__); > + WARN_ONCE(1, "%s: kvm_device ptr is invalid!\n", __func__); > return -EINVAL; > } > > kvm = dev->kvm; > if (kvm->arch.ipi) { > - kvm_err("%s: LoongArch IPI has already been created!\n", __func__); > + WARN_ONCE(1, "%s: LoongArch IPI has already been created!\n", __func__); > return -EINVAL; > } > > @@ -420,7 +420,7 @@ static int kvm_ipi_create(struct kvm_device *dev, u32 type) > ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS, IOCSR_IPI_BASE, IOCSR_IPI_SIZE, device); > mutex_unlock(&kvm->slots_lock); > if (ret < 0) { > - kvm_err("%s: Initialize IOCSR dev failed, ret = %d\n", __func__, ret); > + WARN_ONCE(1, "%s: Initialize IOCSR dev failed, ret = %d\n", __func__, ret); > goto err; > } > > diff --git a/arch/loongarch/kvm/intc/pch_pic.c b/arch/loongarch/kvm/intc/pch_pic.c > index 175a630aceb4..299b4db26833 100644 > --- a/arch/loongarch/kvm/intc/pch_pic.c > +++ b/arch/loongarch/kvm/intc/pch_pic.c > @@ -151,12 +151,12 @@ static int kvm_pch_pic_read(struct kvm_vcpu *vcpu, > struct loongarch_pch_pic *s = vcpu->kvm->arch.pch_pic; > > if (!s) { > - kvm_err("%s: pch pic irqchip not valid!\n", __func__); > + WARN_ONCE(1, "%s: pch pic irqchip not valid!\n", __func__); > return ret; > } > > if (addr & (len - 1)) { > - kvm_err("%s: pch pic not aligned addr %llx len %d\n", __func__, addr, len); > + WARN_ONCE(1, "%s: pch pic not aligned addr %llx len %d\n", __func__, addr, len); > return ret; > } > > @@ -250,12 +250,12 @@ static int kvm_pch_pic_write(struct kvm_vcpu *vcpu, > struct loongarch_pch_pic *s = vcpu->kvm->arch.pch_pic; > > if (!s) { > - kvm_err("%s: pch pic irqchip not valid!\n", __func__); > + WARN_ONCE(1, "%s: pch pic irqchip not valid!\n", __func__); > return ret; > } > > if (addr & (len - 1)) { > - kvm_err("%s: pch pic not aligned addr %llx len %d\n", __func__, addr, len); > + WARN_ONCE(1, "%s: pch pic not aligned addr %llx len %d\n", __func__, addr, len); > return ret; > } > > @@ -390,13 +390,13 @@ static int kvm_pch_pic_set_attr(struct kvm_device *dev, > return -EFAULT; > > if (!dev->kvm->arch.pch_pic) { > - kvm_err("%s: please create pch_pic irqchip first!\n", __func__); > + WARN_ONCE(1, "%s: please create pch_pic irqchip first\n", __func__); > return -ENODEV; > } > > return kvm_pch_pic_init(dev, addr); > default: > - kvm_err("%s: unknown group (%d) attr (%lld)\n", __func__, attr->group, > + WARN_ONCE(1, "%s: unknown group (%d) attr (%lld)\n", __func__, attr->group, > attr->attr); > return -EINVAL; > } > diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c > index 20c207d80e31..361fca46e2b3 100644 > --- a/arch/loongarch/kvm/vcpu.c > +++ b/arch/loongarch/kvm/vcpu.c > @@ -1473,7 +1473,7 @@ int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) > else if (intr < 0) > kvm_dequeue_irq(vcpu, -intr); > else { > - kvm_err("%s: invalid interrupt ioctl %d\n", __func__, irq->irq); > + WARN_ONCE(1, "%s: invalid interrupt ioctl %d\n", __func__, irq->irq); > return -EINVAL; > } > > -- > 2.39.3 > ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v3 3/3] LoongArch: KVM: Use internal API to deliver interrupt in kernel mode 2026-06-29 2:32 [PATCH v3 0/3] LoongArch: KVM: Harden interrupt injection Bibo Mao 2026-06-29 2:32 ` [PATCH v3 1/3] LoongArch: KVM: Set default MAILBOX access size with 8 Bibo Mao 2026-06-29 2:32 ` [PATCH v3 2/3] LoongArch: KVM: Replace kvm_err() with WARN_ONCE() Bibo Mao @ 2026-06-29 2:32 ` Bibo Mao 2026-06-29 2:41 ` sashiko-bot 2 siblings, 1 reply; 8+ messages in thread From: Bibo Mao @ 2026-06-29 2:32 UTC (permalink / raw) To: Huacai Chen; +Cc: kvm, loongarch, linux-kernel API kvm_vcpu_ioctl_interrupt() is mainly to used to deliver interrupt from user mode, and internal APIs kvm_queue_irq() and kvm_dequeue_irq() are used in kernel mode. Also move IPI inject and ack within lock protection to avoid contention in ipi_set() and ipi_clear(). Signed-off-by: Bibo Mao <maobibo@loongson.cn> --- arch/loongarch/kvm/intc/dmsintc.c | 7 ++++--- arch/loongarch/kvm/intc/eiointc.c | 14 +++++++++----- arch/loongarch/kvm/intc/ipi.c | 14 ++++++-------- arch/loongarch/kvm/vcpu.c | 3 +++ 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/arch/loongarch/kvm/intc/dmsintc.c b/arch/loongarch/kvm/intc/dmsintc.c index 708abbcd55bf..ed8553224775 100644 --- a/arch/loongarch/kvm/intc/dmsintc.c +++ b/arch/loongarch/kvm/intc/dmsintc.c @@ -47,7 +47,6 @@ void dmsintc_inject_irq(struct kvm_vcpu *vcpu) int dmsintc_deliver_msi_to_vcpu(struct kvm *kvm, struct kvm_vcpu *vcpu, u32 vector, int level) { - struct kvm_interrupt vcpu_irq; struct dmsintc_state *ds = &vcpu->arch.dmsintc_state; if (!level) @@ -57,9 +56,11 @@ int dmsintc_deliver_msi_to_vcpu(struct kvm *kvm, if (!ds) return -ENODEV; - vcpu_irq.irq = INT_AVEC; + if (!kvm_guest_has_msgint(&vcpu->arch)) + return -EINVAL; + set_bit(vector, (unsigned long *)&ds->vector_map); - kvm_vcpu_ioctl_interrupt(vcpu, &vcpu_irq); + kvm_queue_irq(vcpu, INT_AVEC); kvm_vcpu_kick(vcpu); return 0; diff --git a/arch/loongarch/kvm/intc/eiointc.c b/arch/loongarch/kvm/intc/eiointc.c index 555e55246f0c..681dfb548dbf 100644 --- a/arch/loongarch/kvm/intc/eiointc.c +++ b/arch/loongarch/kvm/intc/eiointc.c @@ -17,7 +17,8 @@ static void eiointc_set_sw_coreisr(struct loongarch_eiointc *s) if (!(s->status & BIT(EIOINTC_ENABLE_INT_ENCODE))) { ipnum = count_trailing_zeros(ipnum); ipnum = ipnum < 4 ? ipnum : 0; - } + } else if (ipnum >= LOONGSON_IP_NUM) + ipnum = 0; cpuid = ((u8 *)s->coremap)[irq]; vcpu = kvm_get_vcpu_by_cpuid(s->kvm, cpuid); @@ -36,13 +37,13 @@ static void eiointc_update_irq(struct loongarch_eiointc *s, int irq, int level) { int ipnum, cpu, found; struct kvm_vcpu *vcpu; - struct kvm_interrupt vcpu_irq; ipnum = (s->ipmap >> (irq / 32 * 8)) & 0xff; if (!(s->status & BIT(EIOINTC_ENABLE_INT_ENCODE))) { ipnum = count_trailing_zeros(ipnum); ipnum = ipnum < 4 ? ipnum : 0; - } + } else if (ipnum >= LOONGSON_IP_NUM) + ipnum = 0; cpu = s->sw_coremap[irq]; vcpu = kvm_get_vcpu_by_id(s->kvm, cpu); @@ -67,8 +68,11 @@ static void eiointc_update_irq(struct loongarch_eiointc *s, int irq, int level) if (found < EIOINTC_IRQS) return; /* other irq is handling, needn't update parent irq */ - vcpu_irq.irq = level ? (INT_HWI0 + ipnum) : -(INT_HWI0 + ipnum); - kvm_vcpu_ioctl_interrupt(vcpu, &vcpu_irq); + if (level) + kvm_queue_irq(vcpu, INT_HWI0 + ipnum); + else + kvm_dequeue_irq(vcpu, INT_HWI0 + ipnum); + kvm_vcpu_kick(vcpu); } static inline void eiointc_update_sw_coremap(struct loongarch_eiointc *s, diff --git a/arch/loongarch/kvm/intc/ipi.c b/arch/loongarch/kvm/intc/ipi.c index 8d9dacfc1b15..eacf2073c603 100644 --- a/arch/loongarch/kvm/intc/ipi.c +++ b/arch/loongarch/kvm/intc/ipi.c @@ -10,16 +10,15 @@ static void ipi_set(struct kvm_vcpu *vcpu, uint32_t data) { uint32_t status; - struct kvm_interrupt irq; spin_lock(&vcpu->arch.ipi_state.lock); status = vcpu->arch.ipi_state.status; vcpu->arch.ipi_state.status |= data; - spin_unlock(&vcpu->arch.ipi_state.lock); if ((status == 0) && data) { - irq.irq = LARCH_INT_IPI; - kvm_vcpu_ioctl_interrupt(vcpu, &irq); + kvm_queue_irq(vcpu, LARCH_INT_IPI); + kvm_vcpu_kick(vcpu); } + spin_unlock(&vcpu->arch.ipi_state.lock); } static void ipi_send(struct kvm *kvm, uint64_t data) @@ -40,16 +39,15 @@ static void ipi_send(struct kvm *kvm, uint64_t data) static void ipi_clear(struct kvm_vcpu *vcpu, uint64_t data) { uint32_t status; - struct kvm_interrupt irq; spin_lock(&vcpu->arch.ipi_state.lock); vcpu->arch.ipi_state.status &= ~data; status = vcpu->arch.ipi_state.status; - spin_unlock(&vcpu->arch.ipi_state.lock); if (status == 0) { - irq.irq = -LARCH_INT_IPI; - kvm_vcpu_ioctl_interrupt(vcpu, &irq); + kvm_dequeue_irq(vcpu, LARCH_INT_IPI); + kvm_vcpu_kick(vcpu); } + spin_unlock(&vcpu->arch.ipi_state.lock); } static uint64_t read_mailbox(struct kvm_vcpu *vcpu, int offset, int len) diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c index 361fca46e2b3..265aaad63315 100644 --- a/arch/loongarch/kvm/vcpu.c +++ b/arch/loongarch/kvm/vcpu.c @@ -1465,6 +1465,9 @@ int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) if (vector >= EXCCODE_INT_NUM) return -EINVAL; + if (kvm_arch_irqchip_in_kernel(vcpu->kvm)) + return -EINVAL; + if (!kvm_guest_has_msgint(&vcpu->arch) && (vector == INT_AVEC)) return -EINVAL; -- 2.39.3 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v3 3/3] LoongArch: KVM: Use internal API to deliver interrupt in kernel mode 2026-06-29 2:32 ` [PATCH v3 3/3] LoongArch: KVM: Use internal API to deliver interrupt in kernel mode Bibo Mao @ 2026-06-29 2:41 ` sashiko-bot 0 siblings, 0 replies; 8+ messages in thread From: sashiko-bot @ 2026-06-29 2:41 UTC (permalink / raw) To: Bibo Mao; +Cc: kvm Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: Pre-existing issues: - [High] Multiple pre-existing WARN_ONCE and WARN_ON_ONCE macros are reachable by unprivileged host userspace and malicious guests, allowing a host-side DoS if `panic_on_warn` is enabled. - [High] Uninitialized array `vector` is conditionally assigned but unconditionally evaluated and used to modify hardware CSRs. -- commit f75612ad87b1cded57456f721c300aad7e8b6150 Author: Bibo Mao <maobibo@loongson.cn> LoongArch: KVM: Use internal API to deliver interrupt in kernel mode This commit updates KVM on LoongArch to use internal APIs kvm_queue_irq() and kvm_dequeue_irq() for delivering interrupts in kernel mode, rather than the user mode kvm_vcpu_ioctl_interrupt(). It also moves IPI injection and ack operations within lock protection to reduce contention. > diff --git a/arch/loongarch/kvm/intc/dmsintc.c b/arch/loongarch/kvm/intc/dmsintc.c > index 708abbcd55bff..ed85532247759 100644 > --- a/arch/loongarch/kvm/intc/dmsintc.c > +++ b/arch/loongarch/kvm/intc/dmsintc.c > @@ -47,7 +47,6 @@ void dmsintc_inject_irq(struct kvm_vcpu *vcpu) [Severity: High] This isn't a bug introduced by this patch, but looking at dmsintc_inject_irq() just above this change, is the vector array properly initialized? arch/loongarch/kvm/intc/dmsintc.c:dmsintc_inject_irq() { unsigned long vector[4], old; ... for (i = 0; i < 4; i++) { old = atomic64_read(&(ds->vector_map[i])); if (old) vector[i] = atomic64_xchg(&(ds->vector_map[i]), 0); } if (vector[0]) { old = kvm_read_hw_gcsr(LOONGARCH_CSR_ISR0); kvm_write_hw_gcsr(LOONGARCH_CSR_ISR0, vector[0] | old); } } If atomic64_read() returns zero, vector[i] is left uninitialized. When it checks if (vector[0]) later, could this evaluate to true using stack garbage and write random data into the guest CSRs? > int dmsintc_deliver_msi_to_vcpu(struct kvm *kvm, > struct kvm_vcpu *vcpu, u32 vector, int level) > { [ ... ] > diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c > index 361fca46e2b32..265aaad633157 100644 > --- a/arch/loongarch/kvm/vcpu.c > +++ b/arch/loongarch/kvm/vcpu.c > @@ -1465,6 +1465,9 @@ int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) > if (vector >= EXCCODE_INT_NUM) > return -EINVAL; > > + if (kvm_arch_irqchip_in_kernel(vcpu->kvm)) > + return -EINVAL; > + [Severity: High] This is a pre-existing issue, but I noticed there are several WARN_ONCE and WARN_ON_ONCE macros reachable by unprivileged host userspace and malicious guests in this subsystem. For example, in kvm_vcpu_ioctl_interrupt(), providing an intr == 0 unconditionally hits a fallback block that calls: WARN_ONCE(1, "%s: invalid interrupt ioctl %d\n", __func__, irq->irq); Similarly, in ipi_send() and eiointc_update_irq(), guest-controlled CPU IDs can yield a NULL vCPU, directly triggering: WARN_ONCE(1, "%s: invalid target cpu: %d\n", __func__, cpu); And in loongarch_ipi_readl(), a guest unaligned MMIO read triggers: WARN_ON_ONCE(offset & (len - 1)); Could these be converted to pr_warn_once(), return an error, or drop the assertions entirely? These could allow a host-side denial of service if panic_on_warn is enabled. > if (!kvm_guest_has_msgint(&vcpu->arch) && (vector == INT_AVEC)) > return -EINVAL; > -- Sashiko AI review · https://sashiko.dev/#/patchset/20260629023213.597030-1-maobibo@loongson.cn?part=3 ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-06-30 4:27 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-06-29 2:32 [PATCH v3 0/3] LoongArch: KVM: Harden interrupt injection Bibo Mao 2026-06-29 2:32 ` [PATCH v3 1/3] LoongArch: KVM: Set default MAILBOX access size with 8 Bibo Mao 2026-06-29 2:45 ` sashiko-bot 2026-06-29 2:32 ` [PATCH v3 2/3] LoongArch: KVM: Replace kvm_err() with WARN_ONCE() Bibo Mao 2026-06-29 2:37 ` sashiko-bot 2026-06-30 4:27 ` Huacai Chen 2026-06-29 2:32 ` [PATCH v3 3/3] LoongArch: KVM: Use internal API to deliver interrupt in kernel mode Bibo Mao 2026-06-29 2:41 ` sashiko-bot
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox