lkml.org 
[lkml]   [2022]   [Jun]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.17 428/772] NFC: hci: fix sleep in atomic context bugs in nfc_hci_hcp_message_tx
    Date
    From: Duoming Zhou <duoming@zju.edu.cn>

    [ Upstream commit b413b0cb008646e9f24ce5253cb3cf7ee217aff6 ]

    There are sleep in atomic context bugs when the request to secure
    element of st21nfca is timeout. The root cause is that kzalloc and
    alloc_skb with GFP_KERNEL parameter and mutex_lock are called in
    st21nfca_se_wt_timeout which is a timer handler. The call tree shows
    the execution paths that could lead to bugs:

    (Interrupt context)
    st21nfca_se_wt_timeout
    nfc_hci_send_event
    nfc_hci_hcp_message_tx
    kzalloc(..., GFP_KERNEL) //may sleep
    alloc_skb(..., GFP_KERNEL) //may sleep
    mutex_lock() //may sleep

    This patch moves the operations that may sleep into a work item.
    The work item will run in another kernel thread which is in
    process context to execute the bottom half of the interrupt.
    So it could prevent atomic context from sleeping.

    Fixes: 2130fb97fecf ("NFC: st21nfca: Adding support for secure element")
    Signed-off-by: Duoming Zhou <duoming@zju.edu.cn>
    Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
    Link: https://lore.kernel.org/r/20220518115733.62111-1-duoming@zju.edu.cn
    Signed-off-by: Jakub Kicinski <kuba@kernel.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/nfc/st21nfca/se.c | 17 ++++++++++++++---
    drivers/nfc/st21nfca/st21nfca.h | 1 +
    2 files changed, 15 insertions(+), 3 deletions(-)

    diff --git a/drivers/nfc/st21nfca/se.c b/drivers/nfc/st21nfca/se.c
    index c922f10d0d7b..7e213f8ddc98 100644
    --- a/drivers/nfc/st21nfca/se.c
    +++ b/drivers/nfc/st21nfca/se.c
    @@ -241,7 +241,7 @@ int st21nfca_hci_se_io(struct nfc_hci_dev *hdev, u32 se_idx,
    }
    EXPORT_SYMBOL(st21nfca_hci_se_io);

    -static void st21nfca_se_wt_timeout(struct timer_list *t)
    +static void st21nfca_se_wt_work(struct work_struct *work)
    {
    /*
    * No answer from the secure element
    @@ -254,8 +254,9 @@ static void st21nfca_se_wt_timeout(struct timer_list *t)
    */
    /* hardware reset managed through VCC_UICC_OUT power supply */
    u8 param = 0x01;
    - struct st21nfca_hci_info *info = from_timer(info, t,
    - se_info.bwi_timer);
    + struct st21nfca_hci_info *info = container_of(work,
    + struct st21nfca_hci_info,
    + se_info.timeout_work);

    info->se_info.bwi_active = false;

    @@ -271,6 +272,13 @@ static void st21nfca_se_wt_timeout(struct timer_list *t)
    info->se_info.cb(info->se_info.cb_context, NULL, 0, -ETIME);
    }

    +static void st21nfca_se_wt_timeout(struct timer_list *t)
    +{
    + struct st21nfca_hci_info *info = from_timer(info, t, se_info.bwi_timer);
    +
    + schedule_work(&info->se_info.timeout_work);
    +}
    +
    static void st21nfca_se_activation_timeout(struct timer_list *t)
    {
    struct st21nfca_hci_info *info = from_timer(info, t,
    @@ -360,6 +368,7 @@ int st21nfca_apdu_reader_event_received(struct nfc_hci_dev *hdev,
    switch (event) {
    case ST21NFCA_EVT_TRANSMIT_DATA:
    del_timer_sync(&info->se_info.bwi_timer);
    + cancel_work_sync(&info->se_info.timeout_work);
    info->se_info.bwi_active = false;
    r = nfc_hci_send_event(hdev, ST21NFCA_DEVICE_MGNT_GATE,
    ST21NFCA_EVT_SE_END_OF_APDU_TRANSFER, NULL, 0);
    @@ -389,6 +398,7 @@ void st21nfca_se_init(struct nfc_hci_dev *hdev)
    struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);

    init_completion(&info->se_info.req_completion);
    + INIT_WORK(&info->se_info.timeout_work, st21nfca_se_wt_work);
    /* initialize timers */
    timer_setup(&info->se_info.bwi_timer, st21nfca_se_wt_timeout, 0);
    info->se_info.bwi_active = false;
    @@ -416,6 +426,7 @@ void st21nfca_se_deinit(struct nfc_hci_dev *hdev)
    if (info->se_info.se_active)
    del_timer_sync(&info->se_info.se_active_timer);

    + cancel_work_sync(&info->se_info.timeout_work);
    info->se_info.bwi_active = false;
    info->se_info.se_active = false;
    }
    diff --git a/drivers/nfc/st21nfca/st21nfca.h b/drivers/nfc/st21nfca/st21nfca.h
    index cb6ad916be91..ae6771cc9894 100644
    --- a/drivers/nfc/st21nfca/st21nfca.h
    +++ b/drivers/nfc/st21nfca/st21nfca.h
    @@ -141,6 +141,7 @@ struct st21nfca_se_info {

    se_io_cb_t cb;
    void *cb_context;
    + struct work_struct timeout_work;
    };

    struct st21nfca_hci_info {
    --
    2.35.1


    \
     
     \ /
      Last update: 2022-06-07 23:18    [W:2.194 / U:0.532 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site