diff options
author | Deepak Nibade <dnibade@nvidia.com> | 2016-10-10 07:03:32 -0400 |
---|---|---|
committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2016-10-10 13:13:56 -0400 |
commit | bb5fd16c67287e53db5165a974ea15ec3be09fe9 (patch) | |
tree | 062f363cbfaa58c64ee377c6d608037cda15acf6 /drivers/gpu/nvgpu/gk20a | |
parent | 3bbd6419767896719833bc5024200ea67b8fb914 (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/gpu/nvgpu/gk20a')
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/channel_gk20a.c | 23 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/channel_gk20a.h | 1 |
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 | ||
775 | void gk20a_set_error_notifier(struct channel_gk20a *ch, __u32 error) | 778 | void 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 | ||
795 | static void gk20a_free_error_notifiers(struct channel_gk20a *ch) | 805 | static 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; |