All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jinyu Tang <jinyu.tang@linux.dev>
To: Anup Patel <anup@brainfault.org>,
	Anup Patel <apatel@ventanamicro.com>,
	Atish Patra <atish.patra@linux.dev>
Cc: kvm@vger.kernel.org, kvm-riscv@lists.infradead.org,
	linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org,
	Paolo Bonzini <pbonzini@redhat.com>,
	Sean Christopherson <seanjc@google.com>,
	Paul Walmsley <pjw@kernel.org>,
	Paul Walmsley <paul.walmsley@sifive.com>,
	Palmer Dabbelt <palmer@dabbelt.com>,
	Albert Ou <aou@eecs.berkeley.edu>,
	Alexandre Ghiti <alex@ghiti.fr>,
	Andrew Jones <andrew.jones@oss.qualcomm.com>,
	Conor Dooley <conor.dooley@microchip.com>,
	Yong-Xuan Wang <yongxuan.wang@sifive.com>,
	Nutty Liu <nutty.liu@hotmail.com>, Jinyu Tang <tjytimi@163.com>,
	Jinyu Tang <jinyu.tang@linux.dev>,
	Sashiko <sashiko-bot@kernel.org>
Subject: [PATCH] KVM: riscv: Avoid overwriting existing G-stage tables with huge leaves
Date: Fri, 14 Aug 2026 06:57:52 -0400	[thread overview]
Message-ID: <20260814105752.565325-1-jinyu.tang@linux.dev> (raw)

RISC-V KVM can overwrite an existing G-stage table entry when installing
a huge leaf mapping. If the target huge range already has a lower-level
page table, kvm_riscv_gstage_set_pte() can replace the non-leaf entry
with a leaf PTE. This disconnects the lower-level page table and can
change guest-visible mappings or leak the page-table page.

Reject replacing a valid non-leaf PTE with a leaf PTE. If huge-page
installation hits such a conflict, fall back to a 4K mapping for the
faulting GPA and leave the existing page-table structure intact.

Suggested-by: Sashiko <sashiko-bot@kernel.org>
Fixes: 9d05c1fee837 ("RISC-V: KVM: Implement stage2 page table programming")
Signed-off-by: Jinyu Tang <jinyu.tang@linux.dev>
---
 arch/riscv/kvm/gstage.c | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/arch/riscv/kvm/gstage.c b/arch/riscv/kvm/gstage.c
index e5002cb9cbef..23cb35e36073 100644
--- a/arch/riscv/kvm/gstage.c
+++ b/arch/riscv/kvm/gstage.c
@@ -174,6 +174,12 @@ int kvm_riscv_gstage_set_pte(struct kvm_gstage *gstage,
 
 	if (pte_val(*ptep) != pte_val(map->pte)) {
 		bool was_invalid = !pte_val(*ptep);
+
+		/* Avoid replacing an existing lower-level table with a leaf mapping. */
+		if (!gstage_pte_leaf(ptep) && !was_invalid &&
+		    gstage_pte_leaf(&map->pte))
+			return -EEXIST;
+
 		set_pte(ptep, map->pte);
 		if (gstage_pte_leaf(ptep) &&
 		    !(was_invalid && riscv_has_extension_unlikely(RISCV_ISA_EXT_SVVPTC)))
@@ -211,12 +217,13 @@ int kvm_riscv_gstage_map_page(struct kvm_gstage *gstage,
 			      struct kvm_gstage_mapping *out_map)
 {
 	bool found_leaf;
+	phys_addr_t huge_page_offset;
 	u32 ptep_level;
 	pgprot_t prot;
 	pte_t *ptep;
 	int ret;
 
-	out_map->addr = gpa;
+	out_map->addr = gpa & PAGE_MASK;
 	out_map->level = 0;
 
 	ret = gstage_page_size_to_level(gstage, page_size, &out_map->level);
@@ -287,7 +294,18 @@ int kvm_riscv_gstage_map_page(struct kvm_gstage *gstage,
 	out_map->pte = pfn_pte(PFN_DOWN(hpa), prot);
 	out_map->pte = pte_mkdirty(out_map->pte);
 
-	return kvm_riscv_gstage_set_pte(gstage, pcache, out_map);
+	ret = kvm_riscv_gstage_set_pte(gstage, pcache, out_map);
+	if (ret == -EEXIST) {
+		huge_page_offset = out_map->addr & (page_size - 1);
+		hpa += huge_page_offset;
+		out_map->level = 0;
+		out_map->pte = pfn_pte(PFN_DOWN(hpa), prot);
+		out_map->pte = pte_mkdirty(out_map->pte);
+
+		ret = kvm_riscv_gstage_set_pte(gstage, pcache, out_map);
+	}
+
+	return ret;
 }
 
 static inline unsigned long make_child_pte(unsigned long huge_pte, int index,
-- 
2.43.0


-- 
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv

WARNING: multiple messages have this Message-ID (diff)
From: Jinyu Tang <jinyu.tang@linux.dev>
To: Anup Patel <anup@brainfault.org>,
	Anup Patel <apatel@ventanamicro.com>,
	Atish Patra <atish.patra@linux.dev>
Cc: kvm@vger.kernel.org, kvm-riscv@lists.infradead.org,
	linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org,
	Paolo Bonzini <pbonzini@redhat.com>,
	Sean Christopherson <seanjc@google.com>,
	Paul Walmsley <pjw@kernel.org>,
	Paul Walmsley <paul.walmsley@sifive.com>,
	Palmer Dabbelt <palmer@dabbelt.com>,
	Albert Ou <aou@eecs.berkeley.edu>,
	Alexandre Ghiti <alex@ghiti.fr>,
	Andrew Jones <andrew.jones@oss.qualcomm.com>,
	Conor Dooley <conor.dooley@microchip.com>,
	Yong-Xuan Wang <yongxuan.wang@sifive.com>,
	Nutty Liu <nutty.liu@hotmail.com>, Jinyu Tang <tjytimi@163.com>,
	Jinyu Tang <jinyu.tang@linux.dev>,
	Sashiko <sashiko-bot@kernel.org>
Subject: [PATCH] KVM: riscv: Avoid overwriting existing G-stage tables with huge leaves
Date: Fri, 14 Aug 2026 06:57:52 -0400	[thread overview]
Message-ID: <20260814105752.565325-1-jinyu.tang@linux.dev> (raw)

RISC-V KVM can overwrite an existing G-stage table entry when installing
a huge leaf mapping. If the target huge range already has a lower-level
page table, kvm_riscv_gstage_set_pte() can replace the non-leaf entry
with a leaf PTE. This disconnects the lower-level page table and can
change guest-visible mappings or leak the page-table page.

Reject replacing a valid non-leaf PTE with a leaf PTE. If huge-page
installation hits such a conflict, fall back to a 4K mapping for the
faulting GPA and leave the existing page-table structure intact.

Suggested-by: Sashiko <sashiko-bot@kernel.org>
Fixes: 9d05c1fee837 ("RISC-V: KVM: Implement stage2 page table programming")
Signed-off-by: Jinyu Tang <jinyu.tang@linux.dev>
---
 arch/riscv/kvm/gstage.c | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/arch/riscv/kvm/gstage.c b/arch/riscv/kvm/gstage.c
index e5002cb9cbef..23cb35e36073 100644
--- a/arch/riscv/kvm/gstage.c
+++ b/arch/riscv/kvm/gstage.c
@@ -174,6 +174,12 @@ int kvm_riscv_gstage_set_pte(struct kvm_gstage *gstage,
 
 	if (pte_val(*ptep) != pte_val(map->pte)) {
 		bool was_invalid = !pte_val(*ptep);
+
+		/* Avoid replacing an existing lower-level table with a leaf mapping. */
+		if (!gstage_pte_leaf(ptep) && !was_invalid &&
+		    gstage_pte_leaf(&map->pte))
+			return -EEXIST;
+
 		set_pte(ptep, map->pte);
 		if (gstage_pte_leaf(ptep) &&
 		    !(was_invalid && riscv_has_extension_unlikely(RISCV_ISA_EXT_SVVPTC)))
@@ -211,12 +217,13 @@ int kvm_riscv_gstage_map_page(struct kvm_gstage *gstage,
 			      struct kvm_gstage_mapping *out_map)
 {
 	bool found_leaf;
+	phys_addr_t huge_page_offset;
 	u32 ptep_level;
 	pgprot_t prot;
 	pte_t *ptep;
 	int ret;
 
-	out_map->addr = gpa;
+	out_map->addr = gpa & PAGE_MASK;
 	out_map->level = 0;
 
 	ret = gstage_page_size_to_level(gstage, page_size, &out_map->level);
@@ -287,7 +294,18 @@ int kvm_riscv_gstage_map_page(struct kvm_gstage *gstage,
 	out_map->pte = pfn_pte(PFN_DOWN(hpa), prot);
 	out_map->pte = pte_mkdirty(out_map->pte);
 
-	return kvm_riscv_gstage_set_pte(gstage, pcache, out_map);
+	ret = kvm_riscv_gstage_set_pte(gstage, pcache, out_map);
+	if (ret == -EEXIST) {
+		huge_page_offset = out_map->addr & (page_size - 1);
+		hpa += huge_page_offset;
+		out_map->level = 0;
+		out_map->pte = pfn_pte(PFN_DOWN(hpa), prot);
+		out_map->pte = pte_mkdirty(out_map->pte);
+
+		ret = kvm_riscv_gstage_set_pte(gstage, pcache, out_map);
+	}
+
+	return ret;
 }
 
 static inline unsigned long make_child_pte(unsigned long huge_pte, int index,
-- 
2.43.0


WARNING: multiple messages have this Message-ID (diff)
From: Jinyu Tang <jinyu.tang@linux.dev>
To: Anup Patel <anup@brainfault.org>,
	Anup Patel <apatel@ventanamicro.com>,
	Atish Patra <atish.patra@linux.dev>
Cc: kvm@vger.kernel.org, kvm-riscv@lists.infradead.org,
	linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org,
	Paolo Bonzini <pbonzini@redhat.com>,
	Sean Christopherson <seanjc@google.com>,
	Paul Walmsley <pjw@kernel.org>,
	Paul Walmsley <paul.walmsley@sifive.com>,
	Palmer Dabbelt <palmer@dabbelt.com>,
	Albert Ou <aou@eecs.berkeley.edu>,
	Alexandre Ghiti <alex@ghiti.fr>,
	Andrew Jones <andrew.jones@oss.qualcomm.com>,
	Conor Dooley <conor.dooley@microchip.com>,
	Yong-Xuan Wang <yongxuan.wang@sifive.com>,
	Nutty Liu <nutty.liu@hotmail.com>, Jinyu Tang <tjytimi@163.com>,
	Jinyu Tang <jinyu.tang@linux.dev>,
	Sashiko <sashiko-bot@kernel.org>
Subject: [PATCH] KVM: riscv: Avoid overwriting existing G-stage tables with huge leaves
Date: Fri, 14 Aug 2026 06:57:52 -0400	[thread overview]
Message-ID: <20260814105752.565325-1-jinyu.tang@linux.dev> (raw)

RISC-V KVM can overwrite an existing G-stage table entry when installing
a huge leaf mapping. If the target huge range already has a lower-level
page table, kvm_riscv_gstage_set_pte() can replace the non-leaf entry
with a leaf PTE. This disconnects the lower-level page table and can
change guest-visible mappings or leak the page-table page.

Reject replacing a valid non-leaf PTE with a leaf PTE. If huge-page
installation hits such a conflict, fall back to a 4K mapping for the
faulting GPA and leave the existing page-table structure intact.

Suggested-by: Sashiko <sashiko-bot@kernel.org>
Fixes: 9d05c1fee837 ("RISC-V: KVM: Implement stage2 page table programming")
Signed-off-by: Jinyu Tang <jinyu.tang@linux.dev>
---
 arch/riscv/kvm/gstage.c | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/arch/riscv/kvm/gstage.c b/arch/riscv/kvm/gstage.c
index e5002cb9cbef..23cb35e36073 100644
--- a/arch/riscv/kvm/gstage.c
+++ b/arch/riscv/kvm/gstage.c
@@ -174,6 +174,12 @@ int kvm_riscv_gstage_set_pte(struct kvm_gstage *gstage,
 
 	if (pte_val(*ptep) != pte_val(map->pte)) {
 		bool was_invalid = !pte_val(*ptep);
+
+		/* Avoid replacing an existing lower-level table with a leaf mapping. */
+		if (!gstage_pte_leaf(ptep) && !was_invalid &&
+		    gstage_pte_leaf(&map->pte))
+			return -EEXIST;
+
 		set_pte(ptep, map->pte);
 		if (gstage_pte_leaf(ptep) &&
 		    !(was_invalid && riscv_has_extension_unlikely(RISCV_ISA_EXT_SVVPTC)))
@@ -211,12 +217,13 @@ int kvm_riscv_gstage_map_page(struct kvm_gstage *gstage,
 			      struct kvm_gstage_mapping *out_map)
 {
 	bool found_leaf;
+	phys_addr_t huge_page_offset;
 	u32 ptep_level;
 	pgprot_t prot;
 	pte_t *ptep;
 	int ret;
 
-	out_map->addr = gpa;
+	out_map->addr = gpa & PAGE_MASK;
 	out_map->level = 0;
 
 	ret = gstage_page_size_to_level(gstage, page_size, &out_map->level);
@@ -287,7 +294,18 @@ int kvm_riscv_gstage_map_page(struct kvm_gstage *gstage,
 	out_map->pte = pfn_pte(PFN_DOWN(hpa), prot);
 	out_map->pte = pte_mkdirty(out_map->pte);
 
-	return kvm_riscv_gstage_set_pte(gstage, pcache, out_map);
+	ret = kvm_riscv_gstage_set_pte(gstage, pcache, out_map);
+	if (ret == -EEXIST) {
+		huge_page_offset = out_map->addr & (page_size - 1);
+		hpa += huge_page_offset;
+		out_map->level = 0;
+		out_map->pte = pfn_pte(PFN_DOWN(hpa), prot);
+		out_map->pte = pte_mkdirty(out_map->pte);
+
+		ret = kvm_riscv_gstage_set_pte(gstage, pcache, out_map);
+	}
+
+	return ret;
 }
 
 static inline unsigned long make_child_pte(unsigned long huge_pte, int index,
-- 
2.43.0


_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

             reply	other threads:[~2026-08-14 10:58 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-14 10:57 Jinyu Tang [this message]
2026-08-14 10:57 ` [PATCH] KVM: riscv: Avoid overwriting existing G-stage tables with huge leaves Jinyu Tang
2026-08-14 10:57 ` Jinyu Tang
2026-08-14 11:21 ` sashiko-bot

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=20260814105752.565325-1-jinyu.tang@linux.dev \
    --to=jinyu.tang@linux.dev \
    --cc=alex@ghiti.fr \
    --cc=andrew.jones@oss.qualcomm.com \
    --cc=anup@brainfault.org \
    --cc=aou@eecs.berkeley.edu \
    --cc=apatel@ventanamicro.com \
    --cc=atish.patra@linux.dev \
    --cc=conor.dooley@microchip.com \
    --cc=kvm-riscv@lists.infradead.org \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-riscv@lists.infradead.org \
    --cc=nutty.liu@hotmail.com \
    --cc=palmer@dabbelt.com \
    --cc=paul.walmsley@sifive.com \
    --cc=pbonzini@redhat.com \
    --cc=pjw@kernel.org \
    --cc=sashiko-bot@kernel.org \
    --cc=seanjc@google.com \
    --cc=tjytimi@163.com \
    --cc=yongxuan.wang@sifive.com \
    /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.