From 0aa2d8ef9bd9705aaecf6e3aad0abb3d534c1f4f Mon Sep 17 00:00:00 2001 From: Arun Kumar Neelakantam Date: Tue, 22 Jan 2019 16:48:57 +0530 Subject: [PATCH 1/2] 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); From e62317caca1d2844c2c7257f405e85e95ec09866 Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Thu, 7 Mar 2019 14:11:43 -0800 Subject: [PATCH 2/2] soc: qcom: qmi_interface: Add send timeout helper Add an api for clients to set the send timeout of the underlying qrtr socket. QMI sets this timeout to 10 seconds by default but this is too long for some clients in critical paths. Change-Id: I4c892a2f034c87b6bf2f71664369140910e72383 Signed-off-by: Chris Lew --- drivers/soc/qcom/qmi_interface.c | 17 +++++++++++++++++ include/linux/soc/qcom/qmi.h | 1 + 2 files changed, 18 insertions(+) diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c index 282364779894..810bd1246673 100644 --- a/drivers/soc/qcom/qmi_interface.c +++ b/drivers/soc/qcom/qmi_interface.c @@ -448,6 +448,7 @@ static void qmi_handle_net_reset(struct qmi_handle *qmi) struct sockaddr_qrtr sq; struct qmi_service *svc; struct socket *sock; + long timeo = qmi->sock->sk->sk_sndtimeo; sock = qmi_sock_create(qmi, &sq); if (IS_ERR(sock)) @@ -467,6 +468,7 @@ static void qmi_handle_net_reset(struct qmi_handle *qmi) sock_release(qmi->sock); qmi->sock = sock; qmi->sq = sq; + qmi->sock->sk->sk_sndtimeo = timeo; mutex_unlock(&qmi->sock_lock); list_for_each_entry(svc, &qmi->lookups, list_node) @@ -620,6 +622,21 @@ static struct socket *qmi_sock_create(struct qmi_handle *qmi, return sock; } +/** + * qmi_set_sndtimeo() - set the sk_sndtimeo of the qmi handle + * @qmi: QMI client handle + * @timeo: timeout in jiffies. + * + * This sets the timeout for the blocking socket send in qmi send. + */ +void qmi_set_sndtimeo(struct qmi_handle *qmi, long timeo) +{ + mutex_lock(&qmi->sock_lock); + qmi->sock->sk->sk_sndtimeo = timeo; + mutex_unlock(&qmi->sock_lock); +} +EXPORT_SYMBOL(qmi_set_sndtimeo); + /** * qmi_handle_init() - initialize a QMI client handle * @qmi: QMI handle to initialize diff --git a/include/linux/soc/qcom/qmi.h b/include/linux/soc/qcom/qmi.h index 011174c6937f..1a8c91482460 100644 --- a/include/linux/soc/qcom/qmi.h +++ b/include/linux/soc/qcom/qmi.h @@ -268,5 +268,6 @@ int qmi_txn_init(struct qmi_handle *qmi, struct qmi_txn *txn, struct qmi_elem_info *ei, void *c_struct); int qmi_txn_wait(struct qmi_txn *txn, unsigned long timeout); void qmi_txn_cancel(struct qmi_txn *txn); +void qmi_set_sndtimeo(struct qmi_handle *qmi, long timeo); #endif