diff options
| -rw-r--r-- | drivers/char/mem.c | 27 |
1 files changed, 16 insertions, 11 deletions
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index dcf6e31970a1..964ff3b1cff4 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c | |||
| @@ -109,24 +109,26 @@ static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t size) | |||
| 109 | #endif | 109 | #endif |
| 110 | 110 | ||
| 111 | #ifdef CONFIG_NONPROMISC_DEVMEM | 111 | #ifdef CONFIG_NONPROMISC_DEVMEM |
| 112 | static inline int range_is_allowed(unsigned long from, unsigned long to) | 112 | static inline int range_is_allowed(unsigned long pfn, unsigned long size) |
| 113 | { | 113 | { |
| 114 | unsigned long cursor; | 114 | u64 from = ((u64)pfn) << PAGE_SHIFT; |
| 115 | u64 to = from + size; | ||
| 116 | u64 cursor = from; | ||
| 115 | 117 | ||
| 116 | cursor = from >> PAGE_SHIFT; | 118 | while (cursor < to) { |
| 117 | while ((cursor << PAGE_SHIFT) < to) { | 119 | if (!devmem_is_allowed(pfn)) { |
| 118 | if (!devmem_is_allowed(cursor)) { | 120 | printk(KERN_INFO |
| 119 | printk(KERN_INFO "Program %s tried to read /dev/mem " | 121 | "Program %s tried to access /dev/mem between %Lx->%Lx.\n", |
| 120 | "between %lx->%lx.\n", | ||
| 121 | current->comm, from, to); | 122 | current->comm, from, to); |
| 122 | return 0; | 123 | return 0; |
| 123 | } | 124 | } |
| 124 | cursor++; | 125 | cursor += PAGE_SIZE; |
| 126 | pfn++; | ||
| 125 | } | 127 | } |
| 126 | return 1; | 128 | return 1; |
| 127 | } | 129 | } |
| 128 | #else | 130 | #else |
| 129 | static inline int range_is_allowed(unsigned long from, unsigned long to) | 131 | static inline int range_is_allowed(unsigned long pfn, unsigned long size) |
| 130 | { | 132 | { |
| 131 | return 1; | 133 | return 1; |
| 132 | } | 134 | } |
| @@ -181,7 +183,7 @@ static ssize_t read_mem(struct file * file, char __user * buf, | |||
| 181 | */ | 183 | */ |
| 182 | ptr = xlate_dev_mem_ptr(p); | 184 | ptr = xlate_dev_mem_ptr(p); |
| 183 | 185 | ||
| 184 | if (!range_is_allowed(p, p+count)) | 186 | if (!range_is_allowed(p >> PAGE_SHIFT, count)) |
| 185 | return -EPERM; | 187 | return -EPERM; |
| 186 | if (copy_to_user(buf, ptr, sz)) | 188 | if (copy_to_user(buf, ptr, sz)) |
| 187 | return -EFAULT; | 189 | return -EFAULT; |
| @@ -240,7 +242,7 @@ static ssize_t write_mem(struct file * file, const char __user * buf, | |||
| 240 | */ | 242 | */ |
| 241 | ptr = xlate_dev_mem_ptr(p); | 243 | ptr = xlate_dev_mem_ptr(p); |
| 242 | 244 | ||
| 243 | if (!range_is_allowed(p, p+sz)) | 245 | if (!range_is_allowed(p >> PAGE_SHIFT, sz)) |
| 244 | return -EPERM; | 246 | return -EPERM; |
| 245 | copied = copy_from_user(ptr, buf, sz); | 247 | copied = copy_from_user(ptr, buf, sz); |
| 246 | if (copied) { | 248 | if (copied) { |
| @@ -309,6 +311,9 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma) | |||
| 309 | if (!private_mapping_ok(vma)) | 311 | if (!private_mapping_ok(vma)) |
| 310 | return -ENOSYS; | 312 | return -ENOSYS; |
| 311 | 313 | ||
| 314 | if (!range_is_allowed(vma->vm_pgoff, size)) | ||
| 315 | return -EPERM; | ||
| 316 | |||
| 312 | vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, | 317 | vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, |
| 313 | size, | 318 | size, |
| 314 | vma->vm_page_prot); | 319 | vma->vm_page_prot); |
