linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] KVM: arm64: vgic: Hold config_lock while tearing down a CPU interface
@ 2024-08-08  9:15 Marc Zyngier
  2024-08-08 17:07 ` Oliver Upton
  2024-08-19  9:39 ` Zenghui Yu
  0 siblings, 2 replies; 6+ messages in thread
From: Marc Zyngier @ 2024-08-08  9:15 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: James Morse, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
	Alexander Potapenko

Tearing down a vcpu CPU interface involves freeing the private interrupt
array. If we don't hold the lock, we may race against another thread
trying to configure it. Yeah, fuzzers do wonderful things...

Taking the lock early solves this particular problem.

Fixes: 03b3d00a70b5 ("KVM: arm64: vgic: Allocate private interrupts on demand")
Reported-by: Alexander Potapenko <glider@google.com>
Tested-by: Alexander Potapenko <glider@google.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/vgic/vgic-init.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 7f68cf58b978..41feb858ff9a 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -438,14 +438,13 @@ void kvm_vgic_destroy(struct kvm *kvm)
 	unsigned long i;
 
 	mutex_lock(&kvm->slots_lock);
+	mutex_lock(&kvm->arch.config_lock);
 
 	vgic_debug_destroy(kvm);
 
 	kvm_for_each_vcpu(i, vcpu, kvm)
 		__kvm_vgic_vcpu_destroy(vcpu);
 
-	mutex_lock(&kvm->arch.config_lock);
-
 	kvm_vgic_dist_destroy(kvm);
 
 	mutex_unlock(&kvm->arch.config_lock);
-- 
2.39.2



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] KVM: arm64: vgic: Hold config_lock while tearing down a CPU interface
  2024-08-08  9:15 [PATCH] KVM: arm64: vgic: Hold config_lock while tearing down a CPU interface Marc Zyngier
@ 2024-08-08 17:07 ` Oliver Upton
  2024-08-19  9:39 ` Zenghui Yu
  1 sibling, 0 replies; 6+ messages in thread
From: Oliver Upton @ 2024-08-08 17:07 UTC (permalink / raw)
  To: kvmarm, Marc Zyngier, linux-arm-kernel
  Cc: Oliver Upton, Suzuki K Poulose, Zenghui Yu, Alexander Potapenko,
	James Morse

On Thu, 8 Aug 2024 10:15:46 +0100, Marc Zyngier wrote:
> Tearing down a vcpu CPU interface involves freeing the private interrupt
> array. If we don't hold the lock, we may race against another thread
> trying to configure it. Yeah, fuzzers do wonderful things...
> 
> Taking the lock early solves this particular problem.
> 
> 
> [...]

Applied to kvmarm/fixes, thanks!

[1/1] KVM: arm64: vgic: Hold config_lock while tearing down a CPU interface
      https://git.kernel.org/kvmarm/kvmarm/c/9eb18136af9f

--
Best,
Oliver


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] KVM: arm64: vgic: Hold config_lock while tearing down a CPU interface
  2024-08-08  9:15 [PATCH] KVM: arm64: vgic: Hold config_lock while tearing down a CPU interface Marc Zyngier
  2024-08-08 17:07 ` Oliver Upton
@ 2024-08-19  9:39 ` Zenghui Yu
  2024-08-19 10:53   ` Marc Zyngier
  1 sibling, 1 reply; 6+ messages in thread
From: Zenghui Yu @ 2024-08-19  9:39 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvmarm, linux-arm-kernel, James Morse, Suzuki K Poulose,
	Oliver Upton, Alexander Potapenko

Hi Marc,

On 2024/8/8 17:15, Marc Zyngier wrote:
> Tearing down a vcpu CPU interface involves freeing the private interrupt
> array. If we don't hold the lock, we may race against another thread
> trying to configure it. Yeah, fuzzers do wonderful things...
> 
> Taking the lock early solves this particular problem.
> 
> Fixes: 03b3d00a70b5 ("KVM: arm64: vgic: Allocate private interrupts on demand")
> Reported-by: Alexander Potapenko <glider@google.com>
> Tested-by: Alexander Potapenko <glider@google.com>
> Signed-off-by: Marc Zyngier <maz@kernel.org>
> ---
>  arch/arm64/kvm/vgic/vgic-init.c | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
> index 7f68cf58b978..41feb858ff9a 100644
> --- a/arch/arm64/kvm/vgic/vgic-init.c
> +++ b/arch/arm64/kvm/vgic/vgic-init.c
> @@ -438,14 +438,13 @@ void kvm_vgic_destroy(struct kvm *kvm)
>  	unsigned long i;
>  
>  	mutex_lock(&kvm->slots_lock);
> +	mutex_lock(&kvm->arch.config_lock);
>  
>  	vgic_debug_destroy(kvm);
>  
>  	kvm_for_each_vcpu(i, vcpu, kvm)
>  		__kvm_vgic_vcpu_destroy(vcpu);
>  
> -	mutex_lock(&kvm->arch.config_lock);
> -
>  	kvm_vgic_dist_destroy(kvm);
>  
>  	mutex_unlock(&kvm->arch.config_lock);

The following splat was triggered when running the vgic_init selftest on
a lockdep kernel (I use rc4, with defconfig + PROVE_LOCKING).

I'm not entirely sure that the splat is related to this change. Just
haven't got time to dig further so post it out early for record.

 ======================================================
 WARNING: possible circular locking dependency detected
 6.11.0-rc4-dirty Not tainted
 ------------------------------------------------------
 vgic_init/358856 is trying to acquire lock:
 ffff2028021b53c8 (&kvm->srcu){.+.+}-{0:0}, at: __synchronize_srcu+0x0/0x170

 but task is already holding lock:
 ffff2028021b4f80 (&kvm->arch.config_lock){+.+.}-{3:3}, at:
kvm_vgic_destroy+0x50/0x1e0

 which lock already depends on the new lock.


 the existing dependency chain (in reverse order) is:

 -> #1 (&kvm->arch.config_lock){+.+.}-{3:3}:
        __mutex_lock+0x84/0x400
        mutex_lock_nested+0x24/0x30
        vgic_mmio_write_v3_misc+0x48/0x120
        dispatch_mmio_write+0x90/0x128
        __kvm_io_bus_write+0xb4/0xec
        kvm_io_bus_write+0x68/0x100
        io_mem_abort+0xf0/0x3f0
        kvm_handle_guest_abort+0x5d0/0x108c
        handle_exit+0x6c/0x1c4
        kvm_arch_vcpu_ioctl_run+0x41c/0xac4
        kvm_vcpu_ioctl+0x310/0xaf4
        __arm64_sys_ioctl+0xa8/0xec
        invoke_syscall+0x48/0x110
        el0_svc_common.constprop.0+0x40/0xe0
        do_el0_svc+0x1c/0x28
        el0_svc+0x4c/0x11c
        el0t_64_sync_handler+0xc0/0xc4
        el0t_64_sync+0x190/0x194

 -> #0 (&kvm->srcu){.+.+}-{0:0}:
        __lock_acquire+0x1304/0x2044
        lock_sync+0xd8/0x128
        __synchronize_srcu+0x50/0x170
        synchronize_srcu_expedited+0x24/0x34
        kvm_io_bus_unregister_dev+0x110/0x26c
        vgic_unregister_redist_iodev+0x20/0x2c
        kvm_vgic_destroy+0xe8/0x1e0
        kvm_vgic_map_resources+0xa8/0x138
        kvm_arch_vcpu_run_pid_change+0xc0/0x430
        kvm_vcpu_ioctl+0xa24/0xaf4
        __arm64_sys_ioctl+0xa8/0xec
        invoke_syscall+0x48/0x110
        el0_svc_common.constprop.0+0x40/0xe0
        do_el0_svc+0x1c/0x28
        el0_svc+0x4c/0x11c
        el0t_64_sync_handler+0xc0/0xc4
        el0t_64_sync+0x190/0x194

 other info that might help us debug this:

  Possible unsafe locking scenario:

        CPU0                    CPU1
        ----                    ----
   lock(&kvm->arch.config_lock);
                                lock(&kvm->srcu);
                                lock(&kvm->arch.config_lock);
   sync(&kvm->srcu);

  *** DEADLOCK ***

 3 locks held by vgic_init/358856:
  #0: ffff20280aa19b40 (&vcpu->mutex){+.+.}-{3:3}, at:
kvm_vcpu_ioctl+0x84/0xaf4
  #1: ffff2028021b40a8 (&kvm->slots_lock){+.+.}-{3:3}, at:
kvm_vgic_destroy+0x44/0x1e0
  #2: ffff2028021b4f80 (&kvm->arch.config_lock){+.+.}-{3:3}, at:
kvm_vgic_destroy+0x50/0x1e0

 stack backtrace:
 CPU: 74 UID: 0 PID: 358856 Comm: vgic_init Kdump: loaded Not tainted
6.11.0-rc4-dirty
 Call trace:
  dump_backtrace+0x98/0xf0
  show_stack+0x18/0x24
  dump_stack_lvl+0x90/0xd0
  dump_stack+0x18/0x24
  print_circular_bug+0x290/0x370
  check_noncircular+0x15c/0x170
  __lock_acquire+0x1304/0x2044
  lock_sync+0xd8/0x128
  __synchronize_srcu+0x50/0x170
  synchronize_srcu_expedited+0x24/0x34
  kvm_io_bus_unregister_dev+0x110/0x26c
  vgic_unregister_redist_iodev+0x20/0x2c
  kvm_vgic_destroy+0xe8/0x1e0
  kvm_vgic_map_resources+0xa8/0x138
  kvm_arch_vcpu_run_pid_change+0xc0/0x430
  kvm_vcpu_ioctl+0xa24/0xaf4
  __arm64_sys_ioctl+0xa8/0xec
  invoke_syscall+0x48/0x110
  el0_svc_common.constprop.0+0x40/0xe0
  do_el0_svc+0x1c/0x28
  el0_svc+0x4c/0x11c
  el0t_64_sync_handler+0xc0/0xc4
  el0t_64_sync+0x190/0x194

Thanks,
Zenghui


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] KVM: arm64: vgic: Hold config_lock while tearing down a CPU interface
  2024-08-19  9:39 ` Zenghui Yu
@ 2024-08-19 10:53   ` Marc Zyngier
  2024-08-19 12:31     ` Zenghui Yu
  0 siblings, 1 reply; 6+ messages in thread
From: Marc Zyngier @ 2024-08-19 10:53 UTC (permalink / raw)
  To: Zenghui Yu
  Cc: kvmarm, linux-arm-kernel, James Morse, Suzuki K Poulose,
	Oliver Upton, Alexander Potapenko

On Mon, 19 Aug 2024 10:39:50 +0100,
Zenghui Yu <yuzenghui@huawei.com> wrote:
> 
> Hi Marc,
> 
> On 2024/8/8 17:15, Marc Zyngier wrote:
> > Tearing down a vcpu CPU interface involves freeing the private interrupt
> > array. If we don't hold the lock, we may race against another thread
> > trying to configure it. Yeah, fuzzers do wonderful things...
> > 
> > Taking the lock early solves this particular problem.
> > 
> > Fixes: 03b3d00a70b5 ("KVM: arm64: vgic: Allocate private interrupts on demand")
> > Reported-by: Alexander Potapenko <glider@google.com>
> > Tested-by: Alexander Potapenko <glider@google.com>
> > Signed-off-by: Marc Zyngier <maz@kernel.org>
> > ---
> >  arch/arm64/kvm/vgic/vgic-init.c | 3 +--
> >  1 file changed, 1 insertion(+), 2 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
> > index 7f68cf58b978..41feb858ff9a 100644
> > --- a/arch/arm64/kvm/vgic/vgic-init.c
> > +++ b/arch/arm64/kvm/vgic/vgic-init.c
> > @@ -438,14 +438,13 @@ void kvm_vgic_destroy(struct kvm *kvm)
> >  	unsigned long i;
> >  
> >  	mutex_lock(&kvm->slots_lock);
> > +	mutex_lock(&kvm->arch.config_lock);
> >  
> >  	vgic_debug_destroy(kvm);
> >  
> >  	kvm_for_each_vcpu(i, vcpu, kvm)
> >  		__kvm_vgic_vcpu_destroy(vcpu);
> >  
> > -	mutex_lock(&kvm->arch.config_lock);
> > -
> >  	kvm_vgic_dist_destroy(kvm);
> >  
> >  	mutex_unlock(&kvm->arch.config_lock);
> 
> The following splat was triggered when running the vgic_init selftest on
> a lockdep kernel (I use rc4, with defconfig + PROVE_LOCKING).
> 
> I'm not entirely sure that the splat is related to this change. Just
> haven't got time to dig further so post it out early for record.

Arghh. Thanks for reporting this. Can you try the following patch? It
does the trick for me, but I don't trust myself anymore...

	M.

diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 41feb858ff9a..e7c53e8af3d1 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -417,10 +417,8 @@ static void __kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
 	kfree(vgic_cpu->private_irqs);
 	vgic_cpu->private_irqs = NULL;
 
-	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) {
-		vgic_unregister_redist_iodev(vcpu);
+	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
 		vgic_cpu->rd_iodev.base_addr = VGIC_ADDR_UNDEF;
-	}
 }
 
 void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
@@ -448,6 +446,11 @@ void kvm_vgic_destroy(struct kvm *kvm)
 	kvm_vgic_dist_destroy(kvm);
 
 	mutex_unlock(&kvm->arch.config_lock);
+
+	if (kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
+		kvm_for_each_vcpu(i, vcpu, kvm)
+			vgic_unregister_redist_iodev(vcpu);
+
 	mutex_unlock(&kvm->slots_lock);
 }
 
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index 2caa64415ff3..f50274fd5581 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -36,6 +36,11 @@ struct vgic_global kvm_vgic_global_state __ro_after_init = {
  * we have to disable IRQs before taking this lock and everything lower
  * than it.
  *
+ * The config_lock has additional ordering requirements:
+ * kvm->slots_lock
+ *   kvm->srcu
+ *     kvm->arch.config_lock
+ *
  * If you need to take multiple locks, always take the upper lock first,
  * then the lower ones, e.g. first take the its_lock, then the irq_lock.
  * If you are already holding a lock and need to take a higher one, you

-- 
Without deviation from the norm, progress is not possible.


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] KVM: arm64: vgic: Hold config_lock while tearing down a CPU interface
  2024-08-19 10:53   ` Marc Zyngier
@ 2024-08-19 12:31     ` Zenghui Yu
  2024-08-19 12:48       ` Marc Zyngier
  0 siblings, 1 reply; 6+ messages in thread
From: Zenghui Yu @ 2024-08-19 12:31 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvmarm, linux-arm-kernel, James Morse, Suzuki K Poulose,
	Oliver Upton, Alexander Potapenko

On 2024/8/19 18:53, Marc Zyngier wrote:
> On Mon, 19 Aug 2024 10:39:50 +0100,
> Zenghui Yu <yuzenghui@huawei.com> wrote:
> >
> > Hi Marc,
> >
> > On 2024/8/8 17:15, Marc Zyngier wrote:
> > > Tearing down a vcpu CPU interface involves freeing the private interrupt
> > > array. If we don't hold the lock, we may race against another thread
> > > trying to configure it. Yeah, fuzzers do wonderful things...
> > >
> > > Taking the lock early solves this particular problem.
> > >
> > > Fixes: 03b3d00a70b5 ("KVM: arm64: vgic: Allocate private interrupts on demand")
> > > Reported-by: Alexander Potapenko <glider@google.com>
> > > Tested-by: Alexander Potapenko <glider@google.com>
> > > Signed-off-by: Marc Zyngier <maz@kernel.org>
> > > ---
> > >  arch/arm64/kvm/vgic/vgic-init.c | 3 +--
> > >  1 file changed, 1 insertion(+), 2 deletions(-)
> > >
> > > diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
> > > index 7f68cf58b978..41feb858ff9a 100644
> > > --- a/arch/arm64/kvm/vgic/vgic-init.c
> > > +++ b/arch/arm64/kvm/vgic/vgic-init.c
> > > @@ -438,14 +438,13 @@ void kvm_vgic_destroy(struct kvm *kvm)
> > >  	unsigned long i;
> > >  
> > >  	mutex_lock(&kvm->slots_lock);
> > > +	mutex_lock(&kvm->arch.config_lock);
> > >  
> > >  	vgic_debug_destroy(kvm);
> > >  
> > >  	kvm_for_each_vcpu(i, vcpu, kvm)
> > >  		__kvm_vgic_vcpu_destroy(vcpu);
> > >  
> > > -	mutex_lock(&kvm->arch.config_lock);
> > > -
> > >  	kvm_vgic_dist_destroy(kvm);
> > >  
> > >  	mutex_unlock(&kvm->arch.config_lock);
> >
> > The following splat was triggered when running the vgic_init selftest on
> > a lockdep kernel (I use rc4, with defconfig + PROVE_LOCKING).
> >
> > I'm not entirely sure that the splat is related to this change. Just
> > haven't got time to dig further so post it out early for record.
> 
> Arghh. Thanks for reporting this. Can you try the following patch? It
> does the trick for me, but I don't trust myself anymore...

I tested it with defconfig+PROVE_LOCKING and my own config, both worked
for me (the WARNING disappeared). I think the locking order should be
correct now.

Thanks,
Zenghui


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] KVM: arm64: vgic: Hold config_lock while tearing down a CPU interface
  2024-08-19 12:31     ` Zenghui Yu
@ 2024-08-19 12:48       ` Marc Zyngier
  0 siblings, 0 replies; 6+ messages in thread
From: Marc Zyngier @ 2024-08-19 12:48 UTC (permalink / raw)
  To: Zenghui Yu
  Cc: kvmarm, linux-arm-kernel, James Morse, Suzuki K Poulose,
	Oliver Upton, Alexander Potapenko

On Mon, 19 Aug 2024 13:31:59 +0100,
Zenghui Yu <yuzenghui@huawei.com> wrote:
> 
> On 2024/8/19 18:53, Marc Zyngier wrote:
> > On Mon, 19 Aug 2024 10:39:50 +0100,
> > Zenghui Yu <yuzenghui@huawei.com> wrote:
> > >
> > > Hi Marc,
> > >
> > > On 2024/8/8 17:15, Marc Zyngier wrote:
> > > > Tearing down a vcpu CPU interface involves freeing the private interrupt
> > > > array. If we don't hold the lock, we may race against another thread
> > > > trying to configure it. Yeah, fuzzers do wonderful things...
> > > >
> > > > Taking the lock early solves this particular problem.
> > > >
> > > > Fixes: 03b3d00a70b5 ("KVM: arm64: vgic: Allocate private interrupts on demand")
> > > > Reported-by: Alexander Potapenko <glider@google.com>
> > > > Tested-by: Alexander Potapenko <glider@google.com>
> > > > Signed-off-by: Marc Zyngier <maz@kernel.org>
> > > > ---
> > > >  arch/arm64/kvm/vgic/vgic-init.c | 3 +--
> > > >  1 file changed, 1 insertion(+), 2 deletions(-)
> > > >
> > > > diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
> > > > index 7f68cf58b978..41feb858ff9a 100644
> > > > --- a/arch/arm64/kvm/vgic/vgic-init.c
> > > > +++ b/arch/arm64/kvm/vgic/vgic-init.c
> > > > @@ -438,14 +438,13 @@ void kvm_vgic_destroy(struct kvm *kvm)
> > > >  	unsigned long i;
> > > >  
> > > >  	mutex_lock(&kvm->slots_lock);
> > > > +	mutex_lock(&kvm->arch.config_lock);
> > > >  
> > > >  	vgic_debug_destroy(kvm);
> > > >  
> > > >  	kvm_for_each_vcpu(i, vcpu, kvm)
> > > >  		__kvm_vgic_vcpu_destroy(vcpu);
> > > >  
> > > > -	mutex_lock(&kvm->arch.config_lock);
> > > > -
> > > >  	kvm_vgic_dist_destroy(kvm);
> > > >  
> > > >  	mutex_unlock(&kvm->arch.config_lock);
> > >
> > > The following splat was triggered when running the vgic_init selftest on
> > > a lockdep kernel (I use rc4, with defconfig + PROVE_LOCKING).
> > >
> > > I'm not entirely sure that the splat is related to this change. Just
> > > haven't got time to dig further so post it out early for record.
> > 
> > Arghh. Thanks for reporting this. Can you try the following patch? It
> > does the trick for me, but I don't trust myself anymore...
> 
> I tested it with defconfig+PROVE_LOCKING and my own config, both worked
> for me (the WARNING disappeared). I think the locking order should be
> correct now.

Awesome. Let me post a proper patch right away.

Thanks again,

	M.

-- 
Without deviation from the norm, progress is not possible.


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2024-08-19 12:49 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-08  9:15 [PATCH] KVM: arm64: vgic: Hold config_lock while tearing down a CPU interface Marc Zyngier
2024-08-08 17:07 ` Oliver Upton
2024-08-19  9:39 ` Zenghui Yu
2024-08-19 10:53   ` Marc Zyngier
2024-08-19 12:31     ` Zenghui Yu
2024-08-19 12:48       ` Marc Zyngier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).