Skip to content

Commit 6082914

Browse files
mchetankumardavem330
authored andcommitted
net: wwan: iosm: fix NULL pointer dereference when removing device
In suspend and resume cycle, the removal and rescan of device ends up in NULL pointer dereference. During driver initialization, if the ipc_imem_wwan_channel_init() fails to get the valid device capabilities it returns an error and further no resource (wwan struct) will be allocated. Now in this situation if driver removal procedure is initiated it would result in NULL pointer exception since unallocated wwan struct is dereferenced inside ipc_wwan_deinit(). ipc_imem_run_state_worker() to handle the called functions return value and to release the resource in failure case. It also reports the link down event in failure cases. The user space application can handle this event to do a device reset for restoring the device communication. Fixes: 3670970 ("net: iosm: shared memory IPC interface") Reported-by: Samuel Wein PhD <[email protected]> Closes: https://lore.kernel.org/netdev/[email protected]/T/ Signed-off-by: M Chetan Kumar <[email protected]> Reviewed-by: Simon Horman <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent dacab57 commit 6082914

File tree

3 files changed

+33
-12
lines changed

3 files changed

+33
-12
lines changed

drivers/net/wwan/iosm/iosm_ipc_imem.c

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -565,24 +565,32 @@ static void ipc_imem_run_state_worker(struct work_struct *instance)
565565
struct ipc_mux_config mux_cfg;
566566
struct iosm_imem *ipc_imem;
567567
u8 ctrl_chl_idx = 0;
568+
int ret;
568569

569570
ipc_imem = container_of(instance, struct iosm_imem, run_state_worker);
570571

571572
if (ipc_imem->phase != IPC_P_RUN) {
572573
dev_err(ipc_imem->dev,
573574
"Modem link down. Exit run state worker.");
574-
return;
575+
goto err_out;
575576
}
576577

577578
if (test_and_clear_bit(IOSM_DEVLINK_INIT, &ipc_imem->flag))
578579
ipc_devlink_deinit(ipc_imem->ipc_devlink);
579580

580-
if (!ipc_imem_setup_cp_mux_cap_init(ipc_imem, &mux_cfg))
581-
ipc_imem->mux = ipc_mux_init(&mux_cfg, ipc_imem);
581+
ret = ipc_imem_setup_cp_mux_cap_init(ipc_imem, &mux_cfg);
582+
if (ret < 0)
583+
goto err_out;
584+
585+
ipc_imem->mux = ipc_mux_init(&mux_cfg, ipc_imem);
586+
if (!ipc_imem->mux)
587+
goto err_out;
588+
589+
ret = ipc_imem_wwan_channel_init(ipc_imem, mux_cfg.protocol);
590+
if (ret < 0)
591+
goto err_ipc_mux_deinit;
582592

583-
ipc_imem_wwan_channel_init(ipc_imem, mux_cfg.protocol);
584-
if (ipc_imem->mux)
585-
ipc_imem->mux->wwan = ipc_imem->wwan;
593+
ipc_imem->mux->wwan = ipc_imem->wwan;
586594

587595
while (ctrl_chl_idx < IPC_MEM_MAX_CHANNELS) {
588596
if (!ipc_chnl_cfg_get(&chnl_cfg_port, ctrl_chl_idx)) {
@@ -622,6 +630,13 @@ static void ipc_imem_run_state_worker(struct work_struct *instance)
622630

623631
/* Complete all memory stores after setting bit */
624632
smp_mb__after_atomic();
633+
634+
return;
635+
636+
err_ipc_mux_deinit:
637+
ipc_mux_deinit(ipc_imem->mux);
638+
err_out:
639+
ipc_uevent_send(ipc_imem->dev, UEVENT_CD_READY_LINK_DOWN);
625640
}
626641

627642
static void ipc_imem_handle_irq(struct iosm_imem *ipc_imem, int irq)

drivers/net/wwan/iosm/iosm_ipc_imem_ops.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ int ipc_imem_sys_wwan_transmit(struct iosm_imem *ipc_imem,
7777
}
7878

7979
/* Initialize wwan channel */
80-
void ipc_imem_wwan_channel_init(struct iosm_imem *ipc_imem,
81-
enum ipc_mux_protocol mux_type)
80+
int ipc_imem_wwan_channel_init(struct iosm_imem *ipc_imem,
81+
enum ipc_mux_protocol mux_type)
8282
{
8383
struct ipc_chnl_cfg chnl_cfg = { 0 };
8484

@@ -87,7 +87,7 @@ void ipc_imem_wwan_channel_init(struct iosm_imem *ipc_imem,
8787
/* If modem version is invalid (0xffffffff), do not initialize WWAN. */
8888
if (ipc_imem->cp_version == -1) {
8989
dev_err(ipc_imem->dev, "invalid CP version");
90-
return;
90+
return -EIO;
9191
}
9292

9393
ipc_chnl_cfg_get(&chnl_cfg, ipc_imem->nr_of_channels);
@@ -104,9 +104,13 @@ void ipc_imem_wwan_channel_init(struct iosm_imem *ipc_imem,
104104

105105
/* WWAN registration. */
106106
ipc_imem->wwan = ipc_wwan_init(ipc_imem, ipc_imem->dev);
107-
if (!ipc_imem->wwan)
107+
if (!ipc_imem->wwan) {
108108
dev_err(ipc_imem->dev,
109109
"failed to register the ipc_wwan interfaces");
110+
return -ENOMEM;
111+
}
112+
113+
return 0;
110114
}
111115

112116
/* Map SKB to DMA for transfer */

drivers/net/wwan/iosm/iosm_ipc_imem_ops.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,11 @@ int ipc_imem_sys_wwan_transmit(struct iosm_imem *ipc_imem, int if_id,
9191
* MUX.
9292
* @ipc_imem: Pointer to iosm_imem struct.
9393
* @mux_type: Type of mux protocol.
94+
*
95+
* Return: 0 on success and failure value on error
9496
*/
95-
void ipc_imem_wwan_channel_init(struct iosm_imem *ipc_imem,
96-
enum ipc_mux_protocol mux_type);
97+
int ipc_imem_wwan_channel_init(struct iosm_imem *ipc_imem,
98+
enum ipc_mux_protocol mux_type);
9799

98100
/**
99101
* ipc_imem_sys_devlink_open - Open a Flash/CD Channel link to CP

0 commit comments

Comments
 (0)