mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-24 02:22:34 +03:00
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>
This commit is contained in:
committed by
mobile promotions
parent
3bbd641976
commit
bb5fd16c67
@@ -742,8 +742,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);
|
||||
@@ -764,16 +763,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 nvgpu_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;
|
||||
@@ -787,13 +793,18 @@ void gk20a_set_error_notifier(struct channel_gk20a *ch, __u32 error)
|
||||
ch->error_notifier->info32 = error;
|
||||
ch->error_notifier->status = 0xffff;
|
||||
|
||||
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);
|
||||
@@ -801,6 +812,7 @@ static void gk20a_free_error_notifiers(struct channel_gk20a *ch)
|
||||
ch->error_notifier = NULL;
|
||||
ch->error_notifier_va = NULL;
|
||||
}
|
||||
mutex_unlock(&ch->error_notifier_mutex);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
c->referenceable = false;
|
||||
init_waitqueue_head(&c->ref_count_dec_wq);
|
||||
mutex_init(&c->ioctl_lock);
|
||||
mutex_init(&c->error_notifier_mutex);
|
||||
spin_lock_init(&c->jobs_lock);
|
||||
raw_spin_lock_init(&c->timeout.lock);
|
||||
mutex_init(&c->sync_lock);
|
||||
|
||||
@@ -177,6 +177,7 @@ struct channel_gk20a {
|
||||
struct dma_buf *error_notifier_ref;
|
||||
struct nvgpu_notification *error_notifier;
|
||||
void *error_notifier_va;
|
||||
struct mutex error_notifier_mutex;
|
||||
|
||||
struct mutex sync_lock;
|
||||
struct gk20a_channel_sync *sync;
|
||||
|
||||
Reference in New Issue
Block a user