[PATCH] nfc/nci: fix task hung in nfc_targets_found

From: Edward Adam Davis
Date: Sun Jan 14 2024 - 03:26:39 EST


nci_start_poll() holds the dev->mutex required by the kworker of nci_close_device(),
and the related tasks are as follows:
|cpu0 |cpu1 |cpu2 |
|nci_close_device() | | |
|mutex_lock(&ndev->req_lock); | | |
|... |nfc_genl_start_poll() | |
|flush_workqueue(ndev->rx_wq) |mutex_lock(&dev->genl_data.genl_data_mutex); | |
| |nfc_start_poll() | |
| |device_lock(&dev->dev); |process_one_work() |
| |nci_start_poll() |nfc_targets_found() |
| |nci_request() |device_lock(&dev->dev); |
| |mutex_lock(&ndev->req_lock); | |

Therefore, before applying for req_lock in nci_request(), it should be determined
whether the execution of nci_close_device() has already begun.

Reported-and-tested-by: syzbot+2b131f51bb4af224ab40@xxxxxxxxxxxxxxxxxxxxxxxxx
Signed-off-by: Edward Adam Davis <eadavis@xxxxxx>
---
net/nfc/nci/core.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index 6c9592d05120..9a277228a875 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -145,6 +145,8 @@ inline int nci_request(struct nci_dev *ndev,
{
int rc;

+ if (test_bit(NCI_UNREG, &ndev->flags))
+ return -ENODEV;
/* Serialize all requests */
mutex_lock(&ndev->req_lock);
/* check the state after obtaing the lock against any races
--
2.43.0