From 0aa2d8ef9bd9705aaecf6e3aad0abb3d534c1f4f Mon Sep 17 00:00:00 2001 From: Arun Kumar Neelakantam Date: Tue, 22 Jan 2019 16:48:57 +0530 Subject: [PATCH] soc: qcom: qmi_interface: Fix race between net_reset and release qmi client calling qmi_handle_release while handling net_reset cause NULL pointer access. Synchronize the net_reset handling with qmi_handle_release to avoid memory leak and invalid pointer access. CRs-Fixed: 2383987 Change-Id: I8179f96e5dfabe945b1a37f83530bc3b05ed746a Signed-off-by: Arun Kumar Neelakantam --- drivers/soc/qcom/qmi_interface.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c index 5fffadd60c93..282364779894 100644 --- a/drivers/soc/qcom/qmi_interface.c +++ b/drivers/soc/qcom/qmi_interface.c @@ -453,17 +453,18 @@ static void qmi_handle_net_reset(struct qmi_handle *qmi) if (IS_ERR(sock)) return; - mutex_lock(&qmi->sock_lock); - sock_release(qmi->sock); - qmi->sock = NULL; - mutex_unlock(&qmi->sock_lock); - qmi_recv_del_server(qmi, -1, -1); if (qmi->ops.net_reset) qmi->ops.net_reset(qmi); mutex_lock(&qmi->sock_lock); + /* Already qmi_handle_release() started */ + if (!qmi->sock) { + sock_release(sock); + return; + } + sock_release(qmi->sock); qmi->sock = sock; qmi->sq = sq; mutex_unlock(&qmi->sock_lock); @@ -695,23 +696,24 @@ EXPORT_SYMBOL(qmi_handle_init); */ void qmi_handle_release(struct qmi_handle *qmi) { - struct socket *sock = qmi->sock; + struct socket *sock; struct qmi_service *svc, *tmp; struct qmi_txn *txn; int txn_id; + mutex_lock(&qmi->sock_lock); + sock = qmi->sock; write_lock_bh(&sock->sk->sk_callback_lock); sock->sk->sk_user_data = NULL; write_unlock_bh(&sock->sk->sk_callback_lock); - cancel_work_sync(&qmi->work); - - qmi_recv_del_server(qmi, -1, -1); - - mutex_lock(&qmi->sock_lock); sock_release(sock); qmi->sock = NULL; mutex_unlock(&qmi->sock_lock); + cancel_work_sync(&qmi->work); + + qmi_recv_del_server(qmi, -1, -1); + destroy_workqueue(qmi->wq); mutex_lock(&qmi->txn_lock);