diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2016-02-19 12:07:21 -0500 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2016-02-24 08:47:45 -0500 |
commit | 0c1d77f4ba5cc9c05a29adca3d6466cdf4969b70 (patch) | |
tree | b7cdb81b498534c3deb7c8685405824ab1fb5b86 | |
parent | 172b2386ed16a9143d9a456aae5ec87275c61489 (diff) |
KVM: x86: fix conversion of addresses to linear in 32-bit protected mode
Commit e8dd2d2d641c ("Silence compiler warning in arch/x86/kvm/emulate.c",
2015-09-06) broke boot of the Hurd. The bug is that the "default:"
case actually could modify "la", but after the patch this change is
not reflected in *linear.
The bug is visible whenever a non-zero segment base causes the linear
address to wrap around the 4GB mark.
Fixes: e8dd2d2d641cb2724ee10e76c0ad02e04289c017
Cc: stable@vger.kernel.org
Reported-by: Aurelien Jarno <aurelien@aurel32.net>
Tested-by: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r-- | arch/x86/kvm/emulate.c | 4 |
1 files changed, 2 insertions, 2 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 1505587d06e9..b9b09fec173b 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -650,10 +650,10 @@ static __always_inline int __linearize(struct x86_emulate_ctxt *ctxt, | |||
650 | u16 sel; | 650 | u16 sel; |
651 | 651 | ||
652 | la = seg_base(ctxt, addr.seg) + addr.ea; | 652 | la = seg_base(ctxt, addr.seg) + addr.ea; |
653 | *linear = la; | ||
654 | *max_size = 0; | 653 | *max_size = 0; |
655 | switch (mode) { | 654 | switch (mode) { |
656 | case X86EMUL_MODE_PROT64: | 655 | case X86EMUL_MODE_PROT64: |
656 | *linear = la; | ||
657 | if (is_noncanonical_address(la)) | 657 | if (is_noncanonical_address(la)) |
658 | goto bad; | 658 | goto bad; |
659 | 659 | ||
@@ -662,6 +662,7 @@ static __always_inline int __linearize(struct x86_emulate_ctxt *ctxt, | |||
662 | goto bad; | 662 | goto bad; |
663 | break; | 663 | break; |
664 | default: | 664 | default: |
665 | *linear = la = (u32)la; | ||
665 | usable = ctxt->ops->get_segment(ctxt, &sel, &desc, NULL, | 666 | usable = ctxt->ops->get_segment(ctxt, &sel, &desc, NULL, |
666 | addr.seg); | 667 | addr.seg); |
667 | if (!usable) | 668 | if (!usable) |
@@ -689,7 +690,6 @@ static __always_inline int __linearize(struct x86_emulate_ctxt *ctxt, | |||
689 | if (size > *max_size) | 690 | if (size > *max_size) |
690 | goto bad; | 691 | goto bad; |
691 | } | 692 | } |
692 | la &= (u32)-1; | ||
693 | break; | 693 | break; |
694 | } | 694 | } |
695 | if (insn_aligned(ctxt, size) && ((la & (size - 1)) != 0)) | 695 | if (insn_aligned(ctxt, size) && ((la & (size - 1)) != 0)) |