Merge branch 'nfc-skb-leaks'

Shang XiaoJing says:

====================
nfc: Fix potential memory leak of skb

There are 6 kinds of send functions can be called by nci_send_frame():
	virtual_nci_send(),
	fdp_nci_send(),
	nxp_nci_send(),
	s3fwrn5_nci_send(),
	nfcmrvl_nci_send(),
	st_nci_send();

1. virtual_nci_send() will memleak the skb, and has been fixed before.

2. fdp_nci_send() won't free the skb no matter whether write() succeed.

3-4. nxp_nci_send() and s3fwrn5_nci_send() will only free the skb when
write() failed, however write() will not free the skb by itself for when
succeeds.

5. nfcmrvl_nci_send() will call nfcmrvl_XXX_nci_send(), where some of
them will free the skb, but nfcmrvl_i2c_nci_send() only free the skb
when i2c_master_send() return >=0, and memleak will happen when
i2c_master_send() failed in nfcmrvl_i2c_nci_send().

6. st_nci_send() will queue the skb into other list and finally be
freed.

Fix the potential memory leak of skb.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2022-10-30 21:43:26 +00:00
commit 5715a50244
4 changed files with 27 additions and 7 deletions

View File

@ -249,11 +249,19 @@ static int fdp_nci_close(struct nci_dev *ndev)
static int fdp_nci_send(struct nci_dev *ndev, struct sk_buff *skb) static int fdp_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
{ {
struct fdp_nci_info *info = nci_get_drvdata(ndev); struct fdp_nci_info *info = nci_get_drvdata(ndev);
int ret;
if (atomic_dec_and_test(&info->data_pkt_counter)) if (atomic_dec_and_test(&info->data_pkt_counter))
info->data_pkt_counter_cb(ndev); info->data_pkt_counter_cb(ndev);
return info->phy_ops->write(info->phy, skb); ret = info->phy_ops->write(info->phy, skb);
if (ret < 0) {
kfree_skb(skb);
return ret;
}
consume_skb(skb);
return 0;
} }
static int fdp_nci_request_firmware(struct nci_dev *ndev) static int fdp_nci_request_firmware(struct nci_dev *ndev)

View File

@ -132,10 +132,15 @@ static int nfcmrvl_i2c_nci_send(struct nfcmrvl_private *priv,
ret = -EREMOTEIO; ret = -EREMOTEIO;
} else } else
ret = 0; ret = 0;
kfree_skb(skb);
} }
return ret; if (ret) {
kfree_skb(skb);
return ret;
}
consume_skb(skb);
return 0;
} }
static void nfcmrvl_i2c_nci_update_config(struct nfcmrvl_private *priv, static void nfcmrvl_i2c_nci_update_config(struct nfcmrvl_private *priv,

View File

@ -80,10 +80,13 @@ static int nxp_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
return -EINVAL; return -EINVAL;
r = info->phy_ops->write(info->phy_id, skb); r = info->phy_ops->write(info->phy_id, skb);
if (r < 0) if (r < 0) {
kfree_skb(skb); kfree_skb(skb);
return r;
}
return r; consume_skb(skb);
return 0;
} }
static int nxp_nci_rf_pll_unlocked_ntf(struct nci_dev *ndev, static int nxp_nci_rf_pll_unlocked_ntf(struct nci_dev *ndev,

View File

@ -110,11 +110,15 @@ static int s3fwrn5_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
} }
ret = s3fwrn5_write(info, skb); ret = s3fwrn5_write(info, skb);
if (ret < 0) if (ret < 0) {
kfree_skb(skb); kfree_skb(skb);
mutex_unlock(&info->mutex);
return ret;
}
consume_skb(skb);
mutex_unlock(&info->mutex); mutex_unlock(&info->mutex);
return ret; return 0;
} }
static int s3fwrn5_nci_post_setup(struct nci_dev *ndev) static int s3fwrn5_nci_post_setup(struct nci_dev *ndev)