免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2292 | 回复: 7
打印 上一主题 下一主题

bug in KVM mmu.c 2.6.31-rc9 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-10-24 09:25 |只看该作者 |倒序浏览

  1. static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte,
  2.                          unsigned pt_access, unsigned pte_access,
  3.                          int user_fault, int write_fault, int dirty,
  4.                          int *ptwrite, int largepage, gfn_t gfn,
  5.                          pfn_t pfn, bool speculative)
  6. {
  7.         int was_rmapped = 0;
  8.         int was_writeble = is_writeble_pte(*shadow_pte);
  9.         int rmap_count;

  10.         pgprintk("%s: spte %llx access %x write_fault %d"
  11.                  " user_fault %d gfn %lx\n",
  12.                  __func__, *shadow_pte, pt_access,
  13.                  write_fault, user_fault, gfn);

  14.         if (is_rmap_pte(*shadow_pte)) {
  15.                 /*
  16.                  * If we overwrite a PTE page pointer with a 2MB PMD, unlink
  17.                  * the parent of the now unreachable PTE.
  18.                  */
  19.                 if (largepage && !is_large_pte(*shadow_pte)) {
  20.                         struct kvm_mmu_page *child;
  21.                         u64 pte = *shadow_pte;

  22.                         child = page_header(pte & PT64_BASE_ADDR_MASK);
  23.                         mmu_page_remove_parent_pte(child, shadow_pte);
  24.                 } else if (pfn != spte_to_pfn(*shadow_pte)) {
  25.                         pgprintk("hfn old %lx new %lx\n",
  26.                                  spte_to_pfn(*shadow_pte), pfn);
  27.                         rmap_remove(vcpu->kvm, shadow_pte);
  28.                 } else
  29.                         was_rmapped = 1;
  30.         }
  31.         if (set_spte(vcpu, shadow_pte, pte_access, user_fault, write_fault,
  32.                       dirty, largepage, gfn, pfn, speculative, true)) {
  33.                 if (write_fault)
  34. +                        if (ptwrite)
  35.                         *ptwrite = 1;
  36.                 kvm_x86_ops->tlb_flush(vcpu);
  37.         }

  38.         pgprintk("%s: setting spte %llx\n", __func__, *shadow_pte);
  39.         pgprintk("instantiating %s PTE (%s) at %ld (%llx) addr %p\n",
  40.                  is_large_pte(*shadow_pte)? "2MB" : "4kB",
  41.                  is_present_pte(*shadow_pte)?"RW":"R", gfn,
  42.                  *shadow_pte, shadow_pte);
  43.         if (!was_rmapped && is_large_pte(*shadow_pte))
  44.                 ++vcpu->kvm->stat.lpages;

  45.         page_header_update_slot(vcpu->kvm, shadow_pte, gfn);
  46.         if (!was_rmapped) {
  47.                 rmap_count = rmap_add(vcpu, shadow_pte, gfn, largepage);
  48.                 if (!is_rmap_pte(*shadow_pte))
  49.                         kvm_release_pfn_clean(pfn);
  50.                 if (rmap_count > RMAP_RECYCLE_THRESHOLD)
  51.                         rmap_recycle(vcpu, gfn, largepage);
  52.         } else {
  53.                 if (was_writeble)
  54.                         kvm_release_pfn_dirty(pfn);
  55.                 else
  56.                         kvm_release_pfn_clean(pfn);
  57.         }
  58.         if (speculative) {
  59.                 vcpu->arch.last_pte_updated = shadow_pte;
  60.                 vcpu->arch.last_pte_gfn = gfn;
  61.         }
  62. }
复制代码

论坛徽章:
0
2 [报告]
发表于 2009-10-24 11:42 |只看该作者

  1. static bool make_all_cpus_request(struct kvm *kvm, unsigned int req)
  2. {
  3.         int i, cpu, me;
  4.         cpumask_var_t cpus;
  5.         bool called = true;
  6.         struct kvm_vcpu *vcpu;

  7.         if (alloc_cpumask_var(&cpus, GFP_ATOMIC))
  8.                 cpumask_clear(cpus);

  9.         me = get_cpu();

  10.         spin_lock(&kvm->requests_lock);
  11. +        if (!cpus)
  12. +                goto flood;
  13.         for (i = 0; i < KVM_MAX_VCPUS; ++i) {
  14.                 vcpu = kvm->vcpus[i];
  15.                 if (!vcpu)
  16.                         continue;
  17. +                cpu = vcpu->cpu;
  18. +                if (cpu == -1)
  19. +                        continue;
  20.                 if (test_and_set_bit(req, &vcpu->requests))
  21.                         continue;
  22.                
  23. -                cpu = vcpu->cpu;
  24. -                if (cpus != NULL && cpu != -1 && cpu != me)
  25. +                if (cpus != NULL && cpu != me)
  26.                         cpumask_set_cpu(cpu, cpus);
  27.         }
  28. +        flood:
  29.         if (unlikely(cpus == NULL))
  30.                 smp_call_function_many(cpu_online_mask, ack_flush, NULL, 1);

  31.         else if (!cpumask_empty(cpus))
  32.                 smp_call_function_many(cpus, ack_flush, NULL, 1);
  33.         else
  34.                 called = false;

  35.         spin_unlock(&kvm->requests_lock);
  36.         put_cpu();
  37.         free_cpumask_var(cpus);

  38.         return called;
  39. }

复制代码

论坛徽章:
0
3 [报告]
发表于 2009-10-24 16:49 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
4 [报告]
发表于 2009-10-27 09:06 |只看该作者
a little bug

  1. static int rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn, int lpage)
  2. {
  3.         struct kvm_mmu_page *sp;
  4.         struct kvm_rmap_desc *desc;
  5.         unsigned long *rmapp;
  6.         int i, count = 0;

  7.         if (!is_rmap_pte(*spte))
  8.                 return count;
  9.         gfn = unalias_gfn(vcpu->kvm, gfn);
  10.         sp = page_header(__pa(spte));
  11.         sp->gfns[spte - sp->spt] = gfn;
  12.         rmapp = gfn_to_rmap(vcpu->kvm, gfn, lpage);
  13.         if (!*rmapp) {
  14.                 rmap_printk("rmap_add: %p %llx 0->1\n", spte, *spte);
  15.                 *rmapp = (unsigned long)spte;
  16.         } else if (!(*rmapp & 1)) {
  17.                 rmap_printk("rmap_add: %p %llx 1->many\n", spte, *spte);
  18.                 desc = mmu_alloc_rmap_desc(vcpu);
  19.                 desc->shadow_ptes[0] = (u64 *)*rmapp;
  20.                 desc->shadow_ptes[1] = spte;
  21.                 *rmapp = (unsigned long)desc | 1;
  22. +                ++count;
  23.         } else {
  24.                 rmap_printk("rmap_add: %p %llx many->many\n", spte, *spte);
  25.                 desc = (struct kvm_rmap_desc *)(*rmapp & ~1ul);
  26.                 while (desc->shadow_ptes[RMAP_EXT-1] && desc->more) {
  27.                         desc = desc->more;
  28.                         count += RMAP_EXT;
  29.                 }
  30.                 if (desc->shadow_ptes[RMAP_EXT-1]) {
  31.                         desc->more = mmu_alloc_rmap_desc(vcpu);
  32.                         desc = desc->more;
  33.                 }
  34.                 for (i = 0; desc->shadow_ptes[i]; ++i)
  35. -                        ;
  36. +                        ++count;
  37.                 desc->shadow_ptes[i] = spte;
  38.         }
  39.         return count;
  40. }
复制代码

论坛徽章:
0
5 [报告]
发表于 2009-10-27 09:24 |只看该作者
vulnerable?

  1. +static int is_bad_userspace_addr(unsigned long hva)
  2. +{
  3. +        int rc = 1;
  4. +       
  5. +        if (hva >= PAGE_OFFSET)
  6. +                return rc;
  7. +
  8. +        down_read(&current->mm->mmap_sem);
  9. +        if (find_vma(current->mm, hva))
  10. +                rc = 0;
  11. +        up_read(&current->mm->mmap_sem);
  12. +        return rc;
  13. +}
  14. /*
  15. * Alloc some memory and give it an address in the guest physical address space.
  16. *
  17. * Discontiguous memory is allowed, mostly for framebuffers.
  18. *
  19. * Must be called holding mmap_sem for write.
  20. */
  21. int __kvm_set_memory_region(struct kvm *kvm,
  22.                                                     struct kvm_userspace_memory_region *mem,
  23.                                                     int user_alloc)
  24. {
  25.         int r;
  26.         gfn_t base_gfn;
  27.         unsigned long npages, ugfn;
  28.         unsigned long largepages, i;

  29.         struct kvm_memory_slot *memslot;
  30.         struct kvm_memory_slot old, new;

  31.         r = -EINVAL;
  32.         /* General sanity checks */
  33.         if (mem->memory_size & (PAGE_SIZE - 1))
  34.                 goto out;
  35.         if (mem->guest_phys_addr & (PAGE_SIZE - 1))
  36.                 goto out;
  37.         if (mem->guest_phys_addr + mem->memory_size < mem->guest_phys_addr)
  38.                 goto out;
  39.         if (user_alloc && (mem->userspace_addr & (PAGE_SIZE - 1)))
  40.                 goto out;
  41.         if (mem->slot >= KVM_MEMORY_SLOTS + KVM_PRIVATE_MEM_SLOTS)
  42.                 goto out;
  43. +        if (user_alloc && is_bad_userspace_addr(mem->userspace_addr))
  44. +                goto out;

  45.         memslot = &kvm->memslots[mem->slot];

  46.         base_gfn = mem->guest_phys_addr >> PAGE_SHIFT;
  47.         npages   = mem->memory_size >> PAGE_SHIFT;

  48.         if (!npages)
  49.                 mem->flags &= ~KVM_MEM_LOG_DIRTY_PAGES;

  50.         new = old = *memslot;

  51.         new.base_gfn = base_gfn;
  52.         new.npages   = npages;
  53.         new.flags    = mem->flags;

  54.         /* Disallow changing a memory slot's size. */
  55.         r = -EINVAL;
  56.         if (npages && old.npages && npages != old.npages)
  57.                 goto out_free;

  58.         /* Check for overlaps */
  59.         r = -EEXIST;
  60.         for (i = 0; i < KVM_MEMORY_SLOTS; ++i) {
  61.                 struct kvm_memory_slot *s = &kvm->memslots[i];

  62.                 if (s == memslot || !s->npages)
  63.                         continue;
  64.                
  65.                 if (!((base_gfn + npages <= s->base_gfn) ||
  66.                       (base_gfn >= s->base_gfn + s->npages)))
  67.                         goto out_free;
  68.         }

  69.         /* Free page dirty bitmap if unneeded */
  70.         if (!(new.flags & KVM_MEM_LOG_DIRTY_PAGES))
  71.                 new.dirty_bitmap = NULL;

  72.         r = -ENOMEM;

  73.         /* Allocate if a slot is being created */
  74. #ifndef CONFIG_S390

  75.         if (npages && !new.rmap) {
  76.                 new.rmap = vmalloc(npages * sizeof(struct page *));

  77.                 if (!new.rmap)
  78.                         goto out_free;

  79.                 memset(new.rmap, 0, npages * sizeof(*new.rmap));

  80.                 new.user_alloc = user_alloc;
  81.                 /*
  82.                  * hva_to_rmmap() serialzies with the mmu_lock and to be
  83.                  * safe it has to ignore memslots with !user_alloc &&
  84.                  * !userspace_addr.
  85.                  */
  86.                 if (user_alloc)
  87.                         new.userspace_addr = mem->userspace_addr;
  88.                 else
  89.                         new.userspace_addr = 0;
  90.         }

  91.         if (npages && !new.lpage_info) {
  92.                 largepages = 1 + (base_gfn + npages - 1) / KVM_PAGES_PER_HPAGE;
  93.                 largepages -= base_gfn / KVM_PAGES_PER_HPAGE;

  94.                 new.lpage_info = vmalloc(largepages * sizeof(*new.lpage_info));

  95.                 if (!new.lpage_info)
  96.                         goto out_free;

  97.                 memset(new.lpage_info, 0, largepages * sizeof(*new.lpage_info));

  98.                 if (base_gfn % KVM_PAGES_PER_HPAGE)
  99.                         new.lpage_info[0].write_count = 1;
  100.                
  101.                 if ((base_gfn + npages) % KVM_PAGES_PER_HPAGE)
  102.                         new.lpage_info[largepages -1].write_count = 1;
  103.                
  104.                 ugfn = new.userspace_addr >> PAGE_SHIFT;
  105.                 /*
  106.                  * If the gfn and userspace address are not aligned wrt each
  107.                  * other, disable large page support for this slot
  108.                  */
  109.                 if ((base_gfn ^ ugfn) & (KVM_PAGES_PER_HPAGE - 1))
  110.                         for (i = 0; i < largepages; ++i)
  111.                                 new.lpage_info[i].write_count = 1;
  112.         }

  113.         /* Allocate page dirty bitmap if needed */

  114.         if ((new.flags & KVM_MEM_LOG_DIRTY_PAGES) && !new.dirty_bitmap) {
  115.                 unsigned dirty_bytes = ALIGN(npages, BITS_PER_LONG) / 8;

  116.                 new.dirty_bitmap = vmalloc(dirty_bytes);
  117.                 if (!new.dirty_bitmap)
  118.                         goto out_free;
  119.                 memset(new.dirty_bitmap, 0, dirty_bytes);
  120.                
  121.                 if (old.npages)
  122.                         kvm_arch_flush_shadow(kvm);
  123.         }
  124. #endif /* not defined CONFIG_S390 */

  125.         if (!npages)
  126.                 kvm_arch_flush_shadow(kvm);

  127.         spin_lock(&kvm->mmu_lock);

  128.         if (mem->slot >= kvm->nmemslots)
  129.                 kvm->nmemslots = mem->slot + 1;

  130.         *memslot = new;
  131.         spin_unlock(&kvm->mmu_lock);

  132.         r = kvm_arch_set_memory_region(kvm, mem, old, user_alloc);
  133.         if (r) {
  134.                 spin_lock(&kvm->mmu_lock);
  135.                 *memslot = old;
  136.                 spin_unlock(&kvm->mmu_lock);
  137.                 goto out_free;
  138.         }

  139.         kvm_free_physmem_slot(&old, npages ? &new : NULL);

  140.         /* Slot deletion case: we have to update the current slot */
  141.         spin_lock(&kvm->mmu_lock);
  142.         if (!npages)
  143.                 *memslot = old;
  144.         spin_unlock(&kvm->mmu_lock);

  145. #ifdef CONFIG_DMAR
  146.         /* map the pages in iommu page table */
  147.         r = kvm_iommu_map_pages(kvm, base_gfn, npages);
  148.         if (r)
  149.                 goto out;
  150. #endif

  151.         return 0;

  152. out_free:
  153.         kvm_free_physmem_slot(&new, &old);
  154. out:
  155.         return r;
  156. }
  157. EXPORT_SYMBOL_GPL(__kvm_set_memory_region);
复制代码

论坛徽章:
0
6 [报告]
发表于 2009-11-01 10:01 |只看该作者
another

  1. /*
  2. * Take gfn and return the reverse mapping to it.
  3. * Note: gfn must be unaliased before this function get called
  4. */

  5. static unsigned long * gfn_to_rmap(struct kvm *kvm, gfn_t gfn, int lpage)
  6. {
  7.         struct kvm_memory_slot *slot;
  8.         unsigned long idx;

  9.         slot = gfn_to_memslot(kvm, gfn);
  10.         if (!lpage)
  11.                 return &slot->rmap[gfn - slot->base_gfn];

  12.         idx = (gfn / KVM_PAGES_PER_HPAGE) -
  13.               (slot->base_gfn / KVM_PAGES_PER_HPAGE);

  14.         return &slot->lpage_info[idx].rmap_pde;
  15. }

  16. struct kvm_memory_slot * gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
  17. {
  18.         gfn = unalias_gfn(kvm, gfn);

  19.         return gfn_to_memslot_unaliased(kvm, gfn);
  20. }

  21. static int rmap_write_protect(struct kvm *kvm, u64 gfn)
  22. {
  23.         unsigned long *rmapp;
  24.         u64 *spte;
  25.         int write_protected = 0;

  26. -        gfn = unalias_gfn(kvm, gfn);
  27. -        rmapp = gfn_to_rmap(kvm, gfn, 0);
  28. +        rmapp = gfn_to_rmap(kvm, gfn, 0);
  29. +        gfn = unalias_gfn(kvm, gfn);

  30.         spte = rmap_next(kvm, rmapp, NULL);
  31.         while (spte) {
  32.                 BUG_ON(!spte);
  33.                 BUG_ON(!(*spte & PT_PRESENT_MASK));
  34.                 rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte);
  35.                 if (is_writeble_pte(*spte)) {
  36.                         set_shadow_pte(spte, *spte & ~PT_WRITABLE_MASK);
  37.                         write_protected = 1;
  38.                 }
  39.                 spte = rmap_next(kvm, rmapp, spte);
  40.         }
  41.         if (write_protected) {
  42.                 pfn_t pfn;

  43.                 spte = rmap_next(kvm, rmapp, NULL);
  44.                 pfn = spte_to_pfn(*spte);
  45.                 kvm_set_pfn_dirty(pfn);
  46.         }

  47.         /* check for huge page mappings */
  48.         rmapp = gfn_to_rmap(kvm, gfn, 1);
  49.         spte = rmap_next(kvm, rmapp, NULL);
  50.         while (spte) {
  51.                 BUG_ON(!spte);
  52.                 BUG_ON(!(*spte & PT_PRESENT_MASK));
  53.                 BUG_ON((*spte & (PT_PAGE_SIZE_MASK|PT_PRESENT_MASK)) != (PT_PAGE_SIZE_MASK|PT_PRESENT_MASK));
  54.                 pgprintk("rmap_write_protect(large): spte %p %llx %lld\n", spte, *spte, gfn);
  55.                 if (is_writeble_pte(*spte)) {
  56.                         rmap_remove(kvm, spte);
  57.                         --kvm->stat.lpages;
  58.                         set_shadow_pte(spte, shadow_trap_nonpresent_pte);
  59.                         spte = NULL;
  60.                         write_protected = 1;
  61.                 }
  62.                 spte = rmap_next(kvm, rmapp, spte);
  63.         }

  64.         return write_protected;
  65. }
复制代码

论坛徽章:
0
7 [报告]
发表于 2009-11-01 18:19 |只看该作者

  1. static int rmap_write_protect(struct kvm *kvm, u64 gfn)
  2. {
  3.         unsigned long *rmapp;
  4.         u64 *spte;
  5.         int write_protected = 0;

  6.         gfn = unalias_gfn(kvm, gfn);
  7.         rmapp = gfn_to_rmap(kvm, gfn, 0);

  8.         spte = rmap_next(kvm, rmapp, NULL);
  9.         while (spte) {
  10.                 BUG_ON(!spte);
  11.                 BUG_ON(!(*spte & PT_PRESENT_MASK));
  12.                 rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte);
  13.                
  14.                 if (is_writeble_pte(*spte)) {
  15.                         set_shadow_pte(spte, *spte & ~PT_WRITABLE_MASK);
  16.                         write_protected = 1;
  17. +                        kvm_set_pfn_dirty(spte_to_pfn(*spte));
  18.                 }
  19.                 spte = rmap_next(kvm, rmapp, spte);
  20.         }
  21. -        if (write_protected) {
  22. -                pfn_t pfn;
  23. -
  24. -                spte = rmap_next(kvm, rmapp, NULL);
  25. -                pfn = spte_to_pfn(*spte);
  26. -                kvm_set_pfn_dirty(pfn);
  27. -        }

  28.         /* check for huge page mappings */
  29.         rmapp = gfn_to_rmap(kvm, gfn, 1);
  30.         spte = rmap_next(kvm, rmapp, NULL);
  31.         while (spte) {
  32.                 BUG_ON(!spte);
  33.                 BUG_ON(!(*spte & PT_PRESENT_MASK));
  34.                 BUG_ON((*spte & (PT_PAGE_SIZE_MASK|PT_PRESENT_MASK)) != (PT_PAGE_SIZE_MASK|PT_PRESENT_MASK));
  35.                 pgprintk("rmap_write_protect(large): spte %p %llx %lld\n", spte, *spte, gfn);
  36.                
  37.                 if (is_writeble_pte(*spte)) {
  38.                         rmap_remove(kvm, spte);
  39.                         --kvm->stat.lpages;
  40.                         set_shadow_pte(spte, shadow_trap_nonpresent_pte);
  41.                         spte = NULL;
  42.                         write_protected = 1;
  43.                 }
  44.                 spte = rmap_next(kvm, rmapp, spte);
  45.         }

  46.         return write_protected;
  47. }
复制代码

论坛徽章:
5
摩羯座
日期:2014-07-22 09:03:552015元宵节徽章
日期:2015-03-06 15:50:392015亚冠之大阪钢巴
日期:2015-06-12 16:01:352015年中国系统架构师大会
日期:2015-06-29 16:11:2815-16赛季CBA联赛之四川
日期:2018-12-17 14:10:21
8 [报告]
发表于 2009-11-02 10:58 |只看该作者
have you commit to kernel
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP