diff options
Diffstat (limited to 'kernel/module.c')
-rw-r--r-- | kernel/module.c | 224 |
1 files changed, 125 insertions, 99 deletions
diff --git a/kernel/module.c b/kernel/module.c index 60cdd0459eac..fb11e2a88233 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -115,6 +115,8 @@ struct load_info { | |||
115 | unsigned long len; | 115 | unsigned long len; |
116 | Elf_Shdr *sechdrs; | 116 | Elf_Shdr *sechdrs; |
117 | char *secstrings, *args, *strtab; | 117 | char *secstrings, *args, *strtab; |
118 | unsigned long *strmap; | ||
119 | unsigned long symoffs, stroffs; | ||
118 | struct { | 120 | struct { |
119 | unsigned int sym, str, mod, vers, info, pcpu; | 121 | unsigned int sym, str, mod, vers, info, pcpu; |
120 | } index; | 122 | } index; |
@@ -402,7 +404,8 @@ static int percpu_modalloc(struct module *mod, | |||
402 | mod->percpu = __alloc_reserved_percpu(size, align); | 404 | mod->percpu = __alloc_reserved_percpu(size, align); |
403 | if (!mod->percpu) { | 405 | if (!mod->percpu) { |
404 | printk(KERN_WARNING | 406 | printk(KERN_WARNING |
405 | "Could not allocate %lu bytes percpu data\n", size); | 407 | "%s: Could not allocate %lu bytes percpu data\n", |
408 | mod->name, size); | ||
406 | return -ENOMEM; | 409 | return -ENOMEM; |
407 | } | 410 | } |
408 | mod->percpu_size = size; | 411 | mod->percpu_size = size; |
@@ -2032,10 +2035,7 @@ static unsigned long layout_symtab(struct module *mod, | |||
2032 | return symoffs; | 2035 | return symoffs; |
2033 | } | 2036 | } |
2034 | 2037 | ||
2035 | static void add_kallsyms(struct module *mod, struct load_info *info, | 2038 | static void add_kallsyms(struct module *mod, struct load_info *info) |
2036 | unsigned long symoffs, | ||
2037 | unsigned long stroffs, | ||
2038 | unsigned long *strmap) | ||
2039 | { | 2039 | { |
2040 | unsigned int i, ndst; | 2040 | unsigned int i, ndst; |
2041 | const Elf_Sym *src; | 2041 | const Elf_Sym *src; |
@@ -2052,21 +2052,22 @@ static void add_kallsyms(struct module *mod, struct load_info *info, | |||
2052 | for (i = 0; i < mod->num_symtab; i++) | 2052 | for (i = 0; i < mod->num_symtab; i++) |
2053 | mod->symtab[i].st_info = elf_type(&mod->symtab[i], info); | 2053 | mod->symtab[i].st_info = elf_type(&mod->symtab[i], info); |
2054 | 2054 | ||
2055 | mod->core_symtab = dst = mod->module_core + symoffs; | 2055 | mod->core_symtab = dst = mod->module_core + info->symoffs; |
2056 | src = mod->symtab; | 2056 | src = mod->symtab; |
2057 | *dst = *src; | 2057 | *dst = *src; |
2058 | for (ndst = i = 1; i < mod->num_symtab; ++i, ++src) { | 2058 | for (ndst = i = 1; i < mod->num_symtab; ++i, ++src) { |
2059 | if (!is_core_symbol(src, info->sechdrs, info->hdr->e_shnum)) | 2059 | if (!is_core_symbol(src, info->sechdrs, info->hdr->e_shnum)) |
2060 | continue; | 2060 | continue; |
2061 | dst[ndst] = *src; | 2061 | dst[ndst] = *src; |
2062 | dst[ndst].st_name = bitmap_weight(strmap, dst[ndst].st_name); | 2062 | dst[ndst].st_name = bitmap_weight(info->strmap, |
2063 | dst[ndst].st_name); | ||
2063 | ++ndst; | 2064 | ++ndst; |
2064 | } | 2065 | } |
2065 | mod->core_num_syms = ndst; | 2066 | mod->core_num_syms = ndst; |
2066 | 2067 | ||
2067 | mod->core_strtab = s = mod->module_core + stroffs; | 2068 | mod->core_strtab = s = mod->module_core + info->stroffs; |
2068 | for (*s = 0, i = 1; i < info->sechdrs[info->index.str].sh_size; ++i) | 2069 | for (*s = 0, i = 1; i < info->sechdrs[info->index.str].sh_size; ++i) |
2069 | if (test_bit(i, strmap)) | 2070 | if (test_bit(i, info->strmap)) |
2070 | *++s = mod->strtab[i]; | 2071 | *++s = mod->strtab[i]; |
2071 | } | 2072 | } |
2072 | #else | 2073 | #else |
@@ -2082,10 +2083,7 @@ static inline unsigned long layout_symtab(struct module *mod, | |||
2082 | return 0; | 2083 | return 0; |
2083 | } | 2084 | } |
2084 | 2085 | ||
2085 | static void add_kallsyms(struct module *mod, struct load_info *info, | 2086 | static void add_kallsyms(struct module *mod, struct load_info *info) |
2086 | unsigned long symoffs, | ||
2087 | unsigned long stroffs, | ||
2088 | unsigned long *strmap) | ||
2089 | { | 2087 | { |
2090 | } | 2088 | } |
2091 | #endif /* CONFIG_KALLSYMS */ | 2089 | #endif /* CONFIG_KALLSYMS */ |
@@ -2150,8 +2148,10 @@ static inline void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr, | |||
2150 | } | 2148 | } |
2151 | #endif | 2149 | #endif |
2152 | 2150 | ||
2153 | /* Sets info->hdr and info->len. */ | 2151 | /* Sets info->hdr, info->len and info->args. */ |
2154 | static int copy_and_check(struct load_info *info, const void __user *umod, unsigned long len) | 2152 | static int copy_and_check(struct load_info *info, |
2153 | const void __user *umod, unsigned long len, | ||
2154 | const char __user *uargs) | ||
2155 | { | 2155 | { |
2156 | int err; | 2156 | int err; |
2157 | Elf_Ehdr *hdr; | 2157 | Elf_Ehdr *hdr; |
@@ -2183,6 +2183,14 @@ static int copy_and_check(struct load_info *info, const void __user *umod, unsig | |||
2183 | err = -ENOEXEC; | 2183 | err = -ENOEXEC; |
2184 | goto free_hdr; | 2184 | goto free_hdr; |
2185 | } | 2185 | } |
2186 | |||
2187 | /* Now copy in args */ | ||
2188 | info->args = strndup_user(uargs, ~0UL >> 1); | ||
2189 | if (IS_ERR(info->args)) { | ||
2190 | err = PTR_ERR(info->args); | ||
2191 | goto free_hdr; | ||
2192 | } | ||
2193 | |||
2186 | info->hdr = hdr; | 2194 | info->hdr = hdr; |
2187 | info->len = len; | 2195 | info->len = len; |
2188 | return 0; | 2196 | return 0; |
@@ -2192,6 +2200,12 @@ free_hdr: | |||
2192 | return err; | 2200 | return err; |
2193 | } | 2201 | } |
2194 | 2202 | ||
2203 | static void free_copy(struct load_info *info) | ||
2204 | { | ||
2205 | kfree(info->args); | ||
2206 | vfree(info->hdr); | ||
2207 | } | ||
2208 | |||
2195 | static int rewrite_section_headers(struct load_info *info) | 2209 | static int rewrite_section_headers(struct load_info *info) |
2196 | { | 2210 | { |
2197 | unsigned int i; | 2211 | unsigned int i; |
@@ -2385,9 +2399,9 @@ static void find_module_sections(struct module *mod, Elf_Ehdr *hdr, | |||
2385 | mod->name); | 2399 | mod->name); |
2386 | } | 2400 | } |
2387 | 2401 | ||
2388 | static struct module *move_module(struct module *mod, | 2402 | static int move_module(struct module *mod, |
2389 | Elf_Ehdr *hdr, Elf_Shdr *sechdrs, | 2403 | Elf_Ehdr *hdr, Elf_Shdr *sechdrs, |
2390 | const char *secstrings, unsigned modindex) | 2404 | const char *secstrings, unsigned modindex) |
2391 | { | 2405 | { |
2392 | int i; | 2406 | int i; |
2393 | void *ptr; | 2407 | void *ptr; |
@@ -2401,7 +2415,7 @@ static struct module *move_module(struct module *mod, | |||
2401 | */ | 2415 | */ |
2402 | kmemleak_not_leak(ptr); | 2416 | kmemleak_not_leak(ptr); |
2403 | if (!ptr) | 2417 | if (!ptr) |
2404 | return ERR_PTR(-ENOMEM); | 2418 | return -ENOMEM; |
2405 | 2419 | ||
2406 | memset(ptr, 0, mod->core_size); | 2420 | memset(ptr, 0, mod->core_size); |
2407 | mod->module_core = ptr; | 2421 | mod->module_core = ptr; |
@@ -2416,7 +2430,7 @@ static struct module *move_module(struct module *mod, | |||
2416 | kmemleak_ignore(ptr); | 2430 | kmemleak_ignore(ptr); |
2417 | if (!ptr && mod->init_size) { | 2431 | if (!ptr && mod->init_size) { |
2418 | module_free(mod, mod->module_core); | 2432 | module_free(mod, mod->module_core); |
2419 | return ERR_PTR(-ENOMEM); | 2433 | return -ENOMEM; |
2420 | } | 2434 | } |
2421 | memset(ptr, 0, mod->init_size); | 2435 | memset(ptr, 0, mod->init_size); |
2422 | mod->module_init = ptr; | 2436 | mod->module_init = ptr; |
@@ -2443,10 +2457,8 @@ static struct module *move_module(struct module *mod, | |||
2443 | DEBUGP("\t0x%lx %s\n", | 2457 | DEBUGP("\t0x%lx %s\n", |
2444 | sechdrs[i].sh_addr, secstrings + sechdrs[i].sh_name); | 2458 | sechdrs[i].sh_addr, secstrings + sechdrs[i].sh_name); |
2445 | } | 2459 | } |
2446 | /* Module has been moved. */ | 2460 | |
2447 | mod = (void *)sechdrs[modindex].sh_addr; | 2461 | return 0; |
2448 | kmemleak_load_module(mod, hdr, sechdrs, secstrings); | ||
2449 | return mod; | ||
2450 | } | 2462 | } |
2451 | 2463 | ||
2452 | static int check_module_license_and_versions(struct module *mod, | 2464 | static int check_module_license_and_versions(struct module *mod, |
@@ -2503,87 +2515,107 @@ static void flush_module_icache(const struct module *mod) | |||
2503 | set_fs(old_fs); | 2515 | set_fs(old_fs); |
2504 | } | 2516 | } |
2505 | 2517 | ||
2506 | /* Allocate and load the module: note that size of section 0 is always | 2518 | static struct module *layout_and_allocate(struct load_info *info) |
2507 | zero, and we rely on this for optional sections. */ | ||
2508 | static noinline struct module *load_module(void __user *umod, | ||
2509 | unsigned long len, | ||
2510 | const char __user *uargs) | ||
2511 | { | 2519 | { |
2512 | struct load_info info = { NULL, }; | 2520 | /* Module within temporary copy. */ |
2513 | struct module *mod; | 2521 | struct module *mod; |
2514 | long err; | 2522 | int err; |
2515 | unsigned long symoffs, stroffs, *strmap; | ||
2516 | void __percpu *percpu; | ||
2517 | struct _ddebug *debug = NULL; | ||
2518 | unsigned int num_debug = 0; | ||
2519 | 2523 | ||
2520 | DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n", | 2524 | mod = setup_load_info(info); |
2521 | umod, len, uargs); | 2525 | if (IS_ERR(mod)) |
2526 | return mod; | ||
2522 | 2527 | ||
2523 | err = copy_and_check(&info, umod, len); | 2528 | err = check_modinfo(mod, info->sechdrs, info->index.info, info->index.vers); |
2524 | if (err) | 2529 | if (err) |
2525 | return ERR_PTR(err); | 2530 | return ERR_PTR(err); |
2526 | 2531 | ||
2527 | mod = setup_load_info(&info); | ||
2528 | if (IS_ERR(mod)) { | ||
2529 | err = PTR_ERR(mod); | ||
2530 | goto free_hdr; | ||
2531 | } | ||
2532 | |||
2533 | err = check_modinfo(mod, info.sechdrs, info.index.info, info.index.vers); | ||
2534 | if (err) | ||
2535 | goto free_hdr; | ||
2536 | |||
2537 | /* Now copy in args */ | ||
2538 | info.args = strndup_user(uargs, ~0UL >> 1); | ||
2539 | if (IS_ERR(info.args)) { | ||
2540 | err = PTR_ERR(info.args); | ||
2541 | goto free_hdr; | ||
2542 | } | ||
2543 | |||
2544 | strmap = kzalloc(BITS_TO_LONGS(info.sechdrs[info.index.str].sh_size) | ||
2545 | * sizeof(long), GFP_KERNEL); | ||
2546 | if (!strmap) { | ||
2547 | err = -ENOMEM; | ||
2548 | goto free_mod; | ||
2549 | } | ||
2550 | |||
2551 | mod->state = MODULE_STATE_COMING; | ||
2552 | |||
2553 | /* Allow arches to frob section contents and sizes. */ | 2532 | /* Allow arches to frob section contents and sizes. */ |
2554 | err = module_frob_arch_sections(info.hdr, info.sechdrs, info.secstrings, mod); | 2533 | err = module_frob_arch_sections(info->hdr, info->sechdrs, info->secstrings, mod); |
2555 | if (err < 0) | 2534 | if (err < 0) |
2556 | goto free_mod; | 2535 | goto free_args; |
2557 | 2536 | ||
2558 | if (info.index.pcpu) { | 2537 | if (info->index.pcpu) { |
2559 | /* We have a special allocation for this section. */ | 2538 | /* We have a special allocation for this section. */ |
2560 | err = percpu_modalloc(mod, info.sechdrs[info.index.pcpu].sh_size, | 2539 | err = percpu_modalloc(mod, info->sechdrs[info->index.pcpu].sh_size, |
2561 | info.sechdrs[info.index.pcpu].sh_addralign); | 2540 | info->sechdrs[info->index.pcpu].sh_addralign); |
2562 | if (err) | 2541 | if (err) |
2563 | goto free_mod; | 2542 | goto free_args; |
2564 | info.sechdrs[info.index.pcpu].sh_flags &= ~(unsigned long)SHF_ALLOC; | 2543 | info->sechdrs[info->index.pcpu].sh_flags &= ~(unsigned long)SHF_ALLOC; |
2565 | } | 2544 | } |
2566 | /* Keep this around for failure path. */ | ||
2567 | percpu = mod_percpu(mod); | ||
2568 | 2545 | ||
2569 | /* Determine total sizes, and put offsets in sh_entsize. For now | 2546 | /* Determine total sizes, and put offsets in sh_entsize. For now |
2570 | this is done generically; there doesn't appear to be any | 2547 | this is done generically; there doesn't appear to be any |
2571 | special cases for the architectures. */ | 2548 | special cases for the architectures. */ |
2572 | layout_sections(mod, info.hdr, info.sechdrs, info.secstrings); | 2549 | layout_sections(mod, info->hdr, info->sechdrs, info->secstrings); |
2573 | symoffs = layout_symtab(mod, info.sechdrs, info.index.sym, info.index.str, info.hdr, | 2550 | |
2574 | info.secstrings, &stroffs, strmap); | 2551 | info->strmap = kzalloc(BITS_TO_LONGS(info->sechdrs[info->index.str].sh_size) |
2552 | * sizeof(long), GFP_KERNEL); | ||
2553 | if (!info->strmap) { | ||
2554 | err = -ENOMEM; | ||
2555 | goto free_percpu; | ||
2556 | } | ||
2557 | info->symoffs = layout_symtab(mod, info->sechdrs, info->index.sym, info->index.str, info->hdr, | ||
2558 | info->secstrings, &info->stroffs, info->strmap); | ||
2575 | 2559 | ||
2576 | /* Allocate and move to the final place */ | 2560 | /* Allocate and move to the final place */ |
2577 | mod = move_module(mod, info.hdr, info.sechdrs, info.secstrings, info.index.mod); | 2561 | err = move_module(mod, info->hdr, info->sechdrs, info->secstrings, info->index.mod); |
2562 | if (err) | ||
2563 | goto free_strmap; | ||
2564 | |||
2565 | /* Module has been copied to its final place now: return it. */ | ||
2566 | mod = (void *)info->sechdrs[info->index.mod].sh_addr; | ||
2567 | kmemleak_load_module(mod, info->hdr, info->sechdrs, info->secstrings); | ||
2568 | return mod; | ||
2569 | |||
2570 | free_strmap: | ||
2571 | kfree(info->strmap); | ||
2572 | free_percpu: | ||
2573 | percpu_modfree(mod); | ||
2574 | free_args: | ||
2575 | kfree(info->args); | ||
2576 | return ERR_PTR(err); | ||
2577 | } | ||
2578 | |||
2579 | /* mod is no longer valid after this! */ | ||
2580 | static void module_deallocate(struct module *mod, struct load_info *info) | ||
2581 | { | ||
2582 | kfree(info->strmap); | ||
2583 | percpu_modfree(mod); | ||
2584 | module_free(mod, mod->module_init); | ||
2585 | module_free(mod, mod->module_core); | ||
2586 | } | ||
2587 | |||
2588 | /* Allocate and load the module: note that size of section 0 is always | ||
2589 | zero, and we rely on this for optional sections. */ | ||
2590 | static noinline struct module *load_module(void __user *umod, | ||
2591 | unsigned long len, | ||
2592 | const char __user *uargs) | ||
2593 | { | ||
2594 | struct load_info info = { NULL, }; | ||
2595 | struct module *mod; | ||
2596 | long err; | ||
2597 | struct _ddebug *debug = NULL; | ||
2598 | unsigned int num_debug = 0; | ||
2599 | |||
2600 | DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n", | ||
2601 | umod, len, uargs); | ||
2602 | |||
2603 | /* Copy in the blobs from userspace, check they are vaguely sane. */ | ||
2604 | err = copy_and_check(&info, umod, len, uargs); | ||
2605 | if (err) | ||
2606 | return ERR_PTR(err); | ||
2607 | |||
2608 | /* Figure out module layout, and allocate all the memory. */ | ||
2609 | mod = layout_and_allocate(&info); | ||
2578 | if (IS_ERR(mod)) { | 2610 | if (IS_ERR(mod)) { |
2579 | err = PTR_ERR(mod); | 2611 | err = PTR_ERR(mod); |
2580 | goto free_percpu; | 2612 | goto free_copy; |
2581 | } | 2613 | } |
2582 | 2614 | ||
2583 | /* Now we've moved module, initialize linked lists, etc. */ | 2615 | /* Now we've moved module, initialize linked lists, etc. */ |
2584 | err = module_unload_init(mod); | 2616 | err = module_unload_init(mod); |
2585 | if (err) | 2617 | if (err) |
2586 | goto free_init; | 2618 | goto free_module; |
2587 | 2619 | ||
2588 | /* Now we've got everything in the final locations, we can | 2620 | /* Now we've got everything in the final locations, we can |
2589 | * find optional sections. */ | 2621 | * find optional sections. */ |
@@ -2600,11 +2632,11 @@ static noinline struct module *load_module(void __user *umod, | |||
2600 | err = simplify_symbols(info.sechdrs, info.index.sym, info.strtab, info.index.vers, info.index.pcpu, | 2632 | err = simplify_symbols(info.sechdrs, info.index.sym, info.strtab, info.index.vers, info.index.pcpu, |
2601 | mod); | 2633 | mod); |
2602 | if (err < 0) | 2634 | if (err < 0) |
2603 | goto cleanup; | 2635 | goto free_modinfo; |
2604 | 2636 | ||
2605 | err = apply_relocations(mod, info.hdr, info.sechdrs, info.index.sym, info.index.str); | 2637 | err = apply_relocations(mod, info.hdr, info.sechdrs, info.index.sym, info.index.str); |
2606 | if (err < 0) | 2638 | if (err < 0) |
2607 | goto cleanup; | 2639 | goto free_modinfo; |
2608 | 2640 | ||
2609 | /* Set up and sort exception table */ | 2641 | /* Set up and sort exception table */ |
2610 | mod->extable = section_objs(info.hdr, info.sechdrs, info.secstrings, "__ex_table", | 2642 | mod->extable = section_objs(info.hdr, info.sechdrs, info.secstrings, "__ex_table", |
@@ -2615,9 +2647,7 @@ static noinline struct module *load_module(void __user *umod, | |||
2615 | percpu_modcopy(mod, (void *)info.sechdrs[info.index.pcpu].sh_addr, | 2647 | percpu_modcopy(mod, (void *)info.sechdrs[info.index.pcpu].sh_addr, |
2616 | info.sechdrs[info.index.pcpu].sh_size); | 2648 | info.sechdrs[info.index.pcpu].sh_size); |
2617 | 2649 | ||
2618 | add_kallsyms(mod, &info, symoffs, stroffs, strmap); | 2650 | add_kallsyms(mod, &info); |
2619 | kfree(strmap); | ||
2620 | strmap = NULL; | ||
2621 | 2651 | ||
2622 | if (!mod->taints) | 2652 | if (!mod->taints) |
2623 | debug = section_objs(info.hdr, info.sechdrs, info.secstrings, "__verbose", | 2653 | debug = section_objs(info.hdr, info.sechdrs, info.secstrings, "__verbose", |
@@ -2625,12 +2655,14 @@ static noinline struct module *load_module(void __user *umod, | |||
2625 | 2655 | ||
2626 | err = module_finalize(info.hdr, info.sechdrs, mod); | 2656 | err = module_finalize(info.hdr, info.sechdrs, mod); |
2627 | if (err < 0) | 2657 | if (err < 0) |
2628 | goto cleanup; | 2658 | goto free_modinfo; |
2629 | 2659 | ||
2630 | flush_module_icache(mod); | 2660 | flush_module_icache(mod); |
2631 | 2661 | ||
2632 | mod->args = info.args; | 2662 | mod->args = info.args; |
2633 | 2663 | ||
2664 | mod->state = MODULE_STATE_COMING; | ||
2665 | |||
2634 | /* Now sew it into the lists so we can get lockdep and oops | 2666 | /* Now sew it into the lists so we can get lockdep and oops |
2635 | * info during argument parsing. Noone should access us, since | 2667 | * info during argument parsing. Noone should access us, since |
2636 | * strong_try_module_get() will fail. | 2668 | * strong_try_module_get() will fail. |
@@ -2666,8 +2698,9 @@ static noinline struct module *load_module(void __user *umod, | |||
2666 | add_sect_attrs(mod, info.hdr->e_shnum, info.secstrings, info.sechdrs); | 2698 | add_sect_attrs(mod, info.hdr->e_shnum, info.secstrings, info.sechdrs); |
2667 | add_notes_attrs(mod, info.hdr->e_shnum, info.secstrings, info.sechdrs); | 2699 | add_notes_attrs(mod, info.hdr->e_shnum, info.secstrings, info.sechdrs); |
2668 | 2700 | ||
2669 | /* Get rid of temporary copy */ | 2701 | /* Get rid of temporary copy and strmap. */ |
2670 | vfree(info.hdr); | 2702 | kfree(info.strmap); |
2703 | free_copy(&info); | ||
2671 | 2704 | ||
2672 | trace_module_load(mod); | 2705 | trace_module_load(mod); |
2673 | 2706 | ||
@@ -2684,21 +2717,14 @@ static noinline struct module *load_module(void __user *umod, | |||
2684 | mutex_unlock(&module_mutex); | 2717 | mutex_unlock(&module_mutex); |
2685 | synchronize_sched(); | 2718 | synchronize_sched(); |
2686 | module_arch_cleanup(mod); | 2719 | module_arch_cleanup(mod); |
2687 | cleanup: | 2720 | free_modinfo: |
2688 | free_modinfo(mod); | 2721 | free_modinfo(mod); |
2689 | free_unload: | 2722 | free_unload: |
2690 | module_unload_free(mod); | 2723 | module_unload_free(mod); |
2691 | free_init: | 2724 | free_module: |
2692 | module_free(mod, mod->module_init); | 2725 | module_deallocate(mod, &info); |
2693 | module_free(mod, mod->module_core); | 2726 | free_copy: |
2694 | /* mod will be freed with core. Don't access it beyond this line! */ | 2727 | free_copy(&info); |
2695 | free_percpu: | ||
2696 | free_percpu(percpu); | ||
2697 | free_mod: | ||
2698 | kfree(info.args); | ||
2699 | kfree(strmap); | ||
2700 | free_hdr: | ||
2701 | vfree(info.hdr); | ||
2702 | return ERR_PTR(err); | 2728 | return ERR_PTR(err); |
2703 | } | 2729 | } |
2704 | 2730 | ||