dri-devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] amdkfd: fix doorbell allocation race creating duplicate allocations
@ 2026-10-09 10:18 Henry Martin
  2026-10-09 10:28 ` sashiko-bot
  2026-10-09 15:00 ` Kuehling, Felix
  0 siblings, 2 replies; 8+ messages in thread
From: Henry Martin @ 2026-10-09 10:18 UTC (permalink / raw)
  To: Felix Kuehling, Alex Deucher, Christian König, David Airlie,
	Simona Vetter, Harry Wentland, Alex Hung
  Cc: amd-gfx, dri-devel, linux-kernel, Henry Martin

The check-and-allocate sequence on pdd->qpd.proc_doorbells is
lockless at every call site of kfd_alloc_process_doorbells():
kfd_get_process_doorbells() (mmap of /dev/kfd), kfd_ioctl_create_queue()
and the CRIU restore path each test the pointer under different
locking (or none), so two racing threads can both observe NULL and
each allocate a doorbell BO and bitmap, orphaning one allocation and
handing the two mappings different backing pages.

Move the serialization into kfd_alloc_process_doorbells() itself:
take kfd->doorbell_mutex and re-check under it, so all three call
sites are covered regardless of their own locking.  The existing
doorbell_mutex users (kfd_get_kernel_doorbell() /
kfd_release_kernel_doorbell()) only guard the device-global
kfd->doorbell_bitmap in short non-sleeping sections and never call
into this path, so there is no nesting.

This vulnerability was discovered by Tencent CodeBuddy Security.

Fixes: 428542d91772 ("drm/amd/display: Setup for mmhubbub3_warmup_mcif with big buffer")
Signed-off-by: Henry Martin <bsdhenrymartin@gmail.com>
---
 drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
index fdcf7f2d1b5b4..07f881573837e 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
@@ -257,12 +257,21 @@ int kfd_alloc_process_doorbells(struct kfd_dev *kfd, struct kfd_process_device *
 	int r;
 	struct qcm_process_device *qpd = &pdd->qpd;

+	mutex_lock(&kfd->doorbell_mutex);
+
+	/* Another thread may have won the check-and-allocate race */
+	if (qpd->proc_doorbells) {
+		mutex_unlock(&kfd->doorbell_mutex);
+		return 0;
+	}
+
 	/* Allocate bitmap for dynamic doorbell allocation */
 	qpd->doorbell_bitmap = bitmap_zalloc(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS,
 					     GFP_KERNEL);
 	if (!qpd->doorbell_bitmap) {
 		DRM_ERROR("Failed to allocate process doorbell bitmap\n");
-		return -ENOMEM;
+		r = -ENOMEM;
+		goto unlock;
 	}

 	r = init_doorbell_bitmap(&pdd->qpd, kfd);
@@ -284,11 +293,15 @@ int kfd_alloc_process_doorbells(struct kfd_dev *kfd, struct kfd_process_device *
 		DRM_ERROR("Failed to allocate process doorbells\n");
 		goto err;
 	}
+
+	mutex_unlock(&kfd->doorbell_mutex);
 	return 0;

 err:
 	bitmap_free(qpd->doorbell_bitmap);
 	qpd->doorbell_bitmap = NULL;
+unlock:
+	mutex_unlock(&kfd->doorbell_mutex);
 	return r;
 }

--
2.43.7

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

* Re: [PATCH] amdkfd: fix doorbell allocation race creating duplicate allocations
  2026-10-09 10:18 [PATCH] amdkfd: fix doorbell allocation race creating duplicate allocations Henry Martin
@ 2026-10-09 10:28 ` sashiko-bot
  2026-10-09 15:00 ` Kuehling, Felix
  1 sibling, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-10-09 10:28 UTC (permalink / raw)
  To: Henry Martin; +Cc: dri-devel

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] amdkfd: broken double-checked locking exposes unpinned doorbell BO
--

commit b7981a37c1ce3dead747819635554510915a169b
Author: Henry Martin <bsdhenrymartin@gmail.com>

amdkfd: fix doorbell allocation race creating duplicate allocations

This commit adds a double-checked locking mechanism to
kfd_alloc_process_doorbells to prevent racing threads from creating
duplicate doorbell allocations. It checks the proc_doorbells pointer
under the doorbell_mutex to synchronize allocation across lockless
call sites.

> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
> index fdcf7f2d1b5b4..07f881573837e 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
> @@ -257,12 +257,21 @@ int kfd_alloc_process_doorbells(struct kfd_dev *kfd, struct kfd_process_device *
>  	int r;
>  	struct qcm_process_device *qpd = &pdd->qpd;
>  
> +	mutex_lock(&kfd->doorbell_mutex);
> +
> +	/* Another thread may have won the check-and-allocate race */
> +	if (qpd->proc_doorbells) {
> +		mutex_unlock(&kfd->doorbell_mutex);
> +		return 0;
> +	}
> +
>  	/* Allocate bitmap for dynamic doorbell allocation */
>  	qpd->doorbell_bitmap = bitmap_zalloc(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS,
>  					     GFP_KERNEL);

[ ... ]

> @@ -284,11 +293,15 @@ int kfd_alloc_process_doorbells(struct kfd_dev *kfd, struct kfd_process_device *
>  		DRM_ERROR("Failed to allocate process doorbells\n");
>  		goto err;
>  	}
> +
> +	mutex_unlock(&kfd->doorbell_mutex);
>  	return 0;

[Severity: High]
Does this code expose an unpinned buffer object to lockless readers?

Since amdgpu_bo_create_kernel() writes the newly allocated buffer object
directly to the provided pointer (&qpd->proc_doorbells) before completing
the reserve and pin phases, this pointer becomes globally visible to any
thread performing the lockless check in kfd_get_process_doorbells():

    if (!pdd->qpd.proc_doorbells) {
        if (kfd_alloc_process_doorbells(pdd->dev->kfd, pdd))
            /* phys_addr_t 0 is error */
            return 0;
    }

Could a concurrent thread bypass the mutex, observe the partially
initialized buffer object, and use it to access invalid GPU memory offsets
before pinning is complete?  Could this also trigger a use-after-free if
the allocation subsequently fails to pin and is freed?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261009101842.3294707-1-bsdhenrymartin@gmail.com?part=1

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

* Re: [PATCH] amdkfd: fix doorbell allocation race creating duplicate allocations
  2026-10-09 10:18 [PATCH] amdkfd: fix doorbell allocation race creating duplicate allocations Henry Martin
  2026-10-09 10:28 ` sashiko-bot
@ 2026-10-09 15:00 ` Kuehling, Felix
  2026-10-09 15:33   ` Kuehling, Felix
  1 sibling, 1 reply; 8+ messages in thread
From: Kuehling, Felix @ 2026-10-09 15:00 UTC (permalink / raw)
  To: Henry Martin, Alex Deucher, Christian König, David Airlie,
	Simona Vetter, Harry Wentland, Alex Hung
  Cc: amd-gfx, dri-devel, linux-kernel

On 2026-10-09 06:18, Henry Martin wrote:
> The check-and-allocate sequence on pdd->qpd.proc_doorbells is
> lockless at every call site of kfd_alloc_process_doorbells():
> kfd_get_process_doorbells() (mmap of /dev/kfd), kfd_ioctl_create_queue()
> and the CRIU restore path each test the pointer under different
> locking (or none), so two racing threads can both observe NULL and
> each allocate a doorbell BO and bitmap, orphaning one allocation and
> handing the two mappings different backing pages.
>
> Move the serialization into kfd_alloc_process_doorbells() itself:
> take kfd->doorbell_mutex and re-check under it, so all three call
> sites are covered regardless of their own locking.  The existing
> doorbell_mutex users (kfd_get_kernel_doorbell() /
> kfd_release_kernel_doorbell()) only guard the device-global
> kfd->doorbell_bitmap in short non-sleeping sections and never call
> into this path, so there is no nesting.
>
> This vulnerability was discovered by Tencent CodeBuddy Security.
>
> Fixes: 428542d91772 ("drm/amd/display: Setup for mmhubbub3_warmup_mcif with big buffer")
> Signed-off-by: Henry Martin <bsdhenrymartin@gmail.com>

Reviewed-by: Felix Kuehling <felix.kuehling@amd.com>

I'm applying the patch to amd-staging-drm-next.

Thanks,
   Felix


> ---
>   drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c | 15 ++++++++++++++-
>   1 file changed, 14 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
> index fdcf7f2d1b5b4..07f881573837e 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
> @@ -257,12 +257,21 @@ int kfd_alloc_process_doorbells(struct kfd_dev *kfd, struct kfd_process_device *
>   	int r;
>   	struct qcm_process_device *qpd = &pdd->qpd;
>
> +	mutex_lock(&kfd->doorbell_mutex);
> +
> +	/* Another thread may have won the check-and-allocate race */
> +	if (qpd->proc_doorbells) {
> +		mutex_unlock(&kfd->doorbell_mutex);
> +		return 0;
> +	}
> +
>   	/* Allocate bitmap for dynamic doorbell allocation */
>   	qpd->doorbell_bitmap = bitmap_zalloc(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS,
>   					     GFP_KERNEL);
>   	if (!qpd->doorbell_bitmap) {
>   		DRM_ERROR("Failed to allocate process doorbell bitmap\n");
> -		return -ENOMEM;
> +		r = -ENOMEM;
> +		goto unlock;
>   	}
>
>   	r = init_doorbell_bitmap(&pdd->qpd, kfd);
> @@ -284,11 +293,15 @@ int kfd_alloc_process_doorbells(struct kfd_dev *kfd, struct kfd_process_device *
>   		DRM_ERROR("Failed to allocate process doorbells\n");
>   		goto err;
>   	}
> +
> +	mutex_unlock(&kfd->doorbell_mutex);
>   	return 0;
>
>   err:
>   	bitmap_free(qpd->doorbell_bitmap);
>   	qpd->doorbell_bitmap = NULL;
> +unlock:
> +	mutex_unlock(&kfd->doorbell_mutex);
>   	return r;
>   }
>
> --
> 2.43.7

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

* Re: [PATCH] amdkfd: fix doorbell allocation race creating duplicate allocations
  2026-10-09 15:00 ` Kuehling, Felix
@ 2026-10-09 15:33   ` Kuehling, Felix
  2026-10-10  2:55     ` henry martin
  2026-10-10  3:02     ` [PATCH v2] " Henry Martin
  0 siblings, 2 replies; 8+ messages in thread
From: Kuehling, Felix @ 2026-10-09 15:33 UTC (permalink / raw)
  To: Henry Martin, Alex Deucher, Christian König, David Airlie,
	Simona Vetter, Harry Wentland, Alex Hung
  Cc: amd-gfx, dri-devel, linux-kernel

On 2026-10-09 11:00, Kuehling, Felix wrote:
> On 2026-10-09 06:18, Henry Martin wrote:
>> The check-and-allocate sequence on pdd->qpd.proc_doorbells is
>> lockless at every call site of kfd_alloc_process_doorbells():
>> kfd_get_process_doorbells() (mmap of /dev/kfd), kfd_ioctl_create_queue()
>> and the CRIU restore path each test the pointer under different
>> locking (or none), so two racing threads can both observe NULL and
>> each allocate a doorbell BO and bitmap, orphaning one allocation and
>> handing the two mappings different backing pages.
>>
>> Move the serialization into kfd_alloc_process_doorbells() itself:
>> take kfd->doorbell_mutex and re-check under it, so all three call
>> sites are covered regardless of their own locking.  The existing
>> doorbell_mutex users (kfd_get_kernel_doorbell() /
>> kfd_release_kernel_doorbell()) only guard the device-global
>> kfd->doorbell_bitmap in short non-sleeping sections and never call
>> into this path, so there is no nesting.
>>
>> This vulnerability was discovered by Tencent CodeBuddy Security.
>>
>> Fixes: 428542d91772 ("drm/amd/display: Setup for 
>> mmhubbub3_warmup_mcif with big buffer")
>> Signed-off-by: Henry Martin <bsdhenrymartin@gmail.com>
>
> Reviewed-by: Felix Kuehling <felix.kuehling@amd.com>
>
> I'm applying the patch to amd-staging-drm-next.

An automatic Claude review pointed out two problems with the patch. I 
agree with both:

The Fixes: tag points at an unrelated drm/amd/display commit 
(428542d91772). It must be corrected — 2105a15a2046 ("drm/amdgpu: use 
doorbell mgr for kfd process doorbells") is the commit that introduced 
the allocation being fixed.

The patch holds the device-global kfd->doorbell_mutex across 
bitmap_zalloc(GFP_KERNEL) and amdgpu_bo_create_kernel(), while that same 
mutex is already acquired under dqm_lock via start_cpsch -> pm_init -> 
kq_initialize -> kfd_get_kernel_doorbell(). That is a plausible ABBA 
inversion once reclaim/TTM eviction runs the KFD eviction fence back 
into dqm_lock. Please either post lockdep (CONFIG_PROVE_LOCKING) results 
for a boot + queue-create cycle, or switch to a per-process-device lock, 
which also avoids serialising unrelated processes behind a device-wide 
mutex for per-process state.

Regards,
   Felix


>
> Thanks,
>   Felix
>
>
>> ---
>>   drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c | 15 ++++++++++++++-
>>   1 file changed, 14 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c 
>> b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
>> index fdcf7f2d1b5b4..07f881573837e 100644
>> --- a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
>> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
>> @@ -257,12 +257,21 @@ int kfd_alloc_process_doorbells(struct kfd_dev 
>> *kfd, struct kfd_process_device *
>>       int r;
>>       struct qcm_process_device *qpd = &pdd->qpd;
>>
>> +    mutex_lock(&kfd->doorbell_mutex);
>> +
>> +    /* Another thread may have won the check-and-allocate race */
>> +    if (qpd->proc_doorbells) {
>> +        mutex_unlock(&kfd->doorbell_mutex);
>> +        return 0;
>> +    }
>> +
>>       /* Allocate bitmap for dynamic doorbell allocation */
>>       qpd->doorbell_bitmap = 
>> bitmap_zalloc(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS,
>>                            GFP_KERNEL);
>>       if (!qpd->doorbell_bitmap) {
>>           DRM_ERROR("Failed to allocate process doorbell bitmap\n");
>> -        return -ENOMEM;
>> +        r = -ENOMEM;
>> +        goto unlock;
>>       }
>>
>>       r = init_doorbell_bitmap(&pdd->qpd, kfd);
>> @@ -284,11 +293,15 @@ int kfd_alloc_process_doorbells(struct kfd_dev 
>> *kfd, struct kfd_process_device *
>>           DRM_ERROR("Failed to allocate process doorbells\n");
>>           goto err;
>>       }
>> +
>> +    mutex_unlock(&kfd->doorbell_mutex);
>>       return 0;
>>
>>   err:
>>       bitmap_free(qpd->doorbell_bitmap);
>>       qpd->doorbell_bitmap = NULL;
>> +unlock:
>> +    mutex_unlock(&kfd->doorbell_mutex);
>>       return r;
>>   }
>>
>> -- 
>> 2.43.7

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

* Re: [PATCH] amdkfd: fix doorbell allocation race creating duplicate allocations
  2026-10-09 15:33   ` Kuehling, Felix
@ 2026-10-10  2:55     ` henry martin
  2026-10-10  3:02     ` [PATCH v2] " Henry Martin
  1 sibling, 0 replies; 8+ messages in thread
From: henry martin @ 2026-10-10  2:55 UTC (permalink / raw)
  To: Kuehling, Felix
  Cc: Alex Deucher, Christian König, David Airlie, Simona Vetter,
	Harry Wentland, Alex Hung, amd-gfx, dri-devel, linux-kernel

Hi Felix,

You're right on both counts, thanks for the careful look.

v2 drops kfd->doorbell_mutex entirely and adds a per-process-device
mutex in struct kfd_process_device (initialized in
kfd_create_process_device_data()).  The device-global mutex is no
longer held across the sleeping allocations, so the existing
dqm->lock -> doorbell_mutex order on the start_cpsch() -> pm_init()
-> kq_initialize() path cannot invert, and unrelated processes no
longer serialize against each other for per-process doorbell setup.

The Fixes tag is corrected to 2105a15a2046 ("drm/amdgpu: use
doorbell mgr for kfd process doorbells").

Regards,
Henry

Kuehling, Felix <felix.kuehling@amd.com> 于2026年10月9日周五 23:33写道:
>
> On 2026-10-09 11:00, Kuehling, Felix wrote:
> > On 2026-10-09 06:18, Henry Martin wrote:
> >> The check-and-allocate sequence on pdd->qpd.proc_doorbells is
> >> lockless at every call site of kfd_alloc_process_doorbells():
> >> kfd_get_process_doorbells() (mmap of /dev/kfd), kfd_ioctl_create_queue()
> >> and the CRIU restore path each test the pointer under different
> >> locking (or none), so two racing threads can both observe NULL and
> >> each allocate a doorbell BO and bitmap, orphaning one allocation and
> >> handing the two mappings different backing pages.
> >>
> >> Move the serialization into kfd_alloc_process_doorbells() itself:
> >> take kfd->doorbell_mutex and re-check under it, so all three call
> >> sites are covered regardless of their own locking.  The existing
> >> doorbell_mutex users (kfd_get_kernel_doorbell() /
> >> kfd_release_kernel_doorbell()) only guard the device-global
> >> kfd->doorbell_bitmap in short non-sleeping sections and never call
> >> into this path, so there is no nesting.
> >>
> >> This vulnerability was discovered by Tencent CodeBuddy Security.
> >>
> >> Fixes: 428542d91772 ("drm/amd/display: Setup for
> >> mmhubbub3_warmup_mcif with big buffer")
> >> Signed-off-by: Henry Martin <bsdhenrymartin@gmail.com>
> >
> > Reviewed-by: Felix Kuehling <felix.kuehling@amd.com>
> >
> > I'm applying the patch to amd-staging-drm-next.
>
> An automatic Claude review pointed out two problems with the patch. I
> agree with both:
>
> The Fixes: tag points at an unrelated drm/amd/display commit
> (428542d91772). It must be corrected — 2105a15a2046 ("drm/amdgpu: use
> doorbell mgr for kfd process doorbells") is the commit that introduced
> the allocation being fixed.
>
> The patch holds the device-global kfd->doorbell_mutex across
> bitmap_zalloc(GFP_KERNEL) and amdgpu_bo_create_kernel(), while that same
> mutex is already acquired under dqm_lock via start_cpsch -> pm_init ->
> kq_initialize -> kfd_get_kernel_doorbell(). That is a plausible ABBA
> inversion once reclaim/TTM eviction runs the KFD eviction fence back
> into dqm_lock. Please either post lockdep (CONFIG_PROVE_LOCKING) results
> for a boot + queue-create cycle, or switch to a per-process-device lock,
> which also avoids serialising unrelated processes behind a device-wide
> mutex for per-process state.
>
> Regards,
>    Felix
>
>
> >
> > Thanks,
> >   Felix
> >
> >
> >> ---
> >>   drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c | 15 ++++++++++++++-
> >>   1 file changed, 14 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
> >> b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
> >> index fdcf7f2d1b5b4..07f881573837e 100644
> >> --- a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
> >> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
> >> @@ -257,12 +257,21 @@ int kfd_alloc_process_doorbells(struct kfd_dev
> >> *kfd, struct kfd_process_device *
> >>       int r;
> >>       struct qcm_process_device *qpd = &pdd->qpd;
> >>
> >> +    mutex_lock(&kfd->doorbell_mutex);
> >> +
> >> +    /* Another thread may have won the check-and-allocate race */
> >> +    if (qpd->proc_doorbells) {
> >> +        mutex_unlock(&kfd->doorbell_mutex);
> >> +        return 0;
> >> +    }
> >> +
> >>       /* Allocate bitmap for dynamic doorbell allocation */
> >>       qpd->doorbell_bitmap =
> >> bitmap_zalloc(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS,
> >>                            GFP_KERNEL);
> >>       if (!qpd->doorbell_bitmap) {
> >>           DRM_ERROR("Failed to allocate process doorbell bitmap\n");
> >> -        return -ENOMEM;
> >> +        r = -ENOMEM;
> >> +        goto unlock;
> >>       }
> >>
> >>       r = init_doorbell_bitmap(&pdd->qpd, kfd);
> >> @@ -284,11 +293,15 @@ int kfd_alloc_process_doorbells(struct kfd_dev
> >> *kfd, struct kfd_process_device *
> >>           DRM_ERROR("Failed to allocate process doorbells\n");
> >>           goto err;
> >>       }
> >> +
> >> +    mutex_unlock(&kfd->doorbell_mutex);
> >>       return 0;
> >>
> >>   err:
> >>       bitmap_free(qpd->doorbell_bitmap);
> >>       qpd->doorbell_bitmap = NULL;
> >> +unlock:
> >> +    mutex_unlock(&kfd->doorbell_mutex);
> >>       return r;
> >>   }
> >>
> >> --
> >> 2.43.7

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

* [PATCH v2] amdkfd: fix doorbell allocation race creating duplicate allocations
  2026-10-09 15:33   ` Kuehling, Felix
  2026-10-10  2:55     ` henry martin
@ 2026-10-10  3:02     ` Henry Martin
  2026-10-10  3:15       ` sashiko-bot
  2026-10-13 17:39       ` Felix Kuehling
  1 sibling, 2 replies; 8+ messages in thread
From: Henry Martin @ 2026-10-10  3:02 UTC (permalink / raw)
  To: Felix Kuehling, Alex Deucher, Christian König, David Airlie,
	Simona Vetter, Harry Wentland, Alex Hung
  Cc: amd-gfx, dri-devel, linux-kernel, Henry Martin, stable

The check-and-allocate sequence on pdd->qpd.proc_doorbells is
lockless at every call site of kfd_alloc_process_doorbells():
kfd_get_process_doorbells() (mmap of /dev/kfd),
kfd_ioctl_create_queue() and the CRIU restore path each test the
pointer under different locking (or none), so two racing threads can
both observe NULL and each allocate a doorbell BO and bitmap,
orphaning one allocation and handing the two mappings different
backing pages.

Move the serialization into kfd_alloc_process_doorbells() itself,
using a new per-process-device mutex so all three call sites are
covered regardless of their own locking.  The device-global
kfd->doorbell_mutex is not suitable here: it is acquired under
dqm->lock on the kernel-doorbell path (start_cpsch() -> pm_init() ->
kq_initialize() -> kfd_get_kernel_doorbell()), so holding it across
the sleeping allocations above would create a lock-ordering
inversion with dqm->lock via TTM eviction, and it would also
serialize doorbell setup of unrelated processes behind a
device-wide lock for per-process state.

This issue was discovered by Tencent CodeBuddy Security.

Cc: stable@vger.kernel.org
Fixes: 2105a15a2046 ("drm/amdgpu: use doorbell mgr for kfd process doorbells")
Signed-off-by: Henry Martin <bsdhenrymartin@gmail.com>
---

v2: Use a per-process-device mutex instead of kfd->doorbell_mutex
    (avoids the dqm->lock ordering inversion and the device-wide
    serialization) and correct the Fixes tag.  Pointed out by Felix
    Kuehling.

 drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c | 15 ++++++++++++++-
 drivers/gpu/drm/amd/amdkfd/kfd_priv.h     |  3 +++
 drivers/gpu/drm/amd/amdkfd/kfd_process.c  |  1 +
 3 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
index fdcf7f2d1b5b4..55acadc986bee 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
@@ -257,12 +257,21 @@ int kfd_alloc_process_doorbells(struct kfd_dev *kfd, struct kfd_process_device *
 	int r;
 	struct qcm_process_device *qpd = &pdd->qpd;
 
+	mutex_lock(&pdd->doorbell_mutex);
+
+	/* Another thread may have won the check-and-allocate race */
+	if (qpd->proc_doorbells) {
+		mutex_unlock(&pdd->doorbell_mutex);
+		return 0;
+	}
+
 	/* Allocate bitmap for dynamic doorbell allocation */
 	qpd->doorbell_bitmap = bitmap_zalloc(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS,
 					     GFP_KERNEL);
 	if (!qpd->doorbell_bitmap) {
 		DRM_ERROR("Failed to allocate process doorbell bitmap\n");
-		return -ENOMEM;
+		r = -ENOMEM;
+		goto unlock;
 	}
 
 	r = init_doorbell_bitmap(&pdd->qpd, kfd);
@@ -284,11 +293,15 @@ int kfd_alloc_process_doorbells(struct kfd_dev *kfd, struct kfd_process_device *
 		DRM_ERROR("Failed to allocate process doorbells\n");
 		goto err;
 	}
+
+	mutex_unlock(&pdd->doorbell_mutex);
 	return 0;
 
 err:
 	bitmap_free(qpd->doorbell_bitmap);
 	qpd->doorbell_bitmap = NULL;
+unlock:
+	mutex_unlock(&pdd->doorbell_mutex);
 	return r;
 }
 
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
index d8631847f0eb9..96e59133fee02 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
@@ -779,6 +779,9 @@ struct kfd_process_device {
 	/* per-process-per device QCM data structure */
 	struct qcm_process_device qpd;
 
+	/* Serializes process doorbell allocation for this device */
+	struct mutex doorbell_mutex;
+
 	/*Apertures*/
 	uint64_t lds_base;
 	uint64_t lds_limit;
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
index 0a7c1900da959..4efe4dae79c13 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
@@ -1788,6 +1788,7 @@ struct kfd_process_device *kfd_create_process_device_data(struct kfd_node *dev,
 	pdd->dev = dev;
 	INIT_LIST_HEAD(&pdd->qpd.queues_list);
 	INIT_LIST_HEAD(&pdd->qpd.priv_queue_list);
+	mutex_init(&pdd->doorbell_mutex);
 	pdd->qpd.dqm = dev->dqm;
 	pdd->qpd.pqm = &p->pqm;
 	pdd->qpd.evicted = 0;
-- 
2.43.7

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

* Re: [PATCH v2] amdkfd: fix doorbell allocation race creating duplicate allocations
  2026-10-10  3:02     ` [PATCH v2] " Henry Martin
@ 2026-10-10  3:15       ` sashiko-bot
  2026-10-13 17:39       ` Felix Kuehling
  1 sibling, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-10-10  3:15 UTC (permalink / raw)
  To: Henry Martin; +Cc: dri-devel

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] amdkfd: Double-Checked Locking vulnerability exposes unpinned doorbell BO to mmap
- [High] drm/amdkfd: TOCTOU race in doorbell allocation exposing unpinned BO
--

commit 8544c203ebbbee60344c5d18d017125a93e18d7c
Author: Henry Martin <bsdhenrymartin@gmail.com>

amdkfd: fix doorbell allocation race creating duplicate allocations

The commit adds a per-process-device mutex doorbell_mutex inside
kfd_alloc_process_doorbells() to fix a check-and-allocate race condition
where concurrent callers could create duplicate doorbell allocations.

> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
> index fdcf7f2d1b5b4..55acadc986bee 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
> @@ -257,12 +257,21 @@ int kfd_alloc_process_doorbells(struct kfd_dev *kfd, struct kfd_process_device *
>  	int r;
>  	struct qcm_process_device *qpd = &pdd->qpd;
>  
> +	mutex_lock(&pdd->doorbell_mutex);
> +
> +	/* Another thread may have won the check-and-allocate race */
> +	if (qpd->proc_doorbells) {
> +		mutex_unlock(&pdd->doorbell_mutex);
> +		return 0;
> +	}
> +
>  	/* Allocate bitmap for dynamic doorbell allocation */
>  	qpd->doorbell_bitmap = bitmap_zalloc(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS,

[ ... ]

>  	/* Allocate doorbells for this process */
>  	r = amdgpu_bo_create_kernel(kfd->adev,
>  				    kfd_doorbell_process_slice(kfd),
>  				    PAGE_SIZE,
>  				    AMDGPU_GEM_DOMAIN_DOORBELL,
>  				    &qpd->proc_doorbells,
>  				    NULL,
>  				    NULL);
>  	if (r) {
>  		DRM_ERROR("Failed to allocate process doorbells\n");
>  		goto err;
>  	}
> +
> +	mutex_unlock(&pdd->doorbell_mutex);

[Severity: Critical]
Does moving the mutex inside this function create a double-checked locking
vulnerability since the outer check is lockless?

When kfd_get_process_doorbells() is called via mmap, it does a lockless check:

	if (!pdd->qpd.proc_doorbells) {
		if (kfd_alloc_process_doorbells(pdd->dev->kfd, pdd))
			/* phys_addr_t 0 is error */
			return 0;
	}

Concurrently, if another thread is inside kfd_alloc_process_doorbells() and
calls amdgpu_bo_create_kernel() while holding the doorbell_mutex, it assigns
the new BO pointer to &qpd->proc_doorbells before the BO is fully pinned.

Can the thread calling mmap() observe the non-NULL proc_doorbells pointer,
bypass the mutex entirely, and use the unpinned BO?  If it calls
amdgpu_bo_gpu_offset() on the unpinned BO, could it calculate a bogus physical
address and map unintended memory to userspace?

>  	return 0;
>  
>  err:
>  	bitmap_free(qpd->doorbell_bitmap);
>  	qpd->doorbell_bitmap = NULL;
> +unlock:
> +	mutex_unlock(&pdd->doorbell_mutex);
>  	return r;
>  }

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261010030230.1764682-1-bsdhenrymartin@gmail.com?part=1

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

* Re: [PATCH v2] amdkfd: fix doorbell allocation race creating duplicate allocations
  2026-10-10  3:02     ` [PATCH v2] " Henry Martin
  2026-10-10  3:15       ` sashiko-bot
@ 2026-10-13 17:39       ` Felix Kuehling
  1 sibling, 0 replies; 8+ messages in thread
From: Felix Kuehling @ 2026-10-13 17:39 UTC (permalink / raw)
  To: Henry Martin, Alex Deucher, Christian König, David Airlie,
	Simona Vetter, Harry Wentland, Alex Hung
  Cc: amd-gfx, dri-devel, linux-kernel, stable

On 2026-10-09 23:02, Henry Martin wrote:
> The check-and-allocate sequence on pdd->qpd.proc_doorbells is
> lockless at every call site of kfd_alloc_process_doorbells():
> kfd_get_process_doorbells() (mmap of /dev/kfd),
> kfd_ioctl_create_queue() and the CRIU restore path each test the
> pointer under different locking (or none), so two racing threads can
> both observe NULL and each allocate a doorbell BO and bitmap,
> orphaning one allocation and handing the two mappings different
> backing pages.
>
> Move the serialization into kfd_alloc_process_doorbells() itself,
> using a new per-process-device mutex so all three call sites are
> covered regardless of their own locking.  The device-global
> kfd->doorbell_mutex is not suitable here: it is acquired under
> dqm->lock on the kernel-doorbell path (start_cpsch() -> pm_init() ->
> kq_initialize() -> kfd_get_kernel_doorbell()), so holding it across
> the sleeping allocations above would create a lock-ordering
> inversion with dqm->lock via TTM eviction, and it would also
> serialize doorbell setup of unrelated processes behind a
> device-wide lock for per-process state.
>
> This issue was discovered by Tencent CodeBuddy Security.
>
> Cc: stable@vger.kernel.org
> Fixes: 2105a15a2046 ("drm/amdgpu: use doorbell mgr for kfd process doorbells")

I don't think the Fixes tag is correct, even though that's what Claude 
suggested. As far as I can see, the code had the same possible race 
condition before that change. I believe the problem goes back all the 
way to 16f0013157bf ("drm/amdkfd: Allocate doorbells only when needed"). 
If you don't mind, I'll update that in the commit description before I 
submit your patch. With that, the patch is

Reviewed-by: Felix Kuehling <felix.kuehling@amd.com>

Thanks,
   Felix


> Signed-off-by: Henry Martin <bsdhenrymartin@gmail.com>
> ---
>
> v2: Use a per-process-device mutex instead of kfd->doorbell_mutex
>      (avoids the dqm->lock ordering inversion and the device-wide
>      serialization) and correct the Fixes tag.  Pointed out by Felix
>      Kuehling.
>
>   drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c | 15 ++++++++++++++-
>   drivers/gpu/drm/amd/amdkfd/kfd_priv.h     |  3 +++
>   drivers/gpu/drm/amd/amdkfd/kfd_process.c  |  1 +
>   3 files changed, 18 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
> index fdcf7f2d1b5b4..55acadc986bee 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
> @@ -257,12 +257,21 @@ int kfd_alloc_process_doorbells(struct kfd_dev *kfd, struct kfd_process_device *
>   	int r;
>   	struct qcm_process_device *qpd = &pdd->qpd;
>   
> +	mutex_lock(&pdd->doorbell_mutex);
> +
> +	/* Another thread may have won the check-and-allocate race */
> +	if (qpd->proc_doorbells) {
> +		mutex_unlock(&pdd->doorbell_mutex);
> +		return 0;
> +	}
> +
>   	/* Allocate bitmap for dynamic doorbell allocation */
>   	qpd->doorbell_bitmap = bitmap_zalloc(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS,
>   					     GFP_KERNEL);
>   	if (!qpd->doorbell_bitmap) {
>   		DRM_ERROR("Failed to allocate process doorbell bitmap\n");
> -		return -ENOMEM;
> +		r = -ENOMEM;
> +		goto unlock;
>   	}
>   
>   	r = init_doorbell_bitmap(&pdd->qpd, kfd);
> @@ -284,11 +293,15 @@ int kfd_alloc_process_doorbells(struct kfd_dev *kfd, struct kfd_process_device *
>   		DRM_ERROR("Failed to allocate process doorbells\n");
>   		goto err;
>   	}
> +
> +	mutex_unlock(&pdd->doorbell_mutex);
>   	return 0;
>   
>   err:
>   	bitmap_free(qpd->doorbell_bitmap);
>   	qpd->doorbell_bitmap = NULL;
> +unlock:
> +	mutex_unlock(&pdd->doorbell_mutex);
>   	return r;
>   }
>   
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
> index d8631847f0eb9..96e59133fee02 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
> @@ -779,6 +779,9 @@ struct kfd_process_device {
>   	/* per-process-per device QCM data structure */
>   	struct qcm_process_device qpd;
>   
> +	/* Serializes process doorbell allocation for this device */
> +	struct mutex doorbell_mutex;
> +
>   	/*Apertures*/
>   	uint64_t lds_base;
>   	uint64_t lds_limit;
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
> index 0a7c1900da959..4efe4dae79c13 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
> @@ -1788,6 +1788,7 @@ struct kfd_process_device *kfd_create_process_device_data(struct kfd_node *dev,
>   	pdd->dev = dev;
>   	INIT_LIST_HEAD(&pdd->qpd.queues_list);
>   	INIT_LIST_HEAD(&pdd->qpd.priv_queue_list);
> +	mutex_init(&pdd->doorbell_mutex);
>   	pdd->qpd.dqm = dev->dqm;
>   	pdd->qpd.pqm = &p->pqm;
>   	pdd->qpd.evicted = 0;

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

end of thread, other threads:[~2026-10-13 17:40 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-09 10:18 [PATCH] amdkfd: fix doorbell allocation race creating duplicate allocations Henry Martin
2026-10-09 10:28 ` sashiko-bot
2026-10-09 15:00 ` Kuehling, Felix
2026-10-09 15:33   ` Kuehling, Felix
2026-10-10  2:55     ` henry martin
2026-10-10  3:02     ` [PATCH v2] " Henry Martin
2026-10-10  3:15       ` sashiko-bot
2026-10-13 17:39       ` Felix Kuehling

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox