Message ID | 20210728230833.1762416-1-zsm@chromium.org |
---|---|
State | New |
Headers | show |
Series | [linux-4.14.y] KVM: x86: determine if an exception has an error code only when injecting it. | expand |
On 29/07/21 01:08, Zubin Mithra wrote: > From: Maxim Levitsky <mlevitsk@redhat.com> > > commit b97f074583736c42fb36f2da1164e28c73758912 upstream. > > A page fault can be queued while vCPU is in real paged mode on AMD, and > AMD manual asks the user to always intercept it > (otherwise result is undefined). > The resulting VM exit, does have an error code. > > Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com> > Message-Id: <20210225154135.405125-2-mlevitsk@redhat.com> > Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> > Signed-off-by: Zubin Mithra <zsm@chromium.org> > --- > Backport Note: > * Syzkaller triggered a WARNING with the following stacktrace: > WARNING: CPU: 3 PID: 3436 at arch/x86/kvm/x86.c:7529 kvm_arch_vcpu_ioctl_run+0x247/0x2dd2 > Kernel panic - not syncing: panic_on_warn set ... > > CPU: 3 PID: 3436 Comm: poc Not tainted 4.14.241-00082-gce4d1565392b #7 > Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-2 04/01/2014 > Call Trace: > dump_stack+0xf8/0x163 > panic+0x15a/0x2c2 > ? unregister_sha256_avx+0x1b/0x1b > ? kvm_arch_vcpu_ioctl_run+0x247/0x2dd2 > __warn+0xe4/0x117 > ? kvm_arch_vcpu_ioctl_run+0x247/0x2dd2 > report_bug+0x93/0xdd > fixup_bug+0x28/0x4b > do_error_trap+0xb6/0x1b2 > ? fixup_bug+0x4b/0x4b > ? kasan_slab_free+0x141/0x154 > ? kasan_slab_free+0xad/0x154 > ? kmem_cache_free+0x14d/0x301 > ? put_pid+0x57/0x6f > ? kvm_vcpu_ioctl+0x214/0x73d > ? vfs_ioctl+0x46/0x5a > ? trace_hardirqs_off_caller+0x10c/0x115 > ? trace_hardirqs_off_thunk+0x1a/0x1c > invalid_op+0x1b/0x40 > RIP: 0010:kvm_arch_vcpu_ioctl_run+0x247/0x2dd2 > > * This commit is present in linux-5.13.y. > > * Conflict arises as the following commit is is not present in > linux-5.10.y and older. > - b3646477d458 ("KVM: x86: use static calls to reduce kvm_x86_ops overhead") > > * Tests run: syzkaller reproducer, Chrome OS tryjobs > > arch/x86/kvm/x86.c | 13 +++++++++---- > 1 file changed, 9 insertions(+), 4 deletions(-) > > diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c > index 37d826acd017..d77caab7ad5e 100644 > --- a/arch/x86/kvm/x86.c > +++ b/arch/x86/kvm/x86.c > @@ -400,8 +400,6 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu, > > if (!vcpu->arch.exception.pending && !vcpu->arch.exception.injected) { > queue: > - if (has_error && !is_protmode(vcpu)) > - has_error = false; > if (reinject) { > /* > * On vmentry, vcpu->arch.exception.pending is only > @@ -6624,13 +6622,20 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu) > kvm_x86_ops->update_cr8_intercept(vcpu, tpr, max_irr); > } > > +static void kvm_inject_exception(struct kvm_vcpu *vcpu) > +{ > + if (vcpu->arch.exception.error_code && !is_protmode(vcpu)) > + vcpu->arch.exception.error_code = false; > + kvm_x86_ops->queue_exception(vcpu); > +} > + > static int inject_pending_event(struct kvm_vcpu *vcpu) > { > int r; > > /* try to reinject previous events if any */ > if (vcpu->arch.exception.injected) { > - kvm_x86_ops->queue_exception(vcpu); > + kvm_inject_exception(vcpu); > return 0; > } > > @@ -6675,7 +6680,7 @@ static int inject_pending_event(struct kvm_vcpu *vcpu) > kvm_update_dr7(vcpu); > } > > - kvm_x86_ops->queue_exception(vcpu); > + kvm_inject_exception(vcpu); > } else if (vcpu->arch.smi_pending && !is_smm(vcpu)) { > vcpu->arch.smi_pending = false; > enter_smm(vcpu); > Acked-by: Paolo Bonzini <pbonzini@redhat.com>
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 37d826acd017..d77caab7ad5e 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -400,8 +400,6 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu, if (!vcpu->arch.exception.pending && !vcpu->arch.exception.injected) { queue: - if (has_error && !is_protmode(vcpu)) - has_error = false; if (reinject) { /* * On vmentry, vcpu->arch.exception.pending is only @@ -6624,13 +6622,20 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu) kvm_x86_ops->update_cr8_intercept(vcpu, tpr, max_irr); } +static void kvm_inject_exception(struct kvm_vcpu *vcpu) +{ + if (vcpu->arch.exception.error_code && !is_protmode(vcpu)) + vcpu->arch.exception.error_code = false; + kvm_x86_ops->queue_exception(vcpu); +} + static int inject_pending_event(struct kvm_vcpu *vcpu) { int r; /* try to reinject previous events if any */ if (vcpu->arch.exception.injected) { - kvm_x86_ops->queue_exception(vcpu); + kvm_inject_exception(vcpu); return 0; } @@ -6675,7 +6680,7 @@ static int inject_pending_event(struct kvm_vcpu *vcpu) kvm_update_dr7(vcpu); } - kvm_x86_ops->queue_exception(vcpu); + kvm_inject_exception(vcpu); } else if (vcpu->arch.smi_pending && !is_smm(vcpu)) { vcpu->arch.smi_pending = false; enter_smm(vcpu);