Re: [PATCH] nfc: st-nci: Add error handling to IRQ handlers
David Heidelberg <[email protected]> Sun, 19 Jul 2026 14:27:09 +0200
| Newsgroups | dev.linux.lists.oe-linux-nfc,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
On 07/07/2026 16:21, Greg Kroah-Hartman wrote: > From: Griffin Kroah-Hartman <[email protected]> > > Add ndlc_remove() to st_nci_i2c_probe() and st_nci_spi_probe() if the > devm_request_threaded_irq() function fails. This is to properly unwind > after ndlc_probe() was called prior to this. > > Assisted-by: gkh_clanker_2000 > Cc: David Heidelberg <[email protected]> > Cc: "Uwe Kleine-König (The Capable Hub)" <[email protected]> > Cc: Krzysztof Kozlowski <[email protected]> > Signed-off-by: Griffin Kroah-Hartman <[email protected]> > Signed-off-by: Greg Kroah-Hartman <[email protected]> > --- > drivers/nfc/st-nci/i2c.c | 4 +++- > drivers/nfc/st-nci/spi.c | 4 +++- > 2 files changed, 6 insertions(+), 2 deletions(-) > Heya, the Sashiko review look reasonable here, check? Thanks David --- Patch [1]: [PATCH] nfc: st-nci: Add error handling to IRQ handlers --- commit ae7497e7a0338b16d82e7783afc2835614c291c1 Author: Griffin Kroah-Hartman <[email protected]> nfc: st-nci: Add error handling to IRQ handlers Add ndlc_remove() to st_nci_i2c_probe() and st_nci_spi_probe() if the devm_request_threaded_irq() function fails. This is to properly unwind after ndlc_probe() was called prior to this. > diff --git a/drivers/nfc/st-nci/i2c.c b/drivers/nfc/st-nci/i2c.c > index 9ae839a6f5cc0..7f727d9b97ba8 100644 > --- a/drivers/nfc/st-nci/i2c.c > +++ b/drivers/nfc/st-nci/i2c.c > @@ -243,8 +243,10 @@ static int st_nci_i2c_probe(struct i2c_client *client) > st_nci_irq_thread_fn, > IRQF_ONESHOT, > ST_NCI_DRIVER_NAME, phy); This is a pre-existing issue, but is there a race condition here? In st_nci_i2c_probe(), the driver calls ndlc_probe() which synchronously registers the device to the netlink subsystem, exposing it to userspace. The IRQ handler is requested immediately after. If userspace opens the device in the brief window between ndlc_probe() and devm_request_threaded_irq(), could st_nci_open() attempt to enable an unrequested IRQ and cause communication timeouts? > - if (r < 0) > + if (r < 0) { > nfc_err(&client->dev, "Unable to register IRQ handler\n"); > + ndlc_remove(phy->ndlc); Does calling ndlc_remove() here lead to an unbalanced IRQ disable? When devm_request_threaded_irq() fails, this new error path calls ndlc_remove(). This function eventually calls st_nci_i2c_disable(), which unconditionally executes disable_irq_nosync(). Since the IRQ registration just failed, would disabling this unrequested shared IRQ line break other devices and trigger an unbalanced IRQ disable warning? Will this error path also cause a blocking wait and memory leak? When ndlc_remove() cascades to ndlc_close(), it sends a synchronous NCI mode-set command via nci_prop_cmd(). Since the device was never opened by userspace during this failed probe, the ST_NCI_RUNNING flag is not set. This causes st_nci_send() to return -EBUSY and drop the transmission without freeing the sk_buff. Because nci_prop_cmd() waits synchronously for a response that will never arrive, won't this block the probe failure path for the full 2-second timeout? This is a pre-existing issue, but does the teardown order in ndlc_remove() allow work items to be re-armed after cancellation? In ndlc_remove(), background work is cancelled before deregistration: drivers/nfc/st-nci/ndlc.c:ndlc_remove() { ... cancel_work_sync(&ndlc->sm_work); st_nci_remove(ndlc->ndev); ... } However, st_nci_remove() delegates to ndlc_close(), which queues a mode-set command. If the interface was running, this command flows to ndlc_send(), which calls schedule_work(&ndlc->sm_work). Could this re-arm the work item after the cancellation sync, allowing it to outlive the device's managed memory and cause a use-after-free? This is a pre-existing issue, but are the Secure Element timers leaking during device removal? The timers bwi_timer and se_active_timer are initialized in st_nci_se_init() using managed memory, but st_nci_remove() orchestrates teardown without ever calling the designated st_nci_se_deinit() cleanup function: drivers/nfc/st-nci/core.c:st_nci_remove() { struct st_nci_info *info = nci_get_drvdata(ndev); ndlc_close(info->ndlc); nci_unregister_device(ndev); nci_free_device(ndev); } If a timer is running when the module unbinds, could it survive the devres cleanup and cause a use-after-free when it fires? This is a pre-existing issue, but is there a missing cleanup step if st_nci_se_init() fails? In st_nci_probe(), the device is registered to the core, but if the subsequent Secure Element initialization fails, it returns early: drivers/nfc/st-nci/core.c:st_nci_probe() { ... r = nci_register_device(ndlc->ndev); if (r) { pr_err("Cannot register nfc device to nci core\n"); goto err_reg_dev; } return st_nci_se_init(ndlc->ndev, se_status); } If st_nci_se_init() returns an error, the devres cleanup will free the driver-private objects, but the NCI interface is never unregistered. Would this leave a dangling interface accessible to userspace, leading to a use-after-free? > + } > > return r; > } [ ... ]