| .. | .. |
|---|
| 29 | 29 | #include <linux/export.h> |
|---|
| 30 | 30 | #include <linux/io.h> |
|---|
| 31 | 31 | #include <linux/uio.h> |
|---|
| 32 | | - |
|---|
| 33 | 32 | #include <linux/uaccess.h> |
|---|
| 33 | +#include <linux/security.h> |
|---|
| 34 | +#include <linux/pseudo_fs.h> |
|---|
| 35 | +#include <uapi/linux/magic.h> |
|---|
| 36 | +#include <linux/mount.h> |
|---|
| 34 | 37 | |
|---|
| 35 | 38 | #ifdef CONFIG_IA64 |
|---|
| 36 | 39 | # include <linux/efi.h> |
|---|
| 37 | 40 | #endif |
|---|
| 38 | 41 | |
|---|
| 42 | +#define DEVMEM_MINOR 1 |
|---|
| 39 | 43 | #define DEVPORT_MINOR 4 |
|---|
| 40 | 44 | |
|---|
| 41 | 45 | static inline unsigned long size_inside_page(unsigned long start, |
|---|
| .. | .. |
|---|
| 167 | 171 | if (!ptr) |
|---|
| 168 | 172 | goto failed; |
|---|
| 169 | 173 | |
|---|
| 170 | | - probe = probe_kernel_read(bounce, ptr, sz); |
|---|
| 174 | + probe = copy_from_kernel_nofault(bounce, ptr, sz); |
|---|
| 171 | 175 | unxlate_dev_mem_ptr(p, ptr); |
|---|
| 172 | 176 | if (probe) |
|---|
| 173 | 177 | goto failed; |
|---|
| .. | .. |
|---|
| 630 | 634 | unsigned long i = *ppos; |
|---|
| 631 | 635 | char __user *tmp = buf; |
|---|
| 632 | 636 | |
|---|
| 633 | | - if (!access_ok(VERIFY_WRITE, buf, count)) |
|---|
| 637 | + if (!access_ok(buf, count)) |
|---|
| 634 | 638 | return -EFAULT; |
|---|
| 635 | 639 | while (count-- > 0 && i < 65536) { |
|---|
| 636 | 640 | if (__put_user(inb(i), tmp) < 0) |
|---|
| .. | .. |
|---|
| 648 | 652 | unsigned long i = *ppos; |
|---|
| 649 | 653 | const char __user *tmp = buf; |
|---|
| 650 | 654 | |
|---|
| 651 | | - if (!access_ok(VERIFY_READ, buf, count)) |
|---|
| 655 | + if (!access_ok(buf, count)) |
|---|
| 652 | 656 | return -EFAULT; |
|---|
| 653 | 657 | while (count-- > 0 && i < 65536) { |
|---|
| 654 | 658 | char c; |
|---|
| .. | .. |
|---|
| 722 | 726 | return written; |
|---|
| 723 | 727 | } |
|---|
| 724 | 728 | |
|---|
| 729 | +static ssize_t read_zero(struct file *file, char __user *buf, |
|---|
| 730 | + size_t count, loff_t *ppos) |
|---|
| 731 | +{ |
|---|
| 732 | + size_t cleared = 0; |
|---|
| 733 | + |
|---|
| 734 | + while (count) { |
|---|
| 735 | + size_t chunk = min_t(size_t, count, PAGE_SIZE); |
|---|
| 736 | + size_t left; |
|---|
| 737 | + |
|---|
| 738 | + left = clear_user(buf + cleared, chunk); |
|---|
| 739 | + if (unlikely(left)) { |
|---|
| 740 | + cleared += (chunk - left); |
|---|
| 741 | + if (!cleared) |
|---|
| 742 | + return -EFAULT; |
|---|
| 743 | + break; |
|---|
| 744 | + } |
|---|
| 745 | + cleared += chunk; |
|---|
| 746 | + count -= chunk; |
|---|
| 747 | + |
|---|
| 748 | + if (signal_pending(current)) |
|---|
| 749 | + break; |
|---|
| 750 | + cond_resched(); |
|---|
| 751 | + } |
|---|
| 752 | + |
|---|
| 753 | + return cleared; |
|---|
| 754 | +} |
|---|
| 755 | + |
|---|
| 725 | 756 | static int mmap_zero(struct file *file, struct vm_area_struct *vma) |
|---|
| 726 | 757 | { |
|---|
| 727 | 758 | #ifndef CONFIG_MMU |
|---|
| .. | .. |
|---|
| 787 | 818 | switch (orig) { |
|---|
| 788 | 819 | case SEEK_CUR: |
|---|
| 789 | 820 | offset += file->f_pos; |
|---|
| 790 | | - /* fall through */ |
|---|
| 821 | + fallthrough; |
|---|
| 791 | 822 | case SEEK_SET: |
|---|
| 792 | 823 | /* to avoid userland mistaking f_pos=-9 as -EBADF=-9 */ |
|---|
| 793 | 824 | if ((unsigned long long)offset >= -MAX_ERRNO) { |
|---|
| .. | .. |
|---|
| 805 | 836 | return ret; |
|---|
| 806 | 837 | } |
|---|
| 807 | 838 | |
|---|
| 839 | +static struct inode *devmem_inode; |
|---|
| 840 | + |
|---|
| 841 | +#ifdef CONFIG_IO_STRICT_DEVMEM |
|---|
| 842 | +void revoke_devmem(struct resource *res) |
|---|
| 843 | +{ |
|---|
| 844 | + /* pairs with smp_store_release() in devmem_init_inode() */ |
|---|
| 845 | + struct inode *inode = smp_load_acquire(&devmem_inode); |
|---|
| 846 | + |
|---|
| 847 | + /* |
|---|
| 848 | + * Check that the initialization has completed. Losing the race |
|---|
| 849 | + * is ok because it means drivers are claiming resources before |
|---|
| 850 | + * the fs_initcall level of init and prevent /dev/mem from |
|---|
| 851 | + * establishing mappings. |
|---|
| 852 | + */ |
|---|
| 853 | + if (!inode) |
|---|
| 854 | + return; |
|---|
| 855 | + |
|---|
| 856 | + /* |
|---|
| 857 | + * The expectation is that the driver has successfully marked |
|---|
| 858 | + * the resource busy by this point, so devmem_is_allowed() |
|---|
| 859 | + * should start returning false, however for performance this |
|---|
| 860 | + * does not iterate the entire resource range. |
|---|
| 861 | + */ |
|---|
| 862 | + if (devmem_is_allowed(PHYS_PFN(res->start)) && |
|---|
| 863 | + devmem_is_allowed(PHYS_PFN(res->end))) { |
|---|
| 864 | + /* |
|---|
| 865 | + * *cringe* iomem=relaxed says "go ahead, what's the |
|---|
| 866 | + * worst that can happen?" |
|---|
| 867 | + */ |
|---|
| 868 | + return; |
|---|
| 869 | + } |
|---|
| 870 | + |
|---|
| 871 | + unmap_mapping_range(inode->i_mapping, res->start, resource_size(res), 1); |
|---|
| 872 | +} |
|---|
| 873 | +#endif |
|---|
| 874 | + |
|---|
| 808 | 875 | static int open_port(struct inode *inode, struct file *filp) |
|---|
| 809 | 876 | { |
|---|
| 810 | | - return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; |
|---|
| 877 | + int rc; |
|---|
| 878 | + |
|---|
| 879 | + if (!capable(CAP_SYS_RAWIO)) |
|---|
| 880 | + return -EPERM; |
|---|
| 881 | + |
|---|
| 882 | + rc = security_locked_down(LOCKDOWN_DEV_MEM); |
|---|
| 883 | + if (rc) |
|---|
| 884 | + return rc; |
|---|
| 885 | + |
|---|
| 886 | + if (iminor(inode) != DEVMEM_MINOR) |
|---|
| 887 | + return 0; |
|---|
| 888 | + |
|---|
| 889 | + /* |
|---|
| 890 | + * Use a unified address space to have a single point to manage |
|---|
| 891 | + * revocations when drivers want to take over a /dev/mem mapped |
|---|
| 892 | + * range. |
|---|
| 893 | + */ |
|---|
| 894 | + inode->i_mapping = devmem_inode->i_mapping; |
|---|
| 895 | + filp->f_mapping = inode->i_mapping; |
|---|
| 896 | + |
|---|
| 897 | + return 0; |
|---|
| 811 | 898 | } |
|---|
| 812 | 899 | |
|---|
| 813 | 900 | #define zero_lseek null_lseek |
|---|
| .. | .. |
|---|
| 861 | 948 | .llseek = zero_lseek, |
|---|
| 862 | 949 | .write = write_zero, |
|---|
| 863 | 950 | .read_iter = read_iter_zero, |
|---|
| 951 | + .read = read_zero, |
|---|
| 864 | 952 | .write_iter = write_iter_zero, |
|---|
| 865 | 953 | .mmap = mmap_zero, |
|---|
| 866 | 954 | .get_unmapped_area = get_unmapped_area_zero, |
|---|
| .. | .. |
|---|
| 882 | 970 | fmode_t fmode; |
|---|
| 883 | 971 | } devlist[] = { |
|---|
| 884 | 972 | #ifdef CONFIG_DEVMEM |
|---|
| 885 | | - [1] = { "mem", 0, &mem_fops, FMODE_UNSIGNED_OFFSET }, |
|---|
| 973 | + [DEVMEM_MINOR] = { "mem", 0, &mem_fops, FMODE_UNSIGNED_OFFSET }, |
|---|
| 886 | 974 | #endif |
|---|
| 887 | 975 | #ifdef CONFIG_DEVKMEM |
|---|
| 888 | 976 | [2] = { "kmem", 0, &kmem_fops, FMODE_UNSIGNED_OFFSET }, |
|---|
| .. | .. |
|---|
| 893 | 981 | #endif |
|---|
| 894 | 982 | [5] = { "zero", 0666, &zero_fops, 0 }, |
|---|
| 895 | 983 | [7] = { "full", 0666, &full_fops, 0 }, |
|---|
| 896 | | - [8] = { "random", 0666, &random_fops, 0 }, |
|---|
| 897 | | - [9] = { "urandom", 0666, &urandom_fops, 0 }, |
|---|
| 984 | + [8] = { "random", 0666, &random_fops, FMODE_NOWAIT }, |
|---|
| 985 | + [9] = { "urandom", 0666, &urandom_fops, FMODE_NOWAIT }, |
|---|
| 898 | 986 | #ifdef CONFIG_PRINTK |
|---|
| 899 | 987 | [11] = { "kmsg", 0644, &kmsg_fops, 0 }, |
|---|
| 900 | 988 | #endif |
|---|
| .. | .. |
|---|
| 936 | 1024 | |
|---|
| 937 | 1025 | static struct class *mem_class; |
|---|
| 938 | 1026 | |
|---|
| 1027 | +static int devmem_fs_init_fs_context(struct fs_context *fc) |
|---|
| 1028 | +{ |
|---|
| 1029 | + return init_pseudo(fc, DEVMEM_MAGIC) ? 0 : -ENOMEM; |
|---|
| 1030 | +} |
|---|
| 1031 | + |
|---|
| 1032 | +static struct file_system_type devmem_fs_type = { |
|---|
| 1033 | + .name = "devmem", |
|---|
| 1034 | + .owner = THIS_MODULE, |
|---|
| 1035 | + .init_fs_context = devmem_fs_init_fs_context, |
|---|
| 1036 | + .kill_sb = kill_anon_super, |
|---|
| 1037 | +}; |
|---|
| 1038 | + |
|---|
| 1039 | +static int devmem_init_inode(void) |
|---|
| 1040 | +{ |
|---|
| 1041 | + static struct vfsmount *devmem_vfs_mount; |
|---|
| 1042 | + static int devmem_fs_cnt; |
|---|
| 1043 | + struct inode *inode; |
|---|
| 1044 | + int rc; |
|---|
| 1045 | + |
|---|
| 1046 | + rc = simple_pin_fs(&devmem_fs_type, &devmem_vfs_mount, &devmem_fs_cnt); |
|---|
| 1047 | + if (rc < 0) { |
|---|
| 1048 | + pr_err("Cannot mount /dev/mem pseudo filesystem: %d\n", rc); |
|---|
| 1049 | + return rc; |
|---|
| 1050 | + } |
|---|
| 1051 | + |
|---|
| 1052 | + inode = alloc_anon_inode(devmem_vfs_mount->mnt_sb); |
|---|
| 1053 | + if (IS_ERR(inode)) { |
|---|
| 1054 | + rc = PTR_ERR(inode); |
|---|
| 1055 | + pr_err("Cannot allocate inode for /dev/mem: %d\n", rc); |
|---|
| 1056 | + simple_release_fs(&devmem_vfs_mount, &devmem_fs_cnt); |
|---|
| 1057 | + return rc; |
|---|
| 1058 | + } |
|---|
| 1059 | + |
|---|
| 1060 | + /* |
|---|
| 1061 | + * Publish /dev/mem initialized. |
|---|
| 1062 | + * Pairs with smp_load_acquire() in revoke_devmem(). |
|---|
| 1063 | + */ |
|---|
| 1064 | + smp_store_release(&devmem_inode, inode); |
|---|
| 1065 | + |
|---|
| 1066 | + return 0; |
|---|
| 1067 | +} |
|---|
| 1068 | + |
|---|
| 939 | 1069 | static int __init chr_dev_init(void) |
|---|
| 940 | 1070 | { |
|---|
| 941 | 1071 | int minor; |
|---|
| .. | .. |
|---|
| 957 | 1087 | */ |
|---|
| 958 | 1088 | if ((minor == DEVPORT_MINOR) && !arch_has_dev_port()) |
|---|
| 959 | 1089 | continue; |
|---|
| 1090 | + if ((minor == DEVMEM_MINOR) && devmem_init_inode() != 0) |
|---|
| 1091 | + continue; |
|---|
| 960 | 1092 | |
|---|
| 961 | 1093 | device_create(mem_class, NULL, MKDEV(MEM_MAJOR, minor), |
|---|
| 962 | 1094 | NULL, devlist[minor].name); |
|---|