driver inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IB9H0P CVE: NA
----------------------------------------------------------------------
Since the qfr operations can race in some cases, the validity checks require locking protection.
Signed-off-by: Yang Shen shenyang39@huawei.com Signed-off-by: JiangShui Yang yangjiangshui@h-partners.com --- drivers/misc/uacce/uacce.c | 46 +++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 16 deletions(-)
diff --git a/drivers/misc/uacce/uacce.c b/drivers/misc/uacce/uacce.c index 26df666a6529..1d50c2e07910 100644 --- a/drivers/misc/uacce/uacce.c +++ b/drivers/misc/uacce/uacce.c @@ -370,26 +370,35 @@ static void uacce_vma_close(struct vm_area_struct *vma) if (vma->vm_pgoff >= UACCE_MAX_REGION) return;
- qfr = q->qfrs[vma->vm_pgoff]; - if (!qfr) - return; - - if (qfr->type == UACCE_QFRT_SS && + if (vma->vm_pgoff == UACCE_QFRT_SS && atomic_read(¤t->active_mm->mm_users) > 0) { /* * uacce_vma_close() and uacce_remove() may be executed concurrently. * To avoid accessing the same address at the same time, takes the uacce->mutex. */ mutex_lock(&uacce->mutex); + mutex_lock(&q->mutex); + qfr = q->qfrs[vma->vm_pgoff]; + if (!qfr) { + mutex_lock(&q->mutex); + mutex_unlock(&uacce->mutex); + return; + } if ((q->state == UACCE_Q_STARTED) && uacce->ops->stop_queue) uacce->ops->stop_queue(q); uacce_free_dma_buffers(q); q->qfrs[vma->vm_pgoff] = NULL; + mutex_unlock(&q->mutex); mutex_unlock(&uacce->mutex); if (qfr != &noiommu_ss_default_qfr) kfree(qfr); - } else if (qfr->type != UACCE_QFRT_SS) { + } else if (vma->vm_pgoff != UACCE_QFRT_SS) { mutex_lock(&q->mutex); + qfr = q->qfrs[vma->vm_pgoff]; + if (!qfr) { + mutex_unlock(&q->mutex); + return; + } q->qfrs[vma->vm_pgoff] = NULL; mutex_unlock(&q->mutex); kfree(qfr); @@ -625,24 +634,28 @@ static int uacce_fops_mmap(struct file *filep, struct vm_area_struct *vma) else return -EINVAL;
- if (q->qfrs[type]) - return -EEXIST; - - qfr = kzalloc(sizeof(*qfr), GFP_KERNEL); - if (!qfr) - return -ENOMEM; - vm_flags_set(vma, VM_DONTCOPY | VM_DONTEXPAND | VM_WIPEONFORK); vma->vm_ops = &uacce_vm_ops; vma->vm_private_data = q; - qfr->type = type;
mutex_lock(&q->mutex); + if (q->qfrs[type]) { + mutex_unlock(&q->mutex); + return -EEXIST; + } + + qfr = kzalloc(sizeof(*qfr), GFP_KERNEL); + if (!qfr) { + ret = -ENOMEM; + goto out_with_lock; + } + if (!uacce_queue_is_valid(q)) { ret = -ENXIO; goto out_with_lock; }
+ qfr->type = type; q->qfrs[type] = qfr;
switch (type) { @@ -674,9 +687,10 @@ static int uacce_fops_mmap(struct file *filep, struct vm_area_struct *vma) return ret;
out_with_lock: - mutex_unlock(&q->mutex); - kfree(qfr); q->qfrs[type] = NULL; + mutex_unlock(&q->mutex); + if (qfr) + kfree(qfr); return ret; }