diff options
Diffstat (limited to 'drivers/char/mem.c')
| -rw-r--r-- | drivers/char/mem.c | 32 |
1 files changed, 27 insertions, 5 deletions
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 964ff3b1cff4..83495885ada0 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c | |||
| @@ -134,6 +134,10 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size) | |||
| 134 | } | 134 | } |
| 135 | #endif | 135 | #endif |
| 136 | 136 | ||
| 137 | void __attribute__((weak)) unxlate_dev_mem_ptr(unsigned long phys, void *addr) | ||
| 138 | { | ||
| 139 | } | ||
| 140 | |||
| 137 | /* | 141 | /* |
| 138 | * This funcion reads the *physical* memory. The f_pos points directly to the | 142 | * This funcion reads the *physical* memory. The f_pos points directly to the |
| 139 | * memory location. | 143 | * memory location. |
| @@ -176,17 +180,25 @@ static ssize_t read_mem(struct file * file, char __user * buf, | |||
| 176 | 180 | ||
| 177 | sz = min_t(unsigned long, sz, count); | 181 | sz = min_t(unsigned long, sz, count); |
| 178 | 182 | ||
| 183 | if (!range_is_allowed(p >> PAGE_SHIFT, count)) | ||
| 184 | return -EPERM; | ||
| 185 | |||
| 179 | /* | 186 | /* |
| 180 | * On ia64 if a page has been mapped somewhere as | 187 | * On ia64 if a page has been mapped somewhere as |
| 181 | * uncached, then it must also be accessed uncached | 188 | * uncached, then it must also be accessed uncached |
| 182 | * by the kernel or data corruption may occur | 189 | * by the kernel or data corruption may occur |
| 183 | */ | 190 | */ |
| 184 | ptr = xlate_dev_mem_ptr(p); | 191 | ptr = xlate_dev_mem_ptr(p); |
| 192 | if (!ptr) | ||
| 193 | return -EFAULT; | ||
| 185 | 194 | ||
| 186 | if (!range_is_allowed(p >> PAGE_SHIFT, count)) | 195 | if (copy_to_user(buf, ptr, sz)) { |
| 187 | return -EPERM; | 196 | unxlate_dev_mem_ptr(p, ptr); |
| 188 | if (copy_to_user(buf, ptr, sz)) | ||
| 189 | return -EFAULT; | 197 | return -EFAULT; |
| 198 | } | ||
| 199 | |||
| 200 | unxlate_dev_mem_ptr(p, ptr); | ||
| 201 | |||
| 190 | buf += sz; | 202 | buf += sz; |
| 191 | p += sz; | 203 | p += sz; |
| 192 | count -= sz; | 204 | count -= sz; |
| @@ -235,22 +247,32 @@ static ssize_t write_mem(struct file * file, const char __user * buf, | |||
| 235 | 247 | ||
| 236 | sz = min_t(unsigned long, sz, count); | 248 | sz = min_t(unsigned long, sz, count); |
| 237 | 249 | ||
| 250 | if (!range_is_allowed(p >> PAGE_SHIFT, sz)) | ||
| 251 | return -EPERM; | ||
| 252 | |||
| 238 | /* | 253 | /* |
| 239 | * On ia64 if a page has been mapped somewhere as | 254 | * On ia64 if a page has been mapped somewhere as |
| 240 | * uncached, then it must also be accessed uncached | 255 | * uncached, then it must also be accessed uncached |
| 241 | * by the kernel or data corruption may occur | 256 | * by the kernel or data corruption may occur |
| 242 | */ | 257 | */ |
| 243 | ptr = xlate_dev_mem_ptr(p); | 258 | ptr = xlate_dev_mem_ptr(p); |
| 259 | if (!ptr) { | ||
| 260 | if (written) | ||
| 261 | break; | ||
| 262 | return -EFAULT; | ||
| 263 | } | ||
| 244 | 264 | ||
| 245 | if (!range_is_allowed(p >> PAGE_SHIFT, sz)) | ||
| 246 | return -EPERM; | ||
| 247 | copied = copy_from_user(ptr, buf, sz); | 265 | copied = copy_from_user(ptr, buf, sz); |
| 248 | if (copied) { | 266 | if (copied) { |
| 249 | written += sz - copied; | 267 | written += sz - copied; |
| 268 | unxlate_dev_mem_ptr(p, ptr); | ||
| 250 | if (written) | 269 | if (written) |
| 251 | break; | 270 | break; |
| 252 | return -EFAULT; | 271 | return -EFAULT; |
| 253 | } | 272 | } |
| 273 | |||
| 274 | unxlate_dev_mem_ptr(p, ptr); | ||
| 275 | |||
| 254 | buf += sz; | 276 | buf += sz; |
| 255 | p += sz; | 277 | p += sz; |
| 256 | count -= sz; | 278 | count -= sz; |
