mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
wifi: mac80211: limit reorder_buf_filtered to avoid UBSAN warning
commitb98c16107cupstream. The commit06470f7468("mac80211: add API to allow filtering frames in BA sessions") added reorder_buf_filtered to mark frames filtered by firmware, and it can only work correctly if hw.max_rx_aggregation_subframes <= 64 since it stores the bitmap in a u64 variable. However, new HE or EHT devices can support BlockAck number up to 256 or 1024, and then using a higher subframe index leads UBSAN warning: UBSAN: shift-out-of-bounds in net/mac80211/rx.c:1129:39 shift exponent 215 is too large for 64-bit type 'long long unsigned int' Call Trace: <IRQ> dump_stack_lvl+0x48/0x70 dump_stack+0x10/0x20 __ubsan_handle_shift_out_of_bounds+0x1ac/0x360 ieee80211_release_reorder_frame.constprop.0.cold+0x64/0x69 [mac80211] ieee80211_sta_reorder_release+0x9c/0x400 [mac80211] ieee80211_prepare_and_rx_handle+0x1234/0x1420 [mac80211] ieee80211_rx_list+0xaef/0xf60 [mac80211] ieee80211_rx_napi+0x53/0xd0 [mac80211] Since only old hardware that supports <=64 BlockAck uses ieee80211_mark_rx_ba_filtered_frames(), limit the use as it is, so add a WARN_ONCE() and comment to note to avoid using this function if hardware capability is not suitable. Signed-off-by: Ping-Ke Shih <pkshih@realtek.com> Link: https://lore.kernel.org/r/20230818014004.16177-1-pkshih@realtek.com [edit commit message] Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
b8b7243aaf
commit
e6a60eccd0
@@ -6444,6 +6444,7 @@ void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap,
|
|||||||
* marks frames marked in the bitmap as having been filtered. Afterwards, it
|
* marks frames marked in the bitmap as having been filtered. Afterwards, it
|
||||||
* checks if any frames in the window starting from @ssn can now be released
|
* checks if any frames in the window starting from @ssn can now be released
|
||||||
* (in case they were only waiting for frames that were filtered.)
|
* (in case they were only waiting for frames that were filtered.)
|
||||||
|
* (Only work correctly if @max_rx_aggregation_subframes <= 64 frames)
|
||||||
*/
|
*/
|
||||||
void ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid,
|
void ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid,
|
||||||
u16 ssn, u64 filtered,
|
u16 ssn, u64 filtered,
|
||||||
|
|||||||
@@ -1102,7 +1102,8 @@ static inline bool ieee80211_rx_reorder_ready(struct tid_ampdu_rx *tid_agg_rx,
|
|||||||
struct sk_buff *tail = skb_peek_tail(frames);
|
struct sk_buff *tail = skb_peek_tail(frames);
|
||||||
struct ieee80211_rx_status *status;
|
struct ieee80211_rx_status *status;
|
||||||
|
|
||||||
if (tid_agg_rx->reorder_buf_filtered & BIT_ULL(index))
|
if (tid_agg_rx->reorder_buf_filtered &&
|
||||||
|
tid_agg_rx->reorder_buf_filtered & BIT_ULL(index))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!tail)
|
if (!tail)
|
||||||
@@ -1143,7 +1144,8 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
|
|||||||
}
|
}
|
||||||
|
|
||||||
no_frame:
|
no_frame:
|
||||||
tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index);
|
if (tid_agg_rx->reorder_buf_filtered)
|
||||||
|
tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index);
|
||||||
tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num);
|
tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4162,6 +4164,7 @@ void ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid,
|
|||||||
u16 ssn, u64 filtered,
|
u16 ssn, u64 filtered,
|
||||||
u16 received_mpdus)
|
u16 received_mpdus)
|
||||||
{
|
{
|
||||||
|
struct ieee80211_local *local;
|
||||||
struct sta_info *sta;
|
struct sta_info *sta;
|
||||||
struct tid_ampdu_rx *tid_agg_rx;
|
struct tid_ampdu_rx *tid_agg_rx;
|
||||||
struct sk_buff_head frames;
|
struct sk_buff_head frames;
|
||||||
@@ -4179,6 +4182,11 @@ void ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid,
|
|||||||
|
|
||||||
sta = container_of(pubsta, struct sta_info, sta);
|
sta = container_of(pubsta, struct sta_info, sta);
|
||||||
|
|
||||||
|
local = sta->sdata->local;
|
||||||
|
WARN_ONCE(local->hw.max_rx_aggregation_subframes > 64,
|
||||||
|
"RX BA marker can't support max_rx_aggregation_subframes %u > 64\n",
|
||||||
|
local->hw.max_rx_aggregation_subframes);
|
||||||
|
|
||||||
if (!ieee80211_rx_data_set_sta(&rx, sta, -1))
|
if (!ieee80211_rx_data_set_sta(&rx, sta, -1))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user