lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Tue, 15 Aug 2017 22:12:00 +0200
From:   Radim Krčmář <rkrcmar@...hat.com>
To:     Denys Vlasenko <dvlasenk@...hat.com>,
        Suravee Suthikulpanit <Suravee.Suthikulpanit@....com>
Cc:     Joerg Roedel <joro@...tes.org>, pbonzini@...hat.com,
        tglx@...utronix.de, mingo@...hat.com, hpa@...or.com,
        x86@...nel.org, kvm@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: [PATCH] KVM: SVM: refactor avic VM ID allocation

2017-08-11 22:11+0200, Denys Vlasenko:
> With lightly tweaked defconfig:
> 
>     text    data     bss      dec     hex filename
> 11259661 5109408 2981888 19350957 12745ad vmlinux.before
> 11259661 5109408  884736 17253805 10745ad vmlinux.after
> 
> Only compile-tested.
> 
> Signed-off-by: Denys Vlasenko <dvlasenk@...hat.com>
> Cc: Joerg Roedel <joro@...tes.org>
> Cc: pbonzini@...hat.com
> Cc: rkrcmar@...hat.com
> Cc: tglx@...utronix.de
> Cc: mingo@...hat.com
> Cc: hpa@...or.com
> Cc: x86@...nel.org
> Cc: kvm@...r.kernel.org
> Cc: linux-kernel@...r.kernel.org
> ---

Ah, I suspected my todo wasn't this short;  thanks for the patch!

> @@ -1468,6 +1433,22 @@ static int avic_vm_init(struct kvm *kvm)
>  	clear_page(page_address(l_page));
>  
>  	spin_lock_irqsave(&svm_vm_data_hash_lock, flags);
> + again:
> +	vm_id = next_vm_id = (next_vm_id + 1) & AVIC_VM_ID_MASK;
> +	if (vm_id == 0) { /* id is 1-based, zero is not okay */

Suravee, did the reserved zero mean something?

> +		next_vm_id_wrapped = 1;
> +		goto again;
> +	}
> +	/* Is it still in use? Only possible if wrapped at least once */
> +	if (next_vm_id_wrapped) {
> +		hash_for_each_possible(svm_vm_data_hash, ka, hnode, vm_id) {
> +			struct kvm *k2 = container_of(ka, struct kvm, arch);
> +			struct kvm_arch *vd2 = &k2->arch;
> +			if (vd2->avic_vm_id == vm_id)
> +				goto again;

Although hitting the case where all 2^24 ids are already used is
practically impossible, I don't like the loose end ...

What about applying something like the following on top?
---8<---
Subject: [PATCH] KVM: SVM: refactor avic VM ID allocation

We missed protection in case someone deserving a medal allocated 2^24
VMs and got a deadlock instead.  I think it is nicer without the goto
even if we droppped the error handling.

Signed-off-by: Radim Krčmář <rkrcmar@...hat.com>
---
 arch/x86/kvm/svm.c | 58 +++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 38 insertions(+), 20 deletions(-)

diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index c21b49b5ee96..4d9ee8d76db3 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -985,8 +985,6 @@ static void disable_nmi_singlestep(struct vcpu_svm *svm)
  */
 #define SVM_VM_DATA_HASH_BITS	8
 static DEFINE_HASHTABLE(svm_vm_data_hash, SVM_VM_DATA_HASH_BITS);
-static u32 next_vm_id = 0;
-static bool next_vm_id_wrapped = 0;
 static DEFINE_SPINLOCK(svm_vm_data_hash_lock);
 
 /* Note:
@@ -1385,6 +1383,38 @@ static int avic_init_backing_page(struct kvm_vcpu *vcpu)
 	return 0;
 }
 
+static bool avic_vm_id_is_used(u32 vm_id)
+{
+	struct kvm_arch *ka;
+
+	hash_for_each_possible(svm_vm_data_hash, ka, hnode, vm_id)
+		if (ka->avic_vm_id == vm_id)
+			return true;
+
+	return false;
+}
+
+static u32 avic_get_next_vm_id(void)
+{
+	static u32 next_vm_id = 0;
+	static bool next_vm_id_wrapped = false;
+	unsigned i;
+
+	for (i = 0; i < AVIC_VM_ID_NR; i++) {
+		next_vm_id = (next_vm_id + 1) & AVIC_VM_ID_MASK;
+
+		if (next_vm_id == 0) { /* id is 1-based, zero is not okay */
+			next_vm_id = 1;
+			next_vm_id_wrapped = true;
+		}
+
+		if (!next_vm_id_wrapped || !avic_vm_id_is_used(next_vm_id))
+			return next_vm_id;
+	}
+
+	return 0;
+}
+
 static void avic_vm_destroy(struct kvm *kvm)
 {
 	unsigned long flags;
@@ -1410,8 +1440,6 @@ static int avic_vm_init(struct kvm *kvm)
 	struct kvm_arch *vm_data = &kvm->arch;
 	struct page *p_page;
 	struct page *l_page;
-	struct kvm_arch *ka;
-	u32 vm_id;
 
 	if (!avic)
 		return 0;
@@ -1432,28 +1460,18 @@ static int avic_vm_init(struct kvm *kvm)
 	vm_data->avic_logical_id_table_page = l_page;
 	clear_page(page_address(l_page));
 
+	err = -EAGAIN;
 	spin_lock_irqsave(&svm_vm_data_hash_lock, flags);
- again:
-	vm_id = next_vm_id = (next_vm_id + 1) & AVIC_VM_ID_MASK;
-	if (vm_id == 0) { /* id is 1-based, zero is not okay */
-		next_vm_id_wrapped = 1;
-		goto again;
-	}
-	/* Is it still in use? Only possible if wrapped at least once */
-	if (next_vm_id_wrapped) {
-		hash_for_each_possible(svm_vm_data_hash, ka, hnode, vm_id) {
-			struct kvm *k2 = container_of(ka, struct kvm, arch);
-			struct kvm_arch *vd2 = &k2->arch;
-			if (vd2->avic_vm_id == vm_id)
-				goto again;
-		}
-	}
-	vm_data->avic_vm_id = vm_id;
+	vm_data->avic_vm_id = avic_get_next_vm_id();
+	if (!vm_data->avic_vm_id)
+		goto unlock;
 	hash_add(svm_vm_data_hash, &vm_data->hnode, vm_data->avic_vm_id);
 	spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags);
 
 	return 0;
 
+unlock:
+	spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags);
 free_avic:
 	avic_vm_destroy(kvm);
 	return err;
-- 
2.13.3

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ