The fixed_rate_idx debugfs file is a plain u32 attribute, so any value can be written to it. minstrel_ht_update_stats() then copies the value into mi->max_tp_rate[] and mi->max_prob_rate, and minstrel_ht_set_rate() uses MI_RATE_GROUP()/MI_RATE_IDX() to index minstrel_mcs_groups[] (42 entries) and mi->groups[].rates[] (10 entries) with it. Writing e.g. 65535 selects group 4095 and rate index 15, far outside both arrays. The out-of-bounds entries are dereferenced and updated as struct minstrel_rate_stats (retry counts, etc.), so the invalid index corrupts adjacent kernel memory. With CONFIG_UBSAN_BOUNDS the access is reported as an array-index-out-of-bounds in minstrel_ht_set_rate(). Only a valid group/rate pair, or U32_MAX to disable fixed rate processing, can be used safely, so reject any other value when the debugfs file is written. The file is only reachable through a root-only debugfs mount, so this is not a privilege boundary. The out-of-bounds access is still a bug that must not be reachable through a writable debugfs attribute. Fixes: 24f7580e852b ("minstrel_ht: fixed rate mode through debugfs") Cc: stable@vger.kernel.org Reported-by: Vega Assisted-by: LLM Signed-off-by: Yuqi Xu Reviewed-by: Ren Wei --- net/mac80211/rc80211_minstrel_ht.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index b73ef3adfcc5..c26221287515 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -1947,14 +1948,39 @@ minstrel_ht_alloc(struct ieee80211_hw *hw) } #ifdef CONFIG_MAC80211_DEBUGFS +static int minstrel_ht_fixed_rate_idx_get(void *data, u64 *val) +{ + *val = *(u32 *)data; + return 0; +} + +static int minstrel_ht_fixed_rate_idx_set(void *data, u64 val) +{ + u32 idx = val; + + /* U32_MAX is the default and keeps fixed rate processing disabled */ + if (val != U32_MAX && + (val > U16_MAX || + MI_RATE_GROUP(idx) >= ARRAY_SIZE(minstrel_mcs_groups) || + MI_RATE_IDX(idx) >= MCS_GROUP_RATES)) + return -EINVAL; + + *(u32 *)data = idx; + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(minstrel_ht_fixed_rate_idx_fops, + minstrel_ht_fixed_rate_idx_get, + minstrel_ht_fixed_rate_idx_set, "%llu\n"); + static void minstrel_ht_add_debugfs(struct ieee80211_hw *hw, void *priv, struct dentry *debugfsdir) { struct minstrel_priv *mp = priv; mp->fixed_rate_idx = (u32) -1; - debugfs_create_u32("fixed_rate_idx", S_IRUGO | S_IWUGO, debugfsdir, - &mp->fixed_rate_idx); + debugfs_create_file("fixed_rate_idx", S_IRUGO | S_IWUGO, debugfsdir, + &mp->fixed_rate_idx, &minstrel_ht_fixed_rate_idx_fops); } #endif -- 2.55.0