lkml.org 
[lkml]   [2022]   [May]   [17]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH net v2] NFC: hci: fix sleep in atomic context bugs in nfc_hci_hcp_message_tx
Date
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 changes allocation mode of kzalloc and alloc_skb from
GFP_KERNEL to GFP_ATOMIC and changes mutex_lock to spin_lock in
order to prevent atomic context from sleeping.

Fixes: 2130fb97fecf ("NFC: st21nfca: Adding support for secure element")
Signed-off-by: Duoming Zhou <duoming@zju.edu.cn>
---
Changes in v2:
- Change mutex_lock to spin_lock.

include/net/nfc/hci.h | 3 ++-
net/nfc/hci/core.c | 18 +++++++++---------
net/nfc/hci/hcp.c | 10 +++++-----
3 files changed, 16 insertions(+), 15 deletions(-)

diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h
index 756c11084f6..8f66e6e6b91 100644
--- a/include/net/nfc/hci.h
+++ b/include/net/nfc/hci.h
@@ -103,7 +103,8 @@ struct nfc_hci_dev {

bool shutting_down;

- struct mutex msg_tx_mutex;
+ /* The spinlock is used to protect resources related with hci message TX */
+ spinlock_t msg_tx_spin;

struct list_head msg_tx_queue;

diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c
index ceb87db57cd..fa22f9fe5fc 100644
--- a/net/nfc/hci/core.c
+++ b/net/nfc/hci/core.c
@@ -68,7 +68,7 @@ static void nfc_hci_msg_tx_work(struct work_struct *work)
struct sk_buff *skb;
int r = 0;

- mutex_lock(&hdev->msg_tx_mutex);
+ spin_lock(&hdev->msg_tx_spin);
if (hdev->shutting_down)
goto exit;

@@ -120,7 +120,7 @@ static void nfc_hci_msg_tx_work(struct work_struct *work)
msecs_to_jiffies(hdev->cmd_pending_msg->completion_delay));

exit:
- mutex_unlock(&hdev->msg_tx_mutex);
+ spin_unlock(&hdev->msg_tx_spin);
}

static void nfc_hci_msg_rx_work(struct work_struct *work)
@@ -165,7 +165,7 @@ static void __nfc_hci_cmd_completion(struct nfc_hci_dev *hdev, int err,
void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result,
struct sk_buff *skb)
{
- mutex_lock(&hdev->msg_tx_mutex);
+ spin_lock(&hdev->msg_tx_spin);

if (hdev->cmd_pending_msg == NULL) {
kfree_skb(skb);
@@ -175,7 +175,7 @@ void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result,
__nfc_hci_cmd_completion(hdev, nfc_hci_result_to_errno(result), skb);

exit:
- mutex_unlock(&hdev->msg_tx_mutex);
+ spin_unlock(&hdev->msg_tx_spin);
}

void nfc_hci_cmd_received(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
@@ -833,7 +833,7 @@ static int hci_se_io(struct nfc_dev *nfc_dev, u32 se_idx,

static void nfc_hci_failure(struct nfc_hci_dev *hdev, int err)
{
- mutex_lock(&hdev->msg_tx_mutex);
+ spin_lock(&hdev->msg_tx_spin);

if (hdev->cmd_pending_msg == NULL) {
nfc_driver_failure(hdev->ndev, err);
@@ -843,7 +843,7 @@ static void nfc_hci_failure(struct nfc_hci_dev *hdev, int err)
__nfc_hci_cmd_completion(hdev, err, NULL);

exit:
- mutex_unlock(&hdev->msg_tx_mutex);
+ spin_unlock(&hdev->msg_tx_spin);
}

static void nfc_hci_llc_failure(struct nfc_hci_dev *hdev, int err)
@@ -1009,7 +1009,7 @@ EXPORT_SYMBOL(nfc_hci_free_device);

int nfc_hci_register_device(struct nfc_hci_dev *hdev)
{
- mutex_init(&hdev->msg_tx_mutex);
+ spin_lock_init(&hdev->msg_tx_spin);

INIT_LIST_HEAD(&hdev->msg_tx_queue);

@@ -1031,7 +1031,7 @@ void nfc_hci_unregister_device(struct nfc_hci_dev *hdev)
{
struct hci_msg *msg, *n;

- mutex_lock(&hdev->msg_tx_mutex);
+ spin_lock(&hdev->msg_tx_spin);

if (hdev->cmd_pending_msg) {
if (hdev->cmd_pending_msg->cb)
@@ -1044,7 +1044,7 @@ void nfc_hci_unregister_device(struct nfc_hci_dev *hdev)

hdev->shutting_down = true;

- mutex_unlock(&hdev->msg_tx_mutex);
+ spin_unlock(&hdev->msg_tx_spin);

del_timer_sync(&hdev->cmd_timer);
cancel_work_sync(&hdev->msg_tx_work);
diff --git a/net/nfc/hci/hcp.c b/net/nfc/hci/hcp.c
index 05c60988f59..f7eccb4ce35 100644
--- a/net/nfc/hci/hcp.c
+++ b/net/nfc/hci/hcp.c
@@ -30,7 +30,7 @@ int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe,
int hci_len, err;
bool firstfrag = true;

- cmd = kzalloc(sizeof(struct hci_msg), GFP_KERNEL);
+ cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
if (cmd == NULL)
return -ENOMEM;

@@ -58,7 +58,7 @@ int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe,
data_link_len + ndev->tx_tailroom;
hci_len -= data_link_len;

- skb = alloc_skb(skb_len, GFP_KERNEL);
+ skb = alloc_skb(skb_len, GFP_ATOMIC);
if (skb == NULL) {
err = -ENOMEM;
goto out_skb_err;
@@ -90,16 +90,16 @@ int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe,
skb_queue_tail(&cmd->msg_frags, skb);
}

- mutex_lock(&hdev->msg_tx_mutex);
+ spin_lock(&hdev->msg_tx_spin);

if (hdev->shutting_down) {
err = -ESHUTDOWN;
- mutex_unlock(&hdev->msg_tx_mutex);
+ spin_unlock(&hdev->msg_tx_spin);
goto out_skb_err;
}

list_add_tail(&cmd->msg_l, &hdev->msg_tx_queue);
- mutex_unlock(&hdev->msg_tx_mutex);
+ spin_unlock(&hdev->msg_tx_spin);

schedule_work(&hdev->msg_tx_work);

--
2.17.1
\
 
 \ /
  Last update: 2022-05-17 12:58    [W:6.308 / U:0.764 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site