Re: [PATCH] nfc: pn533: free queued command skbs during cleanup

David Heidelberg <[email protected]> Sun, 19 Jul 2026 14:14:08 +0200
Newsgroups dev.linux.lists.oe-linux-nfc,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
On 06/07/2026 10:39, raoxu wrote:
> From: Xu Rao <[email protected]>
> 
> pn53x_common_clean() destroys the workqueue and releases the common
> PN533 state. It purges resp_q, but leaves fragment_skb untouched and
> drops queued pn533_cmd objects without freeing their request skbs.
> 
> Queued commands are created by __pn533_send_async() when another command
> is pending. At that point the queued command owns cmd->req until it is
> sent or discarded. Fragmented transfers can also leave skbs queued in
> fragment_skb.
> 
> Purge fragment_skb and free queued command request skbs before freeing
> the command objects.
> 
> Signed-off-by: Xu Rao <[email protected]>
> ---
>   drivers/nfc/pn533/pn533.c | 2 ++
>   1 file changed, 2 insertions(+)
> 
Hello Xu,

thank you for working on this. Could you append Fixes tag and add Cc for stable?

btw. you may want to also look at Sashiko output below [1].
These issues are preexisting, just in case you wanted to fix more of pn533.


commit 6e3289c813a4d66537faa65e9880657bebff74b1
Author: Xu Rao <[email protected]>

     nfc: pn533: free queued command skbs during cleanup

     pn53x_common_clean() destroys the workqueue and releases the common
     PN533 state. It purges resp_q, but leaves fragment_skb untouched and
     drops queued pn533_cmd objects without freeing their request skbs.

 > diff --git a/drivers/nfc/pn533/pn533.c b/drivers/nfc/pn533/pn533.c
 > index d7bdbc82e2ba2..de2b7f4d708c6 100644
 > --- a/drivers/nfc/pn533/pn533.c
 > +++ b/drivers/nfc/pn533/pn533.c
 > @@ -2799,9 +2799,11 @@ void pn53x_common_clean(struct pn533 *priv)
 >  	destroy_workqueue(priv->wq);

This isn't a bug introduced by this patch, but is there a use-after-free
risk in the disconnect paths involving this cleanup?

In drivers/nfc/pn533/usb.c:pn533_usb_disconnect(), the core driver state
is freed via pn53x_common_clean() before hardware transport operations are
stopped:

	pn53x_common_clean(phy->priv);
	...
	usb_kill_urb(phy->in_urb);

When usb_kill_urb() cancels the in-flight URB, the completion callback
pn533_recv_ack() executes with -ENOENT and dereferences the already freed
priv pointer to queue work on this destroyed workqueue:

	case -ENOENT:
		dev_dbg(&phy->udev->dev,
			"The urb has been stopped (status %d)\n",
			urb->status);
		goto sched_wq;
	...
	sched_wq:
		queue_work(priv->wq, &priv->cmd_complete_work);

A similar ordering issue appears in
drivers/nfc/pn533/uart.c:pn532_uart_remove() where priv is freed before
timer_shutdown_sync(&pn532->cmd_timeout).

 >
 >  	skb_queue_purge(&priv->resp_q);
 > +	skb_queue_purge(&priv->fragment_skb);
 >
 >  	list_for_each_entry_safe(cmd, n, &priv->cmd_queue, queue) {
 >  		list_del(&cmd->queue);
 > +		dev_kfree_skb(cmd->req);
 >  		kfree(cmd);

This is a pre-existing issue, but does dropping queued commands here cause
callers to hang?

When commands are removed from the queue and freed, their complete_cb is
never invoked. Callers waiting on wait_for_completion() inside
pn533_send_cmd_sync() could hang forever in TASK_UNINTERRUPTIBLE, and
async callers might leak memory allocated for complete_cb_context.

This is also a pre-existing issue, but does this cleanup routine also need
to free the actively executing command?

If the device is removed while a command is actively in-flight, it seems
priv->cmd and its associated cmd->req SKB might be leaked here when priv
is ultimately freed, since the active command is not in the cmd_queue.

This is another pre-existing issue, but does a transmission failure
permanently stall the command queue elsewhere in this file?

In drivers/nfc/pn533/pn533.c:pn533_wq_cmd(), if the physical layer
transmission fails:

	rc = dev->phy_ops->send_frame(dev, cmd->req);
	if (rc < 0) {
		dev->cmd = NULL;
		dev_kfree_skb(cmd->req);
		kfree(cmd);
		return;
	}

The function frees the command but skips calling its complete_cb (hanging
the caller) and fails to reset dev->cmd_pending = 0. This seems like it
would permanently stall all subsequent commands in the cmd_queue.

 >  	}
 >


[1] 
https://sashiko.dev/#/patchset/3B4941C5D2E3FEE0%2B20260706083926.798888-1-raoxu%40uniontech.com