diff mbox

[1/1,SRU,Precise/Trusty/Utopic/Vivid/Wily,CVE-2015-7513] KVM: x86: Reload pit counters for all channels when restoring state

Message ID 1452204661-62519-2-git-send-email-brad.figg@canonical.com
State New
Headers show

Commit Message

Brad Figg Jan. 7, 2016, 10:11 p.m. UTC
From: Andrew Honig <ahonig@google.com>

BugLink: http://bugs.launchpad.net/bugs/1530956

Currently if userspace restores the pit counters with a count of 0
on channels 1 or 2 and the guest attempts to read the count on those
channels, then KVM will perform a mod of 0 and crash.  This will ensure
that 0 values are converted to 65536 as per the spec.

This is CVE-2015-7513.

Signed-off-by: Andy Honig <ahonig@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Brad Figg <brad.figg@canonical.com>
---
 arch/x86/kvm/x86.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

Comments

Chris J Arges Jan. 7, 2016, 11:25 p.m. UTC | #1
Please add the cherry-picked/backported from
0185604c2d82c560dab2f2933a18f797e74ab5a8 line here.
ACK one this is done.
--chris

On 01/07/2016 04:11 PM, Brad Figg wrote:
> From: Andrew Honig <ahonig@google.com>
> 
> BugLink: http://bugs.launchpad.net/bugs/1530956
> 
> Currently if userspace restores the pit counters with a count of 0
> on channels 1 or 2 and the guest attempts to read the count on those
> channels, then KVM will perform a mod of 0 and crash.  This will ensure
> that 0 values are converted to 65536 as per the spec.
> 
> This is CVE-2015-7513.
> 
> Signed-off-by: Andy Honig <ahonig@google.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> Signed-off-by: Brad Figg <brad.figg@canonical.com>
> ---
>  arch/x86/kvm/x86.c | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index a18ca2e7..00631db 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -2923,10 +2923,12 @@ static int kvm_vm_ioctl_get_pit(struct kvm *kvm, struct kvm_pit_state *ps)
>  static int kvm_vm_ioctl_set_pit(struct kvm *kvm, struct kvm_pit_state *ps)
>  {
>  	int r = 0;
> +	int i;
>  
>  	mutex_lock(&kvm->arch.vpit->pit_state.lock);
>  	memcpy(&kvm->arch.vpit->pit_state, ps, sizeof(struct kvm_pit_state));
> -	kvm_pit_load_count(kvm, 0, ps->channels[0].count, 0);
> +	for (i = 0; i < 3; i++)
> +		kvm_pit_load_count(kvm, i, ps->channels[i].count, 0);
>  	mutex_unlock(&kvm->arch.vpit->pit_state.lock);
>  	return r;
>  }
> @@ -2947,6 +2949,7 @@ static int kvm_vm_ioctl_get_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
>  static int kvm_vm_ioctl_set_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
>  {
>  	int r = 0, start = 0;
> +	int i;
>  	u32 prev_legacy, cur_legacy;
>  	mutex_lock(&kvm->arch.vpit->pit_state.lock);
>  	prev_legacy = kvm->arch.vpit->pit_state.flags & KVM_PIT_FLAGS_HPET_LEGACY;
> @@ -2956,7 +2959,8 @@ static int kvm_vm_ioctl_set_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
>  	memcpy(&kvm->arch.vpit->pit_state.channels, &ps->channels,
>  	       sizeof(kvm->arch.vpit->pit_state.channels));
>  	kvm->arch.vpit->pit_state.flags = ps->flags;
> -	kvm_pit_load_count(kvm, 0, kvm->arch.vpit->pit_state.channels[0].count, start);
> +	for (i = 0; i < 3; i++)
> +		kvm_pit_load_count(kvm, i, kvm->arch.vpit->pit_state.channels[i].count, start);
>  	mutex_unlock(&kvm->arch.vpit->pit_state.lock);
>  	return r;
>  }
>
Tim Gardner Jan. 8, 2016, 12:32 a.m. UTC | #2
Needs 'backported from commit 0185604c2d82c560dab2f2933a18f797e74ab5a8'
in the commit log.
diff mbox

Patch

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index a18ca2e7..00631db 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2923,10 +2923,12 @@  static int kvm_vm_ioctl_get_pit(struct kvm *kvm, struct kvm_pit_state *ps)
 static int kvm_vm_ioctl_set_pit(struct kvm *kvm, struct kvm_pit_state *ps)
 {
 	int r = 0;
+	int i;
 
 	mutex_lock(&kvm->arch.vpit->pit_state.lock);
 	memcpy(&kvm->arch.vpit->pit_state, ps, sizeof(struct kvm_pit_state));
-	kvm_pit_load_count(kvm, 0, ps->channels[0].count, 0);
+	for (i = 0; i < 3; i++)
+		kvm_pit_load_count(kvm, i, ps->channels[i].count, 0);
 	mutex_unlock(&kvm->arch.vpit->pit_state.lock);
 	return r;
 }
@@ -2947,6 +2949,7 @@  static int kvm_vm_ioctl_get_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
 static int kvm_vm_ioctl_set_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
 {
 	int r = 0, start = 0;
+	int i;
 	u32 prev_legacy, cur_legacy;
 	mutex_lock(&kvm->arch.vpit->pit_state.lock);
 	prev_legacy = kvm->arch.vpit->pit_state.flags & KVM_PIT_FLAGS_HPET_LEGACY;
@@ -2956,7 +2959,8 @@  static int kvm_vm_ioctl_set_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
 	memcpy(&kvm->arch.vpit->pit_state.channels, &ps->channels,
 	       sizeof(kvm->arch.vpit->pit_state.channels));
 	kvm->arch.vpit->pit_state.flags = ps->flags;
-	kvm_pit_load_count(kvm, 0, kvm->arch.vpit->pit_state.channels[0].count, start);
+	for (i = 0; i < 3; i++)
+		kvm_pit_load_count(kvm, i, kvm->arch.vpit->pit_state.channels[i].count, start);
 	mutex_unlock(&kvm->arch.vpit->pit_state.lock);
 	return r;
 }