@@ -1914,10 +1914,51 @@ static bool sp_has_gptes(struct kvm_mmu_page *sp)
1914
1914
&(_kvm)->arch.mmu_page_hash[kvm_page_table_hashfn(_gfn)]) \
1915
1915
if ((_sp)->gfn != (_gfn) || !sp_has_gptes(_sp)) {} else
1916
1916
1917
+ static bool kvm_sync_page_check (struct kvm_vcpu * vcpu , struct kvm_mmu_page * sp )
1918
+ {
1919
+ union kvm_mmu_page_role root_role = vcpu -> arch .mmu -> root_role ;
1920
+
1921
+ /*
1922
+ * Ignore various flags when verifying that it's safe to sync a shadow
1923
+ * page using the current MMU context.
1924
+ *
1925
+ * - level: not part of the overall MMU role and will never match as the MMU's
1926
+ * level tracks the root level
1927
+ * - access: updated based on the new guest PTE
1928
+ * - quadrant: not part of the overall MMU role (similar to level)
1929
+ */
1930
+ const union kvm_mmu_page_role sync_role_ign = {
1931
+ .level = 0xf ,
1932
+ .access = 0x7 ,
1933
+ .quadrant = 0x3 ,
1934
+ .passthrough = 0x1 ,
1935
+ };
1936
+
1937
+ /*
1938
+ * Direct pages can never be unsync, and KVM should never attempt to
1939
+ * sync a shadow page for a different MMU context, e.g. if the role
1940
+ * differs then the memslot lookup (SMM vs. non-SMM) will be bogus, the
1941
+ * reserved bits checks will be wrong, etc...
1942
+ */
1943
+ if (WARN_ON_ONCE (sp -> role .direct ||
1944
+ (sp -> role .word ^ root_role .word ) & ~sync_role_ign .word ))
1945
+ return false;
1946
+
1947
+ return true;
1948
+ }
1949
+
1950
+ static int __kvm_sync_page (struct kvm_vcpu * vcpu , struct kvm_mmu_page * sp )
1951
+ {
1952
+ if (!kvm_sync_page_check (vcpu , sp ))
1953
+ return -1 ;
1954
+
1955
+ return vcpu -> arch .mmu -> sync_page (vcpu , sp );
1956
+ }
1957
+
1917
1958
static int kvm_sync_page (struct kvm_vcpu * vcpu , struct kvm_mmu_page * sp ,
1918
1959
struct list_head * invalid_list )
1919
1960
{
1920
- int ret = vcpu -> arch . mmu -> sync_page (vcpu , sp );
1961
+ int ret = __kvm_sync_page (vcpu , sp );
1921
1962
1922
1963
if (ret < 0 )
1923
1964
kvm_mmu_prepare_zap_page (vcpu -> kvm , sp , invalid_list );
0 commit comments