From: Joas Antonio dos Santos Use the spinlock added in the previous commit to prevent completing an SE APDU request more than once. Without this, the timeout work handler (st21nfca_se_wt_work) and the EVT_TRANSMIT_DATA event handler can race and both invoke the callback, leading to a use-after-free or double-free of the callback context. Check bwi_active under the lock in both completion paths and bail out if the request was already completed. Also reject a new SE APDU request in st21nfca_hci_se_io() while one is already in progress by returning -EBUSY. Found by LLM-assisted manual code review. Fixes: 2130fb97fecf ("NFC: st21nfca: Adding support for secure element") Cc: Simon Horman Signed-off-by: Joas Antonio dos Santos --- drivers/nfc/st21nfca/se.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/nfc/st21nfca/se.c b/drivers/nfc/st21nfca/se.c index 03a30f797ff8..3be77420e956 100644 --- a/drivers/nfc/st21nfca/se.c +++ b/drivers/nfc/st21nfca/se.c @@ -228,6 +228,10 @@ int st21nfca_hci_se_io(struct nfc_hci_dev *hdev, u32 se_idx, switch (se_idx) { case ST21NFCA_ESE_HOST_ID: spin_lock(&info->se_info.se_lock); + if (info->se_info.bwi_active) { + spin_unlock(&info->se_info.se_lock); + return -EBUSY; + } info->se_info.cb = cb; info->se_info.cb_context = cb_context; info->se_info.bwi_active = true; @@ -269,6 +273,10 @@ static void st21nfca_se_wt_work(struct work_struct *work) se_info.timeout_work); spin_lock(&info->se_info.se_lock); + if (!info->se_info.bwi_active) { + spin_unlock(&info->se_info.se_lock); + return; + } info->se_info.bwi_active = false; cb = info->se_info.cb; cb_context = info->se_info.cb_context; @@ -395,6 +403,10 @@ int st21nfca_apdu_reader_event_received(struct nfc_hci_dev *hdev, cancel_work_sync(&info->se_info.timeout_work); spin_lock(&info->se_info.se_lock); + if (!info->se_info.bwi_active) { + spin_unlock(&info->se_info.se_lock); + break; + } info->se_info.bwi_active = false; cb = info->se_info.cb; cb_context = info->se_info.cb_context; -- 2.43.0