2022-10-25 12:29:11

by shaozhengchao

[permalink] [raw]
Subject: [PATCH] wifi: mac80211: fix general-protection-fault in ieee80211_subif_start_xmit()

When device is running and the interface status is changed, the gpf issue
is triggered. The problem triggering process is as follows:
Thread A: Thread B
ieee80211_runtime_change_iftype() process_one_work()
... ...
ieee80211_do_stop() ...
... ...
sdata->bss = NULL ...
... ieee80211_subif_start_xmit()
ieee80211_multicast_to_unicast
//!sdata->bss->multicast_to_unicast
cause gpf issue

When the interface status is changed, the sending queue continues to send
packets. After the bss is set to NULL, the bss is accessed. As a result,
this causes a general-protection-fault issue.

The following is the stack information:
general protection fault, probably for non-canonical address
0xdffffc000000002f: 0000 [#1] PREEMPT SMP KASAN
KASAN: null-ptr-deref in range [0x0000000000000178-0x000000000000017f]
Workqueue: mld mld_ifc_work
RIP: 0010:ieee80211_subif_start_xmit+0x25b/0x1310
Call Trace:
<TASK>
dev_hard_start_xmit+0x1be/0x990
__dev_queue_xmit+0x2c9a/0x3b60
ip6_finish_output2+0xf92/0x1520
ip6_finish_output+0x6af/0x11e0
ip6_output+0x1ed/0x540
mld_sendpack+0xa09/0xe70
mld_ifc_work+0x71c/0xdb0
process_one_work+0x9bf/0x1710
worker_thread+0x665/0x1080
kthread+0x2e4/0x3a0
ret_from_fork+0x1f/0x30
</TASK>

Fixes: 107395f9cf44 ("wifi: mac80211: Drop support for TX push path")
Reported-by: [email protected]
Signed-off-by: Zhengchao Shao <[email protected]>
---
net/mac80211/iface.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index dd9ac1f7d2ea..5a924459bfd1 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1900,6 +1900,9 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
IEEE80211_QUEUE_STOP_REASON_IFTYPE_CHANGE);
synchronize_net();

+ if (sdata->dev)
+ netif_tx_stop_all_queues(sdata->dev);
+
ieee80211_do_stop(sdata, false);

ieee80211_teardown_sdata(sdata);
@@ -1922,6 +1925,9 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
err = ieee80211_do_open(&sdata->wdev, false);
WARN(err, "type change: do_open returned %d", err);

+ if (sdata->dev)
+ netif_tx_start_all_queues(sdata->dev);
+
ieee80211_wake_vif_queues(local, sdata,
IEEE80211_QUEUE_STOP_REASON_IFTYPE_CHANGE);
return ret;
--
2.17.1



2022-10-25 14:44:31

by Alexander Wetzel

[permalink] [raw]
Subject: Re: [PATCH] wifi: mac80211: fix general-protection-fault in ieee80211_subif_start_xmit()

On 25.10.22 14:32, Zhengchao Shao wrote:
> When device is running and the interface status is changed, the gpf issue
> is triggered. The problem triggering process is as follows:
> Thread A: Thread B
> ieee80211_runtime_change_iftype() process_one_work()
> ... ...
> ieee80211_do_stop() ...
> ... ...
> sdata->bss = NULL ...
> ... ieee80211_subif_start_xmit()
> ieee80211_multicast_to_unicast
> //!sdata->bss->multicast_to_unicast
> cause gpf issue
>
> When the interface status is changed, the sending queue continues to send
> packets. After the bss is set to NULL, the bss is accessed. As a result,
> this causes a general-protection-fault issue.
>
> The following is the stack information:
> general protection fault, probably for non-canonical address
> 0xdffffc000000002f: 0000 [#1] PREEMPT SMP KASAN
> KASAN: null-ptr-deref in range [0x0000000000000178-0x000000000000017f]
> Workqueue: mld mld_ifc_work
> RIP: 0010:ieee80211_subif_start_xmit+0x25b/0x1310
> Call Trace:
> <TASK>
> dev_hard_start_xmit+0x1be/0x990
> __dev_queue_xmit+0x2c9a/0x3b60
> ip6_finish_output2+0xf92/0x1520
> ip6_finish_output+0x6af/0x11e0
> ip6_output+0x1ed/0x540
> mld_sendpack+0xa09/0xe70
> mld_ifc_work+0x71c/0xdb0
> process_one_work+0x9bf/0x1710
> worker_thread+0x665/0x1080
> kthread+0x2e4/0x3a0
> ret_from_fork+0x1f/0x30
> </TASK>
>
> Fixes: 107395f9cf44 ("wifi: mac80211: Drop support for TX push path")

Don't think this patch fixes an issue introduced with the patch you
refer to. This patch changed nothing from a flow perspective and is just
cleaning up unused code.
It still may still make sense to refer to the series: It next to be sure
triggered the issue for at least one driver (I assume it was hwsim here.)

That said this seems to be more related to whatever caused this bug:
f856373e2f31 ("wifi: mac80211: do not wake queues on a vif that is being
stopped")


> Reported-by: [email protected]
> Signed-off-by: Zhengchao Shao <[email protected]>
> ---
> net/mac80211/iface.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
> index dd9ac1f7d2ea..5a924459bfd1 100644
> --- a/net/mac80211/iface.c
> +++ b/net/mac80211/iface.c
> @@ -1900,6 +1900,9 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
> IEEE80211_QUEUE_STOP_REASON_IFTYPE_CHANGE);
> synchronize_net();
>
> + if (sdata->dev)
> + netif_tx_stop_all_queues(sdata->dev);

All mac80211 interfaces are now non-queuing interfaces.
When you stop the netif queues for a non-queuing interface netdev will
warn about that.

To avoid that you have to replace the netif call with
clear_bit(SDATA_STATE_RUNNING, &sdata->state);

Should just work the same for you here.
> +
> ieee80211_do_stop(sdata, false);
>
> ieee80211_teardown_sdata(sdata);
> @@ -1922,6 +1925,9 @@ static int ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
> err = ieee80211_do_open(&sdata->wdev, false);
> WARN(err, "type change: do_open returned %d", err);
>
> + if (sdata->dev)
> + netif_tx_start_all_queues(sdata->dev);

That must then be of course
set_bit(SDATA_STATE_RUNNING, &sdata->state);


> +
> ieee80211_wake_vif_queues(local, sdata,
> IEEE80211_QUEUE_STOP_REASON_IFTYPE_CHANGE);
> return ret;

Alexander

2022-10-26 01:01:38

by shaozhengchao

[permalink] [raw]
Subject: Re: [PATCH] wifi: mac80211: fix general-protection-fault in ieee80211_subif_start_xmit()



On 2022/10/25 22:42, Alexander Wetzel wrote:
> On 25.10.22 14:32, Zhengchao Shao wrote:
>> When device is running and the interface status is changed, the gpf issue
>> is triggered. The problem triggering process is as follows:
>> Thread A:                           Thread B
>> ieee80211_runtime_change_iftype()   process_one_work()
>>      ...                                 ...
>>      ieee80211_do_stop()                 ...
>>      ...                                 ...
>>          sdata->bss = NULL               ...
>>          ...                             ieee80211_subif_start_xmit()
>>
>> ieee80211_multicast_to_unicast
>>                                      //!sdata->bss->multicast_to_unicast
>>                                        cause gpf issue
>>
>> When the interface status is changed, the sending queue continues to send
>> packets. After the bss is set to NULL, the bss is accessed. As a result,
>> this causes a general-protection-fault issue.
>>
>> The following is the stack information:
>> general protection fault, probably for non-canonical address
>> 0xdffffc000000002f: 0000 [#1] PREEMPT SMP KASAN
>> KASAN: null-ptr-deref in range [0x0000000000000178-0x000000000000017f]
>> Workqueue: mld mld_ifc_work
>> RIP: 0010:ieee80211_subif_start_xmit+0x25b/0x1310
>> Call Trace:
>> <TASK>
>> dev_hard_start_xmit+0x1be/0x990
>> __dev_queue_xmit+0x2c9a/0x3b60
>> ip6_finish_output2+0xf92/0x1520
>> ip6_finish_output+0x6af/0x11e0
>> ip6_output+0x1ed/0x540
>> mld_sendpack+0xa09/0xe70
>> mld_ifc_work+0x71c/0xdb0
>> process_one_work+0x9bf/0x1710
>> worker_thread+0x665/0x1080
>> kthread+0x2e4/0x3a0
>> ret_from_fork+0x1f/0x30
>> </TASK>
>>
>> Fixes: 107395f9cf44 ("wifi: mac80211: Drop support for TX push path")
>
> Don't think this patch fixes an issue introduced with the patch you
> refer to. This patch changed nothing from a flow perspective and is just
> cleaning up unused code.
> It still may still make sense to refer to the series: It next to be sure
> triggered the issue for at least one driver (I assume it was hwsim here.)
>
> That said this seems to be more related to whatever caused this bug:
> f856373e2f31 ("wifi: mac80211: do not wake queues on a vif that is being
> stopped")
>
>
>> Reported-by: [email protected]
>> Signed-off-by: Zhengchao Shao <[email protected]>
>> ---
>>   net/mac80211/iface.c | 6 ++++++
>>   1 file changed, 6 insertions(+)
>>
>> diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
>> index dd9ac1f7d2ea..5a924459bfd1 100644
>> --- a/net/mac80211/iface.c
>> +++ b/net/mac80211/iface.c
>> @@ -1900,6 +1900,9 @@ static int
>> ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
>>                     IEEE80211_QUEUE_STOP_REASON_IFTYPE_CHANGE);
>>       synchronize_net();
>> +    if (sdata->dev)
>> +        netif_tx_stop_all_queues(sdata->dev);
>
> All mac80211 interfaces are now non-queuing interfaces.
> When you stop the netif queues for a non-queuing interface netdev will
> warn about that.
>
> To avoid that you have to replace the netif call with
>     clear_bit(SDATA_STATE_RUNNING, &sdata->state);
>
> Should just work the same for you here.
>> +
>>       ieee80211_do_stop(sdata, false);
>>       ieee80211_teardown_sdata(sdata);
>> @@ -1922,6 +1925,9 @@ static int
>> ieee80211_runtime_change_iftype(struct ieee80211_sub_if_data *sdata,
>>       err = ieee80211_do_open(&sdata->wdev, false);
>>       WARN(err, "type change: do_open returned %d", err);
>> +    if (sdata->dev)
>> +        netif_tx_start_all_queues(sdata->dev);
>
> That must then be of course
>     set_bit(SDATA_STATE_RUNNING, &sdata->state);
>
>
>> +
>>       ieee80211_wake_vif_queues(local, sdata,
>>                     IEEE80211_QUEUE_STOP_REASON_IFTYPE_CHANGE);
>>       return ret;
>
> Alexander
Hi Alexander:
Thank you for your review. I will fix them in V2.

Zhengchao Shao