[PATCH V2 2/3] drivers: nfc: nfcmrvl: fix double free bug in nfc_fw_download_done()

Duoming Zhou
2022-04-14T05:31:53Z

There are potential double free bug in nfc_fw_download_done().
The timer handler fw_dnld_timeout() and work item fw_dnld_rx_work()
could both reach in fw_dnld_over() and nfc_fw_download_done() is not
protected by any lock, which leads to double free.

The race between fw_dnld_rx_work() and fw_dnld_timeout()
can be shown as below:

(Thread 1) | (Thread 2)
fw_dnld_timeout | fw_dnld_rx_work
| fw_dnld_over
fw_dnld_over | nfc_fw_download_done
nfc_fw_download_done | nfc_genl_fw_download_done
nfc_genl_fw_download_done| nlmsg_free(msg) //(1)
nlmsg_free(msg) //(2) | ...
... |

The nlmsg_free() will deallocate sk_buff in position (1), but
nlmsg_free will be deallocated again in position (2), which
leads to double free.

This patch adds spin_lock_irq() and check in fw_dnld_over()
in order to synchronize among different threads that call
fw_dnld_over(). So the double free bug could be prevented.

Fixes: 3194c6870158e3 ("NFC: nfcmrvl: add firmware download support")
Signed-off-by: Duoming Zhou <duoming@zju.edu.cn>
Reviewed-by: Lin Ma <linma@zju.edu.cn>
---
Changes in V2:
- Fix the check in spin_lock_irq.

drivers/nfc/nfcmrvl/fw_dnld.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/nfc/nfcmrvl/fw_dnld.c b/drivers/nfc/nfcmrvl/fw_dnld.c
index c22a4556db5..bb9e7e2bdec 100644
--- a/drivers/nfc/nfcmrvl/fw_dnld.c
+++ b/drivers/nfc/nfcmrvl/fw_dnld.c
@@ -115,8 +115,10 @@ static void fw_dnld_over(struct nfcmrvl_private *priv, u32 error)
/* failed, halt the chip to avoid power consumption */
nfcmrvl_chip_halt(priv);
}
-
- nfc_fw_download_done(priv->ndev->nfc_dev, priv->fw_dnld.name, error);
+ spin_lock_irq(&priv->fw_dnld.lock);
+ if (priv->ndev->nfc_dev->fw_download_in_progress)
+ nfc_fw_download_done(priv->ndev->nfc_dev, priv->fw_dnld.name, error);
+ spin_unlock_irq(&priv->fw_dnld.lock);
}

static void fw_dnld_timeout(struct timer_list *t)
--
2.17.1