.. | .. |
---|
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); |
---|