Commit 1395f8df authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge tag 'mac80211-for-net-2020-11-13' of...

Merge tag 'mac80211-for-net-2020-11-13' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211

Johannes Berg says:

====================
A handful of fixes:
 * a use-after-free fix in rfkill
 * a memory leak fix in the mac80211 TX status path
 * some rate scaling fixes
 * a fix for the often-reported (by syzbot) sleeping
   in atomic issue with mac80211's station removal

* tag 'mac80211-for-net-2020-11-13' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211:
  mac80211: free sta in sta_info_insert_finish() on errors
  mac80211: minstrel: fix tx status processing corner case
  mac80211: minstrel: remove deferred sampling code
  mac80211: fix memory leak on filtered powersave frames
  rfkill: Fix use-after-free in rfkill_resume()
====================

Link: https://lore.kernel.org/r/20201113093421.24025-1-johannes@sipsolutions.net


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 4ee18c17 7bc40aed
Loading
Loading
Loading
Loading
+5 −22
Original line number Diff line number Diff line
@@ -274,7 +274,7 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
	success = !!(info->flags & IEEE80211_TX_STAT_ACK);

	for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
		if (ar[i].idx < 0)
		if (ar[i].idx < 0 || !ar[i].count)
			break;

		ndx = rix_to_ndx(mi, ar[i].idx);
@@ -287,12 +287,6 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
			mi->r[ndx].stats.success += success;
	}

	if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && (i >= 0))
		mi->sample_packets++;

	if (mi->sample_deferred > 0)
		mi->sample_deferred--;

	if (time_after(jiffies, mi->last_stats_update +
				mp->update_interval / (mp->new_avg ? 2 : 1)))
		minstrel_update_stats(mp, mi);
@@ -367,7 +361,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
		return;

	delta = (mi->total_packets * sampling_ratio / 100) -
			(mi->sample_packets + mi->sample_deferred / 2);
			mi->sample_packets;

	/* delta < 0: no sampling required */
	prev_sample = mi->prev_sample;
@@ -376,7 +370,6 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
		return;

	if (mi->total_packets >= 10000) {
		mi->sample_deferred = 0;
		mi->sample_packets = 0;
		mi->total_packets = 0;
	} else if (delta > mi->n_rates * 2) {
@@ -401,19 +394,8 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
	 * rate sampling method should be used.
	 * Respect such rates that are not sampled for 20 interations.
	 */
	if (mrr_capable &&
	    msr->perfect_tx_time > mr->perfect_tx_time &&
	    msr->stats.sample_skipped < 20) {
		/* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark
		 * packets that have the sampling rate deferred to the
		 * second MRR stage. Increase the sample counter only
		 * if the deferred sample rate was actually used.
		 * Use the sample_deferred counter to make sure that
		 * the sampling is not done in large bursts */
		info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
		rate++;
		mi->sample_deferred++;
	} else {
	if (msr->perfect_tx_time < mr->perfect_tx_time ||
	    msr->stats.sample_skipped >= 20) {
		if (!msr->sample_limit)
			return;

@@ -433,6 +415,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,

	rate->idx = mi->r[ndx].rix;
	rate->count = minstrel_get_retry_count(&mi->r[ndx], info);
	info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
}


+0 −1
Original line number Diff line number Diff line
@@ -126,7 +126,6 @@ struct minstrel_sta_info {
	u8 max_prob_rate;
	unsigned int total_packets;
	unsigned int sample_packets;
	int sample_deferred;

	unsigned int sample_row;
	unsigned int sample_column;
+4 −10
Original line number Diff line number Diff line
@@ -705,7 +705,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
 out_drop_sta:
	local->num_sta--;
	synchronize_net();
	__cleanup_single_sta(sta);
	cleanup_single_sta(sta);
 out_err:
	mutex_unlock(&local->sta_mtx);
	kfree(sinfo);
@@ -724,19 +724,13 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)

	err = sta_info_insert_check(sta);
	if (err) {
		sta_info_free(local, sta);
		mutex_unlock(&local->sta_mtx);
		rcu_read_lock();
		goto out_free;
		return err;
	}

	err = sta_info_insert_finish(sta);
	if (err)
		goto out_free;

	return 0;
 out_free:
	sta_info_free(local, sta);
	return err;
	return sta_info_insert_finish(sta);
}

int sta_info_insert(struct sta_info *sta)
+8 −10
Original line number Diff line number Diff line
@@ -49,7 +49,8 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
	int ac;

	if (info->flags & (IEEE80211_TX_CTL_NO_PS_BUFFER |
			   IEEE80211_TX_CTL_AMPDU)) {
			   IEEE80211_TX_CTL_AMPDU |
			   IEEE80211_TX_CTL_HW_80211_ENCAP)) {
		ieee80211_free_txskb(&local->hw, skb);
		return;
	}
@@ -915,15 +916,6 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
			ieee80211_mpsp_trigger_process(
				ieee80211_get_qos_ctl(hdr), sta, true, acked);

		if (!acked && test_sta_flag(sta, WLAN_STA_PS_STA)) {
			/*
			 * The STA is in power save mode, so assume
			 * that this TX packet failed because of that.
			 */
			ieee80211_handle_filtered_frame(local, sta, skb);
			return;
		}

		if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL) &&
		    (ieee80211_is_data(hdr->frame_control)) &&
		    (rates_idx != -1))
@@ -1150,6 +1142,12 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw,
							    -info->status.ack_signal);
				}
			} else if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
				/*
				 * The STA is in power save mode, so assume
				 * that this TX packet failed because of that.
				 */
				if (skb)
					ieee80211_handle_filtered_frame(local, sta, skb);
				return;
			} else if (noack_success) {
				/* nothing to do here, do not account as lost */
+3 −0
Original line number Diff line number Diff line
@@ -876,6 +876,9 @@ static int rfkill_resume(struct device *dev)

	rfkill->suspended = false;

	if (!rfkill->registered)
		return 0;

	if (!rfkill->persistent) {
		cur = !!(rfkill->state & RFKILL_BLOCK_SW);
		rfkill_set_block(rfkill, cur);