All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: Dylan.Wu <fredwudi0305@gmail.com>
Cc: kvm@vger.kernel.org
Subject: Re: [PATCH v2 3/3] KVM: riscv: Register ptdump with debugfs on guest creation
Date: Mon, 27 Jul 2026 13:01:08 +0000	[thread overview]
Message-ID: <20260727130108.A871C1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260727123013.118984-4-fredwudi0305@gmail.com>

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] gstage_ptdump_show traverses KVM guest stage-2 page tables without holding kvm->mmu_lock, creating a severe use-after-free race condition.
- [High] Using the host's generic page table walker for KVM guest stage-2 page tables causes incorrect parsing and potential kernel panics due to mismatched root page table geometries.
- [Medium] Concurrent accesses to the debugfs file cause a data race and persistent state corruption due to mutation of the static `gstage_pg_levels` array.
- [Medium] If `kvm->arch.pgd` is NULL, the walker silently falls back to walking the host process's page tables, leaking the host virtual memory layout.
- [Medium] gstage_note_page_flush triggers an integer underflow, printing an astronomically huge size and an incorrect range boundary.
--

--- Patch [3]: [PATCH v2 3/3] KVM: riscv: Register ptdump with debugfs on guest creation ---
commit d69a647519dc99ece115797b207b3ba4248c4915
Author: Dylan.Wu <fredwudi0305@gmail.com>

KVM: riscv: Register ptdump with debugfs on guest creation
    
Add a new RISC-V KVM specific ptdump implementation that dumps the
guest stage-2 (gstage) pagetables via debugfs. The code reuses the
common ptdump data structures and helpers from asm/ptdump.h, and
exposes a "gstage_page_tables" file in each guest VM's debugfs
directory (kvm->debugfs_dentry).

[ ... ]

> diff --git a/arch/riscv/kvm/ptdump.c b/arch/riscv/kvm/ptdump.c
> new file mode 100644
> index 0000000000000..83a92969bd419
> --- /dev/null
> +++ b/arch/riscv/kvm/ptdump.c

[ ... ]

> +static void gstage_note_page_flush(struct ptdump_state *pt_st)
> +{
> +	pte_t pte_zero = {0};
> +
> +	gstage_note_page(pt_st, 0, -1, pte_val(pte_zero));
> +}

[Severity: Medium]
Will this trigger an integer underflow when calculating the block size?

The generic host code uses 0 to denote ULONG_MAX + 1 for address spaces
ending at the top of the 64-bit space, where 0 - start_address gracefully
yields the correct distance.

However, the KVM guest physical address space ends at gpa_size (e.g., 2TB).
Passing 0 here means addr >= st->marker[1].start_address evaluates to
false, skipping the 'Guest Physical Address End' marker. It then calculates
the size as (0 - start_address) >> 10, which underflows into a massive
unsigned integer.

Should this pass the actual end of the guest physical address space instead
of 0?

> +
> +static int gstage_ptdump_show(struct seq_file *m, void *v)
> +{
> +	struct kvm *kvm = m->private;
> +	gpa_t gpa_size = kvm_riscv_gstage_gpa_size(kvm->arch.pgd_levels);

[ ... ]

> +	unsigned int i, j;
> +
> +	for (i = 0; i < ARRAY_SIZE(gstage_pg_levels); i++) {
> +		gstage_pg_levels[i].mask = 0;
> +		for (j = 0; j < ARRAY_SIZE(gstage_pte_bits); j++)
> +			gstage_pg_levels[i].mask |= gstage_pte_bits[j].mask;
> +	}
> +
> +	if (kvm->arch.pgd_levels < 5)
> +		gstage_pg_levels[1].name = "PGD";
> +	if (kvm->arch.pgd_levels < 4)
> +		gstage_pg_levels[2].name = "PGD";
> +	if (kvm->arch.pgd_levels < 3)
> +		gstage_pg_levels[3].name = "PGD";

[Severity: Medium]
Is it safe to mutate the static global array gstage_pg_levels here without
any synchronization?

Since gstage_pg_levels is a global static array, concurrent reads of the
debugfs file for different VMs will race here, which could lead to omitted
protection bits.

Additionally, downgrading a level's name to "PGD" permanently modifies the
array for subsequent reads of VMs that might have deeper page tables. Could
this state be maintained per-VM instead of globally?

> +
> +	ptdump_walk_pgd(&st.ptdump, kvm->mm, kvm->arch.pgd);

[Severity: High]
Does this traversal require kvm->mmu_lock to safely walk the guest page
tables?

If a user reads the debugfs file while the VM is concurrently modifying or
tearing down its page tables, the walker will traverse these structures
locklessly. ptdump_walk_pgd() acquires the host userspace mmap_write_lock
for kvm->mm, but does not acquire kvm->mmu_lock, which could lead to
dereferencing freed intermediate page table pages (use-after-free).


[Severity: High]
Can the host's generic page table walker safely handle KVM guest stage-2
page tables with different geometries?

KVM RISC-V guest page tables have dynamically configured depth through
kvm->arch.pgd_levels, which can differ from the host's compile-time depth
in CONFIG_PGTABLE_LEVELS.

If the host uses 4 levels and the guest uses 3 levels, the generic walker
will treat the guest's 3-level root as a 4-level root. It will descend one
level too deep, extracting a PFN from leaf PTEs, converting it to a kernel
virtual address, and dereferencing it. Could this trigger an out-of-bounds
direct map access and panic the host kernel?


[Severity: Medium]
What happens if kvm->arch.pgd is NULL when this is called?

If the debugfs file is read while kvm_arch_flush_shadow_all() is executing
during process exit, kvm->arch.pgd could be NULL.

Inside the generic walker, it detects a NULL pgd and falls back to
pgd_offset(walk->mm, addr). Since walk->mm is the host QEMU process's mm,
the walker will format and leak the host process's page table layout as if
it were the guest's stage-2 memory. Should we check for a NULL pgd before
initiating the walk?

> +
> +	return 0;
> +}

[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260727123013.118984-1-fredwudi0305@gmail.com?part=3

      reply	other threads:[~2026-07-27 13:01 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-27 12:30 [PATCH v2 0/3] riscv: ptdump: Refactor for KVM gstage ptdump support Dylan.Wu
2026-07-27 12:30 ` Dylan.Wu
2026-07-27 12:30 ` Dylan.Wu
2026-07-27 12:30 ` [PATCH v2 1/3] riscv: ptdump: Create ptdump.h and move declarations Dylan.Wu
2026-07-27 12:30   ` Dylan.Wu
2026-07-27 12:30   ` Dylan.Wu
2026-07-27 12:41   ` sashiko-bot
2026-07-27 12:30 ` [PATCH v2 2/3] riscv: ptdump: Use per-level attribute bits for parsing Dylan.Wu
2026-07-27 12:30   ` Dylan.Wu
2026-07-27 12:30   ` Dylan.Wu
2026-07-27 12:45   ` sashiko-bot
2026-07-27 12:30 ` [PATCH v2 3/3] KVM: riscv: Register ptdump with debugfs on guest creation Dylan.Wu
2026-07-27 12:30   ` Dylan.Wu
2026-07-27 12:30   ` Dylan.Wu
2026-07-27 13:01   ` sashiko-bot [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260727130108.A871C1F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=fredwudi0305@gmail.com \
    --cc=kvm@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.