Unverified Commit c93f7899 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!12072 sdma-dae: fix possible mremap error

Merge Pull Request from: @zhangshuowen96 
 
1. add mremap to avoid possible remap attack risk
2. delete spinlock while open sdma device
3. release channel lock after dev_release

zhangshuowen96 (1):
  drivers:misc:sdma-dae: add vma_ops to avoid mremap error 
 
Link:https://gitee.com/openeuler/kernel/pulls/12072

 

Reviewed-by: default avatarYang Yingliang <yangyingliang@huawei.com>
Signed-off-by: default avatarYang Yingliang <yangyingliang@huawei.com>
parents 31421c83 1319c0de
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;