msm: ipa: Fix rndis client disconnection gracefully

if there are packets coming from rndis client to device
IPA driver tries to gives those packets to network driver.
If at the same time USB disconnection is in progress, there
can be a possibility of race where callback is called with NULL
private data and it can result in a undefined behavior at client
driver. Make changes to add proper checks to handle the scenario
gracefully.

Change-Id: I7b3a5731ae21362dc67c53a2de464b17a223d4ba
Signed-off-by: Praveen Kurapati <pkurapat@codeaurora.org>
Signed-off-by: Chaitanya Pratapa <cpratapa@codeaurora.org>
This commit is contained in:
Chaitanya Pratapa 2019-10-24 19:45:20 -07:00 committed by Praveen Kurapati
parent e4022b8689
commit a861d69435
4 changed files with 40 additions and 6 deletions
drivers/platform/msm/ipa

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/debugfs.h>
@ -659,13 +659,21 @@ static void ecm_ipa_packet_receive_notify
packet_len = skb->len;
ECM_IPA_DEBUG("packet RX, len=%d\n", skb->len);
if (unlikely(ecm_ipa_ctx == NULL)) {
ECM_IPA_DEBUG("Private context is NULL. Drop SKB.\n");
dev_kfree_skb_any(skb);
return;
}
if (unlikely(ecm_ipa_ctx->state != ECM_IPA_CONNECTED_AND_UP)) {
ECM_IPA_DEBUG("Missing pipe connected and/or iface up\n");
dev_kfree_skb_any(skb);
return;
}
if (unlikely(evt != IPA_RECEIVE)) {
ECM_IPA_ERROR("A none IPA_RECEIVE event in ecm_ipa_receive\n");
dev_kfree_skb_any(skb);
return;
}

View file

@ -1122,6 +1122,12 @@ static void rndis_ipa_packet_receive_notify(
("packet Rx, len=%d\n",
skb->len);
if (unlikely(rndis_ipa_ctx == NULL)) {
RNDIS_IPA_DEBUG("Private context is NULL. Drop SKB.\n");
dev_kfree_skb_any(skb);
return;
}
if (unlikely(rndis_ipa_ctx->rx_dump_enable))
rndis_ipa_dump_skb(skb);
@ -1129,11 +1135,15 @@ static void rndis_ipa_packet_receive_notify(
RNDIS_IPA_DEBUG("use connect()/up() before receive()\n");
RNDIS_IPA_DEBUG("packet dropped (length=%d)\n",
skb->len);
rndis_ipa_ctx->rx_dropped++;
dev_kfree_skb_any(skb);
return;
}
if (unlikely(evt != IPA_RECEIVE)) {
RNDIS_IPA_ERROR("a none IPA_RECEIVE event in driver RX\n");
rndis_ipa_ctx->rx_dropped++;
dev_kfree_skb_any(skb);
return;
}

View file

@ -1467,7 +1467,10 @@ int ipa3_release_gsi_channel(u32 clnt_hdl)
IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(clnt_hdl));
/* Set the disconnect in progress flag to avoid calling cb.*/
spin_lock(&ipa3_ctx->disconnect_lock);
atomic_set(&ep->disconnect_in_progress, 1);
spin_unlock(&ipa3_ctx->disconnect_lock);
gsi_res = gsi_dealloc_channel(ep->gsi_chan_hdl);
if (gsi_res != GSI_STATUS_SUCCESS) {
@ -1487,7 +1490,9 @@ int ipa3_release_gsi_channel(u32 clnt_hdl)
if (!ep->keep_ipa_awake)
IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl));
spin_lock(&ipa3_ctx->disconnect_lock);
memset(&ipa3_ctx->ep[clnt_hdl], 0, sizeof(struct ipa3_ep_context));
spin_unlock(&ipa3_ctx->disconnect_lock);
IPADBG("exit\n");
return 0;

View file

@ -3259,14 +3259,18 @@ void ipa3_lan_rx_cb(void *priv, enum ipa_dp_evt_type evt, unsigned long data)
unsigned int src_pipe;
u32 metadata;
u8 ucp;
void (*client_notify)(void *client_priv, enum ipa_dp_evt_type evt,
unsigned long data);
void *client_priv;
ipahal_pkt_status_parse_thin(rx_skb->data, &status);
src_pipe = status.endp_src_idx;
metadata = status.metadata;
ucp = status.ucp;
ep = &ipa3_ctx->ep[src_pipe];
if (unlikely(src_pipe >= ipa3_ctx->ipa_num_pipes)) {
IPAERR_RL("drop pipe=%d\n", src_pipe);
if (unlikely(src_pipe >= ipa3_ctx->ipa_num_pipes) ||
unlikely(atomic_read(&ep->disconnect_in_progress))) {
IPAERR("drop pipe=%d\n", src_pipe);
dev_kfree_skb_any(rx_skb);
return;
}
@ -3288,12 +3292,19 @@ void ipa3_lan_rx_cb(void *priv, enum ipa_dp_evt_type evt, unsigned long data)
metadata, *(u32 *)rx_skb->cb);
IPADBG_LOW("ucp: %d\n", *(u8 *)(rx_skb->cb + 4));
spin_lock(&ipa3_ctx->disconnect_lock);
if (likely((!atomic_read(&ep->disconnect_in_progress)) &&
ep->valid && ep->client_notify))
ep->client_notify(ep->priv, IPA_RECEIVE,
ep->valid && ep->client_notify)) {
client_notify = ep->client_notify;
client_priv = ep->priv;
spin_unlock(&ipa3_ctx->disconnect_lock);
client_notify(client_priv, IPA_RECEIVE,
(unsigned long)(rx_skb));
else
} else {
spin_unlock(&ipa3_ctx->disconnect_lock);
dev_kfree_skb_any(rx_skb);
}
}
static void ipa3_recycle_rx_wrapper(struct ipa3_rx_pkt_wrapper *rx_pkt)