wifi: mac80211: set up the TX info early to fix failure paths

The previous commit 2c51457d93 ("wifi: mac80211: free ack status
frame on TX header build failure") cleaned up the leak, but still
left the code a bit messy and the failed SKB didn't get reported
to userspace.

Fix this up by initialising skb->cb[] earlier, which allows using
ieee80211_free_txskb() and therefore reports it for the failure
in ieee80211_build_hdr(), and unifies the ieee80211_skb_resize()
failure path with it.

Assisted-by: LLM
Fixes: c3e7724b6b ("mac80211: use ieee80211_free_txskb to fix possible skb leaks")
Link: https://patch.msgid.link/20260908122838.201719-22-johannes@sipsolutions.net
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg 2026-09-08 14:28:21 +02:00
parent ae97fff649
commit 50d3d79dc0

View File

@ -2981,10 +2981,23 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
*/
skb = skb_share_check(skb, GFP_ATOMIC);
if (unlikely(!skb)) {
ret = -ENOMEM;
goto free;
/* skb_share_check() already freed the skb */
if (info_id)
ieee80211_remove_ack_skb(local, info_id);
return ERR_PTR(-ENOMEM);
}
/* set this up so failure paths can clean up ack skb */
info = IEEE80211_SKB_CB(skb);
memset(info, 0, sizeof(*info));
info->flags = info_flags;
if (info_id) {
info->status_data = info_id;
info->status_data_idr = 1;
}
info->band = band;
hdr.frame_control = fc;
hdr.duration_id = 0;
hdr.seq_ctrl = 0;
@ -3023,10 +3036,8 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
head_need += local->tx_headroom;
head_need = max_t(int, 0, head_need);
if (ieee80211_skb_resize(sdata, skb, head_need, ENCRYPT_DATA)) {
ieee80211_free_txskb(&local->hw, skb);
skb = NULL;
ret = -ENOMEM;
goto free;
goto free_txskb;
}
}
@ -3053,16 +3064,6 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
skb_reset_mac_header(skb);
info = IEEE80211_SKB_CB(skb);
memset(info, 0, sizeof(*info));
info->flags = info_flags;
if (info_id) {
info->status_data = info_id;
info->status_data_idr = 1;
}
info->band = band;
if (likely(!cookie)) {
ctrl_flags |= u32_encode_bits(link_id,
IEEE80211_TX_CTRL_MLO_LINK);
@ -3086,16 +3087,17 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
pre_conf_link_id, link_id);
#endif
ret = -EINVAL;
goto free;
goto free_txskb;
}
}
info->control.flags = ctrl_flags;
return skb;
free_txskb:
ieee80211_free_txskb(&local->hw, skb);
return ERR_PTR(ret);
free:
if (info_id)
ieee80211_remove_ack_skb(local, info_id);
kfree_skb(skb);
return ERR_PTR(ret);
}