staging: rtl8723bs: fix several memory-safety bugs
v2 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.
v2:
- Remove some redundant comments in patch 2 and patch 3.
v1:
- https://lore.kernel.org/all/[email protected]/
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 | 3 ++- drivers/staging/rtl8723bs/core/rtw_recv.c | 5 ++++- drivers/staging/rtl8723bs/os_dep/os_intfs.c | 14 ++------------ drivers/staging/rtl8723bs/os_dep/sdio_intf.c | 2 +- 4 files changed, 9 insertions(+), 15 deletions(-)
Signature · 1 line
2.25.1
PATCH v2 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 v2 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 | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-)
drivers/staging/rtl8723bs/os_dep/os_intfs.c +2 -12
@@ -754,7 +754,6 @@ u8 rtw_free_drv_sw(struct adapter *padapter)static int _rtw_drv_register_netdev (struct adapter *padapter,char *name) { -int ret = _SUCCESS;struct net_device *pnetdev = padapter->pnetdev;/* alloc netdev name */
@@ -765,19 +764,10 @@ static int _rtw_drv_register_netdev(struct adapter *padapter, char *name)/* Tell the network stack we exist */ if (register_netdev (pnetdev) !=0 ) { - ret = _FAIL; - goto error_register_netdev; +return _FAIL; } -return ret; - -error_register_netdev: - -rtw_free_drv_sw (padapter); - -rtw_free_netdev (pnetdev); - -return ret; +return _SUCCESS; }int rtw_drv_register_netdev (struct adapter *if1)
Signature · 1 line
2.25.1
Greg KH
maintainerRe: [PATCH v2 2/4] staging: rtl8723bs: fix double free when register_netdev() fails
Quoted 11 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.
Quoted 5 lines
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]>
You forgot to use the proper "Assisted-by:" tags for this series, right?
thanks,
greg k-h
Re: [PATCH v2 2/4] staging: rtl8723bs: fix double free when register_netdev() fails
Quoted 13 lines · Greg KH
Quoted 11 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.
Quoted 8 lines
Quoted 5 lines
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]>You forgot to use the proper "Assisted-by:" tags for this series, right?
Thank you for the reminder.
I have added the "Assisted-by:" tag in Patch v3.
Regards,
Yi Cong
PATCH v2 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 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/staging/rtl8723bs/core/rtw_cmd.c +2 -1
@@ -1716,7 +1716,8 @@ static void c2h_wk_callback(struct work_struct *work)kfree (c2h_evt);continue ; } - } + }else +continue ; }/* Special pointer to trigger c2h_evt_clear only */
Signature · 1 line
2.25.1
PATCH v2 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