dsp: q6lsm: Avoid null pointer access in SSR

Synchronize both contexts of SSR and SVA close
to avoid access of client handle after free.
Check whether the client is valid or not when
retrieved from private data in q6lsm_callback along
with NULL check to avoid invalidated pointer access.

Change-Id: I51c13cd79fd947c624bf0cade4c93a3fdf07353e
Signed-off-by: Laxminath Kasam <lkasam@codeaurora.org>
diff --git a/dsp/q6lsm.c b/dsp/q6lsm.c
index d03f24c..a702661 100644
--- a/dsp/q6lsm.c
+++ b/dsp/q6lsm.c
@@ -78,6 +78,7 @@
 	uint32_t param_id;
 };
 
+static DEFINE_MUTEX(session_lock);
 static struct lsm_common lsm_common;
 /*
  * mmap_handle_p can point either client->sound_model.mem_map_handle or
@@ -130,6 +131,24 @@
 	}
 }
 
+static int q6lsm_get_session_id_from_lsm_client(struct lsm_client *client)
+{
+	int n;
+
+	for (n = LSM_MIN_SESSION_ID; n <= LSM_MAX_SESSION_ID; n++) {
+		if (lsm_session[n] == client)
+			return n;
+	}
+	pr_err("%s: cannot find matching lsm client. client = %pa\n",
+		__func__, client);
+	return LSM_INVALID_SESSION_ID;
+}
+
+static bool q6lsm_is_valid_lsm_client(struct lsm_client *client)
+{
+	return q6lsm_get_session_id_from_lsm_client(client) ? 1 : 0;
+}
+
 static int q6lsm_callback(struct apr_client_data *data, void *priv)
 {
 	struct lsm_client *client = (struct lsm_client *)priv;
@@ -148,6 +167,13 @@
 			 __func__, data->opcode, data->reset_event,
 			 data->reset_proc);
 
+		mutex_lock(&session_lock);
+		if (!client || !q6lsm_is_valid_lsm_client(client)) {
+			pr_err("%s: client already freed/invalid, return\n",
+				__func__);
+			mutex_unlock(&session_lock);
+			return 0;
+		}
 		apr_reset(client->apr);
 		client->apr = NULL;
 		atomic_set(&client->cmd_state, CMD_STATE_CLEARED);
@@ -157,6 +183,7 @@
 		mutex_lock(&lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]->lock);
 		lsm_common.set_custom_topology = 1;
 		mutex_unlock(&lsm_common.cal_data[LSM_CUSTOM_TOP_IDX]->lock);
+		mutex_unlock(&session_lock);
 		return 0;
 	}
 
@@ -369,6 +396,7 @@
 		pr_err("%s: Invalid Session %d\n", __func__, client->session);
 		return;
 	}
+	mutex_lock(&session_lock);
 	apr_deregister(client->apr);
 	client->mmap_apr = NULL;
 	q6lsm_session_free(client);
@@ -376,6 +404,7 @@
 	mutex_destroy(&client->cmd_lock);
 	kfree(client);
 	client = NULL;
+	mutex_unlock(&session_lock);
 }
 EXPORT_SYMBOL(q6lsm_client_free);