diff options
author | Gagan Grover <ggrover@nvidia.com> | 2016-10-12 17:05:06 +0530 |
---|---|---|
committer | Winnie Hsu <whsu@nvidia.com> | 2016-10-26 15:39:18 -0700 |
commit | 1b1420c3fd59880e0a9220bae507b2191d73e2b0 (patch) | |
tree | 3201da11e0aabc459f0a9c0e4cfb5305853b464a | |
parent | 563bca879a039771c666a03965e14d10989a5b07 (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.c | 32 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/channel_gk20a.h | 1 |
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; }; |