summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDeepak Nibade <dnibade@nvidia.com>2016-10-10 07:03:32 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2016-10-10 13:13:56 -0400
commitbb5fd16c67287e53db5165a974ea15ec3be09fe9 (patch)
tree062f363cbfaa58c64ee377c6d608037cda15acf6 /drivers
parent3bbd6419767896719833bc5024200ea67b8fb914 (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 Signed-off-by: Deepak Nibade <dnibade@nvidia.com> Reviewed-on: http://git-master/r/1233988 Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/nvgpu/gk20a/channel_gk20a.c23
-rw-r--r--drivers/gpu/nvgpu/gk20a/channel_gk20a.h1
2 files changed, 19 insertions, 5 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
index 92b43c8a..6a69de3e 100644
--- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c
@@ -742,8 +742,7 @@ static int gk20a_init_error_notifier(struct channel_gk20a *ch,
742 742
743 dmabuf = dma_buf_get(args->mem); 743 dmabuf = dma_buf_get(args->mem);
744 744
745 if (ch->error_notifier_ref) 745 gk20a_free_error_notifiers(ch);
746 gk20a_free_error_notifiers(ch);
747 746
748 if (IS_ERR(dmabuf)) { 747 if (IS_ERR(dmabuf)) {
749 pr_err("Invalid handle: %d\n", args->mem); 748 pr_err("Invalid handle: %d\n", args->mem);
@@ -764,16 +763,23 @@ static int gk20a_init_error_notifier(struct channel_gk20a *ch,
764 return -ENOMEM; 763 return -ENOMEM;
765 } 764 }
766 765
767 /* set channel notifiers pointer */
768 ch->error_notifier_ref = dmabuf;
769 ch->error_notifier = va + args->offset; 766 ch->error_notifier = va + args->offset;
770 ch->error_notifier_va = va; 767 ch->error_notifier_va = va;
771 memset(ch->error_notifier, 0, sizeof(struct nvgpu_notification)); 768 memset(ch->error_notifier, 0, sizeof(struct nvgpu_notification));
769
770 /* set channel notifiers pointer */
771 mutex_lock(&ch->error_notifier_mutex);
772 ch->error_notifier_ref = dmabuf;
773 mutex_unlock(&ch->error_notifier_mutex);
774
772 return 0; 775 return 0;
773} 776}
774 777
775void gk20a_set_error_notifier(struct channel_gk20a *ch, __u32 error) 778void gk20a_set_error_notifier(struct channel_gk20a *ch, __u32 error)
776{ 779{
780 bool notifier_set = false;
781
782 mutex_lock(&ch->error_notifier_mutex);
777 if (ch->error_notifier_ref) { 783 if (ch->error_notifier_ref) {
778 struct timespec time_data; 784 struct timespec time_data;
779 u64 nsec; 785 u64 nsec;
@@ -787,13 +793,18 @@ void gk20a_set_error_notifier(struct channel_gk20a *ch, __u32 error)
787 ch->error_notifier->info32 = error; 793 ch->error_notifier->info32 = error;
788 ch->error_notifier->status = 0xffff; 794 ch->error_notifier->status = 0xffff;
789 795
796 notifier_set = true;
797 }
798 mutex_unlock(&ch->error_notifier_mutex);
799
800 if (notifier_set)
790 gk20a_err(dev_from_gk20a(ch->g), 801 gk20a_err(dev_from_gk20a(ch->g),
791 "error notifier set to %d for ch %d", error, ch->hw_chid); 802 "error notifier set to %d for ch %d", error, ch->hw_chid);
792 }
793} 803}
794 804
795static void gk20a_free_error_notifiers(struct channel_gk20a *ch) 805static void gk20a_free_error_notifiers(struct channel_gk20a *ch)
796{ 806{
807 mutex_lock(&ch->error_notifier_mutex);
797 if (ch->error_notifier_ref) { 808 if (ch->error_notifier_ref) {
798 dma_buf_vunmap(ch->error_notifier_ref, ch->error_notifier_va); 809 dma_buf_vunmap(ch->error_notifier_ref, ch->error_notifier_va);
799 dma_buf_put(ch->error_notifier_ref); 810 dma_buf_put(ch->error_notifier_ref);
@@ -801,6 +812,7 @@ static void gk20a_free_error_notifiers(struct channel_gk20a *ch)
801 ch->error_notifier = NULL; 812 ch->error_notifier = NULL;
802 ch->error_notifier_va = NULL; 813 ch->error_notifier_va = NULL;
803 } 814 }
815 mutex_unlock(&ch->error_notifier_mutex);
804} 816}
805 817
806/* Returns delta of cyclic integers a and b. If a is ahead of b, delta 818/* Returns delta of cyclic integers a and b. If a is ahead of b, delta
@@ -2387,6 +2399,7 @@ int gk20a_init_channel_support(struct gk20a *g, u32 chid)
2387 c->referenceable = false; 2399 c->referenceable = false;
2388 init_waitqueue_head(&c->ref_count_dec_wq); 2400 init_waitqueue_head(&c->ref_count_dec_wq);
2389 mutex_init(&c->ioctl_lock); 2401 mutex_init(&c->ioctl_lock);
2402 mutex_init(&c->error_notifier_mutex);
2390 spin_lock_init(&c->jobs_lock); 2403 spin_lock_init(&c->jobs_lock);
2391 raw_spin_lock_init(&c->timeout.lock); 2404 raw_spin_lock_init(&c->timeout.lock);
2392 mutex_init(&c->sync_lock); 2405 mutex_init(&c->sync_lock);
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h
index a44321bc..f6571b6f 100644
--- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.h
@@ -177,6 +177,7 @@ struct channel_gk20a {
177 struct dma_buf *error_notifier_ref; 177 struct dma_buf *error_notifier_ref;
178 struct nvgpu_notification *error_notifier; 178 struct nvgpu_notification *error_notifier;
179 void *error_notifier_va; 179 void *error_notifier_va;
180 struct mutex error_notifier_mutex;
180 181
181 struct mutex sync_lock; 182 struct mutex sync_lock;
182 struct gk20a_channel_sync *sync; 183 struct gk20a_channel_sync *sync;