From 1319c0def32b50b4ece74412bc74a4808c5f98b2 Mon Sep 17 00:00:00 2001 From: zhangshuowen96 Date: Thu, 10 Oct 2024 10:12:34 +0800 Subject: [PATCH] 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: zhangshuowen96 Fixes: 7d91f398c880 ("drivers: misc: sdma-dae: support sqe task send and execute") --- drivers/misc/sdma-dae/sdma_cdev.c | 44 +++++++++++++++++-------------- drivers/misc/sdma-dae/sdma_dbg.c | 16 ++++++----- drivers/misc/sdma-dae/sdma_main.c | 4 +-- drivers/misc/sdma-dae/sdma_umem.c | 7 ++++- drivers/misc/sdma-dae/sdma_umem.h | 2 +- 5 files changed, 43 insertions(+), 30 deletions(-) diff --git a/drivers/misc/sdma-dae/sdma_cdev.c b/drivers/misc/sdma-dae/sdma_cdev.c index e06a0140369b..b6ee3a8a79e8 100644 --- a/drivers/misc/sdma-dae/sdma_cdev.c +++ b/drivers/misc/sdma-dae/sdma_cdev.c @@ -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); diff --git a/drivers/misc/sdma-dae/sdma_dbg.c b/drivers/misc/sdma-dae/sdma_dbg.c index 32321d437f39..f677e0e4d0aa 100644 --- a/drivers/misc/sdma-dae/sdma_dbg.c +++ b/drivers/misc/sdma-dae/sdma_dbg.c @@ -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); diff --git a/drivers/misc/sdma-dae/sdma_main.c b/drivers/misc/sdma-dae/sdma_main.c index a54a8ddde720..9753ad8c698e 100644 --- a/drivers/misc/sdma-dae/sdma_main.c +++ b/drivers/misc/sdma-dae/sdma_main.c @@ -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; diff --git a/drivers/misc/sdma-dae/sdma_umem.c b/drivers/misc/sdma-dae/sdma_umem.c index 43e079209ee0..b34ac62583ee 100644 --- a/drivers/misc/sdma-dae/sdma_umem.c +++ b/drivers/misc/sdma-dae/sdma_umem.c @@ -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; diff --git a/drivers/misc/sdma-dae/sdma_umem.h b/drivers/misc/sdma-dae/sdma_umem.h index fec7c70e80f3..23573f653a01 100644 --- a/drivers/misc/sdma-dae/sdma_umem.h +++ b/drivers/misc/sdma-dae/sdma_umem.h @@ -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; -- Gitee