diff options
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.9.21/0015-KVM-SVM-do-not-zero-out-segment-attributes-if-segmen.patch')
-rw-r--r-- | common/recipes-kernel/linux/linux-yocto-4.9.21/0015-KVM-SVM-do-not-zero-out-segment-attributes-if-segmen.patch | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.9.21/0015-KVM-SVM-do-not-zero-out-segment-attributes-if-segmen.patch b/common/recipes-kernel/linux/linux-yocto-4.9.21/0015-KVM-SVM-do-not-zero-out-segment-attributes-if-segmen.patch new file mode 100644 index 00000000..913e3fe5 --- /dev/null +++ b/common/recipes-kernel/linux/linux-yocto-4.9.21/0015-KVM-SVM-do-not-zero-out-segment-attributes-if-segmen.patch @@ -0,0 +1,95 @@ +From 348032cf73954af79ac077ae0c13d6faa99294af Mon Sep 17 00:00:00 2001 +From: Roman Pen <roman.penyaev@profitbricks.com> +Date: Thu, 1 Jun 2017 10:55:03 +0200 +Subject: [PATCH 15/93] KVM: SVM: do not zero out segment attributes if segment + is unusable or not present +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +[ Upstream commit d9c1b5431d5f0e07575db785a022bce91051ac1d ] + +This is a fix for the problem [1], where VMCB.CPL was set to 0 and interrupt +was taken on userspace stack. The root cause lies in the specific AMD CPU +behaviour which manifests itself as unusable segment attributes on SYSRET. +The corresponding work around for the kernel is the following: + +61f01dd941ba ("x86_64, asm: Work around AMD SYSRET SS descriptor attribute issue") + +In other turn virtualization side treated unusable segment incorrectly and +restored CPL from SS attributes, which were zeroed out few lines above. + +In current patch it is assured only that P bit is cleared in VMCB.save state +and segment attributes are not zeroed out if segment is not presented or is +unusable, therefore CPL can be safely restored from DPL field. + +This is only one part of the fix, since QEMU side should be fixed accordingly +not to zero out attributes on its side. Corresponding patch will follow. + +[1] Message id: CAJrWOzD6Xq==b-zYCDdFLgSRMPM-NkNuTSDFEtX=7MreT45i7Q@mail.gmail.com + +Signed-off-by: Roman Pen <roman.penyaev@profitbricks.com> +Signed-off-by: Mikhail Sennikovskii <mikhail.sennikovskii@profitbricks.com> +Cc: Paolo Bonzini <pbonzini@redhat.com> +Cc: Radim KrÄmář <rkrcmar@redhat.com> +Cc: kvm@vger.kernel.org +Cc: linux-kernel@vger.kernel.org +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> +Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + arch/x86/kvm/svm.c | 24 +++++++++++------------- + 1 file changed, 11 insertions(+), 13 deletions(-) + +diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c +index 2d96e30..8551a54 100644 +--- a/arch/x86/kvm/svm.c ++++ b/arch/x86/kvm/svm.c +@@ -1876,6 +1876,7 @@ static void svm_get_segment(struct kvm_vcpu *vcpu, + */ + if (var->unusable) + var->db = 0; ++ /* This is symmetric with svm_set_segment() */ + var->dpl = to_svm(vcpu)->vmcb->save.cpl; + break; + } +@@ -2021,18 +2022,14 @@ static void svm_set_segment(struct kvm_vcpu *vcpu, + s->base = var->base; + s->limit = var->limit; + s->selector = var->selector; +- if (var->unusable) +- s->attrib = 0; +- else { +- s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK); +- s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT; +- s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT; +- s->attrib |= (var->present & 1) << SVM_SELECTOR_P_SHIFT; +- s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT; +- s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT; +- s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT; +- s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT; +- } ++ s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK); ++ s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT; ++ s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT; ++ s->attrib |= ((var->present & 1) && !var->unusable) << SVM_SELECTOR_P_SHIFT; ++ s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT; ++ s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT; ++ s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT; ++ s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT; + + /* + * This is always accurate, except if SYSRET returned to a segment +@@ -2041,7 +2038,8 @@ static void svm_set_segment(struct kvm_vcpu *vcpu, + * would entail passing the CPL to userspace and back. + */ + if (seg == VCPU_SREG_SS) +- svm->vmcb->save.cpl = (s->attrib >> SVM_SELECTOR_DPL_SHIFT) & 3; ++ /* This is symmetric with svm_get_segment() */ ++ svm->vmcb->save.cpl = (var->dpl & 3); + + mark_dirty(svm->vmcb, VMCB_SEG); + } +-- +2.7.4 + |