soc: qcom: glink_probe: use lock while sending ssr notification

In ssr handling of remote subsystem down, all rpmsg devices are removed
for that edge. If at the same time ssr down is received for other remote
subsystem, it may try to notify already down remote and end up using
invalid rpmsg device which causes use after free.

Store device state in ssr context and update this with holding a lock.
SSR notification function should also use the same lock and perform
check for validity of rpmsg device.

CRs-Fixed: 2580433
Change-Id: I339e228a527f7b6a737944d8e9e53caa31992914
Signed-off-by: Deepak Kumar Singh <deesin@codeaurora.org>
This commit is contained in:
Deepak Kumar Singh 2020-12-03 13:45:26 +05:30 committed by Salendarsingh Gaud
parent 70fcaf5fc5
commit 6a06fa188c

View File

@ -16,6 +16,7 @@
#define MSM_SSR_LOG_PAGE_CNT 4
static void *ssr_ilc;
static DEFINE_MUTEX(ssr_lock);
#define MSM_SSR_INFO(x, ...) ipc_log_string(ssr_ilc, x, ##__VA_ARGS__)
@ -97,14 +98,15 @@ static int glink_ssr_ssr_cb(struct notifier_block *this,
{
struct glink_ssr_nb *nb = container_of(this, struct glink_ssr_nb, nb);
struct glink_ssr *ssr = nb->ssr;
struct device *dev = ssr->dev;
struct device *dev;
struct do_cleanup_msg msg;
int ret;
if (!dev || !ssr->ept)
return NOTIFY_DONE;
kref_get(&ssr->refcount);
mutex_lock(&ssr_lock);
dev = ssr->dev;
if (!dev || !ssr->ept)
goto out;
if (code == SUBSYS_AFTER_SHUTDOWN || code == SUBSYS_POWERUP_FAILURE) {
ssr->seq_num++;
@ -124,14 +126,15 @@ static int glink_ssr_ssr_cb(struct notifier_block *this,
if (ret) {
MSM_SSR_ERR(dev, "fail to send do cleanup to %s %d\n",
nb->ssr_label, ret);
kref_put(&ssr->refcount, glink_ssr_release);
return NOTIFY_DONE;
goto out;
}
ret = wait_for_completion_timeout(&ssr->completion, HZ);
if (!ret)
MSM_SSR_ERR(dev, "timeout waiting for cleanup resp\n");
}
out:
mutex_unlock(&ssr_lock);
kref_put(&ssr->refcount, glink_ssr_release);
return NOTIFY_DONE;
}
@ -252,11 +255,12 @@ static void glink_ssr_remove(struct rpmsg_device *rpdev)
{
struct glink_ssr *ssr = dev_get_drvdata(&rpdev->dev);
mutex_lock(&ssr_lock);
ssr->dev = NULL;
ssr->ept = NULL;
mutex_unlock(&ssr_lock);
dev_set_drvdata(&rpdev->dev, NULL);
schedule_work(&ssr->unreg_work);
}