diff mbox series

wifi: mac80211: fix general-protection-fault in ieee80211_subif_start_xmit()

Message ID 20221025123250.143952-1-shaozhengchao@huawei.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series wifi: mac80211: fix general-protection-fault in ieee80211_subif_start_xmit() | expand

Checks

Context Check Description
netdev/tree_selection success Guessed tree name to be net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix warning Target tree name not specified in the subject
netdev/cover_letter success Single patches do not need cover letters
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/cc_maintainers success CCed 7 of 7 maintainers
netdev/build_clang success Errors and warnings before: 0 this patch: 0
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes fail Problems with Fixes tag: 1
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/checkpatch warning WARNING: Unknown commit id '107395f9cf44', maybe rebased or not pulled?
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

shaozhengchao Oct. 25, 2022, 12:32 p.m. UTC
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: syzbot+c6e8fca81c294fd5620a@syzkaller.appspotmail.com
Signed-off-by: Zhengchao Shao <shaozhengchao@huawei.com>
---
 net/mac80211/iface.c | 6 ++++++
 1 file changed, 6 insertions(+)

Comments

Alexander Wetzel Oct. 25, 2022, 2:42 p.m. UTC | #1
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: syzbot+c6e8fca81c294fd5620a@syzkaller.appspotmail.com
> Signed-off-by: Zhengchao Shao <shaozhengchao@huawei.com>
> ---
>   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
shaozhengchao Oct. 26, 2022, 12:58 a.m. UTC | #2
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: syzbot+c6e8fca81c294fd5620a@syzkaller.appspotmail.com
>> Signed-off-by: Zhengchao Shao <shaozhengchao@huawei.com>
>> ---
>>   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
diff mbox series

Patch

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;