Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

KVM: s390: vsie: Fix guest page tables protection

When shadowing, the guest page tables are write-protected, in order to
trap changes and properly unshadow the shadow mapping for the nested
guest. Already shadowed levels are skipped, so that only the needed
levels are write protected.

Currently the levels that get write protected are exactly one level too
deep: the last level (nested guest memory) gets protected in the wrong
way, and will be protected again correctly a few lines afterwards; most
importantly, the highest non-shadowed level does *not* get write
protected.

Moreover, if the nested guest is running in a real address space, there
are no DAT tables to shadow.

Write protect the correct levels, so that all the levels that need to
be protected are protected, and avoid double protecting the last level;
skip attempting to shadow the DAT tables when the nested guest is
running in a real address space.

Fixes: e38c884df921 ("KVM: s390: Switch to new gmap")
Tested-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>

+10 -2
+10 -2
arch/s390/kvm/gaccess.c
··· 1529 1529 1530 1530 gl = get_level(table, ptep); 1531 1531 1532 + /* In case of a real address space */ 1533 + if (w->level <= LEVEL_MEM) { 1534 + l = TABLE_TYPE_PAGE_TABLE; 1535 + hl = TABLE_TYPE_REGION1; 1536 + goto real_address_space; 1537 + } 1538 + 1532 1539 /* 1533 1540 * Skip levels that are already protected. For each level, protect 1534 1541 * only the page containing the entry, not the whole table. 1535 1542 */ 1536 1543 for (i = gl ; i >= w->level; i--) { 1537 - rc = gmap_protect_rmap(mc, sg, entries[i - 1].gfn, gpa_to_gfn(saddr), 1538 - entries[i - 1].pfn, i, entries[i - 1].writable); 1544 + rc = gmap_protect_rmap(mc, sg, entries[i].gfn, gpa_to_gfn(saddr), 1545 + entries[i].pfn, i + 1, entries[i].writable); 1539 1546 if (rc) 1540 1547 return rc; 1541 1548 if (!sg->parent) ··· 1558 1551 /* Get the smallest granularity */ 1559 1552 l = min3(gl, hl, w->level); 1560 1553 1554 + real_address_space: 1561 1555 flags = DAT_WALK_SPLIT_ALLOC | (uses_skeys(sg->parent) ? DAT_WALK_USES_SKEYS : 0); 1562 1556 /* If necessary, create the shadow mapping */ 1563 1557 if (l < gl) {