Commit 8e391906 authored by Yang Shen's avatar Yang Shen Committed by JangShui Yang
Browse files

uacce: add mutex for check qfr

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: default avatarYang Shen <shenyang39@huawei.com>
Signed-off-by: default avatarJiangShui Yang <yangjiangshui@h-partners.com>
parent 642aa732
Loading
Loading
Loading
Loading
+28 −15
Original line number Diff line number Diff line
@@ -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(&current->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,9 @@ static int uacce_fops_mmap(struct file *filep, struct vm_area_struct *vma)
	return ret;

out_with_lock:
	q->qfrs[type] = NULL;
	mutex_unlock(&q->mutex);
	kfree(qfr);
	q->qfrs[type] = NULL;
	return ret;
}