diff options
Diffstat (limited to 'kernel/module.c')
| -rw-r--r-- | kernel/module.c | 19 |
1 files changed, 18 insertions, 1 deletions
diff --git a/kernel/module.c b/kernel/module.c index 99fdf94efce8..ec53f594e9c9 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -2479,6 +2479,23 @@ static int elf_header_check(struct load_info *info) | |||
| 2479 | return 0; | 2479 | return 0; |
| 2480 | } | 2480 | } |
| 2481 | 2481 | ||
| 2482 | #define COPY_CHUNK_SIZE (16*PAGE_SIZE) | ||
| 2483 | |||
| 2484 | static int copy_chunked_from_user(void *dst, const void __user *usrc, unsigned long len) | ||
| 2485 | { | ||
| 2486 | do { | ||
| 2487 | unsigned long n = min(len, COPY_CHUNK_SIZE); | ||
| 2488 | |||
| 2489 | if (copy_from_user(dst, usrc, n) != 0) | ||
| 2490 | return -EFAULT; | ||
| 2491 | cond_resched(); | ||
| 2492 | dst += n; | ||
| 2493 | usrc += n; | ||
| 2494 | len -= n; | ||
| 2495 | } while (len); | ||
| 2496 | return 0; | ||
| 2497 | } | ||
| 2498 | |||
| 2482 | /* Sets info->hdr and info->len. */ | 2499 | /* Sets info->hdr and info->len. */ |
| 2483 | static int copy_module_from_user(const void __user *umod, unsigned long len, | 2500 | static int copy_module_from_user(const void __user *umod, unsigned long len, |
| 2484 | struct load_info *info) | 2501 | struct load_info *info) |
| @@ -2498,7 +2515,7 @@ static int copy_module_from_user(const void __user *umod, unsigned long len, | |||
| 2498 | if (!info->hdr) | 2515 | if (!info->hdr) |
| 2499 | return -ENOMEM; | 2516 | return -ENOMEM; |
| 2500 | 2517 | ||
| 2501 | if (copy_from_user(info->hdr, umod, info->len) != 0) { | 2518 | if (copy_chunked_from_user(info->hdr, umod, info->len) != 0) { |
| 2502 | vfree(info->hdr); | 2519 | vfree(info->hdr); |
| 2503 | return -EFAULT; | 2520 | return -EFAULT; |
| 2504 | } | 2521 | } |
