aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakuya Yoshikawa <yoshikawa_takuya_b1@lab.ntt.co.jp>2013-01-30 05:40:41 -0500
committerMarcelo Tosatti <mtosatti@redhat.com>2013-02-04 19:56:47 -0500
commit75d61fbcf563373696578570e914f555e12c8d97 (patch)
tree8835d8a5cf79704569f568675792672c930746ae
parentf64c0398939483eb1d8951f24fbc21e94ed54457 (diff)
KVM: set_memory_region: Disallow changing read-only attribute later
As Xiao pointed out, there are a few problems with it: - kvm_arch_commit_memory_region() write protects the memory slot only for GET_DIRTY_LOG when modifying the flags. - FNAME(sync_page) uses the old spte value to set a new one without checking KVM_MEM_READONLY flag. Since we flush all shadow pages when creating a new slot, the simplest fix is to disallow such problematic flag changes: this is safe because no one is doing such things. Reviewed-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Takuya Yoshikawa <yoshikawa_takuya_b1@lab.ntt.co.jp> Cc: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> Cc: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rw-r--r--Documentation/virtual/kvm/api.txt12
-rw-r--r--virt/kvm/kvm_main.c35
2 files changed, 18 insertions, 29 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 09905cbcbb0b..0e03b1968272 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -874,12 +874,12 @@ It is recommended that the lower 21 bits of guest_phys_addr and userspace_addr
874be identical. This allows large pages in the guest to be backed by large 874be identical. This allows large pages in the guest to be backed by large
875pages in the host. 875pages in the host.
876 876
877The flags field supports two flag, KVM_MEM_LOG_DIRTY_PAGES, which instructs 877The flags field supports two flags: KVM_MEM_LOG_DIRTY_PAGES and
878kvm to keep track of writes to memory within the slot. See KVM_GET_DIRTY_LOG 878KVM_MEM_READONLY. The former can be set to instruct KVM to keep track of
879ioctl. The KVM_CAP_READONLY_MEM capability indicates the availability of the 879writes to memory within the slot. See KVM_GET_DIRTY_LOG ioctl to know how to
880KVM_MEM_READONLY flag. When this flag is set for a memory region, KVM only 880use it. The latter can be set, if KVM_CAP_READONLY_MEM capability allows it,
881allows read accesses. Writes will be posted to userspace as KVM_EXIT_MMIO 881to make a new slot read-only. In this case, writes to this memory will be
882exits. 882posted to userspace as KVM_EXIT_MMIO exits.
883 883
884When the KVM_CAP_SYNC_MMU capability is available, changes in the backing of 884When the KVM_CAP_SYNC_MMU capability is available, changes in the backing of
885the memory region are automatically reflected into the guest. For example, an 885the memory region are automatically reflected into the guest. For example, an
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 64c5dc37c6a1..2e93630b4add 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -754,7 +754,6 @@ int __kvm_set_memory_region(struct kvm *kvm,
754 struct kvm_memory_slot *slot; 754 struct kvm_memory_slot *slot;
755 struct kvm_memory_slot old, new; 755 struct kvm_memory_slot old, new;
756 struct kvm_memslots *slots = NULL, *old_memslots; 756 struct kvm_memslots *slots = NULL, *old_memslots;
757 bool old_iommu_mapped;
758 enum kvm_mr_change change; 757 enum kvm_mr_change change;
759 758
760 r = check_memory_region_flags(mem); 759 r = check_memory_region_flags(mem);
@@ -797,15 +796,14 @@ int __kvm_set_memory_region(struct kvm *kvm,
797 new.npages = npages; 796 new.npages = npages;
798 new.flags = mem->flags; 797 new.flags = mem->flags;
799 798
800 old_iommu_mapped = old.npages;
801
802 r = -EINVAL; 799 r = -EINVAL;
803 if (npages) { 800 if (npages) {
804 if (!old.npages) 801 if (!old.npages)
805 change = KVM_MR_CREATE; 802 change = KVM_MR_CREATE;
806 else { /* Modify an existing slot. */ 803 else { /* Modify an existing slot. */
807 if ((mem->userspace_addr != old.userspace_addr) || 804 if ((mem->userspace_addr != old.userspace_addr) ||
808 (npages != old.npages)) 805 (npages != old.npages) ||
806 ((new.flags ^ old.flags) & KVM_MEM_READONLY))
809 goto out; 807 goto out;
810 808
811 if (base_gfn != old.base_gfn) 809 if (base_gfn != old.base_gfn)
@@ -867,7 +865,6 @@ int __kvm_set_memory_region(struct kvm *kvm,
867 865
868 /* slot was deleted or moved, clear iommu mapping */ 866 /* slot was deleted or moved, clear iommu mapping */
869 kvm_iommu_unmap_pages(kvm, &old); 867 kvm_iommu_unmap_pages(kvm, &old);
870 old_iommu_mapped = false;
871 /* From this point no new shadow pages pointing to a deleted, 868 /* From this point no new shadow pages pointing to a deleted,
872 * or moved, memslot will be created. 869 * or moved, memslot will be created.
873 * 870 *
@@ -898,25 +895,17 @@ int __kvm_set_memory_region(struct kvm *kvm,
898 895
899 /* 896 /*
900 * IOMMU mapping: New slots need to be mapped. Old slots need to be 897 * IOMMU mapping: New slots need to be mapped. Old slots need to be
901 * un-mapped and re-mapped if their base changes or if flags that the 898 * un-mapped and re-mapped if their base changes. Since base change
902 * iommu cares about change (read-only). Base change unmapping is 899 * unmapping is handled above with slot deletion, mapping alone is
903 * handled above with slot deletion, so we only unmap incompatible 900 * needed here. Anything else the iommu might care about for existing
904 * flags here. Anything else the iommu might care about for existing 901 * slots (size changes, userspace addr changes and read-only flag
905 * slots (size changes, userspace addr changes) is disallowed above, 902 * changes) is disallowed above, so any other attribute changes getting
906 * so any other attribute changes getting here can be skipped. 903 * here can be skipped.
907 */ 904 */
908 if (change != KVM_MR_DELETE) { 905 if ((change == KVM_MR_CREATE) || (change == KVM_MR_MOVE)) {
909 if (old_iommu_mapped && 906 r = kvm_iommu_map_pages(kvm, &new);
910 ((new.flags ^ old.flags) & KVM_MEM_READONLY)) { 907 if (r)
911 kvm_iommu_unmap_pages(kvm, &old); 908 goto out_slots;
912 old_iommu_mapped = false;
913 }
914
915 if (!old_iommu_mapped) {
916 r = kvm_iommu_map_pages(kvm, &new);
917 if (r)
918 goto out_slots;
919 }
920 } 909 }
921 910
922 /* actual memory is freed via old in kvm_free_physmem_slot below */ 911 /* actual memory is freed via old in kvm_free_physmem_slot below */