| From 15462e37ca848abac7477dece65f8af25febd744 Mon Sep 17 00:00:00 2001 |
| From: David Hildenbrand <dahi@linux.vnet.ibm.com> |
| Date: Wed, 4 Feb 2015 15:59:11 +0100 |
| Subject: KVM: s390: reinjection of irqs can fail in the tpi handler |
| |
| From: David Hildenbrand <dahi@linux.vnet.ibm.com> |
| |
| commit 15462e37ca848abac7477dece65f8af25febd744 upstream. |
| |
| The reinjection of an I/O interrupt can fail if the list is at the limit |
| and between the dequeue and the reinjection, another I/O interrupt is |
| injected (e.g. if user space floods kvm with I/O interrupts). |
| |
| This patch avoids this memory leak and returns -EFAULT in this special |
| case. This error is not recoverable, so let's fail hard. This can later |
| be avoided by not dequeuing the interrupt but working directly on the |
| locked list. |
| |
| Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com> |
| Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/s390/kvm/interrupt.c | 4 ++-- |
| arch/s390/kvm/kvm-s390.h | 4 ++-- |
| arch/s390/kvm/priv.c | 5 ++++- |
| 3 files changed, 8 insertions(+), 5 deletions(-) |
| |
| --- a/arch/s390/kvm/interrupt.c |
| +++ b/arch/s390/kvm/interrupt.c |
| @@ -1332,10 +1332,10 @@ int kvm_s390_inject_vm(struct kvm *kvm, |
| return rc; |
| } |
| |
| -void kvm_s390_reinject_io_int(struct kvm *kvm, |
| +int kvm_s390_reinject_io_int(struct kvm *kvm, |
| struct kvm_s390_interrupt_info *inti) |
| { |
| - __inject_vm(kvm, inti); |
| + return __inject_vm(kvm, inti); |
| } |
| |
| int s390int_to_s390irq(struct kvm_s390_interrupt *s390int, |
| --- a/arch/s390/kvm/kvm-s390.h |
| +++ b/arch/s390/kvm/kvm-s390.h |
| @@ -151,8 +151,8 @@ int __must_check kvm_s390_inject_vcpu(st |
| int __must_check kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code); |
| struct kvm_s390_interrupt_info *kvm_s390_get_io_int(struct kvm *kvm, |
| u64 cr6, u64 schid); |
| -void kvm_s390_reinject_io_int(struct kvm *kvm, |
| - struct kvm_s390_interrupt_info *inti); |
| +int kvm_s390_reinject_io_int(struct kvm *kvm, |
| + struct kvm_s390_interrupt_info *inti); |
| int kvm_s390_mask_adapter(struct kvm *kvm, unsigned int id, bool masked); |
| |
| /* implemented in intercept.c */ |
| --- a/arch/s390/kvm/priv.c |
| +++ b/arch/s390/kvm/priv.c |
| @@ -279,7 +279,10 @@ reinject_interrupt: |
| * instruction is suppressed from the guest's view: reinject the |
| * interrupt. |
| */ |
| - kvm_s390_reinject_io_int(vcpu->kvm, inti); |
| + if (kvm_s390_reinject_io_int(vcpu->kvm, inti)) { |
| + kfree(inti); |
| + rc = -EFAULT; |
| + } |
| /* don't set the cc, a pgm irq was injected or we drop to user space */ |
| return rc ? -EFAULT : 0; |
| } |