diff options
Diffstat (limited to 'kernel/module.c')
-rw-r--r-- | kernel/module.c | 27 |
1 files changed, 22 insertions, 5 deletions
diff --git a/kernel/module.c b/kernel/module.c index d8f8ab271c2b..650b038ae520 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -1865,7 +1865,7 @@ static void free_module(struct module *mod) | |||
1865 | kfree(mod->args); | 1865 | kfree(mod->args); |
1866 | percpu_modfree(mod); | 1866 | percpu_modfree(mod); |
1867 | 1867 | ||
1868 | /* Free lock-classes: */ | 1868 | /* Free lock-classes; relies on the preceding sync_rcu(). */ |
1869 | lockdep_free_key_range(mod->module_core, mod->core_size); | 1869 | lockdep_free_key_range(mod->module_core, mod->core_size); |
1870 | 1870 | ||
1871 | /* Finally, free the core (containing the module structure) */ | 1871 | /* Finally, free the core (containing the module structure) */ |
@@ -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 | } |
@@ -3352,9 +3369,6 @@ static int load_module(struct load_info *info, const char __user *uargs, | |||
3352 | module_bug_cleanup(mod); | 3369 | module_bug_cleanup(mod); |
3353 | mutex_unlock(&module_mutex); | 3370 | mutex_unlock(&module_mutex); |
3354 | 3371 | ||
3355 | /* Free lock-classes: */ | ||
3356 | lockdep_free_key_range(mod->module_core, mod->core_size); | ||
3357 | |||
3358 | /* we can't deallocate the module until we clear memory protection */ | 3372 | /* we can't deallocate the module until we clear memory protection */ |
3359 | unset_module_init_ro_nx(mod); | 3373 | unset_module_init_ro_nx(mod); |
3360 | unset_module_core_ro_nx(mod); | 3374 | unset_module_core_ro_nx(mod); |
@@ -3378,6 +3392,9 @@ static int load_module(struct load_info *info, const char __user *uargs, | |||
3378 | synchronize_rcu(); | 3392 | synchronize_rcu(); |
3379 | mutex_unlock(&module_mutex); | 3393 | mutex_unlock(&module_mutex); |
3380 | free_module: | 3394 | free_module: |
3395 | /* Free lock-classes; relies on the preceding sync_rcu() */ | ||
3396 | lockdep_free_key_range(mod->module_core, mod->core_size); | ||
3397 | |||
3381 | module_deallocate(mod, info); | 3398 | module_deallocate(mod, info); |
3382 | free_copy: | 3399 | free_copy: |
3383 | free_copy(info); | 3400 | free_copy(info); |