From: Claudio Imbrenda <imbrenda@linux.ibm.com>
To: kvm@vger.kernel.org
Cc: linux-s390@vger.kernel.org, borntraeger@de.ibm.com,
frankja@linux.ibm.com, david@kernel.org, nrb@linux.ibm.com,
schlameuss@linux.ibm.com, gra@linux.ibm.com
Subject: [PATCH v3 4/4] KVM: s390: vsie: Fix pinning using the wrong flag
Date: Tue, 27 Oct 2026 18:32:39 +0100 [thread overview]
Message-ID: <20261027173239.224849-5-imbrenda@linux.ibm.com> (raw)
In-Reply-To: <20261027173239.224849-1-imbrenda@linux.ibm.com>
When pinning guest memory using pin_blocks(), gfn_to_page() was used,
which under the hood uses FOLL_GET, which is the wrong type of flag for
memory that is accessed directly by hardware.
Fix by using kvm_vcpu_{,un}map(), which uses FOLL_PIN and is the
correct thing to do.
While technically a bugfix, the previous behaviour can only lead to
guest corruption in extremely convoluted test scenarios that cannot
happen in real/production systems.
Fixes: e38c884df921 ("KVM: s390: Switch to new gmap")
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Cc: stable@vger.kernel.org #7.0+
---
arch/s390/kvm/s390/vsie.c | 137 ++++++++++++++------------------------
1 file changed, 50 insertions(+), 87 deletions(-)
diff --git a/arch/s390/kvm/s390/vsie.c b/arch/s390/kvm/s390/vsie.c
index 5926689fa226..cdaa84539645 100644
--- a/arch/s390/kvm/s390/vsie.c
+++ b/arch/s390/kvm/s390/vsie.c
@@ -49,20 +49,21 @@ struct vsie_page {
/* address of the last reported fault to guest2 */
unsigned long fault_addr; /* 0x0228 */
/* calculated guest addresses of satellite control blocks */
- gpa_t sca_gpa; /* 0x0230 */
- gpa_t itdba_gpa; /* 0x0238 */
- gpa_t gvrd_gpa; /* 0x0240 */
- gpa_t riccbd_gpa; /* 0x0248 */
- gpa_t sdnx_gpa; /* 0x0250 */
+ struct kvm_host_map sca_map; /* 0x0230 */
+ struct kvm_host_map itdba_map; /* 0x0260 */
+ struct kvm_host_map gvrd_map; /* 0x0290 */
+ struct kvm_host_map riccbd_map; /* 0x02c0 */
+ struct kvm_host_map sdnx_map; /* 0x02f0 */
+ struct kvm_host_map scb_map; /* 0x0320 */
/*
* guest address of the original SCB. Remains set for free vsie
* pages, so we can properly look them up in our addr_to_page
* radix tree.
*/
- gpa_t scb_gpa; /* 0x0258 */
+ gpa_t scb_gpa; /* 0x0350 */
/* the shadow gmap in use by the vsie_page */
- struct gmap_cache gmap_cache; /* 0x0260 */
- __u8 reserved[0x06f8 - 0x0278]; /* 0x0278 */
+ struct gmap_cache gmap_cache; /* 0x0358 */
+ __u8 reserved[0x06f8 - 0x0370]; /* 0x0370 */
struct kvm_s390_crypto_cb crycb; /* 0x06f8 */
__u8 fac[8 + S390_ARCH_FAC_LIST_SIZE_BYTE];/* 0x07f8 */
};
@@ -681,72 +682,45 @@ static int map_prefix(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page, struct
}
/*
- * Pin the guest page given by gpa and set hpa to the pinned host address.
+ * pin_guest_page() - Pin the given guest page and return its hpa.
+ * @vcpu: the vCPU
+ * @gpa: the gpa to pin
+ * @map: the map representing this pinning.
+ *
* Will always be pinned writable.
*
- * Returns: - 0 on success
- * - -EINVAL if the gpa is not valid guest storage
+ * Returns: - 0 if the gpa is not valid guest storage,
+ * - The host hpa of the pinned page in case of success
*/
-static int pin_guest_page(struct kvm *kvm, gpa_t gpa, hpa_t *hpa)
+static hpa_t pin_guest_page(struct kvm_vcpu *vcpu, gpa_t gpa, struct kvm_host_map *map)
{
- struct page *page;
-
- page = gfn_to_page(kvm, gpa_to_gfn(gpa));
- if (!page)
- return -EINVAL;
- *hpa = (hpa_t)page_to_phys(page) + (gpa & ~PAGE_MASK);
- return 0;
-}
-
-/* Unpins a page previously pinned via pin_guest_page, marking it as dirty. */
-static void unpin_guest_page(struct kvm *kvm, gpa_t gpa, hpa_t hpa)
-{
- kvm_release_page_dirty(pfn_to_page(phys_to_pfn(hpa)));
- /* mark the page always as dirty for migration */
- mark_page_dirty(kvm, gpa_to_gfn(gpa));
+ if (kvm_vcpu_map(vcpu, gpa_to_gfn(gpa), map))
+ return 0;
+ if (!kvm_vcpu_mapped(map))
+ return 0;
+ return (hpa_t)PFN_PHYS(map->pfn) + (gpa & ~PAGE_MASK);
}
/* unpin all blocks previously pinned by pin_blocks(), marking them dirty */
static void unpin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
{
struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
- hpa_t hpa;
- hpa = (u64) scb_s->scaoh << 32 | scb_s->scaol;
- if (hpa) {
- unpin_guest_page(vcpu->kvm, vsie_page->sca_gpa, hpa);
- vsie_page->sca_gpa = 0;
- scb_s->scaol = 0;
- scb_s->scaoh = 0;
- }
+ kvm_vcpu_unmap(vcpu, &vsie_page->sca_map);
+ scb_s->scaol = 0;
+ scb_s->scaoh = 0;
- hpa = scb_s->itdba;
- if (hpa) {
- unpin_guest_page(vcpu->kvm, vsie_page->itdba_gpa, hpa);
- vsie_page->itdba_gpa = 0;
- scb_s->itdba = 0;
- }
+ kvm_vcpu_unmap(vcpu, &vsie_page->itdba_map);
+ scb_s->itdba = 0;
- hpa = scb_s->gvrd;
- if (hpa) {
- unpin_guest_page(vcpu->kvm, vsie_page->gvrd_gpa, hpa);
- vsie_page->gvrd_gpa = 0;
- scb_s->gvrd = 0;
- }
+ kvm_vcpu_unmap(vcpu, &vsie_page->gvrd_map);
+ scb_s->gvrd = 0;
- hpa = scb_s->riccbd;
- if (hpa) {
- unpin_guest_page(vcpu->kvm, vsie_page->riccbd_gpa, hpa);
- vsie_page->riccbd_gpa = 0;
- scb_s->riccbd = 0;
- }
+ kvm_vcpu_unmap(vcpu, &vsie_page->riccbd_map);
+ scb_s->riccbd = 0;
- hpa = scb_s->sdnxo;
- if (hpa) {
- unpin_guest_page(vcpu->kvm, vsie_page->sdnx_gpa, hpa);
- vsie_page->sdnx_gpa = 0;
- scb_s->sdnxo = 0;
- }
+ kvm_vcpu_unmap(vcpu, &vsie_page->sdnx_map);
+ scb_s->sdnxo = 0;
}
/*
@@ -783,13 +757,12 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
((gpa + offsetof(struct bsca_block, cpu[0]) - 1) & PAGE_MASK))
rc = set_validity_icpt(scb_s, 0x003bU);
if (!rc) {
- rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
- if (rc)
+ hpa = pin_guest_page(vcpu, gpa, &vsie_page->sca_map);
+ if (!hpa)
rc = set_validity_icpt(scb_s, 0x0034U);
}
- if (rc)
+ if (rc || !hpa)
goto unpin;
- vsie_page->sca_gpa = gpa;
scb_s->scaoh = (u32)((u64)hpa >> 32);
scb_s->scaol = (u32)(u64)hpa;
}
@@ -801,12 +774,11 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
goto unpin;
}
/* 256 bytes cannot cross page boundaries */
- rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
- if (rc) {
+ hpa = pin_guest_page(vcpu, gpa, &vsie_page->itdba_map);
+ if (!hpa) {
rc = set_validity_icpt(scb_s, 0x0080U);
goto unpin;
}
- vsie_page->itdba_gpa = gpa;
scb_s->itdba = hpa;
}
@@ -820,12 +792,11 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
* 512 bytes vector registers cannot cross page boundaries
* if this block gets bigger, we have to shadow it.
*/
- rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
- if (rc) {
+ hpa = pin_guest_page(vcpu, gpa, &vsie_page->gvrd_map);
+ if (!hpa) {
rc = set_validity_icpt(scb_s, 0x1310U);
goto unpin;
}
- vsie_page->gvrd_gpa = gpa;
scb_s->gvrd = hpa;
}
@@ -836,13 +807,12 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
goto unpin;
}
/* 64 bytes cannot cross page boundaries */
- rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
- if (rc) {
+ hpa = pin_guest_page(vcpu, gpa, &vsie_page->riccbd_map);
+ if (!hpa) {
rc = set_validity_icpt(scb_s, 0x0043U);
goto unpin;
}
/* Validity 0x0044 will be checked by SIE */
- vsie_page->riccbd_gpa = gpa;
scb_s->riccbd = hpa;
}
if (((scb_s->ecb & ECB_GS) && !(scb_s->ecd & ECD_HOSTREGMGMT)) ||
@@ -866,12 +836,11 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
/* Due to alignment rules (checked above) this cannot
* cross page boundaries
*/
- rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
- if (rc) {
+ hpa = pin_guest_page(vcpu, gpa, &vsie_page->sdnx_map);
+ if (!hpa) {
rc = set_validity_icpt(scb_s, 0x10b0U);
goto unpin;
}
- vsie_page->sdnx_gpa = gpa;
scb_s->sdnxo = hpa | sdnxc;
}
return 0;
@@ -881,13 +850,9 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
}
/* unpin the scb provided by guest 2, marking it as dirty */
-static void unpin_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page,
- gpa_t gpa)
+static void unpin_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
{
- hpa_t hpa = virt_to_phys(vsie_page->scb_o);
-
- if (hpa)
- unpin_guest_page(vcpu->kvm, gpa, hpa);
+ kvm_vcpu_unmap(vcpu, &vsie_page->scb_map);
vsie_page->scb_o = NULL;
}
@@ -901,12 +866,10 @@ static int pin_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page,
gpa_t gpa)
{
hpa_t hpa;
- int rc;
- rc = pin_guest_page(vcpu->kvm, gpa, &hpa);
- if (rc) {
- rc = kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
- WARN_ON_ONCE(rc);
+ hpa = pin_guest_page(vcpu, gpa, &vsie_page->scb_map);
+ if (!hpa) {
+ WARN_ON_ONCE(kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING));
return 1;
}
vsie_page->scb_o = phys_to_virt(hpa);
@@ -1601,7 +1564,7 @@ int kvm_s390_handle_vsie(struct kvm_vcpu *vcpu)
out_unshadow:
unshadow_scb(vcpu, vsie_page);
out_unpin_scb:
- unpin_scb(vcpu, vsie_page, scb_addr);
+ unpin_scb(vcpu, vsie_page);
out_put:
put_vsie_page(vsie_page);
--
2.56.0
next prev parent reply other threads:[~2026-10-27 17:32 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-27 17:32 [PATCH v3 0/4] KVM: s390: Misc bugfixes for 7.4 Claudio Imbrenda
2026-10-27 17:32 ` [PATCH v3 1/4] KVM: s390: Fix UCONTROL inconsistencies Claudio Imbrenda
2026-10-27 17:54 ` sashiko-bot
2026-10-27 17:32 ` [PATCH v3 2/4] KVM: s390: Move some skey functions to headers Claudio Imbrenda
2026-10-27 17:34 ` sashiko-bot
2026-10-27 17:32 ` [PATCH v3 3/4] KVM: s390: Improve unmapping of large ranges Claudio Imbrenda
2026-10-27 17:52 ` sashiko-bot
2026-10-27 17:32 ` Claudio Imbrenda [this message]
2026-10-27 17:38 ` [PATCH v3 4/4] KVM: s390: vsie: Fix pinning using the wrong flag 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=20261027173239.224849-5-imbrenda@linux.ibm.com \
--to=imbrenda@linux.ibm.com \
--cc=borntraeger@de.ibm.com \
--cc=david@kernel.org \
--cc=frankja@linux.ibm.com \
--cc=gra@linux.ibm.com \
--cc=kvm@vger.kernel.org \
--cc=linux-s390@vger.kernel.org \
--cc=nrb@linux.ibm.com \
--cc=schlameuss@linux.ibm.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.