--- zzzz-none-000/linux-3.10.107/drivers/char/mem.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/char/mem.c 2021-02-04 17:41:59.000000000 +0000 @@ -21,16 +21,14 @@ #include #include #include -#include #include -#include #include #include #include #include -#include +#include -#include +#include #ifdef CONFIG_IA64 # include @@ -61,10 +59,6 @@ #endif #ifdef CONFIG_STRICT_DEVMEM -static inline int page_is_allowed(unsigned long pfn) -{ - return devmem_is_allowed(pfn); -} static inline int range_is_allowed(unsigned long pfn, unsigned long size) { u64 from = ((u64)pfn) << PAGE_SHIFT; @@ -72,27 +66,30 @@ u64 cursor = from; while (cursor < to) { - if (!devmem_is_allowed(pfn)) + if (!devmem_is_allowed(pfn)) { + printk(KERN_INFO + "Program %s tried to access /dev/mem between %Lx->%Lx.\n", + current->comm, from, to); return 0; + } cursor += PAGE_SIZE; pfn++; } return 1; } #else -static inline int page_is_allowed(unsigned long pfn) -{ - return 1; -} static inline int range_is_allowed(unsigned long pfn, unsigned long size) { return 1; } #endif -void __weak unxlate_dev_mem_ptr(unsigned long phys, void *addr) +#ifndef unxlate_dev_mem_ptr +#define unxlate_dev_mem_ptr unxlate_dev_mem_ptr +void __weak unxlate_dev_mem_ptr(phys_addr_t phys, void *addr) { } +#endif /* * This funcion reads the *physical* memory. The f_pos points directly to the @@ -103,7 +100,10 @@ { phys_addr_t p = *ppos; ssize_t read, sz; - char *ptr; + void *ptr; + + if (p != *ppos) + return 0; if (!valid_phys_addr_range(p, count)) return -EFAULT; @@ -125,31 +125,23 @@ while (count > 0) { unsigned long remaining; - int allowed; sz = size_inside_page(p, count); - allowed = page_is_allowed(p >> PAGE_SHIFT); - if (!allowed) + if (!range_is_allowed(p >> PAGE_SHIFT, count)) return -EPERM; - if (allowed == 2) { - /* Show zeros for restricted memory. */ - remaining = clear_user(buf, sz); - } else { - /* - * On ia64 if a page has been mapped somewhere as - * uncached, then it must also be accessed uncached - * by the kernel or data corruption may occur. - */ - ptr = xlate_dev_mem_ptr(p); - if (!ptr) - return -EFAULT; - - remaining = copy_to_user(buf, ptr, sz); - unxlate_dev_mem_ptr(p, ptr); - } + /* + * On ia64 if a page has been mapped somewhere as uncached, then + * it must also be accessed uncached by the kernel or data + * corruption may occur. + */ + ptr = xlate_dev_mem_ptr(p); + if (!ptr) + return -EFAULT; + remaining = copy_to_user(buf, ptr, sz); + unxlate_dev_mem_ptr(p, ptr); if (remaining) return -EFAULT; @@ -171,6 +163,9 @@ unsigned long copied; void *ptr; + if (p != *ppos) + return -EFBIG; + if (!valid_phys_addr_range(p, count)) return -EFAULT; @@ -189,36 +184,30 @@ #endif while (count > 0) { - int allowed; - sz = size_inside_page(p, count); - allowed = page_is_allowed(p >> PAGE_SHIFT); - if (!allowed) + if (!range_is_allowed(p >> PAGE_SHIFT, sz)) return -EPERM; - /* Skip actual writing when a page is marked as restricted. */ - if (allowed == 1) { - /* - * On ia64 if a page has been mapped somewhere as - * uncached, then it must also be accessed uncached - * by the kernel or data corruption may occur. - */ - ptr = xlate_dev_mem_ptr(p); - if (!ptr) { - if (written) - break; - return -EFAULT; - } + /* + * On ia64 if a page has been mapped somewhere as uncached, then + * it must also be accessed uncached by the kernel or data + * corruption may occur. + */ + ptr = xlate_dev_mem_ptr(p); + if (!ptr) { + if (written) + break; + return -EFAULT; + } - copied = copy_from_user(ptr, buf, sz); - unxlate_dev_mem_ptr(p, ptr); - if (copied) { - written += sz - copied; - if (written) - break; - return -EFAULT; - } + copied = copy_from_user(ptr, buf, sz); + unxlate_dev_mem_ptr(p, ptr); + if (copied) { + written += sz - copied; + if (written) + break; + return -EFAULT; } buf += sz; @@ -298,13 +287,24 @@ return pgoff << PAGE_SHIFT; } +/* permit direct mmap, for read, write or exec */ +static unsigned memory_mmap_capabilities(struct file *file) +{ + return NOMMU_MAP_DIRECT | + NOMMU_MAP_READ | NOMMU_MAP_WRITE | NOMMU_MAP_EXEC; +} + +static unsigned zero_mmap_capabilities(struct file *file) +{ + return NOMMU_MAP_COPY; +} + /* can't do an in-place private mapping if there's no MMU */ static inline int private_mapping_ok(struct vm_area_struct *vma) { return vma->vm_flags & VM_MAYSHARE; } #else -#define get_unmapped_area_mem NULL static inline int private_mapping_ok(struct vm_area_struct *vma) { @@ -352,7 +352,6 @@ return 0; } -#ifdef CONFIG_DEVKMEM static int mmap_kmem(struct file *file, struct vm_area_struct *vma) { unsigned long pfn; @@ -373,43 +372,7 @@ vma->vm_pgoff = pfn; return mmap_mem(file, vma); } -#endif - -#ifdef CONFIG_CRASH_DUMP -/* - * Read memory corresponding to the old kernel. - */ -static ssize_t read_oldmem(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - unsigned long pfn, offset; - size_t read = 0, csize; - int rc = 0; - - while (count) { - pfn = *ppos / PAGE_SIZE; - if (pfn > saved_max_pfn) - return read; - - offset = (unsigned long)(*ppos % PAGE_SIZE); - if (count > PAGE_SIZE - offset) - csize = PAGE_SIZE - offset; - else - csize = count; - - rc = copy_oldmem_page(pfn, buf, csize, offset, 1); - if (rc < 0) - return rc; - buf += csize; - *ppos += csize; - read += csize; - count -= csize; - } - return read; -} -#endif -#ifdef CONFIG_DEVKMEM /* * This function reads the *virtual* memory as seen by the kernel. */ @@ -448,7 +411,7 @@ * uncached, then it must also be accessed uncached * by the kernel or data corruption may occur */ - kbuf = xlate_dev_kmem_ptr((char *)p); + kbuf = xlate_dev_kmem_ptr((void *)p); if (copy_to_user(buf, kbuf, sz)) return -EFAULT; @@ -509,7 +472,7 @@ #endif while (count > 0) { - char *ptr; + void *ptr; sz = size_inside_page(p, count); @@ -518,7 +481,7 @@ * it must also be accessed uncached by the kernel or data * corruption may occur. */ - ptr = xlate_dev_kmem_ptr((char *)p); + ptr = xlate_dev_kmem_ptr((void *)p); copied = copy_from_user(ptr, buf, sz); if (copied) { @@ -589,9 +552,7 @@ *ppos = p; return virtr + wrote ? : err; } -#endif -#ifdef CONFIG_DEVPORT static ssize_t read_port(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -620,6 +581,7 @@ return -EFAULT; while (count-- > 0 && i < 65536) { char c; + if (__get_user(c, tmp)) { if (tmp > buf) break; @@ -632,7 +594,6 @@ *ppos = i; return tmp-buf; } -#endif static ssize_t read_null(struct file *file, char __user *buf, size_t count, loff_t *ppos) @@ -646,16 +607,16 @@ return count; } -static ssize_t aio_read_null(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +static ssize_t read_iter_null(struct kiocb *iocb, struct iov_iter *to) { return 0; } -static ssize_t aio_write_null(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +static ssize_t write_iter_null(struct kiocb *iocb, struct iov_iter *from) { - return iov_length(iov, nr_segs); + size_t count = iov_iter_count(from); + iov_iter_advance(from, count); + return count; } static int pipe_to_null(struct pipe_inode_info *info, struct pipe_buffer *buf, @@ -670,53 +631,24 @@ return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_null); } -static ssize_t read_zero(struct file *file, char __user *buf, - size_t count, loff_t *ppos) +static ssize_t read_iter_zero(struct kiocb *iocb, struct iov_iter *iter) { - size_t written; - - if (!count) - return 0; - - if (!access_ok(VERIFY_WRITE, buf, count)) - return -EFAULT; + size_t written = 0; - written = 0; - while (count) { - unsigned long unwritten; - size_t chunk = count; + while (iov_iter_count(iter)) { + size_t chunk = iov_iter_count(iter), n; if (chunk > PAGE_SIZE) chunk = PAGE_SIZE; /* Just for latency reasons */ - unwritten = __clear_user(buf, chunk); - written += chunk - unwritten; - if (unwritten) - break; + n = iov_iter_zero(chunk, iter); + if (!n && iov_iter_count(iter)) + return written ? written : -EFAULT; + written += n; if (signal_pending(current)) return written ? written : -ERESTARTSYS; - buf += chunk; - count -= chunk; cond_resched(); } - return written ? written : -EFAULT; -} - -static ssize_t aio_read_zero(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) -{ - size_t written = 0; - unsigned long i; - ssize_t ret; - - for (i = 0; i < nr_segs; i++) { - ret = read_zero(iocb->ki_filp, iov[i].iov_base, iov[i].iov_len, - &pos); - if (ret < 0) - break; - written += ret; - } - - return written ? written : -EFAULT; + return written; } static int mmap_zero(struct file *file, struct vm_area_struct *vma) @@ -763,7 +695,7 @@ offset += file->f_pos; case SEEK_SET: /* to avoid userland mistaking f_pos=-9 as -EBADF=-9 */ - if ((unsigned long long)offset >= ~0xFFFULL) { + if (IS_ERR_VALUE((unsigned long long)offset)) { ret = -EOVERFLOW; break; } @@ -786,106 +718,89 @@ #define zero_lseek null_lseek #define full_lseek null_lseek #define write_zero write_null -#define read_full read_zero -#define aio_write_zero aio_write_null +#define write_iter_zero write_iter_null #define open_mem open_port #define open_kmem open_mem -#define open_oldmem open_mem -static const struct file_operations mem_fops = { +static const struct file_operations __maybe_unused mem_fops = { .llseek = memory_lseek, .read = read_mem, .write = write_mem, .mmap = mmap_mem, .open = open_mem, +#ifndef CONFIG_MMU .get_unmapped_area = get_unmapped_area_mem, + .mmap_capabilities = memory_mmap_capabilities, +#endif }; -#ifdef CONFIG_DEVKMEM -static const struct file_operations kmem_fops = { +static const struct file_operations __maybe_unused kmem_fops = { .llseek = memory_lseek, .read = read_kmem, .write = write_kmem, .mmap = mmap_kmem, .open = open_kmem, +#ifndef CONFIG_MMU .get_unmapped_area = get_unmapped_area_mem, -}; + .mmap_capabilities = memory_mmap_capabilities, #endif +}; static const struct file_operations null_fops = { .llseek = null_lseek, .read = read_null, .write = write_null, - .aio_read = aio_read_null, - .aio_write = aio_write_null, + .read_iter = read_iter_null, + .write_iter = write_iter_null, .splice_write = splice_write_null, }; -#ifdef CONFIG_DEVPORT -static const struct file_operations port_fops = { +static const struct file_operations __maybe_unused port_fops = { .llseek = memory_lseek, .read = read_port, .write = write_port, .open = open_port, }; -#endif static const struct file_operations zero_fops = { .llseek = zero_lseek, - .read = read_zero, .write = write_zero, - .aio_read = aio_read_zero, - .aio_write = aio_write_zero, + .read_iter = read_iter_zero, + .write_iter = write_iter_zero, .mmap = mmap_zero, -}; - -/* - * capabilities for /dev/zero - * - permits private mappings, "copies" are taken of the source of zeros - * - no writeback happens - */ -static struct backing_dev_info zero_bdi = { - .name = "char/mem", - .capabilities = BDI_CAP_MAP_COPY | BDI_CAP_NO_ACCT_AND_WRITEBACK, +#ifndef CONFIG_MMU + .mmap_capabilities = zero_mmap_capabilities, +#endif }; static const struct file_operations full_fops = { .llseek = full_lseek, - .read = read_full, + .read_iter = read_iter_zero, .write = write_full, }; -#ifdef CONFIG_CRASH_DUMP -static const struct file_operations oldmem_fops = { - .read = read_oldmem, - .open = open_oldmem, - .llseek = default_llseek, -}; -#endif - static const struct memdev { const char *name; umode_t mode; const struct file_operations *fops; - struct backing_dev_info *dev_info; + fmode_t fmode; } devlist[] = { - [1] = { "mem", 0, &mem_fops, &directly_mappable_cdev_bdi }, +#ifdef CONFIG_DEVMEM + [1] = { "mem", 0, &mem_fops, FMODE_UNSIGNED_OFFSET }, +#endif #ifdef CONFIG_DEVKMEM - [2] = { "kmem", 0, &kmem_fops, &directly_mappable_cdev_bdi }, + [2] = { "kmem", 0, &kmem_fops, FMODE_UNSIGNED_OFFSET }, #endif - [3] = { "null", 0666, &null_fops, NULL }, + [3] = { "null", 0666, &null_fops, 0 }, #ifdef CONFIG_DEVPORT - [4] = { "port", 0, &port_fops, NULL }, + [4] = { "port", 0, &port_fops, 0 }, #endif - [5] = { "zero", 0666, &zero_fops, &zero_bdi }, - [7] = { "full", 0666, &full_fops, NULL }, - [8] = { "random", 0666, &random_fops, NULL }, - [9] = { "urandom", 0666, &urandom_fops, NULL }, + [5] = { "zero", 0666, &zero_fops, 0 }, + [7] = { "full", 0666, &full_fops, 0 }, + [8] = { "random", 0666, &random_fops, 0 }, + [9] = { "urandom", 0666, &urandom_fops, 0 }, #ifdef CONFIG_PRINTK - [11] = { "kmsg", 0644, &kmsg_fops, NULL }, -#endif -#ifdef CONFIG_CRASH_DUMP - [12] = { "oldmem", 0, &oldmem_fops, NULL }, + [11] = { "kmsg", 0644, &kmsg_fops, 0 }, #endif }; @@ -903,12 +818,7 @@ return -ENXIO; filp->f_op = dev->fops; - if (dev->dev_info) - filp->f_mapping->backing_dev_info = dev->dev_info; - - /* Is /dev/mem or /dev/kmem ? */ - if (dev->dev_info == &directly_mappable_cdev_bdi) - filp->f_mode |= FMODE_UNSIGNED_OFFSET; + filp->f_mode |= dev->fmode; if (dev->fops->open) return dev->fops->open(inode, filp); @@ -933,11 +843,6 @@ static int __init chr_dev_init(void) { int minor; - int err; - - err = bdi_init(&zero_bdi); - if (err) - return err; if (register_chrdev(MEM_MAJOR, "mem", &memory_fops)) printk("unable to get major %d for memory devs\n", MEM_MAJOR);