diff mbox series

wifi: nl80211: avoid NULL-ptr deref after cfg80211_cqm_rssi_update

Message ID eb944f1f-8d7c-5057-35f2-34812907e4d1@online.de (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series wifi: nl80211: avoid NULL-ptr deref after cfg80211_cqm_rssi_update | expand

Checks

Context Check Description
netdev/series_format warning Single patches do not need cover letters; Target tree name not specified in the subject
netdev/tree_selection success Guessed tree name to be net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 1330 this patch: 1330
netdev/cc_maintainers warning 1 maintainers not CCed: johannes@sipsolutions.net
netdev/build_clang success Errors and warnings before: 1353 this patch: 1353
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 1353 this patch: 1353
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 8 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Max Schulze Aug. 11, 2023, 7:30 a.m. UTC
In cfg80211_cqm_rssi_notify, when calling cfg80211_cqm_rssi_update, this might free
the wdev->cqm_config . Check for this when it returns.

This has been observed on brcmfmac, when a RSSI event is generated just right
after disconnecting from AP. Then probing for STA details returns nothing, as
evidenced i.e. by
"ieee80211 phy0: brcmf_cfg80211_get_station: GET STA INFO failed, -52".


Signed-off-by: Max Schulze <max.schulze@online.de>
Tested-by: Max Schulze <max.schulze@online.de>
Link: https://lore.kernel.org/linux-wireless/bc3bf8f6-7ad7-bf69-9227-f972dac4e66b@online.de/
---

I have deployed this to 22 systems without issues and eliminating those null-ptr deref.

Example Trace from Problem:

wpa_supplicant[332]: wlan0: CTRL-EVENT-DISCONNECTED bssid=XX:XX:XX:XX:74:1f reason=3 locally_generated=1
brcmfmac: brcmf_rx_event Enter: mmc1:0001:1: rxp=0000000017163222
brcmfmac: brcmf_fweh_event_worker event LINK (16) ifidx 0 bsscfg 0 addr xx:xx:xx:xx:74:1f
brcmfmac: brcmf_fweh_event_worker   version 2 flags 0 status 0 reason 2
brcmutil: event payload, len=0
brcmfmac: brcmf_is_linkdown Processing link down
brcmfmac: brcmf_notify_connect_status Linkdown
brcmfmac: brcmf_rx_event Enter: mmc1:0001:1: rxp=00000000dcf7c0c0
brcmfmac: brcmf_fweh_event_worker event RSSI (56) ifidx 0 bsscfg 0 addr 00:00:xx:xx:00:50
brcmfmac: brcmf_fweh_event_worker   version 2 flags 0 status 0 reason 0
brcmutil: event payload, len=12
00000000: 00 00 00 00 00 00 00 00 00 00 00 00              ............
brcmfmac: brcmf_notify_rssi LOW rssi=0
brcmfmac: brcmf_cfg80211_del_key key index (0)
brcmfmac: brcmf_cfg80211_del_key Ignore clearing of (never configured) key
brcmfmac: brcmf_fil_cmd_data Firmware error: BCME_NOTFOUND (-30)
brcmfmac: brcmf_fil_iovar_data_get ifidx=0, name=tdls_sta_info, len=296, err=-52
brcmfmac: brcmf_fil_cmd_data Firmware error: BCME_BADADDR (-21)
brcmfmac: brcmf_fil_iovar_data_get ifidx=0, name=sta_info, len=296, err=-52
ieee80211 phy0: brcmf_cfg80211_get_station: GET STA INFO failed, -52
==================================================================
BUG: KASAN: null-ptr-deref in cfg80211_cqm_rssi_notify (/home/r/linux/net/wireless/nl80211.c:19089) cfg80211


 net/wireless/nl80211.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Johannes Berg Aug. 11, 2023, 9:54 a.m. UTC | #1
On Fri, 2023-08-11 at 09:30 +0200, Max Schulze wrote:
> In cfg80211_cqm_rssi_notify, when calling cfg80211_cqm_rssi_update, this might free
> the wdev->cqm_config . Check for this when it returns.

That doesn't seem right? How does cfg80211_cqm_rssi_update() free it?

> This has been observed on brcmfmac, when a RSSI event is generated just right
> after disconnecting from AP. Then probing for STA details returns nothing, as
> evidenced i.e. by
> "ieee80211 phy0: brcmf_cfg80211_get_station: GET STA INFO failed, -52".

I think the issue then isn't that this frees it but rather than a free
of it races with the reporting?

> --- a/net/wireless/nl80211.c
> +++ b/net/wireless/nl80211.c
> @@ -19088,7 +19088,7 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
>  
>  		cfg80211_cqm_rssi_update(rdev, dev);
>  
> -		if (rssi_level == 0)
> +		if (rssi_level == 0 && wdev->cqm_config)
>  			rssi_level = wdev->cqm_config->last_rssi_event_value;
> 

But if it's a race, then this isn't actually going to really fix the
issue, rather it just makes it (much) less likely.

Since we can probably neither lock the wdev here nor require calls to
this function with wdev lock held, it looks like we need to protect the
pointer with RCU instead?

johannes
Max Schulze Aug. 12, 2023, 9:35 a.m. UTC | #2
Am 11.08.23 um 11:54 schrieb Johannes Berg:
> On Fri, 2023-08-11 at 09:30 +0200, Max Schulze wrote:
>> In cfg80211_cqm_rssi_notify, when calling cfg80211_cqm_rssi_update, this might free
>> the wdev->cqm_config . Check for this when it returns.
> 
> That doesn't seem right? How does cfg80211_cqm_rssi_update() free it?
> 


You are probably right, that it doesn't. I amended the original bug report where I have a trace of the free and it is not a descendant of _rssi_update().



>> This has been observed on brcmfmac, when a RSSI event is generated just right
>> after disconnecting from AP. Then probing for STA details returns nothing, as
>> evidenced i.e. by
>> "ieee80211 phy0: brcmf_cfg80211_get_station: GET STA INFO failed, -52".
> 
> I think the issue then isn't that this frees it but rather than a free
> of it races with the reporting?


I do not understand what you mean. I think there is a race, yes, somewhere else it get's freed, and when we access it, there is the null-ptr-deref.
The GET STA INFO failed is just the expected answer from the chip, because it currently is not associated with any station.


> 
>> --- a/net/wireless/nl80211.c
>> +++ b/net/wireless/nl80211.c
>> @@ -19088,7 +19088,7 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
>>  
>>  		cfg80211_cqm_rssi_update(rdev, dev);
>>  
>> -		if (rssi_level == 0)
>> +		if (rssi_level == 0 && wdev->cqm_config)
>>  			rssi_level = wdev->cqm_config->last_rssi_event_value;
>>
> 
> But if it's a race, then this isn't actually going to really fix the
> issue, rather it just makes it (much) less likely.
> 

You have been right with your prediction. It made it around ~15x less likely but I have recorded a trace. It just has the null-ptr somewhere else.

> Since we can probably neither lock the wdev here nor require calls to
> this function with wdev lock held, it looks like we need to protect the
> pointer with RCU instead?
> 

I do not know how to do that and need help.

Max

[this is with my patch some lines above, no more crashes in _rssi_notify, but now somewhere else ].

13:15:03: brcmfmac: brcmf_is_linkdown Processing link down
13:15:03: brcmfmac: brcmf_notify_connect_status Linkdown
13:15:03: brcmfmac: brcmf_fweh_event_worker event RSSI (56) ifidx 0 bsscfg 0 addr xx:xx:xx:xx:00:50
13:15:03: brcmfmac: brcmf_fweh_event_worker   version 2 flags 0 status 0 reason 0
13:15:03: brcmutil: event payload, len=12
13:15:03: 00000000: 00 00 00 00 00 00 00 00 00 00 00 00              ............
13:15:03: brcmfmac: brcmf_notify_rssi LOW rssi=0
13:15:03: brcmfmac: brcmf_fil_iovar_data_set ifidx=0, name=rssi_event, len=16
13:15:03: Unable to handle kernel NULL pointer dereference at virtual address 000000000000000c
13:15:03: brcmutil: data
13:15:03: Mem abort info:
13:15:03: 00000000: 00 00 00 00 03 00 00 7f 00 00 00 00 00 00 00 00  ................
13:15:03:   ESR = 0x0000000096000005
13:15:03:   EC = 0x25: DABT (current EL), IL = 32 bits
13:15:03:   SET = 0, FnV = 0
13:15:03:   EA = 0, S1PTW = 0
13:15:03:   FSC = 0x05: level 1 translation fault
13:15:03: Data abort info:
13:15:03:   ISV = 0, ISS = 0x00000005, ISS2 = 0x00000000
13:15:03:   CM = 0, WnR = 0, TnD = 0, TagAccess = 0
13:15:03:   GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
13:15:03: user pgtable: 4k pages, 39-bit VAs, pgdp=00000000456cf000
13:15:03: [000000000000000c] pgd=0000000000000000, p4d=0000000000000000, pud=0000000000000000
13:15:03: Internal error: Oops: 0000000096000005 [#1] PREEMPT SMP
13:15:03: Modules linked in: brcmfmac_wcc vc4 brcmfmac snd_soc_hdmi_codec snd_soc_core snd_pcm_dmaengine snd_pcm cfg80211 rpivid_hevc(C) bcm2835_isp(C) snd_timer bcm2835_mmal_vchiq(C) snd videobuf2_dma_contig videobuf2_memops v4l2_mem2mem xt_tcpudp rtc_pcf85063 nft_compat regmap_i2c nf_tables videobuf2_v4l2 v3d videodev drm_display_helper drm_shmem_helper nfnetlink drm_dma_helper gpu_sched i2c_mux_pinctrl i2c_mux gpio_keys drm_kms_helper raspberrypi_hwmon rfkill hid_microsoft joydev i2c_brcmstb ff_memless brcmutil i2c_bcm2835 videobuf2_common vc_sm_cma(C) mc cec nvmem_rmem uio_pdrv_genirq uio drm fuse drm_panel_orientation_quirks backlight ip_tables x_tables ipv6
13:15:04: CPU: 1 PID: 57 Comm: kworker/1:2 Tainted: G         C         6.5.0-rc5-v8-g963e8f68ce3b #4
13:15:04: Hardware name: Raspberry Pi Compute Module 4 Rev 1.0 (DT)
13:15:04: Workqueue: events brcmf_fweh_event_worker [brcmfmac]
13:15:04: pstate: 80000005 (Nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
13:15:04: pc : cfg80211_cqm_rssi_update (/home/r/linux/net/wireless/nl80211.c:12838) cfg80211
13:15:04: lr : cfg80211_cqm_rssi_notify (/home/r/linux/net/wireless/nl80211.c:19088) cfg80211
13:15:04: sp : ffffffc08060baf0
13:15:04: x29: ffffffc08060baf0 x28: ffffff8052b798f0 x27: ffffff8052b798a0
13:15:04: x26: ffffff8055d4c8c0 x25: ffffff8055d4ca68 x24: ffffff8055d4c3c0
13:15:04: x23: ffffff8044a52008 x22: 0000000000000000 x21: ffffff8055d4c000
13:15:04: x20: ffffff8044a63000 x19: ffffff8044a52008 x18: 00000000fffffffe
13:15:04: x17: 2e2e2e2e2e202020 x16: ffffffddb73c9498 x15: 0000000000000020
13:15:04: x14: 0000000000000000 x13: 303d697373722057 x12: 4f4c20697373725f
13:15:04: x11: fffffffffffe39f8 x10: ffffff804018c700 x9 : ffffffdd39d20660
13:15:04: x8 : 000000005108ccd0 x7 : 0000000000000000 x6 : 000000005108ccd0
13:15:04: x5 : 0000000000000000 x4 : 0000000000000000 x3 : 0000000000000000
13:15:04: x2 : 0000000000000000 x1 : 0000000000000000 x0 : 0000000000000004
13:15:04: Call trace:
13:15:04: cfg80211_cqm_rssi_update (/home/r/linux/net/wireless/nl80211.c:12838) cfg80211
13:15:04: cfg80211_cqm_rssi_notify (/home/r/linux/net/wireless/nl80211.c:19088) cfg80211
13:15:04: brcmf_notify_rssi (/home/r/linux/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c:6651) brcmfmac
13:15:04: brcmf_fweh_call_event_handler (/home/r/linux/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c:116) brcmfmac
13:15:04: brcmf_fweh_event_worker (/home/r/linux/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c:268) brcmfmac
13:15:04: process_one_work (/home/r/linux/./arch/arm64/include/asm/jump_label.h:21 /home/r/linux/./include/linux/jump_label.h:207 /home/r/linux/./include/trace/events/workqueue.h:108 /home/r/linux/kernel/workqueue.c:2602) 
13:15:04: worker_thread (/home/r/linux/./include/linux/list.h:292 /home/r/linux/kernel/workqueue.c:2749) 
13:15:04: kthread (/home/r/linux/kernel/kthread.c:389) 
13:15:04: ret_from_fork (/home/r/linux/arch/arm64/kernel/entry.S:854) 
13:15:04: Code: f941b264 0a020062 93407c45 8b22c883 (b9400c63)
All code
========
   0:	f941b264 	ldr	x4, [x19, #864]
   4:	0a020062 	and	w2, w3, w2
   8:	93407c45 	sxtw	x5, w2
   c:	8b22c883 	add	x3, x4, w2, sxtw #2
  10:*	b9400c63 	ldr	w3, [x3, #12]		<-- trapping instruction

Code starting with the faulting instruction
===========================================
   0:	b9400c63 	ldr	w3, [x3, #12]
13:15:04: ---[ end trace 0000000000000000 ]---
13:15:04: brcmfmac: brcmf_fil_iovar_data_get ifidx=0, name=qtxpower, len=4, err=0
13:15:04: brcmutil: data
diff mbox series

Patch

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 8bcf8e293..b12424382 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -19088,7 +19088,7 @@  void cfg80211_cqm_rssi_notify(struct net_device *dev,
 
 		cfg80211_cqm_rssi_update(rdev, dev);
 
-		if (rssi_level == 0)
+		if (rssi_level == 0 && wdev->cqm_config)
 			rssi_level = wdev->cqm_config->last_rssi_event_value;
 	}