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