staging: rtl8723bs: fix several memory-safety bugs
cover staging: rtl8723bs: fix several memory-safety bugs
From: Yi Cong <[email protected]>
This small series fixes four memory-safety / resource-management bugs in the rtl8723bs SDIO staging driver.
All four are tagged:
1/4 - kfree() used on a vzalloc() allocation (HalData) in the probe
error path.
2/4 - double free / UAF when register_netdev() fails: the error label
frees objects that the caller also frees.
3/4 - NULL deref in c2h_wk_callback() when the re-read allocation under
memory pressure fails.
4/4 - NULL deref on a bcmc station lookup in the 802.11 defrag path,
reachable from a fragment with an unknown transmitter address.
Yi Cong (4):
staging: rtl8723bs: free HalData with vfree, not kfree
staging: rtl8723bs: fix double free when register_netdev() fails
staging: rtl8723bs: fix NULL deref in c2h_wk_callback() on alloc
failure
staging: rtl8723bs: fix NULL deref on bcmc station lookup in defrag
path
drivers/staging/rtl8723bs/core/rtw_cmd.c | 6 ++++++ drivers/staging/rtl8723bs/core/rtw_recv.c | 5 ++++- drivers/staging/rtl8723bs/os_dep/os_intfs.c | 10 ++++++---- drivers/staging/rtl8723bs/os_dep/sdio_intf.c | 2 +- 4 files changed, 17 insertions(+), 6 deletions(-)
Signature · 1 line
2.25.1
PATCH 1/4 staging: rtl8723bs: free HalData with vfree, not kfree
From: Yi Cong <[email protected]>
In the probe error path of rtw_sdio_if1_init(), HalData is released with kfree(), but it is allocated with vzalloc() in rtw_hal_data_init(). Freeing a vmalloc allocation with kfree() is undefined behaviour and can corrupt the allocator.
Use rtw_hal_data_deinit() instead, which calls vfree() and is the matching deallocator used on the normal tear-down path. It also NULLs the pointer and clears hal_data_sz, making it safe to call here.
--- drivers/staging/rtl8723bs/os_dep/sdio_intf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/staging/rtl8723bs/os_dep/sdio_intf.c +1 -1
@@ -286,7 +286,7 @@ static struct adapter *rtw_sdio_if1_init(struct dvobj_priv *dvobj, const struct free_hal_data:if (status != _SUCCESS && padapter->HalData) -kfree (padapter->HalData); +rtw_hal_data_deinit (padapter);if (status != _SUCCESS) {rtw_wdev_unregister (padapter->rtw_wdev);
Signature · 1 line
2.25.1
PATCH 2/4 staging: rtl8723bs: fix double free when register_netdev() fails
In reply to Yi CongFrom: Yi Cong <[email protected]>
When register_netdev() fails, the error_register_netdev label in _rtw_drv_register_netdev() frees the adapter and netdev via rtw_free_drv_sw()/rtw_free_netdev() and then returns _FAIL.
The caller rtw_drv_init(), however, still holds a non-NULL if1 on this failure path and jumps to free_if1, where rtw_sdio_if1_deinit() invokes rtw_free_drv_sw() and rtw_free_netdev() again on the same already-freed objects, resulting in a double free / use-after-free.
Drop the freeing from error_register_netdev and let rtw_sdio_if1_deinit() perform the tear-down, which is the single owner for this path.
--- drivers/staging/rtl8723bs/os_dep/os_intfs.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/staging/rtl8723bs/os_dep/os_intfs.c +6 -4
@@ -773,10 +773,12 @@ static int _rtw_drv_register_netdev(struct adapter *padapter, char *name) error_register_netdev: -rtw_free_drv_sw (padapter); - -rtw_free_netdev (pnetdev); - +/* Let the caller (rtw_drv_init -> rtw_sdio_if1_deinit) release the +* adapter and netdev. Freeing them here would lead to a double free: +* rtw_drv_init() still holds a non-NULL if1 and calls +* rtw_sdio_if1_deinit(), which invokes rtw_free_drv_sw() and +* rtw_free_netdev() again on the already-freed objects. +*/ return ret; }
Signature · 1 line
2.25.1
Re: [PATCH 2/4] staging: rtl8723bs: fix double free when register_netdev() fails
Quoted 28 lines · Yi Cong
From: Yi Cong <[email protected]>
When
register_netdev()fails, theerror_register_netdevlabel in_rtw_drv_register_netdev()frees the adapter and netdev via rtw_free_drv_sw()/rtw_free_netdev() and then returns_FAIL.The caller
rtw_drv_init(), however, still holds a non-NULL if1 on this failure path and jumps tofree_if1, wherertw_sdio_if1_deinit()invokesrtw_free_drv_sw()andrtw_free_netdev()again on the same already-freed objects, resulting in a double free / use-after-free.Drop the freeing from
error_register_netdevand letrtw_sdio_if1_deinit()perform the tear-down, which is the single owner for this path.Fixes 554c0a3abf21 ("staging: Add rtl8723bs sdio wifi driver")Signed-off-by Yi Cong <[email protected]>--- drivers/staging/rtl8723bs/os_dep/os_intfs.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)drivers/staging/rtl8723bs/os_dep/os_intfs.c +0
-0@@ -773,10 +773,12 @@ static int _rtw_drv_register_netdev(struct adapter *padapter, char *name) error_register_netdev:
drivers/staging/rtl8723bs/os_dep/os_intfs.c static int _rtw_drv_register_netdev(struct adapter *padapter, char *name) · line 781
Quoted 10 lines
drivers/staging/rtl8723bs/os_dep/os_intfs.c +6
-4-rtw_free_drv_sw (padapter); - -rtw_free_netdev (pnetdev); - +/* Let the caller (rtw_drv_init -> rtw_sdio_if1_deinit) release the +* adapter and netdev. Freeing them here would lead to a double free: +* rtw_drv_init() still holds a non-NULL if1 and calls +* rtw_sdio_if1_deinit(), which invokes rtw_free_drv_sw() and +* rtw_free_netdev() again on the already-freed objects. +*/
No need for this comment. These weren't allocated in _rtw_drv_register_netdev() and no one really expects them to be freed here either. AI always adds obvious comments but eventually the kernel will turn into the Terms of Service text which no one can possibly read in a life time.
regards,
dan carpenter
PATCH 3/4 staging: rtl8723bs: fix NULL deref in c2h_wk_callback() on alloc failure
In reply to Yi CongFrom: Yi Cong <[email protected]>
When the SDIO interrupt handler cannot allocate a c2h event buffer (GFP_ATOMIC under memory pressure) it pushes NULL onto c2h_queue as a "needs re-read" marker and wakes c2h_wk. In c2h_wk_callback(), if the re-allocation also fails, c2h_evt stays NULL and execution falls through to rtw_hal_c2h_valid(adapter, c2h_evt), whose underlying macro dereferences c2h_evt->id, causing a NULL pointer dereference panic.
C2H interrupts are produced by firmware/network events at runtime, so this is reachable under memory pressure. Add a continue in the re-allocation failure branch to give up this event instead of dereferencing NULL.
--- drivers/staging/rtl8723bs/core/rtw_cmd.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/staging/rtl8723bs/core/rtw_cmd.c +6 -0
@@ -1716,6 +1716,12 @@ static void c2h_wk_callback(struct work_struct *work)kfree (c2h_evt);continue ; } + }else { +/* Give up this event; re-allocation failed. Falling +* through would dereference the NULL c2h_evt in +* rtw_hal_c2h_valid() below. +*/ +continue ; } }
Signature · 1 line
2.25.1
PATCH 4/4 staging: rtl8723bs: fix NULL deref on bcmc station lookup in defrag path
In reply to Yi CongFrom: Yi Cong <[email protected]>
In recvframe_chk_defrag(), when a fragment's transmitter address is unknown (no associated station) and the frame is not a data frame, the code looks up the broadcast/multicast station with rtw_get_bcmc_stainfo() and immediately dereferences the result to obtain defrag_q, without a NULL check. rtw_get_bcmc_stainfo() (a thin wrapper around rtw_get_stainfo()) can return NULL, for example if the bcmc station has not been or is no longer allocated.
Every other call site of rtw_get_bcmc_stainfo() in the driver checks the return value; this one was missed. A fragment with an unknown transmitter address received from the network (e.g. an injected/rogue management fragment) could thus trigger a NULL pointer dereference panic.
Check the return value and set pdefrag_q = NULL when no bcmc station is available, consistent with the adjacent data-frame branch (the later code already handles pdefrag_q == NULL).
--- drivers/staging/rtl8723bs/core/rtw_recv.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/staging/rtl8723bs/core/rtw_recv.c +4 -1
@@ -1146,7 +1146,10 @@ static union recv_frame *recvframe_chk_defrag(struct adapter *padapter, union reif (type !=WIFI_DATA_TYPE ) { psta =rtw_get_bcmc_stainfo (padapter); - pdefrag_q = &psta->sta_recvpriv.defrag_q; +if (psta) + pdefrag_q = &psta->sta_recvpriv.defrag_q; +else + pdefrag_q =NULL ; }else { pdefrag_q =NULL ; }
Signature · 1 line
2.25.1
Greg KH
maintainerQuoted 26 lines · Yi Cong
From: Yi Cong <[email protected]>
This small series fixes four memory-safety / resource-management bugs in the rtl8723bs SDIO staging driver.
All four are tagged:
Fixes 554c0a3abf21 ("staging: Add rtl8723bs sdio wifi driver")1/4 -
kfree()used on avzalloc()allocation (HalData) in the probe
error path.
2/4 - double free / UAF whenregister_netdev()fails: the error label
frees objects that the caller also frees.
3/4 - NULL deref inc2h_wk_callback()when the re-read allocation under
memory pressure fails.
4/4 - NULL deref on a bcmc station lookup in the 802.11 defrag path,
reachable from a fragment with an unknown transmitter address.Yi Cong (4):
staging: rtl8723bs: free HalData with vfree, not kfree
staging: rtl8723bs: fix double free whenregister_netdev()fails
staging: rtl8723bs: fix NULL deref inc2h_wk_callback()on alloc
failure
staging: rtl8723bs: fix NULL deref on bcmc station lookup in defrag
path
Quoted 5 lines
drivers/staging/rtl8723bs/core/rtw_cmd.c | 6 ++++++ drivers/staging/rtl8723bs/core/rtw_recv.c | 5 ++++- drivers/staging/rtl8723bs/os_dep/os_intfs.c | 10 ++++++---- drivers/staging/rtl8723bs/os_dep/sdio_intf.c | 2 +- 4 files changed, 17 insertions(+), 6 deletions(-)
Did you forget to document the tool you used to find and fix these issues?
thanks,
greg k-h