summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGagan Grover <ggrover@nvidia.com>2016-10-12 17:05:06 +0530
committerWinnie Hsu <whsu@nvidia.com>2016-10-26 15:39:18 -0700
commit1b1420c3fd59880e0a9220bae507b2191d73e2b0 (patch)
tree3201da11e0aabc459f0a9c0e4cfb5305853b464a
parent563bca879a039771c666a03965e14d10989a5b07 (diff)
gpu: nvgpu: fix use-after-free in case of error notifier
A use-after-free scenario is possible where one thread in gk20a_free_error_notifiers() is trying to free the error notifier and another thread in gk20a_set_error_notifier() is still using the error notifier Fix this by introducing mutex error_notifier_mutex for error notifier accesses Take mutex in gk20a_free_error_notifiers() and in gk20a_set_error_notifier() before accessing notifier In gk20a_init_error_notifier(), set the pointer ch->error_notifier_ref inside the mutex and only after notifier is completely initialized Bug 1824788 Change-Id: I47e1ab57d54f391799f5a0999840b663fd34585f Reviewed-on: http://git-master/r/1233988 Signed-off-by: Gagan Grover <ggrover@nvidia.com> Signed-off-by: Gaurav Singh <gaursingh@nvidia.com> Reviewed-on: http://git-master/r/1236695 GVS: Gerrit_Virtual_Submit Reviewed-by: Deepak Nibade <dnibade@nvidia.com> Reviewed-by: Bibek Basu <bbasu@nvidia.com>
-rw-r--r--drivers/gpu/nvgpu/gk20a/channel_gk20a.c32
-rw-r--r--drivers/gpu/nvgpu/gk20a/channel_gk20a.h1
2 files changed, 24 insertions, 9 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
index f64bda9b6dc5..b1b59a9a55b9 100644
--- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
@@ -552,8 +552,7 @@ static int gk20a_init_error_notifier(struct channel_gk20a *ch,
dmabuf = dma_buf_get(args->mem);
- if (ch->error_notifier_ref)
- gk20a_free_error_notifiers(ch);
+ gk20a_free_error_notifiers(ch);
if (IS_ERR(dmabuf)) {
pr_err("Invalid handle: %d\n", args->mem);
@@ -574,16 +573,23 @@ static int gk20a_init_error_notifier(struct channel_gk20a *ch,
return -ENOMEM;
}
- /* set channel notifiers pointer */
- ch->error_notifier_ref = dmabuf;
ch->error_notifier = va + args->offset;
ch->error_notifier_va = va;
memset(ch->error_notifier, 0, sizeof(struct nvhost_notification));
+
+ /* set channel notifiers pointer */
+ mutex_lock(&ch->error_notifier_mutex);
+ ch->error_notifier_ref = dmabuf;
+ mutex_unlock(&ch->error_notifier_mutex);
+
return 0;
}
void gk20a_set_error_notifier(struct channel_gk20a *ch, __u32 error)
{
+ bool notifier_set = false;
+
+ mutex_lock(&ch->error_notifier_mutex);
if (ch->error_notifier_ref) {
struct timespec time_data;
u64 nsec;
@@ -596,20 +602,27 @@ void gk20a_set_error_notifier(struct channel_gk20a *ch, __u32 error)
(u32)(nsec >> 32);
ch->error_notifier->info32 = error;
ch->error_notifier->status = 0xffff;
- gk20a_err(dev_from_gk20a(ch->g),
- "error notifier set to %d\n", error);
+
+ notifier_set = true;
}
+ mutex_unlock(&ch->error_notifier_mutex);
+
+ if (notifier_set)
+ gk20a_err(dev_from_gk20a(ch->g),
+ "error notifier set to %d for ch %d", error, ch->hw_chid);
}
static void gk20a_free_error_notifiers(struct channel_gk20a *ch)
{
+ mutex_lock(&ch->error_notifier_mutex);
if (ch->error_notifier_ref) {
dma_buf_vunmap(ch->error_notifier_ref, ch->error_notifier_va);
dma_buf_put(ch->error_notifier_ref);
- ch->error_notifier_ref = 0;
- ch->error_notifier = 0;
- ch->error_notifier_va = 0;
+ ch->error_notifier_ref = NULL;
+ ch->error_notifier = NULL;
+ ch->error_notifier_va = NULL;
}
+ mutex_unlock(&ch->error_notifier_mutex);
}
void gk20a_free_channel(struct channel_gk20a *ch, bool finish)
@@ -1630,6 +1643,7 @@ int gk20a_init_channel_support(struct gk20a *g, u32 chid)
c->bound = false;
c->remove_support = gk20a_remove_channel_support;
mutex_init(&c->jobs_lock);
+ mutex_init(&c->error_notifier_mutex);
INIT_LIST_HEAD(&c->jobs);
#if defined(CONFIG_GK20A_CYCLE_STATS)
mutex_init(&c->cyclestate.cyclestate_buffer_mutex);
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h
index 320ada62a965..547bb064fd63 100644
--- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h
@@ -132,6 +132,7 @@ struct channel_gk20a {
struct dma_buf *error_notifier_ref;
struct nvhost_notification *error_notifier;
void *error_notifier_va;
+ struct mutex error_notifier_mutex;
struct gk20a_channel_sync *sync;
};