537c688
Bugzilla: 1042090
537c688
Upstream-status: 3.13 and sent for stable                                                                                                                                                                                                                                                               
537c688
Delivered-To: jwboyer@gmail.com
537c688
Received: by 10.76.104.107 with SMTP id gd11csp361293oab;
537c688
        Thu, 12 Dec 2013 12:41:12 -0800 (PST)
537c688
X-Received: by 10.68.244.2 with SMTP id xc2mr15600217pbc.58.1386880872483;
537c688
        Thu, 12 Dec 2013 12:41:12 -0800 (PST)
537c688
Return-Path: <stable-owner@vger.kernel.org>
537c688
Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67])
537c688
        by mx.google.com with ESMTP id 5si8126292pbj.245.2013.12.12.12.40.49
537c688
        for <multiple recipients>;
537c688
        Thu, 12 Dec 2013 12:41:12 -0800 (PST)
537c688
Received-SPF: pass (google.com: best guess record for domain of stable-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67;
537c688
Authentication-Results: mx.google.com;
537c688
       spf=pass (google.com: best guess record for domain of stable-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mail=stable-owner@vger.kernel.org;
537c688
       dkim=neutral (bad format) header.i=@gmail.com
537c688
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
537c688
	id S1751901Ab3LLUiK (ORCPT <rfc822;kumadasu@gmail.com> + 64 others);
537c688
	Thu, 12 Dec 2013 15:38:10 -0500
537c688
Received: from mail-ea0-f169.google.com ([209.85.215.169]:43997 "EHLO
537c688
	mail-ea0-f169.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
537c688
	with ESMTP id S1751940Ab3LLUhR (ORCPT
537c688
	<rfc822;stable@vger.kernel.org>); Thu, 12 Dec 2013 15:37:17 -0500
537c688
Received: by mail-ea0-f169.google.com with SMTP id l9so411843eaj.0
537c688
        for <multiple recipients>; Thu, 12 Dec 2013 12:37:15 -0800 (PST)
537c688
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
537c688
        d=gmail.com; s=20120113;
537c688
        h=sender:from:to:cc:subject:date:message-id;
537c688
        bh=2MLmYgVGbv9FpnyP90yrPKk21SJoXFj93yQcaRn4G8Y=;
537c688
        b=ouBadI22VTf1UuezbySC80FWJYdpF/8Ks6I8f5rq1/7SDQPTpScjOYjZX0UtIf1ihj
537c688
         aeQ7IHqpmIYGKWadUbH2l88ZP1+rP7T+f2dZQeCb3HLNsPum0Ix8dzm/koeDnuS3dx75
537c688
         50E9ZcFXO13Hx24tM8p0SAuYZ1DvbCNnPRK0yxHOmCtCWe+mQLBIgig1rg8TzSAazWm7
537c688
         8LhpztDlIzNyZcfzKQvtdqTOBdnhadx5x39fxOe54Yw4JbppDa7R+BY5Jz6GOd3U0Op1
537c688
         Nf97rU0pe/jeyOtjF0LVs/d9iyPPeRoSE+VAr91iT8qj9S2PFEN1QxxWL8sdvsDPZK6B
537c688
         ZCmw==
537c688
X-Received: by 10.14.182.199 with SMTP id o47mr10030582eem.7.1386880635352;
537c688
        Thu, 12 Dec 2013 12:37:15 -0800 (PST)
537c688
Received: from playground.com (net-2-35-202-54.cust.dsl.vodafone.it. [2.35.202.54])
537c688
        by mx.google.com with ESMTPSA id o47sm70323739eem.21.2013.12.12.12.37.13
537c688
        for <multiple recipients>
537c688
        (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);
537c688
        Thu, 12 Dec 2013 12:37:14 -0800 (PST)
537c688
From:	Paolo Bonzini <pbonzini@redhat.com>
537c688
To:	linux-kernel@vger.kernel.org
537c688
Cc:	gleb@redhat.com, kvm@vger.kernel.org, pmatouse@redhat.com,
537c688
	Andy Honig <ahonig@google.com>, stable@vger.kernel.org
537c688
Subject: [PATCH] KVM: x86: Convert vapic synchronization to _cached functions (CVE-2013-6368)
537c688
Date:	Thu, 12 Dec 2013 21:36:53 +0100
537c688
Message-Id: <1386880614-23300-3-git-send-email-pbonzini@redhat.com>
537c688
X-Mailer: git-send-email 1.8.3.1
537c688
Sender:	stable-owner@vger.kernel.org
537c688
Precedence: bulk
537c688
List-ID: <stable.vger.kernel.org>
537c688
X-Mailing-List:	stable@vger.kernel.org
537c688
537c688
From: Andy Honig <ahonig@google.com>
537c688
537c688
In kvm_lapic_sync_from_vapic and kvm_lapic_sync_to_vapic there is the
537c688
potential to corrupt kernel memory if userspace provides an address that
537c688
is at the end of a page.  This patches concerts those functions to use
537c688
kvm_write_guest_cached and kvm_read_guest_cached.  It also checks the
537c688
vapic_address specified by userspace during ioctl processing and returns
537c688
an error to userspace if the address is not a valid GPA.
537c688
537c688
This is generally not guest triggerable, because the required write is
537c688
done by firmware that runs before the guest.  Also, it only affects AMD
537c688
processors and oldish Intel that do not have the FlexPriority feature
537c688
(unless you disable FlexPriority, of course; then newer processors are
537c688
also affected).
537c688
537c688
Fixes: b93463aa59d6 ('KVM: Accelerated apic support')
537c688
537c688
Reported-by: Andrew Honig <ahonig@google.com>
537c688
Cc: stable@vger.kernel.org
537c688
Signed-off-by: Andrew Honig <ahonig@google.com>
537c688
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
537c688
---
537c688
 arch/x86/kvm/lapic.c | 27 +++++++++++++++------------
537c688
 arch/x86/kvm/lapic.h |  4 ++--
537c688
 arch/x86/kvm/x86.c   | 40 +---------------------------------------
537c688
 3 files changed, 18 insertions(+), 53 deletions(-)
537c688
537c688
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
537c688
index 89b52ec7d09c..b8bec45c1610 100644
537c688
--- a/arch/x86/kvm/lapic.c
537c688
+++ b/arch/x86/kvm/lapic.c
537c688
@@ -1692,7 +1692,6 @@ static void apic_sync_pv_eoi_from_guest(struct kvm_vcpu *vcpu,
537c688
 void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu)
537c688
 {
537c688
 	u32 data;
537c688
-	void *vapic;
537c688
 
537c688
 	if (test_bit(KVM_APIC_PV_EOI_PENDING, &vcpu->arch.apic_attention))
537c688
 		apic_sync_pv_eoi_from_guest(vcpu, vcpu->arch.apic);
537c688
@@ -1700,9 +1699,8 @@ void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu)
537c688
 	if (!test_bit(KVM_APIC_CHECK_VAPIC, &vcpu->arch.apic_attention))
537c688
 		return;
537c688
 
537c688
-	vapic = kmap_atomic(vcpu->arch.apic->vapic_page);
537c688
-	data = *(u32 *)(vapic + offset_in_page(vcpu->arch.apic->vapic_addr));
537c688
-	kunmap_atomic(vapic);
537c688
+	kvm_read_guest_cached(vcpu->kvm, &vcpu->arch.apic->vapic_cache, &data,
537c688
+				sizeof(u32));
537c688
 
537c688
 	apic_set_tpr(vcpu->arch.apic, data & 0xff);
537c688
 }
537c688
@@ -1738,7 +1736,6 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu)
537c688
 	u32 data, tpr;
537c688
 	int max_irr, max_isr;
537c688
 	struct kvm_lapic *apic = vcpu->arch.apic;
537c688
-	void *vapic;
537c688
 
537c688
 	apic_sync_pv_eoi_to_guest(vcpu, apic);
537c688
 
537c688
@@ -1754,18 +1751,24 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu)
537c688
 		max_isr = 0;
537c688
 	data = (tpr & 0xff) | ((max_isr & 0xf0) << 8) | (max_irr << 24);
537c688
 
537c688
-	vapic = kmap_atomic(vcpu->arch.apic->vapic_page);
537c688
-	*(u32 *)(vapic + offset_in_page(vcpu->arch.apic->vapic_addr)) = data;
537c688
-	kunmap_atomic(vapic);
537c688
+	kvm_write_guest_cached(vcpu->kvm, &vcpu->arch.apic->vapic_cache, &data,
537c688
+				sizeof(u32));
537c688
 }
537c688
 
537c688
-void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr)
537c688
+int kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr)
537c688
 {
537c688
-	vcpu->arch.apic->vapic_addr = vapic_addr;
537c688
-	if (vapic_addr)
537c688
+	if (vapic_addr) {
537c688
+		if (kvm_gfn_to_hva_cache_init(vcpu->kvm,
537c688
+					&vcpu->arch.apic->vapic_cache,
537c688
+					vapic_addr, sizeof(u32)))
537c688
+			return -EINVAL;
537c688
 		__set_bit(KVM_APIC_CHECK_VAPIC, &vcpu->arch.apic_attention);
537c688
-	else
537c688
+	} else {
537c688
 		__clear_bit(KVM_APIC_CHECK_VAPIC, &vcpu->arch.apic_attention);
537c688
+	}
537c688
+
537c688
+	vcpu->arch.apic->vapic_addr = vapic_addr;
537c688
+	return 0;
537c688
 }
537c688
 
537c688
 int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data)
537c688
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
537c688
index c730ac9fe801..c8b0d0d2da5c 100644
537c688
--- a/arch/x86/kvm/lapic.h
537c688
+++ b/arch/x86/kvm/lapic.h
537c688
@@ -34,7 +34,7 @@ struct kvm_lapic {
537c688
 	 */
537c688
 	void *regs;
537c688
 	gpa_t vapic_addr;
537c688
-	struct page *vapic_page;
537c688
+	struct gfn_to_hva_cache vapic_cache;
537c688
 	unsigned long pending_events;
537c688
 	unsigned int sipi_vector;
537c688
 };
537c688
@@ -76,7 +76,7 @@ void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data);
537c688
 void kvm_apic_write_nodecode(struct kvm_vcpu *vcpu, u32 offset);
537c688
 void kvm_apic_set_eoi_accelerated(struct kvm_vcpu *vcpu, int vector);
537c688
 
537c688
-void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr);
537c688
+int kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr);
537c688
 void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu);
537c688
 void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu);
537c688
 
537c688
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
537c688
index 21ef1ba184ae..5d004da1e35d 100644
537c688
--- a/arch/x86/kvm/x86.c
537c688
+++ b/arch/x86/kvm/x86.c
537c688
@@ -3214,8 +3214,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
537c688
 		r = -EFAULT;
537c688
 		if (copy_from_user(&va, argp, sizeof va))
537c688
 			goto out;
537c688
-		r = 0;
537c688
-		kvm_lapic_set_vapic_addr(vcpu, va.vapic_addr);
537c688
+		r = kvm_lapic_set_vapic_addr(vcpu, va.vapic_addr);
537c688
 		break;
537c688
 	}
537c688
 	case KVM_X86_SETUP_MCE: {
537c688
@@ -5739,36 +5738,6 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu)
537c688
 			!kvm_event_needs_reinjection(vcpu);
537c688
 }
537c688
 
537c688
-static int vapic_enter(struct kvm_vcpu *vcpu)
537c688
-{
537c688
-	struct kvm_lapic *apic = vcpu->arch.apic;
537c688
-	struct page *page;
537c688
-
537c688
-	if (!apic || !apic->vapic_addr)
537c688
-		return 0;
537c688
-
537c688
-	page = gfn_to_page(vcpu->kvm, apic->vapic_addr >> PAGE_SHIFT);
537c688
-	if (is_error_page(page))
537c688
-		return -EFAULT;
537c688
-
537c688
-	vcpu->arch.apic->vapic_page = page;
537c688
-	return 0;
537c688
-}
537c688
-
537c688
-static void vapic_exit(struct kvm_vcpu *vcpu)
537c688
-{
537c688
-	struct kvm_lapic *apic = vcpu->arch.apic;
537c688
-	int idx;
537c688
-
537c688
-	if (!apic || !apic->vapic_addr)
537c688
-		return;
537c688
-
537c688
-	idx = srcu_read_lock(&vcpu->kvm->srcu);
537c688
-	kvm_release_page_dirty(apic->vapic_page);
537c688
-	mark_page_dirty(vcpu->kvm, apic->vapic_addr >> PAGE_SHIFT);
537c688
-	srcu_read_unlock(&vcpu->kvm->srcu, idx);
537c688
-}
537c688
-
537c688
 static void update_cr8_intercept(struct kvm_vcpu *vcpu)
537c688
 {
537c688
 	int max_irr, tpr;
537c688
@@ -6069,11 +6038,6 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
537c688
 	struct kvm *kvm = vcpu->kvm;
537c688
 
537c688
 	vcpu->srcu_idx = srcu_read_lock(&kvm->srcu);
537c688
-	r = vapic_enter(vcpu);
537c688
-	if (r) {
537c688
-		srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);
537c688
-		return r;
537c688
-	}
537c688
 
537c688
 	r = 1;
537c688
 	while (r > 0) {
537c688
@@ -6132,8 +6096,6 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
537c688
 
537c688
 	srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);
537c688
 
537c688
-	vapic_exit(vcpu);
537c688
-
537c688
 	return r;
537c688
 }
537c688
 
537c688
-- 
537c688
1.8.3.1
537c688
537c688
--
537c688
To unsubscribe from this list: send the line "unsubscribe stable" in
537c688
the body of a message to majordomo@vger.kernel.org
537c688
More majordomo info at  http://vger.kernel.org/majordomo-info.html