* [PATCH] RISC-V: KVM: Publish NACL HFENCE configuration last
@ 2026-09-06 8:07 Pengpeng Hou
2026-09-06 8:19 ` sashiko-bot
2026-09-12 7:19 ` Anup Patel
0 siblings, 2 replies; 3+ messages in thread
From: Pengpeng Hou @ 2026-09-06 8:07 UTC (permalink / raw)
To: Anup Patel, Atish Patra
Cc: Pengpeng Hou, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, kvm, kvm-riscv, linux-riscv, linux-kernel,
Andrew Jones
The SBI NACL interface requires software to write Page_Number and
Page_Count before publishing an HFENCE entry with Config.Pending set.
__kvm_riscv_nacl_hfence() currently stores the pending configuration first.
Write the payload first and order those stores before publishing the
configuration word with WRITE_ONCE(). Use a write barrier that also
applies to UP kernels, since the consumer is outside the Linux SMP
domain.
Keep nacl_hfence_mkconfig() unchanged: setting Pending in a local value
does not publish the entry. The shared-memory store is the publication
point.
The issue was found by our static-analysis tool and manually reviewed.
Fixes: d466c19cead5 ("RISC-V: KVM: Add common nested acceleration support")
Assisted-by: GPT-5
Signed-off-by: Pengpeng Hou <hppiscas@163.com>
---
diff --git a/arch/riscv/kvm/nacl.c b/arch/riscv/kvm/nacl.c
index 9aff03c4..c5c4907a 100644
--- a/arch/riscv/kvm/nacl.c
+++ b/arch/riscv/kvm/nacl.c
@@ -5,6 +5,7 @@
#include <linux/kvm_host.h>
#include <linux/vmalloc.h>
+#include <asm/barrier.h>
#include <asm/kvm_nacl.h>
DEFINE_STATIC_KEY_FALSE(kvm_riscv_nacl_available);
@@ -42,12 +43,15 @@ again:
}
}
- entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_CONFIG(i);
- *entp = cpu_to_lelong(control);
entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_PNUM(i);
*entp = cpu_to_lelong(page_num);
entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_PCOUNT(i);
*entp = cpu_to_lelong(page_count);
+
+ /* Publish the payload before setting Config.Pending. */
+ wmb();
+ entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_CONFIG(i);
+ WRITE_ONCE(*entp, cpu_to_lelong(control));
}
int kvm_riscv_nacl_enable(void)
base-commit: 4d7d9486c04d917265f64c55bd23b2cc4fe7749c
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] RISC-V: KVM: Publish NACL HFENCE configuration last
2026-09-06 8:07 [PATCH] RISC-V: KVM: Publish NACL HFENCE configuration last Pengpeng Hou
@ 2026-09-06 8:19 ` sashiko-bot
2026-09-12 7:19 ` Anup Patel
1 sibling, 0 replies; 3+ messages in thread
From: sashiko-bot @ 2026-09-06 8:19 UTC (permalink / raw)
To: Pengpeng Hou; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Pre-existing issues:
- [High] KVM silently drops TLB flush (HFENCE) requests when the NACL shared memory is exhausted, leading to guest memory corruption and use-after-free vulnerabilities.
- [High] Per-CPU `nacl_shmem()` is evaluated and accessed in a preemptible context, causing a race condition that corrupts shared memory entries and drops TLB flushes.
- [High] The shared memory entry configuration is read without `READ_ONCE()`, violating Linux Kernel Memory Model (LKMM) rules for shared memory and control dependencies.
--
commit c8294fdfde274970a69be416dee2db8089a33132
Author: Pengpeng Hou <hppiscas@163.com>
Subject: RISC-V: KVM: Publish NACL HFENCE configuration last
The SBI NACL interface requires software to write Page_Number and
Page_Count before publishing an HFENCE entry with Config.Pending set.
__kvm_riscv_nacl_hfence() currently stores the pending configuration first.
> diff --git a/arch/riscv/kvm/nacl.c b/arch/riscv/kvm/nacl.c
> index 9aff03c4f667a..c5c4907aca08a 100644
> --- a/arch/riscv/kvm/nacl.c
> +++ b/arch/riscv/kvm/nacl.c
> @@ -5,6 +5,7 @@
>
> #include <linux/kvm_host.h>
> #include <linux/vmalloc.h>
> +#include <asm/barrier.h>
> #include <asm/kvm_nacl.h>
>
> DEFINE_STATIC_KEY_FALSE(kvm_riscv_nacl_available);
> @@ -42,12 +43,15 @@ void __kvm_riscv_nacl_hfence(void *shmem,
[Severity: High]
This isn't a bug introduced by this patch, but in __kvm_riscv_nacl_hfence(),
KVM silently drops TLB flush requests when the NACL shared memory fills up.
When the shared memory queue fills up, the function calls
nacl_sync_hfence(-1UL) and retries 5 times. If the firmware is sluggish or
fails to drain the queue in time, it returns void without notifying the
caller:
arch/riscv/kvm/nacl.c:__kvm_riscv_nacl_hfence() {
...
if (ent < 0) {
if (try_count--) {
nacl_sync_hfence(-1UL);
goto again;
} else {
pr_warn("KVM: No free entry in NACL shared memory\n");
return;
}
}
...
}
Could KVM return a hard error or BUG() instead if a TLB flush cannot be
completed, to prevent guests from accessing stale physical memory mappings
and causing data corruption or use-after-free?
[Severity: High]
This is a pre-existing issue, but does reading the shared memory entry
configuration without READ_ONCE() violate the Linux Kernel Memory Model for
shared memory and control dependencies?
arch/riscv/kvm/nacl.c:__kvm_riscv_nacl_hfence() {
...
again:
for (i = 0; i < SBI_NACL_SHMEM_HFENCE_ENTRY_MAX; i++) {
entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_CONFIG(i);
if (lelong_to_cpu(*entp) & SBI_NACL_SHMEM_HFENCE_CONFIG_PEND)
continue;
...
}
While this patch correctly adds a WRITE_ONCE() and a barrier for publishing
the payload, the read side is left unprotected. Without READ_ONCE() around
*entp, might the compiler optimize the read from shared memory by caching the
value or issuing multiple loads, which could result in an infinite loop or
incorrect synchronization with the firmware?
> }
> }
>
> - entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_CONFIG(i);
> - *entp = cpu_to_lelong(control);
> entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_PNUM(i);
> *entp = cpu_to_lelong(page_num);
> entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_PCOUNT(i);
> *entp = cpu_to_lelong(page_count);
> +
> + /* Publish the payload before setting Config.Pending. */
> + wmb();
> + entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_CONFIG(i);
> + WRITE_ONCE(*entp, cpu_to_lelong(control));
> }
[Severity: High]
This isn't a bug introduced by this patch, but is it safe to evaluate and
access the per-CPU nacl_shmem() in a preemptible context?
In kvm_arch_vcpu_ioctl_run(), vCPU requests are processed before preemption
is disabled:
arch/riscv/kvm/vcpu.c:kvm_arch_vcpu_ioctl_run() {
...
ret = kvm_riscv_check_vcpu_requests(vcpu);
if (ret <= 0)
continue;
preempt_disable();
...
}
When processing HFENCE requests, kvm_riscv_hfence_process() evaluates
nacl_shmem(), which expands to a per-CPU pointer:
arch/riscv/include/asm/kvm_nacl.h:
#define nacl_shmem() \
this_cpu_ptr(&kvm_riscv_nacl)->shmem
arch/riscv/kvm/tlb.c:kvm_riscv_hfence_process() {
...
nacl_hfence_gvma_vmid(nacl_shmem(), d.vmid,
d.addr, d.size, d.order);
...
}
If the vCPU thread is preempted and migrated to another CPU after evaluating
nacl_shmem(), wouldn't this cause a race condition that overwrites another
CPU's TLB flush queue, potentially leading to dropped flushes and guest
isolation breaches?
--
Sashiko AI review · https://sashiko.dev/#/patchset/caplitmus-rv.c91c005b844342d9a9f60949b04c520d.d65@163.com?part=1
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] RISC-V: KVM: Publish NACL HFENCE configuration last
2026-09-06 8:07 [PATCH] RISC-V: KVM: Publish NACL HFENCE configuration last Pengpeng Hou
2026-09-06 8:19 ` sashiko-bot
@ 2026-09-12 7:19 ` Anup Patel
1 sibling, 0 replies; 3+ messages in thread
From: Anup Patel @ 2026-09-12 7:19 UTC (permalink / raw)
To: Pengpeng Hou
Cc: Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, kvm, kvm-riscv, linux-riscv, linux-kernel,
Andrew Jones
On Sun, Sep 6, 2026 at 1:37 PM Pengpeng Hou <hppiscas@163.com> wrote:
>
> The SBI NACL interface requires software to write Page_Number and
> Page_Count before publishing an HFENCE entry with Config.Pending set.
> __kvm_riscv_nacl_hfence() currently stores the pending configuration first.
>
> Write the payload first and order those stores before publishing the
> configuration word with WRITE_ONCE(). Use a write barrier that also
> applies to UP kernels, since the consumer is outside the Linux SMP
> domain.
>
> Keep nacl_hfence_mkconfig() unchanged: setting Pending in a local value
> does not publish the entry. The shared-memory store is the publication
> point.
>
> The issue was found by our static-analysis tool and manually reviewed.
>
> Fixes: d466c19cead5 ("RISC-V: KVM: Add common nested acceleration support")
> Assisted-by: GPT-5
> Signed-off-by: Pengpeng Hou <hppiscas@163.com>
There was another patch from Zongmin Zhou which is relatively
more complete hence I have merged that one.
Regards,
Anup
> ---
>
> diff --git a/arch/riscv/kvm/nacl.c b/arch/riscv/kvm/nacl.c
> index 9aff03c4..c5c4907a 100644
> --- a/arch/riscv/kvm/nacl.c
> +++ b/arch/riscv/kvm/nacl.c
> @@ -5,6 +5,7 @@
>
> #include <linux/kvm_host.h>
> #include <linux/vmalloc.h>
> +#include <asm/barrier.h>
> #include <asm/kvm_nacl.h>
>
> DEFINE_STATIC_KEY_FALSE(kvm_riscv_nacl_available);
> @@ -42,12 +43,15 @@ again:
> }
> }
>
> - entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_CONFIG(i);
> - *entp = cpu_to_lelong(control);
> entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_PNUM(i);
> *entp = cpu_to_lelong(page_num);
> entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_PCOUNT(i);
> *entp = cpu_to_lelong(page_count);
> +
> + /* Publish the payload before setting Config.Pending. */
> + wmb();
> + entp = shmem + SBI_NACL_SHMEM_HFENCE_ENTRY_CONFIG(i);
> + WRITE_ONCE(*entp, cpu_to_lelong(control));
> }
>
> int kvm_riscv_nacl_enable(void)
>
> base-commit: 4d7d9486c04d917265f64c55bd23b2cc4fe7749c
>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-09-12 7:20 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-06 8:07 [PATCH] RISC-V: KVM: Publish NACL HFENCE configuration last Pengpeng Hou
2026-09-06 8:19 ` sashiko-bot
2026-09-12 7:19 ` Anup Patel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox