| @@ -21,6 +21,7 @@ · 20 unmodified lines |
| 21 | 21 | #include <linux/ftrace_event.h> |
| 22 | 22 | #include <linux/init.h> |
| 23 | 23 | #include <linux/kallsyms.h> |
| 24 | +#include <linux/file.h> |
| 24 | 25 | #include <linux/fs.h> |
| 25 | 26 | #include <linux/sysfs.h> |
| 26 | 27 | #include <linux/kernel.h> |
| @@ -2425,18 +2426,17 @@ static inline void kmemleak_load_module(const struct module *mod, · 2398 unmodified lines |
| 2425 | 2426 | #endif |
| 2426 | 2427 | |
| 2427 | 2428 | #ifdef CONFIG_MODULE_SIG |
| 2428 | | −static int module_sig_check(struct load_info *info, |
| 2429 | | − const void *mod, unsigned long *_len) |
| 2429 | +static int module_sig_check(struct load_info *info) |
| 2430 | 2430 | { |
| 2431 | 2431 | int err = -ENOKEY; |
| 2432 | | − unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1; |
| 2433 | | − unsigned long len = *_len; |
| 2432 | + const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1; |
| 2433 | + const void *mod = info->hdr; |
| 2434 | 2434 | |
| 2435 | | − if (len > markerlen && |
| 2436 | | − memcmp(mod + len - markerlen, MODULE_SIG_STRING, markerlen) == 0) { |
| 2435 | + if (info->len > markerlen && |
| 2436 | + memcmp(mod + info->len - markerlen, MODULE_SIG_STRING, markerlen) == 0) { |
| 2437 | 2437 | /* We truncate the module to discard the signature */ |
| 2438 | | − *_len -= markerlen; |
| 2439 | | − err = mod_verify_sig(mod, _len); |
| 2438 | + info->len -= markerlen; |
| 2439 | + err = mod_verify_sig(mod, &info->len); |
| 2440 | 2440 | } |
| 2441 | 2441 | |
| 2442 | 2442 | if (!err) { |
| @@ -2454,59 +2454,97 @@ static int module_sig_check(struct load_info *info, · 11 unmodified lines |
| 2454 | 2454 | return err; |
| 2455 | 2455 | } |
| 2456 | 2456 | #else /* !CONFIG_MODULE_SIG */ |
| 2457 | | −static int module_sig_check(struct load_info *info, |
| 2458 | | − void *mod, unsigned long *len) |
| 2457 | +static int module_sig_check(struct load_info *info) |
| 2459 | 2458 | { |
| 2460 | 2459 | return 0; |
| 2461 | 2460 | } |
| 2462 | 2461 | #endif /* !CONFIG_MODULE_SIG */ |
| 2463 | 2462 | |
| 2464 | | −/* Sets info->hdr, info->len and info->sig_ok. */ |
| 2465 | | −static int copy_and_check(struct load_info *info, |
| 2466 | | − const void __user *umod, unsigned long len, |
| 2467 | | − const char __user *uargs) |
| 2463 | +/* Sanity checks against invalid binaries, wrong arch, weird elf version. */ |
| 2464 | +static int elf_header_check(struct load_info *info) |
| 2468 | 2465 | { |
| 2469 | | − int err; |
| 2470 | | − Elf_Ehdr *hdr; |
| 2466 | + if (info->len < sizeof(*(info->hdr))) |
| 2467 | + return -ENOEXEC; |
| 2468 | + |
| 2469 | + if (memcmp(info->hdr->e_ident, ELFMAG, SELFMAG) != 0 |
| 2470 | + || info->hdr->e_type != ET_REL |
| 2471 | + || !elf_check_arch(info->hdr) |
| 2472 | + || info->hdr->e_shentsize != sizeof(Elf_Shdr)) |
| 2473 | + return -ENOEXEC; |
| 2474 | + |
| 2475 | + if (info->hdr->e_shoff >= info->len |
| 2476 | + || (info->hdr->e_shnum * sizeof(Elf_Shdr) > |
| 2477 | + info->len - info->hdr->e_shoff)) |
| 2478 | + return -ENOEXEC; |
| 2471 | 2479 | |
| 2472 | | − if (len < sizeof(*hdr)) |
| 2480 | + return 0; |
| 2481 | +} |
| 2482 | + |
| 2483 | +/* Sets info->hdr and info->len. */ |
| 2484 | +static int copy_module_from_user(const void __user *umod, unsigned long len, |
| 2485 | + struct load_info *info) |
| 2486 | +{ |
| 2487 | + info->len = len; |
| 2488 | + if (info->len < sizeof(*(info->hdr))) |
| 2473 | 2489 | return -ENOEXEC; |
| 2474 | 2490 | |
| 2475 | 2491 | /* Suck in entire file: we'll want most of it. */ |
| 2476 | | − if ((hdr = vmalloc(len)) == NULL) |
| 2492 | + info->hdr = vmalloc(info->len); |
| 2493 | + if (!info->hdr) |
| 2477 | 2494 | return -ENOMEM; |
| 2478 | 2495 | |
| 2479 | | − if (copy_from_user(hdr, umod, len) != 0) { |
| 2480 | | − err = -EFAULT; |
| 2481 | | − goto free_hdr; |
| 2496 | + if (copy_from_user(info->hdr, umod, info->len) != 0) { |
| 2497 | + vfree(info->hdr); |
| 2498 | + return -EFAULT; |
| 2482 | 2499 | } |
| 2483 | 2500 | |
| 2484 | | − err = module_sig_check(info, hdr, &len); |
| 2501 | + return 0; |
| 2502 | +} |
| 2503 | + |
| 2504 | +/* Sets info->hdr and info->len. */ |
| 2505 | +static int copy_module_from_fd(int fd, struct load_info *info) |
| 2506 | +{ |
| 2507 | + struct file *file; |
| 2508 | + int err; |
| 2509 | + struct kstat stat; |
| 2510 | + loff_t pos; |
| 2511 | + ssize_t bytes = 0; |
| 2512 | + |
| 2513 | + file = fget(fd); |
| 2514 | + if (!file) |
| 2515 | + return -ENOEXEC; |
| 2516 | + |
| 2517 | + err = vfs_getattr(file->f_vfsmnt, file->f_dentry, &stat); |
| 2485 | 2518 | if (err) |
| 2486 | | − goto free_hdr; |
| 2519 | + goto out; |
| 2487 | 2520 | |
| 2488 | | − /* Sanity checks against insmoding binaries or wrong arch, |
| 2489 | | − weird elf version */ |
| 2490 | | − if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0 |
| 2491 | | − || hdr->e_type != ET_REL |
| 2492 | | − || !elf_check_arch(hdr) |
| 2493 | | − || hdr->e_shentsize != sizeof(Elf_Shdr)) { |
| 2494 | | − err = -ENOEXEC; |
| 2495 | | − goto free_hdr; |
| 2521 | + if (stat.size > INT_MAX) { |
| 2522 | + err = -EFBIG; |
| 2523 | + goto out; |
| 2496 | 2524 | } |
| 2497 | | − |
| 2498 | | − if (hdr->e_shoff >= len || |
| 2499 | | − hdr->e_shnum * sizeof(Elf_Shdr) > len - hdr->e_shoff) { |
| 2500 | | − err = -ENOEXEC; |
| 2501 | | − goto free_hdr; |
| 2525 | + info->hdr = vmalloc(stat.size); |
| 2526 | + if (!info->hdr) { |
| 2527 | + err = -ENOMEM; |
| 2528 | + goto out; |
| 2502 | 2529 | } |
| 2503 | 2530 | |
| 2504 | | − info->hdr = hdr; |
| 2505 | | − info->len = len; |
| 2506 | | − return 0; |
| 2531 | + pos = 0; |
| 2532 | + while (pos < stat.size) { |
| 2533 | + bytes = kernel_read(file, pos, (char *)(info->hdr) + pos, |
| 2534 | + stat.size - pos); |
| 2535 | + if (bytes < 0) { |
| 2536 | + vfree(info->hdr); |
| 2537 | + err = bytes; |
| 2538 | + goto out; |
| 2539 | + } |
| 2540 | + if (bytes == 0) |
| 2541 | + break; |
| 2542 | + pos += bytes; |
| 2543 | + } |
| 2544 | + info->len = pos; |
| 2507 | 2545 | |
| 2508 | | −free_hdr: |
| 2509 | | − vfree(hdr); |
| 2546 | +out: |
| 2547 | + fput(file); |
| 2510 | 2548 | return err; |
| 2511 | 2549 | } |
| 2512 | 2550 | |
| @@ -2945,33 +2983,123 @@ static bool finished_loading(const char *name) · 432 unmodified lines |
| 2945 | 2983 | return ret; |
| 2946 | 2984 | } |
| 2947 | 2985 | |
| 2986 | +/* Call module constructors. */ |
| 2987 | +static void do_mod_ctors(struct module *mod) |
| 2988 | +{ |
| 2989 | +#ifdef CONFIG_CONSTRUCTORS |
| 2990 | + unsigned long i; |
| 2991 | + |
| 2992 | + for (i = 0; i < mod->num_ctors; i++) |
| 2993 | + mod->ctors[i](); |
| 2994 | +#endif |
| 2995 | +} |
| 2996 | + |
| 2997 | +/* This is where the real work happens */ |
| 2998 | +static int do_init_module(struct module *mod) |
| 2999 | +{ |
| 3000 | + int ret = 0; |
| 3001 | + |
| 3002 | + blocking_notifier_call_chain(&module_notify_list, |
| 3003 | + MODULE_STATE_COMING, mod); |
| 3004 | + |
| 3005 | + /* Set RO and NX regions for core */ |
| 3006 | + set_section_ro_nx(mod->module_core, |
| 3007 | + mod->core_text_size, |
| 3008 | + mod->core_ro_size, |
| 3009 | + mod->core_size); |
| 3010 | + |
| 3011 | + /* Set RO and NX regions for init */ |
| 3012 | + set_section_ro_nx(mod->module_init, |
| 3013 | + mod->init_text_size, |
| 3014 | + mod->init_ro_size, |
| 3015 | + mod->init_size); |
| 3016 | + |
| 3017 | + do_mod_ctors(mod); |
| 3018 | + /* Start the module */ |
| 3019 | + if (mod->init != NULL) |
| 3020 | + ret = do_one_initcall(mod->init); |
| 3021 | + if (ret < 0) { |
| 3022 | + /* Init routine failed: abort. Try to protect us from |
| 3023 | + buggy refcounters. */ |
| 3024 | + mod->state = MODULE_STATE_GOING; |
| 3025 | + synchronize_sched(); |
| 3026 | + module_put(mod); |
| 3027 | + blocking_notifier_call_chain(&module_notify_list, |
| 3028 | + MODULE_STATE_GOING, mod); |
| 3029 | + free_module(mod); |
| 3030 | + wake_up_all(&module_wq); |
| 3031 | + return ret; |
| 3032 | + } |
| 3033 | + if (ret > 0) { |
| 3034 | + printk(KERN_WARNING |
| 3035 | +"%s: '%s'->init suspiciously returned %d, it should follow 0/-E convention\n" |
| 3036 | +"%s: loading module anyway...\n", |
| 3037 | + __func__, mod->name, ret, |
| 3038 | + __func__); |
| 3039 | + dump_stack(); |
| 3040 | + } |
| 3041 | + |
| 3042 | + /* Now it's a first class citizen! */ |
| 3043 | + mod->state = MODULE_STATE_LIVE; |
| 3044 | + blocking_notifier_call_chain(&module_notify_list, |
| 3045 | + MODULE_STATE_LIVE, mod); |
| 3046 | + |
| 3047 | + /* We need to finish all async code before the module init sequence is done */ |
| 3048 | + async_synchronize_full(); |
| 3049 | + |
| 3050 | + mutex_lock(&module_mutex); |
| 3051 | + /* Drop initial reference. */ |
| 3052 | + module_put(mod); |
| 3053 | + trim_init_extable(mod); |
| 3054 | +#ifdef CONFIG_KALLSYMS |
| 3055 | + mod->num_symtab = mod->core_num_syms; |
| 3056 | + mod->symtab = mod->core_symtab; |
| 3057 | + mod->strtab = mod->core_strtab; |
| 3058 | +#endif |
| 3059 | + unset_module_init_ro_nx(mod); |
| 3060 | + module_free(mod, mod->module_init); |
| 3061 | + mod->module_init = NULL; |
| 3062 | + mod->init_size = 0; |
| 3063 | + mod->init_ro_size = 0; |
| 3064 | + mod->init_text_size = 0; |
| 3065 | + mutex_unlock(&module_mutex); |
| 3066 | + wake_up_all(&module_wq); |
| 3067 | + |
| 3068 | + return 0; |
| 3069 | +} |
| 3070 | + |
| 3071 | +static int may_init_module(void) |
| 3072 | +{ |
| 3073 | + if (!capable(CAP_SYS_MODULE) || modules_disabled) |
| 3074 | + return -EPERM; |
| 3075 | + |
| 3076 | + return 0; |
| 3077 | +} |
| 3078 | + |
| 2948 | 3079 | /* Allocate and load the module: note that size of section 0 is always |
| 2949 | 3080 | zero, and we rely on this for optional sections. */ |
| 2950 | | −static struct module *load_module(void __user *umod, |
| 2951 | | − unsigned long len, |
| 2952 | | − const char __user *uargs) |
| 3081 | +static int load_module(struct load_info *info, const char __user *uargs) |
| 2953 | 3082 | { |
| 2954 | | − struct load_info info = { NULL, }; |
| 2955 | 3083 | struct module *mod, *old; |
| 2956 | 3084 | long err; |
| 2957 | 3085 | |
| 2958 | | − pr_debug("load_module: umod=%p, len=%lu, uargs=%p\n", |
| 2959 | | − umod, len, uargs); |
| 3086 | + err = module_sig_check(info); |
| 3087 | + if (err) |
| 3088 | + goto free_copy; |
| 2960 | 3089 | |
| 2961 | | − /* Copy in the blobs from userspace, check they are vaguely sane. */ |
| 2962 | | − err = copy_and_check(&info, umod, len, uargs); |
| 3090 | + err = elf_header_check(info); |
| 2963 | 3091 | if (err) |
| 2964 | | − return ERR_PTR(err); |
| 3092 | + goto free_copy; |
| 2965 | 3093 | |
| 2966 | 3094 | /* Figure out module layout, and allocate all the memory. */ |
| 2967 | | − mod = layout_and_allocate(&info); |
| 3095 | + mod = layout_and_allocate(info); |
| 2968 | 3096 | if (IS_ERR(mod)) { |
| 2969 | 3097 | err = PTR_ERR(mod); |
| 2970 | 3098 | goto free_copy; |
| 2971 | 3099 | } |
| 2972 | 3100 | |
| 2973 | 3101 | #ifdef CONFIG_MODULE_SIG |
| 2974 | | − mod->sig_ok = info.sig_ok; |
| 3102 | + mod->sig_ok = info->sig_ok; |
| 2975 | 3103 | if (!mod->sig_ok) |
| 2976 | 3104 | add_taint_module(mod, TAINT_FORCED_MODULE); |
| 2977 | 3105 | #endif |
| @@ -2983,25 +3111,25 @@ static struct module *load_module(void __user *umod, · 5 unmodified lines |
| 2983 | 3111 | |
| 2984 | 3112 | /* Now we've got everything in the final locations, we can |
| 2985 | 3113 | * find optional sections. */ |
| 2986 | | − find_module_sections(mod, &info); |
| 3114 | + find_module_sections(mod, info); |
| 2987 | 3115 | |
| 2988 | 3116 | err = check_module_license_and_versions(mod); |
| 2989 | 3117 | if (err) |
| 2990 | 3118 | goto free_unload; |
| 2991 | 3119 | |
| 2992 | 3120 | /* Set up MODINFO_ATTR fields */ |
| 2993 | | − setup_modinfo(mod, &info); |
| 3121 | + setup_modinfo(mod, info); |
| 2994 | 3122 | |
| 2995 | 3123 | /* Fix up syms, so that st_value is a pointer to location. */ |
| 2996 | | − err = simplify_symbols(mod, &info); |
| 3124 | + err = simplify_symbols(mod, info); |
| 2997 | 3125 | if (err < 0) |
| 2998 | 3126 | goto free_modinfo; |
| 2999 | 3127 | |
| 3000 | | − err = apply_relocations(mod, &info); |
| 3128 | + err = apply_relocations(mod, info); |
| 3001 | 3129 | if (err < 0) |
| 3002 | 3130 | goto free_modinfo; |
| 3003 | 3131 | |
| 3004 | | − err = post_relocation(mod, &info); |
| 3132 | + err = post_relocation(mod, info); |
| 3005 | 3133 | if (err < 0) |
| 3006 | 3134 | goto free_modinfo; |
| 3007 | 3135 | |
| @@ -3041,14 +3169,14 @@ again: · 33 unmodified lines |
| 3041 | 3169 | } |
| 3042 | 3170 | |
| 3043 | 3171 | /* This has to be done once we're sure module name is unique. */ |
| 3044 | | − dynamic_debug_setup(info.debug, info.num_debug); |
| 3172 | + dynamic_debug_setup(info->debug, info->num_debug); |
| 3045 | 3173 | |
| 3046 | 3174 | /* Find duplicate symbols */ |
| 3047 | 3175 | err = verify_export_symbols(mod); |
| 3048 | 3176 | if (err < 0) |
| 3049 | 3177 | goto ddebug; |
| 3050 | 3178 | |
| 3051 | | − module_bug_finalize(info.hdr, info.sechdrs, mod); |
| 3179 | + module_bug_finalize(info->hdr, info->sechdrs, mod); |
| 3052 | 3180 | list_add_rcu(&mod->list, &modules); |
| 3053 | 3181 | mutex_unlock(&module_mutex); |
| 3054 | 3182 | |
| @@ -3059,16 +3187,17 @@ again: · 4 unmodified lines |
| 3059 | 3187 | goto unlink; |
| 3060 | 3188 | |
| 3061 | 3189 | /* Link in to syfs. */ |
| 3062 | | − err = mod_sysfs_setup(mod, &info, mod->kp, mod->num_kp); |
| 3190 | + err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp); |
| 3063 | 3191 | if (err < 0) |
| 3064 | 3192 | goto unlink; |
| 3065 | 3193 | |
| 3066 | 3194 | /* Get rid of temporary copy. */ |
| 3067 | | − free_copy(&info); |
| 3195 | + free_copy(info); |
| 3068 | 3196 | |
| 3069 | 3197 | /* Done! */ |
| 3070 | 3198 | trace_module_load(mod); |
| 3071 | | − return mod; |
| 3199 | + |
| 3200 | + return do_init_module(mod); |
| 3072 | 3201 | |
| 3073 | 3202 | unlink: |
| 3074 | 3203 | mutex_lock(&module_mutex); |
| @@ -3077,7 +3206,7 @@ again: · 2 unmodified lines |
| 3077 | 3206 | module_bug_cleanup(mod); |
| 3078 | 3207 | wake_up_all(&module_wq); |
| 3079 | 3208 | ddebug: |
| 3080 | | − dynamic_debug_remove(info.debug); |
| 3209 | + dynamic_debug_remove(info->debug); |
| 3081 | 3210 | unlock: |
| 3082 | 3211 | mutex_unlock(&module_mutex); |
| 3083 | 3212 | synchronize_sched(); |
| @@ -3089,106 +3218,48 @@ again: · 5 unmodified lines |
| 3089 | 3218 | free_unload: |
| 3090 | 3219 | module_unload_free(mod); |
| 3091 | 3220 | free_module: |
| 3092 | | − module_deallocate(mod, &info); |
| 3221 | + module_deallocate(mod, info); |
| 3093 | 3222 | free_copy: |
| 3094 | | − free_copy(&info); |
| 3095 | | − return ERR_PTR(err); |
| 3096 | | −} |
| 3097 | | − |
| 3098 | | −/* Call module constructors. */ |
| 3099 | | −static void do_mod_ctors(struct module *mod) |
| 3100 | | −{ |
| 3101 | | −#ifdef CONFIG_CONSTRUCTORS |
| 3102 | | − unsigned long i; |
| 3103 | | − |
| 3104 | | − for (i = 0; i < mod->num_ctors; i++) |
| 3105 | | − mod->ctors[i](); |
| 3106 | | −#endif |
| 3223 | + free_copy(info); |
| 3224 | + return err; |
| 3107 | 3225 | } |
| 3108 | 3226 | |
| 3109 | | −/* This is where the real work happens */ |
| 3110 | 3227 | SYSCALL_DEFINE3(init_module, void __user *, umod, |
| 3111 | 3228 | unsigned long, len, const char __user *, uargs) |
| 3112 | 3229 | { |
| 3113 | | − struct module *mod; |
| 3114 | | − int ret = 0; |
| 3115 | | − |
| 3116 | | − /* Must have permission */ |
| 3117 | | − if (!capable(CAP_SYS_MODULE) || modules_disabled) |
| 3118 | | − return -EPERM; |
| 3230 | + int err; |
| 3231 | + struct load_info info = { }; |
| 3119 | 3232 | |
| 3120 | | − /* Do all the hard work */ |
| 3121 | | − mod = load_module(umod, len, uargs); |
| 3122 | | − if (IS_ERR(mod)) |
| 3123 | | − return PTR_ERR(mod); |
| 3233 | + err = may_init_module(); |
| 3234 | + if (err) |
| 3235 | + return err; |
| 3124 | 3236 | |
| 3125 | | − blocking_notifier_call_chain(&module_notify_list, |
| 3126 | | − MODULE_STATE_COMING, mod); |
| 3237 | + pr_debug("init_module: umod=%p, len=%lu, uargs=%p\n", |
| 3238 | + umod, len, uargs); |
| 3127 | 3239 | |
| 3128 | | − /* Set RO and NX regions for core */ |
| 3129 | | − set_section_ro_nx(mod->module_core, |
| 3130 | | − mod->core_text_size, |
| 3131 | | − mod->core_ro_size, |
| 3132 | | − mod->core_size); |
| 3240 | + err = copy_module_from_user(umod, len, &info); |
| 3241 | + if (err) |
| 3242 | + return err; |
| 3133 | 3243 | |
| 3134 | | − /* Set RO and NX regions for init */ |
| 3135 | | − set_section_ro_nx(mod->module_init, |
| 3136 | | − mod->init_text_size, |
| 3137 | | − mod->init_ro_size, |
| 3138 | | − mod->init_size); |
| 3244 | + return load_module(&info, uargs); |
| 3245 | +} |
| 3139 | 3246 | |
| 3140 | | − do_mod_ctors(mod); |
| 3141 | | − /* Start the module */ |
| 3142 | | − if (mod->init != NULL) |
| 3143 | | − ret = do_one_initcall(mod->init); |
| 3144 | | − if (ret < 0) { |
| 3145 | | − /* Init routine failed: abort. Try to protect us from |
| 3146 | | − buggy refcounters. */ |
| 3147 | | − mod->state = MODULE_STATE_GOING; |
| 3148 | | − synchronize_sched(); |
| 3149 | | − module_put(mod); |
| 3150 | | − blocking_notifier_call_chain(&module_notify_list, |
| 3151 | | − MODULE_STATE_GOING, mod); |
| 3152 | | − free_module(mod); |
| 3153 | | − wake_up_all(&module_wq); |
| 3154 | | − return ret; |
| 3155 | | − } |
| 3156 | | − if (ret > 0) { |
| 3157 | | − printk(KERN_WARNING |
| 3158 | | −"%s: '%s'->init suspiciously returned %d, it should follow 0/-E convention\n" |
| 3159 | | −"%s: loading module anyway...\n", |
| 3160 | | − __func__, mod->name, ret, |
| 3161 | | − __func__); |
| 3162 | | − dump_stack(); |
| 3163 | | − } |
| 3247 | +SYSCALL_DEFINE2(finit_module, int, fd, const char __user *, uargs) |
| 3248 | +{ |
| 3249 | + int err; |
| 3250 | + struct load_info info = { }; |
| 3164 | 3251 | |
| 3165 | | − /* Now it's a first class citizen! */ |
| 3166 | | − mod->state = MODULE_STATE_LIVE; |
| 3167 | | − blocking_notifier_call_chain(&module_notify_list, |
| 3168 | | − MODULE_STATE_LIVE, mod); |
| 3252 | + err = may_init_module(); |
| 3253 | + if (err) |
| 3254 | + return err; |
| 3169 | 3255 | |
| 3170 | | − /* We need to finish all async code before the module init sequence is done */ |
| 3171 | | − async_synchronize_full(); |
| 3256 | + pr_debug("finit_module: fd=%d, uargs=%p\n", fd, uargs); |
| 3172 | 3257 | |
| 3173 | | − mutex_lock(&module_mutex); |
| 3174 | | − /* Drop initial reference. */ |
| 3175 | | − module_put(mod); |
| 3176 | | − trim_init_extable(mod); |
| 3177 | | −#ifdef CONFIG_KALLSYMS |
| 3178 | | − mod->num_symtab = mod->core_num_syms; |
| 3179 | | − mod->symtab = mod->core_symtab; |
| 3180 | | − mod->strtab = mod->core_strtab; |
| 3181 | | −#endif |
| 3182 | | − unset_module_init_ro_nx(mod); |
| 3183 | | − module_free(mod, mod->module_init); |
| 3184 | | − mod->module_init = NULL; |
| 3185 | | − mod->init_size = 0; |
| 3186 | | − mod->init_ro_size = 0; |
| 3187 | | − mod->init_text_size = 0; |
| 3188 | | − mutex_unlock(&module_mutex); |
| 3189 | | − wake_up_all(&module_wq); |
| 3258 | + err = copy_module_from_fd(fd, &info); |
| 3259 | + if (err) |
| 3260 | + return err; |
| 3190 | 3261 | |
| 3191 | | − return 0; |
| 3262 | + return load_module(&info, uargs); |
| 3192 | 3263 | } |
| 3193 | 3264 | |
| 3194 | 3265 | static inline int within(unsigned long addr, void *start, unsigned long size) |