From: Lijun Fang fanglijun3@huawei.com
ascend inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4JMM0 CVE: NA
--------
This feature is to use debug the process memory.
Signed-off-by: Lijun Fang fanglijun3@huawei.com Reviewed-by: Weilong Chen chenweilong@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/char/svm.c | 160 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+)
diff --git a/drivers/char/svm.c b/drivers/char/svm.c index 60e9f022bfb3..bf9e299ceb4e 100644 --- a/drivers/char/svm.c +++ b/drivers/char/svm.c @@ -36,12 +36,14 @@ #define SVM_DEVICE_NAME "svm" #define ASID_SHIFT 48
+#define SVM_IOCTL_REMAP_PROC 0xfff4 #define SVM_IOCTL_LOAD_FLAG 0xfffa #define SVM_IOCTL_PROCESS_BIND 0xffff
#define CORE_SID 0
#define SVM_IOCTL_RELEASE_PHYS32 0xfff3 +#define SVM_REMAP_MEM_LEN_MAX (16 * 1024 * 1024) #define MMAP_PHY32_MAX (16 * 1024 * 1024)
static int probe_index; @@ -96,11 +98,21 @@ struct svm_process { struct iommu_sva *sva; };
+struct svm_proc_mem { + u32 dev_id; + u32 len; + u64 pid; + u64 vaddr; + u64 buf; +}; + static char *svm_cmd_to_string(unsigned int cmd) { switch (cmd) { case SVM_IOCTL_PROCESS_BIND: return "bind"; + case SVM_IOCTL_REMAP_PROC: + return "remap proc"; case SVM_IOCTL_LOAD_FLAG: return "load flag"; case SVM_IOCTL_RELEASE_PHYS32: @@ -497,6 +509,151 @@ static int svm_open(struct inode *inode, struct file *file) return 0; }
+static long svm_remap_get_phys(struct mm_struct *mm, struct vm_area_struct *vma, + unsigned long addr, unsigned long *phys, + unsigned long *page_size, unsigned long *offset) +{ + long err = -EINVAL; + pgd_t *pgd = NULL; + p4d_t *p4d = NULL; + pud_t *pud = NULL; + pte_t *pte = NULL; + + if (mm == NULL || vma == NULL || phys == NULL || + page_size == NULL || offset == NULL) + return err; + + pgd = pgd_offset(mm, addr); + if (pgd_none_or_clear_bad(pgd)) + return err; + + p4d = p4d_offset(pgd, addr); + if (p4d_none_or_clear_bad(p4d)) + return err; + + pud = pud_offset(p4d, addr); + if (pud_none_or_clear_bad(pud)) + return err; + + pte = svm_get_pte(vma, pud, addr, page_size, offset); + if (pte && pte_present(*pte)) { + *phys = PFN_PHYS(pte_pfn(*pte)); + return 0; + } + + return err; +} + +static long svm_remap_proc(unsigned long __user *arg) +{ + long ret = -EINVAL; + struct svm_proc_mem pmem; + struct task_struct *ptask = NULL; + struct mm_struct *pmm = NULL, *mm = current->mm; + struct vm_area_struct *pvma = NULL, *vma = NULL; + unsigned long end, vaddr, phys, buf, offset, pagesize; + + if (!acpi_disabled) + return -EPERM; + + if (arg == NULL) { + pr_err("arg is invalid.\n"); + return ret; + } + + ret = copy_from_user(&pmem, (void __user *)arg, sizeof(pmem)); + if (ret) { + pr_err("failed to copy args from user space.\n"); + return -EFAULT; + } + + if (pmem.buf & (PAGE_SIZE - 1)) { + pr_err("address is not aligned with page size, addr:%pK.\n", + (void *)pmem.buf); + return -EINVAL; + } + + rcu_read_lock(); + if (pmem.pid) { + ptask = find_task_by_vpid(pmem.pid); + if (!ptask) { + rcu_read_unlock(); + pr_err("No task for this pid\n"); + return -EINVAL; + } + } else { + ptask = current; + } + + get_task_struct(ptask); + rcu_read_unlock(); + pmm = ptask->mm; + + down_read(&mm->mmap_lock); + down_read(&pmm->mmap_lock); + + pvma = find_vma(pmm, pmem.vaddr); + if (pvma == NULL) { + ret = -ESRCH; + goto err; + } + + vma = find_vma(mm, pmem.buf); + if (vma == NULL) { + ret = -ESRCH; + goto err; + } + + if (pmem.len > SVM_REMAP_MEM_LEN_MAX) { + ret = -EINVAL; + pr_err("too large length of memory.\n"); + goto err; + } + vaddr = pmem.vaddr; + end = vaddr + pmem.len; + buf = pmem.buf; + vma->vm_flags |= VM_SHARED; + if (end > pvma->vm_end || end < vaddr) { + ret = -EINVAL; + pr_err("memory length is out of range, vaddr:%pK, len:%u.\n", + (void *)vaddr, pmem.len); + goto err; + } + + do { + ret = svm_remap_get_phys(pmm, pvma, vaddr, + &phys, &pagesize, &offset); + if (ret) { + ret = -EINVAL; + goto err; + } + + vaddr += pagesize - offset; + + do { + if (remap_pfn_range(vma, buf, phys >> PAGE_SHIFT, + PAGE_SIZE, + __pgprot(vma->vm_page_prot.pgprot | + PTE_DIRTY))) { + + ret = -ESRCH; + goto err; + } + + offset += PAGE_SIZE; + buf += PAGE_SIZE; + phys += PAGE_SIZE; + } while (offset < pagesize); + + } while (vaddr < end); + +err: + up_read(&pmm->mmap_lock); + up_read(&mm->mmap_lock); + put_task_struct(ptask); + return ret; +} + static int svm_proc_load_flag(int __user *arg) { static atomic_t l2buf_load_flag = ATOMIC_INIT(0); @@ -711,6 +868,9 @@ static long svm_ioctl(struct file *file, unsigned int cmd, return -EFAULT; } break; + case SVM_IOCTL_REMAP_PROC: + err = svm_remap_proc((unsigned long __user *)arg); + break; case SVM_IOCTL_LOAD_FLAG: err = svm_proc_load_flag((int __user *)arg); break;