Commit 87da7e66a40532b743cd50972fcf85a1f15b14ea
Committed by
Marcelo Tosatti
1 parent
35fd3dc58d
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
KVM: x86: fix vcpu->mmio_fragments overflow
After commit b3356bf0dbb349 (KVM: emulator: optimize "rep ins" handling), the pieces of io data can be collected and write them to the guest memory or MMIO together Unfortunately, kvm splits the mmio access into 8 bytes and store them to vcpu->mmio_fragments. If the guest uses "rep ins" to move large data, it will cause vcpu->mmio_fragments overflow The bug can be exposed by isapc (-M isapc): [23154.818733] general protection fault: 0000 [#1] SMP DEBUG_PAGEALLOC [ ......] [23154.858083] Call Trace: [23154.859874] [<ffffffffa04f0e17>] kvm_get_cr8+0x1d/0x28 [kvm] [23154.861677] [<ffffffffa04fa6d4>] kvm_arch_vcpu_ioctl_run+0xcda/0xe45 [kvm] [23154.863604] [<ffffffffa04f5a1a>] ? kvm_arch_vcpu_load+0x17b/0x180 [kvm] Actually, we can use one mmio_fragment to store a large mmio access then split it when we pass the mmio-exit-info to userspace. After that, we only need two entries to store mmio info for the cross-mmio pages access Signed-off-by: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Showing 2 changed files with 36 additions and 39 deletions Side-by-side Diff
arch/x86/kvm/x86.c
... | ... | @@ -3779,7 +3779,7 @@ |
3779 | 3779 | { |
3780 | 3780 | struct kvm_mmio_fragment *frag = &vcpu->mmio_fragments[0]; |
3781 | 3781 | |
3782 | - memcpy(vcpu->run->mmio.data, frag->data, frag->len); | |
3782 | + memcpy(vcpu->run->mmio.data, frag->data, min(8u, frag->len)); | |
3783 | 3783 | return X86EMUL_CONTINUE; |
3784 | 3784 | } |
3785 | 3785 | |
... | ... | @@ -3832,18 +3832,11 @@ |
3832 | 3832 | bytes -= handled; |
3833 | 3833 | val += handled; |
3834 | 3834 | |
3835 | - while (bytes) { | |
3836 | - unsigned now = min(bytes, 8U); | |
3837 | - | |
3838 | - frag = &vcpu->mmio_fragments[vcpu->mmio_nr_fragments++]; | |
3839 | - frag->gpa = gpa; | |
3840 | - frag->data = val; | |
3841 | - frag->len = now; | |
3842 | - | |
3843 | - gpa += now; | |
3844 | - val += now; | |
3845 | - bytes -= now; | |
3846 | - } | |
3835 | + WARN_ON(vcpu->mmio_nr_fragments >= KVM_MAX_MMIO_FRAGMENTS); | |
3836 | + frag = &vcpu->mmio_fragments[vcpu->mmio_nr_fragments++]; | |
3837 | + frag->gpa = gpa; | |
3838 | + frag->data = val; | |
3839 | + frag->len = bytes; | |
3847 | 3840 | return X86EMUL_CONTINUE; |
3848 | 3841 | } |
3849 | 3842 | |
... | ... | @@ -3890,7 +3883,7 @@ |
3890 | 3883 | vcpu->mmio_needed = 1; |
3891 | 3884 | vcpu->mmio_cur_fragment = 0; |
3892 | 3885 | |
3893 | - vcpu->run->mmio.len = vcpu->mmio_fragments[0].len; | |
3886 | + vcpu->run->mmio.len = min(8u, vcpu->mmio_fragments[0].len); | |
3894 | 3887 | vcpu->run->mmio.is_write = vcpu->mmio_is_write = ops->write; |
3895 | 3888 | vcpu->run->exit_reason = KVM_EXIT_MMIO; |
3896 | 3889 | vcpu->run->mmio.phys_addr = gpa; |
3897 | 3890 | |
3898 | 3891 | |
3899 | 3892 | |
3900 | 3893 | |
... | ... | @@ -5522,28 +5515,44 @@ |
5522 | 5515 | * |
5523 | 5516 | * read: |
5524 | 5517 | * for each fragment |
5525 | - * write gpa, len | |
5526 | - * exit | |
5527 | - * copy data | |
5518 | + * for each mmio piece in the fragment | |
5519 | + * write gpa, len | |
5520 | + * exit | |
5521 | + * copy data | |
5528 | 5522 | * execute insn |
5529 | 5523 | * |
5530 | 5524 | * write: |
5531 | 5525 | * for each fragment |
5532 | - * write gpa, len | |
5533 | - * copy data | |
5534 | - * exit | |
5526 | + * for each mmio piece in the fragment | |
5527 | + * write gpa, len | |
5528 | + * copy data | |
5529 | + * exit | |
5535 | 5530 | */ |
5536 | 5531 | static int complete_emulated_mmio(struct kvm_vcpu *vcpu) |
5537 | 5532 | { |
5538 | 5533 | struct kvm_run *run = vcpu->run; |
5539 | 5534 | struct kvm_mmio_fragment *frag; |
5535 | + unsigned len; | |
5540 | 5536 | |
5541 | 5537 | BUG_ON(!vcpu->mmio_needed); |
5542 | 5538 | |
5543 | 5539 | /* Complete previous fragment */ |
5544 | - frag = &vcpu->mmio_fragments[vcpu->mmio_cur_fragment++]; | |
5540 | + frag = &vcpu->mmio_fragments[vcpu->mmio_cur_fragment]; | |
5541 | + len = min(8u, frag->len); | |
5545 | 5542 | if (!vcpu->mmio_is_write) |
5546 | - memcpy(frag->data, run->mmio.data, frag->len); | |
5543 | + memcpy(frag->data, run->mmio.data, len); | |
5544 | + | |
5545 | + if (frag->len <= 8) { | |
5546 | + /* Switch to the next fragment. */ | |
5547 | + frag++; | |
5548 | + vcpu->mmio_cur_fragment++; | |
5549 | + } else { | |
5550 | + /* Go forward to the next mmio piece. */ | |
5551 | + frag->data += len; | |
5552 | + frag->gpa += len; | |
5553 | + frag->len -= len; | |
5554 | + } | |
5555 | + | |
5547 | 5556 | if (vcpu->mmio_cur_fragment == vcpu->mmio_nr_fragments) { |
5548 | 5557 | vcpu->mmio_needed = 0; |
5549 | 5558 | if (vcpu->mmio_is_write) |
5550 | 5559 | |
... | ... | @@ -5551,13 +5560,12 @@ |
5551 | 5560 | vcpu->mmio_read_completed = 1; |
5552 | 5561 | return complete_emulated_io(vcpu); |
5553 | 5562 | } |
5554 | - /* Initiate next fragment */ | |
5555 | - ++frag; | |
5563 | + | |
5556 | 5564 | run->exit_reason = KVM_EXIT_MMIO; |
5557 | 5565 | run->mmio.phys_addr = frag->gpa; |
5558 | 5566 | if (vcpu->mmio_is_write) |
5559 | - memcpy(run->mmio.data, frag->data, frag->len); | |
5560 | - run->mmio.len = frag->len; | |
5567 | + memcpy(run->mmio.data, frag->data, min(8u, frag->len)); | |
5568 | + run->mmio.len = min(8u, frag->len); | |
5561 | 5569 | run->mmio.is_write = vcpu->mmio_is_write; |
5562 | 5570 | vcpu->arch.complete_userspace_io = complete_emulated_mmio; |
5563 | 5571 | return 0; |
include/linux/kvm_host.h
... | ... | @@ -42,19 +42,8 @@ |
42 | 42 | */ |
43 | 43 | #define KVM_MEMSLOT_INVALID (1UL << 16) |
44 | 44 | |
45 | -/* | |
46 | - * If we support unaligned MMIO, at most one fragment will be split into two: | |
47 | - */ | |
48 | -#ifdef KVM_UNALIGNED_MMIO | |
49 | -# define KVM_EXTRA_MMIO_FRAGMENTS 1 | |
50 | -#else | |
51 | -# define KVM_EXTRA_MMIO_FRAGMENTS 0 | |
52 | -#endif | |
53 | - | |
54 | -#define KVM_USER_MMIO_SIZE 8 | |
55 | - | |
56 | -#define KVM_MAX_MMIO_FRAGMENTS \ | |
57 | - (KVM_MMIO_SIZE / KVM_USER_MMIO_SIZE + KVM_EXTRA_MMIO_FRAGMENTS) | |
45 | +/* Two fragments for cross MMIO pages. */ | |
46 | +#define KVM_MAX_MMIO_FRAGMENTS 2 | |
58 | 47 | |
59 | 48 | /* |
60 | 49 | * For the normal pfn, the highest 12 bits should be zero, |