Commit a4926abb authored by Ryder Lee's avatar Ryder Lee Committed by Johannes Berg
Browse files

wifi: mac80211: check skb_shared in ieee80211_8023_xmit()



Add a missing skb_shared check into 802.3 path to prevent potential
use-after-free from happening. This also uses skb_share_check()
instead of open-coding in tx path.

Signed-off-by: default avatarRyder Lee <ryder.lee@mediatek.com>
Link: https://lore.kernel.org/r/e7a73aaf7742b17e43421c56625646dfc5c4d2cb.1653571902.git.ryder.lee@mediatek.com


Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 03895c84
Loading
Loading
Loading
Loading
+13 −23
Original line number Diff line number Diff line
@@ -2818,20 +2818,11 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
	/*
	 * If the skb is shared we need to obtain our own copy.
	 */
	if (skb_shared(skb)) {
		struct sk_buff *tmp_skb = skb;

		/* can't happen -- skb is a clone if info_id != 0 */
		WARN_ON(info_id);

		skb = skb_clone(skb, GFP_ATOMIC);
		kfree_skb(tmp_skb);

		if (!skb) {
	skb = skb_share_check(skb, GFP_ATOMIC);
	if (unlikely(!skb)) {
		ret = -ENOMEM;
		goto free;
	}
	}

	hdr.frame_control = fc;
	hdr.duration_id = 0;
@@ -3539,15 +3530,9 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,

	/* after this point (skb is modified) we cannot return false */

	if (skb_shared(skb)) {
		struct sk_buff *tmp_skb = skb;

		skb = skb_clone(skb, GFP_ATOMIC);
		kfree_skb(tmp_skb);

		if (!skb)
	skb = skb_share_check(skb, GFP_ATOMIC);
	if (unlikely(!skb))
		return true;
	}

	if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) &&
	    ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb))
@@ -4437,7 +4422,7 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
				struct net_device *dev, struct sta_info *sta,
				struct ieee80211_key *key, struct sk_buff *skb)
{
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
	struct ieee80211_tx_info *info;
	struct ieee80211_local *local = sdata->local;
	struct tid_ampdu_tx *tid_tx;
	u8 tid;
@@ -4452,6 +4437,11 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
	    test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
		goto out_free;

	skb = skb_share_check(skb, GFP_ATOMIC);
	if (unlikely(!skb))
		return;

	info = IEEE80211_SKB_CB(skb);
	memset(info, 0, sizeof(*info));

	ieee80211_aggr_check(sdata, sta, skb);