[PATCH] accel/amdxdna: fix double-free on mailbox channel stop

Deniz Aydogan posted 1 patch 4 weeks, 1 day ago
drivers/accel/amdxdna/amdxdna_mailbox.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
[PATCH] accel/amdxdna: fix double-free on mailbox channel stop
Posted by Deniz Aydogan 4 weeks, 1 day ago
mailbox_release_msg() frees the message with kfree() but does not
remove it from the xarray. The stop function uses two loops to walk
pending entries in cyclic order, but since released entries remain in
the xarray, overlapping ranges cause the same entry to be freed twice.

In particular, when next_msgid is 0 (the initial value after kzalloc),
xa_for_each_start() covers all entries from index 0 onward, and
xa_for_each_range() with max=(u32)(0 - 1) = U32_MAX also covers all
entries. Every pending message gets double-freed.

Use xa_for_each() to iterate all remaining entries exactly once.
At this point the IRQ is already freed and the workqueue is drained,
so traversal order does not matter.

Fixes: 3ba13f5e7180 ("Merge tag 'devicetree-fixes-for-7.3-1'")
Signed-off-by: Deniz Aydogan <denizaydogan1902@gmail.com>
---
 drivers/accel/amdxdna/amdxdna_mailbox.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/accel/amdxdna/amdxdna_mailbox.c b/drivers/accel/amdxdna/amdxdna_mailbox.c
index cc8865f4e..271617347 100644
--- a/drivers/accel/amdxdna/amdxdna_mailbox.c
+++ b/drivers/accel/amdxdna/amdxdna_mailbox.c
@@ -556,9 +556,7 @@ void xdna_mailbox_stop_channel(struct mailbox_channel *mb_chann)
 	drain_workqueue(mb_chann->work_q);
 
 	/* We can clean up and release resources */
-	xa_for_each_start(&mb_chann->chan_xa, msg_id, mb_msg, mb_chann->next_msgid)
-		mailbox_release_msg(mb_chann, mb_msg);
-	xa_for_each_range(&mb_chann->chan_xa, msg_id, mb_msg, 0, mb_chann->next_msgid - 1)
+	xa_for_each(&mb_chann->chan_xa, msg_id, mb_msg)
 		mailbox_release_msg(mb_chann, mb_msg);
 	xa_destroy(&mb_chann->chan_xa);
 
-- 
2.55.0
Re: [PATCH] accel/amdxdna: fix double-free on mailbox channel stop
Posted by Lizhi Hou 3 weeks, 5 days ago
On 8/28/26 14:24, Deniz Aydogan wrote:
> mailbox_release_msg() frees the message with kfree() but does not
> remove it from the xarray. The stop function uses two loops to walk
> pending entries in cyclic order, but since released entries remain in
> the xarray, overlapping ranges cause the same entry to be freed twice.
>
> In particular, when next_msgid is 0 (the initial value after kzalloc),
> xa_for_each_start() covers all entries from index 0 onward, and
> xa_for_each_range() with max=(u32)(0 - 1) = U32_MAX also covers all
> entries. Every pending message gets double-freed.
>
> Use xa_for_each() to iterate all remaining entries exactly once.
> At this point the IRQ is already freed and the workqueue is drained,
> so traversal order does not matter.
>
> Fixes: 3ba13f5e7180 ("Merge tag 'devicetree-fixes-for-7.3-1'")
> Signed-off-by: Deniz Aydogan <denizaydogan1902@gmail.com>
> ---
>   drivers/accel/amdxdna/amdxdna_mailbox.c | 4 +---
>   1 file changed, 1 insertion(+), 3 deletions(-)
>
> diff --git a/drivers/accel/amdxdna/amdxdna_mailbox.c b/drivers/accel/amdxdna/amdxdna_mailbox.c
> index cc8865f4e..271617347 100644
> --- a/drivers/accel/amdxdna/amdxdna_mailbox.c
> +++ b/drivers/accel/amdxdna/amdxdna_mailbox.c
> @@ -556,9 +556,7 @@ void xdna_mailbox_stop_channel(struct mailbox_channel *mb_chann)
>   	drain_workqueue(mb_chann->work_q);
>   
>   	/* We can clean up and release resources */
> -	xa_for_each_start(&mb_chann->chan_xa, msg_id, mb_msg, mb_chann->next_msgid)
> -		mailbox_release_msg(mb_chann, mb_msg);
> -	xa_for_each_range(&mb_chann->chan_xa, msg_id, mb_msg, 0, mb_chann->next_msgid - 1)
> +	xa_for_each(&mb_chann->chan_xa, msg_id, mb_msg)

The msg need to be released in sequence. And I would suggest to release 
msgid in mailbox_release_msg()

@@ -192,6 +192,7 @@ static void mailbox_release_msg(struct 
mailbox_channel *mb_chann,
                mb_msg->pkg.header.id, mb_msg->pkg.header.opcode);
         if (mb_msg->notify_cb)
                 mb_msg->notify_cb(mb_msg->handle, NULL, 0);
+       mailbox_release_msgid(mb_chann, mb_msg->pkg.header.id);
         kfree(mb_msg);

Thanks,

Lizhi

>   		mailbox_release_msg(mb_chann, mb_msg);
>   	xa_destroy(&mb_chann->chan_xa);
>