[PATCH] mac80211_hwsim: fix divide error in mac80211_hwsim_link_info_changed

Deepakkumar Karn posted 1 patch 1 week, 6 days ago
drivers/net/wireless/virtual/mac80211_hwsim.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
[PATCH] mac80211_hwsim: fix divide error in mac80211_hwsim_link_info_changed
Posted by Deepakkumar Karn 1 week, 6 days ago
Prevent a division by zero crash when userspace provides a zero beacon
interval value. The crash occurs in the beacon timer setup code path when
info->beacon_int is 0, causing bcn_int to be 0 and triggering a divide
error in the do_div() macro.The issue can be triggered from userspace via
nl80211/cfg80211 when configuring a virtual interface in AP mode with an
invalid beacon interval.

Fixes: e57f8a489c29 ("wifi: mac80211_hwsim: send a beacon per link")
Reported-by: syzbot+5bb5f06f99924ea0cf86@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=5bb5f06f99924ea0cf86
Signed-off-by: Deepakkumar Karn <dkarn@redhat.com>
---
 drivers/net/wireless/virtual/mac80211_hwsim.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c
index 5903d82e1ab1..e67e2c989ea6 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim.c
@@ -2595,11 +2595,14 @@ static void mac80211_hwsim_link_info_changed(struct ieee80211_hw *hw,
 			link_data->beacon_int = info->beacon_int * 1024;
 			tsf = mac80211_hwsim_get_tsf(hw, vif);
 			bcn_int = link_data->beacon_int;
-			until_tbtt = bcn_int - do_div(tsf, bcn_int);
+			/* Proceed only when bcn_int != 0 */
+			if (bcn_int) {
+				until_tbtt = bcn_int - do_div(tsf, bcn_int);
 
-			hrtimer_start(&link_data->beacon_timer,
-				      ns_to_ktime(until_tbtt * NSEC_PER_USEC),
-				      HRTIMER_MODE_REL_SOFT);
+				hrtimer_start(&link_data->beacon_timer,
+					      ns_to_ktime(until_tbtt * NSEC_PER_USEC),
+					      HRTIMER_MODE_REL_SOFT);
+			}
 		} else if (!info->enable_beacon) {
 			unsigned int count = 0;
 			ieee80211_iterate_active_interfaces_atomic(
-- 
2.51.1
Re: [PATCH] mac80211_hwsim: fix divide error in mac80211_hwsim_link_info_changed
Posted by Johannes Berg 1 week, 6 days ago
On Fri, 2025-12-05 at 21:05 +0530, Deepakkumar Karn wrote:
> Prevent a division by zero crash when userspace provides a zero beacon
> interval value. The crash occurs in the beacon timer setup code path when
> info->beacon_int is 0, causing bcn_int to be 0 and triggering a divide
> error in the do_div() macro.The issue can be triggered from userspace via
> nl80211/cfg80211 when configuring a virtual interface in AP mode with an
> invalid beacon interval.

Seems like we should not let userspace do that, to protect all other
drivers too, not just hwsim.

johannes
Re: [PATCH] mac80211_hwsim: fix divide error in mac80211_hwsim_link_info_changed
Posted by Deepakkumar Karn 1 week, 6 days ago
On Fri, 05 Dec 2025 18:39:49 +0100, Johannes Berg wrote:
> Seems like we should not let userspace do that, to protect all other
> drivers too, not just hwsim.
 
As suggested, we should provide a zero-value division check for other 
drivers as well. I will investigate other places where divide errors can 
occur due to edge cases.

Please let me know if you meant something different. In the meantime,
I will analyze other drivers for similar cases.

Thanks,
Deepakkumar Karn
Re: [PATCH] mac80211_hwsim: fix divide error in mac80211_hwsim_link_info_changed
Posted by Johannes Berg 1 week, 5 days ago
On Sat, 2025-12-06 at 04:33 +0530, Deepakkumar Karn wrote:
> On Fri, 05 Dec 2025 18:39:49 +0100, Johannes Berg wrote:
> > Seems like we should not let userspace do that, to protect all other
> > drivers too, not just hwsim.
>  
> As suggested, we should provide a zero-value division check for other 
> drivers as well. I will investigate other places where divide errors can 
> occur due to edge cases.

What, no no.

> Please let me know if you meant something different. In the meantime,
> I will analyze other drivers for similar cases.

I did. My point is we shouldn't _have_ to check any drivers for this at
all, it's nonsense and higher layers (here cfg80211) should reject it.

johannes
Re: [PATCH] mac80211_hwsim: fix divide error in mac80211_hwsim_link_info_changed
Posted by Deepakkumar Karn 1 week, 5 days ago
> On Sat, 2025-12-06 at 04:33 +0530, Deepakkumar Karn wrote:
> > On Fri, 05 Dec 2025 18:39:49 +0100, Johannes Berg wrote:
> > > Seems like we should not let userspace do that, to protect all other
> > > drivers too, not just hwsim.
> >  
> > As suggested, we should provide a zero-value division check for other 
> > drivers as well. I will investigate other places where divide errors can 
> > occur due to edge cases.

> What, no no.

> > Please let me know if you meant something different. In the meantime,
> > I will analyze other drivers for similar cases.

> I did. My point is we shouldn't _have_ to check any drivers for this at
> all, it's nonsense and higher layers (here cfg80211) should reject it.

Thank you for your response Johannes. cfg80211 already have validation 
in cfg80211_validate_beacon_int(). The problem seems to occur in 
case of interface shutdown which calls ieee80211_do_stop() that makes 
beacon_int = 0 or set_tsf which causes divides by zero.

What if we:
1. Handle off-channel operation:

diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index ae82533e3c02..14a103d320e3 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -156,10 +156,12 @@ void ieee80211_offchannel_return(struct ieee80211_local *local)
 
                if (test_and_clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED,
                                       &sdata->state)) {
-                       sdata->vif.bss_conf.enable_beacon = true;
-                       ieee80211_link_info_change_notify(
-                               sdata, &sdata->deflink,
-                               BSS_CHANGED_BEACON_ENABLED);
+                       if (sdata->vif.bss_conf.beacon_int) {
+                               sdata->vif.bss_conf.enable_beacon = true;
+                               ieee80211_link_info_change_notify(
+                                       sdata, &sdata->deflink,
+                                       BSS_CHANGED_BEACON_ENABLED);
+                       }
                }
        }

2. Handle case where debugfs is written after shutdown or any race condition during disable beaconing:

diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c
index 551f5eb4e747..8363cdd17a97 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim.c
@@ -1242,7 +1242,7 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw,
        struct ieee80211_bss_conf *conf;
 
        conf = link_conf_dereference_protected(vif, data->link_data[0].link_id);
-       if (conf && !conf->enable_beacon)
+       if ((conf && !conf->enable_beacon) || !bcn_int)
                return;
 
        /* adjust after beaconing with new timestamp at old TBTT */

3. As other drivers already have beacon_int 0 value validation, consider 
   earlier patch along with above 2 points?
Re: [PATCH] mac80211_hwsim: fix divide error in mac80211_hwsim_link_info_changed
Posted by Johannes Berg 1 week, 4 days ago
On Sat, 2025-12-06 at 23:03 +0530, Deepakkumar Karn wrote:
> 
> 
> Thank you for your response Johannes. cfg80211 already have validation 
> in cfg80211_validate_beacon_int().

Oh OK.

> The problem seems to occur in 
> case of interface shutdown which calls ieee80211_do_stop() that makes 
> beacon_int = 0 or set_tsf which causes divides by zero.

Why would that call set_tsf()?

And yeah that should make beacon_int=0, but not have beaconing enabled.

> What if we:
> 1. Handle off-channel operation:

>                 if (test_and_clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED,
>                                        &sdata->state)) {
> -                       sdata->vif.bss_conf.enable_beacon = true;
> -                       ieee80211_link_info_change_notify(
> -                               sdata, &sdata->deflink,
> -                               BSS_CHANGED_BEACON_ENABLED);
> +                       if (sdata->vif.bss_conf.beacon_int) {
> +                               sdata->vif.bss_conf.enable_beacon = true;
> +                               ieee80211_link_info_change_notify(
> +                                       sdata, &sdata->deflink,
> +                                       BSS_CHANGED_BEACON_ENABLED);
> +                       }

don't follow, that only does it when beacon was actually stopped ...
maybe do_stop() needs to clear that bit if there's a possibility of this
happening in the wrong order, but I don't see how there could be a race
since off-channel must also be stopped at that point anyway, unless that
is in the wrong order.

> 2. Handle case where debugfs is written after shutdown or any race condition during disable beaconing:
> 
> diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c
> index 551f5eb4e747..8363cdd17a97 100644
> --- a/drivers/net/wireless/virtual/mac80211_hwsim.c

first of all, I really do think you should *not* (need to) modify hwsim
at all

>         conf = link_conf_dereference_protected(vif, data->link_data[0].link_id);
> -       if (conf && !conf->enable_beacon)
> +       if ((conf && !conf->enable_beacon) || !bcn_int)
>                 return;

But this also makes no sense, it shouldn't be possible to have beacon
enabled and beacon interval == 0.

johannes
Re: [PATCH] mac80211_hwsim: fix divide error in mac80211_hwsim_link_info_changed
Posted by Deepak Karn 1 week, 1 day ago
On Mon, Dec 8, 2025 at 2:00 PM Johannes Berg <johannes@sipsolutions.net> wrote:
>
> On Sat, 2025-12-06 at 23:03 +0530, Deepakkumar Karn wrote:
> >
> >
> > Thank you for your response Johannes. cfg80211 already have validation
> > in cfg80211_validate_beacon_int().
>
> Oh OK.
>
> > The problem seems to occur in
> > case of interface shutdown which calls ieee80211_do_stop() that makes
> > beacon_int = 0 or set_tsf which causes divides by zero.
>
> Why would that call set_tsf()?
>
> And yeah that should make beacon_int=0, but not have beaconing enabled.
>
> > What if we:
> > 1. Handle off-channel operation:
>
> >                 if (test_and_clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED,
> >                                        &sdata->state)) {
> > -                       sdata->vif.bss_conf.enable_beacon = true;
> > -                       ieee80211_link_info_change_notify(
> > -                               sdata, &sdata->deflink,
> > -                               BSS_CHANGED_BEACON_ENABLED);
> > +                       if (sdata->vif.bss_conf.beacon_int) {
> > +                               sdata->vif.bss_conf.enable_beacon = true;
> > +                               ieee80211_link_info_change_notify(
> > +                                       sdata, &sdata->deflink,
> > +                                       BSS_CHANGED_BEACON_ENABLED);
> > +                       }
>
> don't follow, that only does it when beacon was actually stopped ...
> maybe do_stop() needs to clear that bit if there's a possibility of this
> happening in the wrong order, but I don't see how there could be a race
> since off-channel must also be stopped at that point anyway, unless that
> is in the wrong order.
>
> > 2. Handle case where debugfs is written after shutdown or any race condition during disable beaconing:
> >
> > diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c
> > index 551f5eb4e747..8363cdd17a97 100644
> > --- a/drivers/net/wireless/virtual/mac80211_hwsim.c
>
> first of all, I really do think you should *not* (need to) modify hwsim
> at all
>
> >         conf = link_conf_dereference_protected(vif, data->link_data[0].link_id);
> > -       if (conf && !conf->enable_beacon)
> > +       if ((conf && !conf->enable_beacon) || !bcn_int)
> >                 return;
>
> But this also makes no sense, it shouldn't be possible to have beacon
> enabled and beacon interval == 0.
>

Thank you Johannes. As you highlighted I searched for a code path if
there is any place that has the
invariant condition of beacon being enabled and beacon int is 0 but
none seems to be having that.

Regards,
Deepakkumar Karn