Commit 1319c0de authored by zhangshuowen96's avatar zhangshuowen96
Browse files

drivers:misc:sdma-dae: add vma_ops to avoid mremap error

kunpeng inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/IAVMSO


CVE: NA

----------------------------------------------------------------------

1.add vm_ops in mmap to avoid possible mremap error
2.change some function to static type
3.delete device lock in cdev.c
4.fix umem resource recycle problem
5.fix debugfs global variable problem
6.release channel lock while no proc use

Signed-off-by: default avatarzhangshuowen96 <zhangshuowen@hisilicon.com>
Fixes: 7d91f398 ("drivers: misc: sdma-dae: support sqe task send and execute")
parent c9c7afae
Loading
Loading
Loading
Loading
+24 −20
Original line number Diff line number Diff line
@@ -279,18 +279,17 @@ static int ioctl_sdma_get_chn(struct file *file, unsigned long arg)
	list_add(&list_node->chn_list, &data->non_share_chn_list);
	pchannel = pdev->channels + idx;
	pchannel->ida = (u32)data->ida;
	spin_unlock(&pdev->channel_lock);

	dev_dbg(&pdev->pdev->dev, "sdma get chn %u\n", idx);
	if (copy_to_user((u32 __user *)(uintptr_t)arg, &idx, sizeof(u32))) {
		ret = -EFAULT;
		goto put_chn;
	}
	spin_unlock(&pdev->channel_lock);
	dev_dbg(&pdev->pdev->dev, "sdma get chn %u\n", idx);

	return 0;

put_chn:
	spin_lock(&pdev->channel_lock);
	list_del(&list_node->chn_list);
	bitmap_set(pdev->channel_map, idx - share_chns, 1);
	pdev->nr_channel_used--;
@@ -369,17 +368,14 @@ static int ioctl_get_near_sdmaid(struct file *file SDMA_UNUSED, unsigned long ar
	}

	for (i = 0; i < num; i++) {
		spin_lock(&g_info.core_dev->device_lock);
		sdma_dev = g_info.core_dev->sdma_devices[i];
		dev = &sdma_dev->pdev->dev;
		sdma_numa[i].idx = sdma_dev->idx;
		sdma_numa[i].pxm = sdma_dev->node_idx;
		if (sdma_numa[i].pxm < 0) {
			spin_unlock(&g_info.core_dev->device_lock);
			dev_err(dev, "sdma%d PXM domain not reported!\n", sdma_numa[i].idx);
			return -ENODATA;
		}
		spin_unlock(&g_info.core_dev->device_lock);
		dev_dbg(dev, "sdma%d PXM = %d\n", sdma_numa[i].idx, sdma_numa[i].pxm);
	}

@@ -470,8 +466,11 @@ static int ioctl_sdma_chn_used_refcount(struct file *file, unsigned long arg)
		list_for_each_entry_safe(c, n, &data->share_chn_list, chn_list) {
			if (c->chn_idx == share_chn.chn_idx) {
				pchannel->cnt_used--;
				if (pchannel->cnt_used == 0)
				if (pchannel->cnt_used == 0) {
					pchannel->sync_info_base->err_cnt = 0;
					pchannel->sync_info_base->lock_pid = 0;
					pchannel->sync_info_base->lock = 0;
				}
				dev_dbg(dev, "release share_chn%u\n", c->chn_idx);
				list_del(&c->chn_list);
				kfree(c);
@@ -928,7 +927,6 @@ static int sdma_core_open(struct inode *inode, struct file *file)
	struct hisi_sdma_device *psdma_dev;
	dev_t sdma_dev;
	u32 sdma_idx;
	int ret;

	if (g_info.core_dev->sdma_device_num == 0) {
		pr_err("cannot find a sdma device\n");
@@ -940,21 +938,13 @@ static int sdma_core_open(struct inode *inode, struct file *file)
		pr_err("wrong id of sdma device\n");
		return -ENODEV;
	}
	spin_lock(&g_info.core_dev->device_lock);
	psdma_dev = g_info.core_dev->sdma_devices[sdma_idx];
	if (!psdma_dev) {
		spin_unlock(&g_info.core_dev->device_lock);
		pr_err("cannot find sdma%u\n", sdma_idx);
		return -ENODEV;
	}
	ret = __do_sdma_open(psdma_dev, file);
	spin_unlock(&g_info.core_dev->device_lock);
	if (ret != 0) {
		pr_err("open sdma failed\n");
		return ret;
	}

	return 0;
	return __do_sdma_open(psdma_dev, file);
}

ssize_t sdma_read_info(struct file *file, char __user *buf SDMA_UNUSED, size_t size SDMA_UNUSED,
@@ -1005,12 +995,15 @@ static int sdma_dev_release(struct inode *inode SDMA_UNUSED, struct file *file)
		pchannel->cnt_used--;
		if (pchannel->sync_info_base->lock != 0 &&
			pchannel->sync_info_base->lock_pid == (u32)current->tgid) {
			dev_err(dev, "process %d exit with lock\n", current->tgid);
			pchannel->sync_info_base->lock = 0;
			dev_warn(dev, "process %d exit with lock\n", current->tgid);
			pchannel->sync_info_base->lock_pid = 0;
			pchannel->sync_info_base->lock = 0;
		}
		if (pchannel->cnt_used == 0)
		if (pchannel->cnt_used == 0) {
			pchannel->sync_info_base->err_cnt = 0;
			pchannel->sync_info_base->lock_pid = 0;
			pchannel->sync_info_base->lock = 0;
		}
		list_del(&c->chn_list);
		kfree(c);
	}
@@ -1068,6 +1061,16 @@ static int remap_addr_range(u32 chn_num, u64 offset, u64 size)
	}
}

static int sdma_vma_remap(struct vm_area_struct *vma)
{
	pr_err("sdma vma remap not supported!\n");
	return -EINVAL;
}

static const struct vm_operations_struct sdma_vm_ops = {
	.mremap = sdma_vma_remap,
};

static int sdma_dev_mmap(struct file *file, struct vm_area_struct *vma)
{
	struct file_open_data *data = file->private_data;
@@ -1083,6 +1086,7 @@ static int sdma_dev_mmap(struct file *file, struct vm_area_struct *vma)
	io_base = data->psdma_dev->base_addr;
	size = vma->vm_end - vma->vm_start;
	offset = vma->vm_pgoff;
	vma->vm_ops = &sdma_vm_ops;
	vma->vm_flags |= VM_DONTEXPAND | VM_WIPEONFORK | VM_DONTCOPY;

	dev_dbg(dev, "sdma total channel num = %u, user mmap offset = 0x%llx", chn_num, offset);
+10 −6
Original line number Diff line number Diff line
@@ -389,7 +389,9 @@ static int sdma_debugfs_channels_show(struct seq_file *f, void *data SDMA_UNUSED
	struct hisi_sdma_chn_num chn_num;
	struct hisi_sdma_device *sdev;
	struct hisi_sdma_channel *chn;
	u32 dbg_mode = debug_mode;
	u32 chn_idx;
	u32 dev_idx;
	u32 i;

	split_line(f);
@@ -397,7 +399,7 @@ static int sdma_debugfs_channels_show(struct seq_file *f, void *data SDMA_UNUSED
	if (num == 0 || num > HISI_SDMA_MAX_DEVS)
		return -ENOENT;

	if (debug_mode == ALL_CHANNEL_SELECTED) {
	if (dbg_mode == ALL_CHANNEL_SELECTED) {
		for (i = 0; i < num; i++) {
			spin_lock(&dbg_g_info.core_dev->device_lock);
			sdev = dbg_g_info.core_dev->sdma_devices[i];
@@ -417,21 +419,23 @@ static int sdma_debugfs_channels_show(struct seq_file *f, void *data SDMA_UNUSED
			}
			spin_unlock(&dbg_g_info.core_dev->device_lock);
		}
	} else if (debug_mode == SINGLE_CHANNEL_SELECTED) {
		if (device_id >= HISI_SDMA_MAX_DEVS ||
		    channel_id >= HISI_SDMA_DEFAULT_CHANNEL_NUM) {
	} else if (dbg_mode == SINGLE_CHANNEL_SELECTED) {
		chn_idx = channel_id;
		dev_idx = device_id;
		if (dev_idx >= HISI_SDMA_MAX_DEVS ||
		    chn_idx >= HISI_SDMA_DEFAULT_CHANNEL_NUM) {
			seq_puts(f, "Unsupported device or channel!\n");
			return -EINVAL;
		}
		spin_lock(&dbg_g_info.core_dev->device_lock);
		sdev = dbg_g_info.core_dev->sdma_devices[device_id];
		sdev = dbg_g_info.core_dev->sdma_devices[dev_idx];
		if (!sdev) {
			seq_puts(f, "sdma_devices already released!\n");
			spin_unlock(&dbg_g_info.core_dev->device_lock);
			return -ENXIO;
		}
		chn_num = sdma_chn_info(f, sdev);
		chn = sdev->channels + channel_id;
		chn = sdev->channels + chn_idx;
		split_line(f);
		sdma_debugfs_get_channel_dfx(f, chn, sdev->idx);
		sdma_sqe_cqe_list(f, chn);
+2 −2
Original line number Diff line number Diff line
@@ -156,7 +156,7 @@ static void sdma_free_all_sq_cq(struct hisi_sdma_device *psdma_dev)
	}
}

void sdma_destroy_channels(struct hisi_sdma_device *psdma_dev)
static void sdma_destroy_channels(struct hisi_sdma_device *psdma_dev)
{
	if (!psdma_dev || !psdma_dev->channels)
		return;
@@ -166,7 +166,7 @@ void sdma_destroy_channels(struct hisi_sdma_device *psdma_dev)
	psdma_dev->channels = NULL;
}

int sdma_init_channels(struct hisi_sdma_device *psdma_dev)
static int sdma_init_channels(struct hisi_sdma_device *psdma_dev)
{
	u32 chn_num = psdma_dev->nr_channel;
	struct hisi_sdma_channel *pchan;
+6 −1
Original line number Diff line number Diff line
@@ -127,6 +127,8 @@ static int record_umem(u64 addr, struct list_head *list_head, int ida, u64 *cook
	idr = idr_alloc(&entry->pin_mem_region, pmem, 0, 0, GFP_ATOMIC);
	if (idr < 0) {
		ret = idr;
		if (entry_find == false)
			hash_del(&entry->node);
		spin_unlock(&g_hash_table->hash_lock);
		pr_err("Sdma failed to alloc idr!\n");
		if (entry_find)
@@ -155,6 +157,7 @@ static int pin_umem(u64 addr, int npages, struct list_head *p_head)
	size_t node_size = sizeof(struct p_list);
	struct page **page_list;
	struct p_list *cur_node;
	u64 pin_addr = addr;

	to_pin_pages = unpin_pages = npages;
	while (unpin_pages != 0) {
@@ -167,7 +170,7 @@ static int pin_umem(u64 addr, int npages, struct list_head *p_head)
			return -ENOMEM;
		}

		pinned = pin_user_pages_fast(addr, to_pin_pages, FOLL_WRITE, page_list);
		pinned = pin_user_pages_fast(pin_addr, to_pin_pages, FOLL_WRITE, page_list);
		if (pinned < 0) {
			pr_err("Sdma failed to pin user pages!\n");
			ret = pinned;
@@ -189,6 +192,8 @@ static int pin_umem(u64 addr, int npages, struct list_head *p_head)
		cur_node->pnode.pinned = pinned;
		list_add(&cur_node->list, p_head);
		unpin_pages -= to_pin_pages;
		if (unpin_pages > 0)
			pin_addr += to_pin_pages * PAGE_SIZE;
		to_pin_pages = unpin_pages;
	}
	goto exit;
+1 −1
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@

#define HISI_SDMA_HASH_BUCKETS_BITS	3
#define COOKIE_IDA_SHIFT		32
#define COOKIE_IDA_MASK			0xffff
#define COOKIE_IDA_MASK			0xffffffff

struct page_node {
	struct page **page_list;