NFC: nci: fix sleep in atomic context bugs caused by nci_skb_alloc
authorDuoming Zhou <duoming@zju.edu.cn>
Tue, 17 May 2022 01:25:30 +0000 (09:25 +0800)
committerJakub Kicinski <kuba@kernel.org>
Wed, 18 May 2022 00:55:53 +0000 (17:55 -0700)
There are sleep in atomic context bugs when the request to secure
element of st-nci is timeout. The root cause is that nci_skb_alloc
with GFP_KERNEL parameter is called in st_nci_se_wt_timeout which is
a timer handler. The call paths that could trigger bugs are shown below:

    (interrupt context 1)
st_nci_se_wt_timeout
  nci_hci_send_event
    nci_hci_send_data
      nci_skb_alloc(..., GFP_KERNEL) //may sleep

   (interrupt context 2)
st_nci_se_wt_timeout
  nci_hci_send_event
    nci_hci_send_data
      nci_send_data
        nci_queue_tx_data_frags
          nci_skb_alloc(..., GFP_KERNEL) //may sleep

This patch changes allocation mode of nci_skb_alloc from GFP_KERNEL to
GFP_ATOMIC in order to prevent atomic context sleeping. The GFP_ATOMIC
flag makes memory allocation operation could be used in atomic context.

Fixes: ed06aeefdac3 ("nfc: st-nci: Rename st21nfcb to st-nci")
Signed-off-by: Duoming Zhou <duoming@zju.edu.cn>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Link: https://lore.kernel.org/r/20220517012530.75714-1-duoming@zju.edu.cn
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/nfc/nci/data.c
net/nfc/nci/hci.c

index 6055dc9a82aa0de28211ddc85b2291fb59bd7483..aa5e712adf0782f69827290911e6d9a8a9efe67f 100644 (file)
@@ -118,7 +118,7 @@ static int nci_queue_tx_data_frags(struct nci_dev *ndev,
 
                skb_frag = nci_skb_alloc(ndev,
                                         (NCI_DATA_HDR_SIZE + frag_len),
-                                        GFP_KERNEL);
+                                        GFP_ATOMIC);
                if (skb_frag == NULL) {
                        rc = -ENOMEM;
                        goto free_exit;
index 19703a649b5a685c5e56294a928e5f7ff46d3eb8..78c4b6addf15aa79add61b4bd9e920c3a7e1e7de 100644 (file)
@@ -153,7 +153,7 @@ static int nci_hci_send_data(struct nci_dev *ndev, u8 pipe,
 
        i = 0;
        skb = nci_skb_alloc(ndev, conn_info->max_pkt_payload_len +
-                           NCI_DATA_HDR_SIZE, GFP_KERNEL);
+                           NCI_DATA_HDR_SIZE, GFP_ATOMIC);
        if (!skb)
                return -ENOMEM;
 
@@ -184,7 +184,7 @@ static int nci_hci_send_data(struct nci_dev *ndev, u8 pipe,
                if (i < data_len) {
                        skb = nci_skb_alloc(ndev,
                                            conn_info->max_pkt_payload_len +
-                                           NCI_DATA_HDR_SIZE, GFP_KERNEL);
+                                           NCI_DATA_HDR_SIZE, GFP_ATOMIC);
                        if (!skb)
                                return -ENOMEM;