diff options
Diffstat (limited to 'drivers/char/mem.c')
-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); |