diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/module.c | 65 |
1 files changed, 21 insertions, 44 deletions
diff --git a/kernel/module.c b/kernel/module.c index cf9f1b6b3268..4928cffc3dcc 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -138,7 +138,6 @@ struct load_info { | |||
138 | unsigned long len; | 138 | unsigned long len; |
139 | Elf_Shdr *sechdrs; | 139 | Elf_Shdr *sechdrs; |
140 | char *secstrings, *strtab; | 140 | char *secstrings, *strtab; |
141 | unsigned long *strmap; | ||
142 | unsigned long symoffs, stroffs; | 141 | unsigned long symoffs, stroffs; |
143 | struct _ddebug *debug; | 142 | struct _ddebug *debug; |
144 | unsigned int num_debug; | 143 | unsigned int num_debug; |
@@ -2178,12 +2177,19 @@ static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs, | |||
2178 | return true; | 2177 | return true; |
2179 | } | 2178 | } |
2180 | 2179 | ||
2180 | /* | ||
2181 | * We only allocate and copy the strings needed by the parts of symtab | ||
2182 | * we keep. This is simple, but has the effect of making multiple | ||
2183 | * copies of duplicates. We could be more sophisticated, see | ||
2184 | * linux-kernel thread starting with | ||
2185 | * <73defb5e4bca04a6431392cc341112b1@localhost>. | ||
2186 | */ | ||
2181 | static void layout_symtab(struct module *mod, struct load_info *info) | 2187 | static void layout_symtab(struct module *mod, struct load_info *info) |
2182 | { | 2188 | { |
2183 | Elf_Shdr *symsect = info->sechdrs + info->index.sym; | 2189 | Elf_Shdr *symsect = info->sechdrs + info->index.sym; |
2184 | Elf_Shdr *strsect = info->sechdrs + info->index.str; | 2190 | Elf_Shdr *strsect = info->sechdrs + info->index.str; |
2185 | const Elf_Sym *src; | 2191 | const Elf_Sym *src; |
2186 | unsigned int i, nsrc, ndst; | 2192 | unsigned int i, nsrc, ndst, strtab_size; |
2187 | 2193 | ||
2188 | /* Put symbol section at end of init part of module. */ | 2194 | /* Put symbol section at end of init part of module. */ |
2189 | symsect->sh_flags |= SHF_ALLOC; | 2195 | symsect->sh_flags |= SHF_ALLOC; |
@@ -2194,38 +2200,23 @@ static void layout_symtab(struct module *mod, struct load_info *info) | |||
2194 | src = (void *)info->hdr + symsect->sh_offset; | 2200 | src = (void *)info->hdr + symsect->sh_offset; |
2195 | nsrc = symsect->sh_size / sizeof(*src); | 2201 | nsrc = symsect->sh_size / sizeof(*src); |
2196 | 2202 | ||
2197 | /* | 2203 | /* Compute total space required for the core symbols' strtab. */ |
2198 | * info->strmap has a '1' bit for each byte of .strtab we want to | 2204 | for (ndst = i = strtab_size = 1; i < nsrc; ++i, ++src) |
2199 | * keep resident in mod->core_strtab. Everything else in .strtab | ||
2200 | * is unreferenced by the symbols in mod->core_symtab, and will be | ||
2201 | * discarded when add_kallsyms() compacts the string table. | ||
2202 | */ | ||
2203 | for (ndst = i = 1; i < nsrc; ++i, ++src) | ||
2204 | if (is_core_symbol(src, info->sechdrs, info->hdr->e_shnum)) { | 2205 | if (is_core_symbol(src, info->sechdrs, info->hdr->e_shnum)) { |
2205 | unsigned int j = src->st_name; | 2206 | strtab_size += strlen(&info->strtab[src->st_name]) + 1; |
2206 | 2207 | ndst++; | |
2207 | while (!__test_and_set_bit(j, info->strmap) | ||
2208 | && info->strtab[j]) | ||
2209 | ++j; | ||
2210 | ++ndst; | ||
2211 | } | 2208 | } |
2212 | 2209 | ||
2213 | /* Append room for core symbols at end of core part. */ | 2210 | /* Append room for core symbols at end of core part. */ |
2214 | info->symoffs = ALIGN(mod->core_size, symsect->sh_addralign ?: 1); | 2211 | info->symoffs = ALIGN(mod->core_size, symsect->sh_addralign ?: 1); |
2215 | mod->core_size = info->symoffs + ndst * sizeof(Elf_Sym); | 2212 | info->stroffs = mod->core_size = info->symoffs + ndst * sizeof(Elf_Sym); |
2213 | mod->core_size += strtab_size; | ||
2216 | 2214 | ||
2217 | /* Put string table section at end of init part of module. */ | 2215 | /* Put string table section at end of init part of module. */ |
2218 | strsect->sh_flags |= SHF_ALLOC; | 2216 | strsect->sh_flags |= SHF_ALLOC; |
2219 | strsect->sh_entsize = get_offset(mod, &mod->init_size, strsect, | 2217 | strsect->sh_entsize = get_offset(mod, &mod->init_size, strsect, |
2220 | info->index.str) | INIT_OFFSET_MASK; | 2218 | info->index.str) | INIT_OFFSET_MASK; |
2221 | DEBUGP("\t%s\n", info->secstrings + strsect->sh_name); | 2219 | DEBUGP("\t%s\n", info->secstrings + strsect->sh_name); |
2222 | |||
2223 | /* Append room for core symbols' strings at end of core part. */ | ||
2224 | info->stroffs = mod->core_size; | ||
2225 | |||
2226 | /* First strtab byte (and first symtab entry) are zeroes. */ | ||
2227 | __set_bit(0, info->strmap); | ||
2228 | mod->core_size += bitmap_weight(info->strmap, strsect->sh_size); | ||
2229 | } | 2220 | } |
2230 | 2221 | ||
2231 | static void add_kallsyms(struct module *mod, const struct load_info *info) | 2222 | static void add_kallsyms(struct module *mod, const struct load_info *info) |
@@ -2246,22 +2237,19 @@ static void add_kallsyms(struct module *mod, const struct load_info *info) | |||
2246 | mod->symtab[i].st_info = elf_type(&mod->symtab[i], info); | 2237 | mod->symtab[i].st_info = elf_type(&mod->symtab[i], info); |
2247 | 2238 | ||
2248 | mod->core_symtab = dst = mod->module_core + info->symoffs; | 2239 | mod->core_symtab = dst = mod->module_core + info->symoffs; |
2240 | mod->core_strtab = s = mod->module_core + info->stroffs; | ||
2249 | src = mod->symtab; | 2241 | src = mod->symtab; |
2250 | *dst = *src; | 2242 | *dst = *src; |
2243 | *s++ = 0; | ||
2251 | for (ndst = i = 1; i < mod->num_symtab; ++i, ++src) { | 2244 | for (ndst = i = 1; i < mod->num_symtab; ++i, ++src) { |
2252 | if (!is_core_symbol(src, info->sechdrs, info->hdr->e_shnum)) | 2245 | if (!is_core_symbol(src, info->sechdrs, info->hdr->e_shnum)) |
2253 | continue; | 2246 | continue; |
2247 | |||
2254 | dst[ndst] = *src; | 2248 | dst[ndst] = *src; |
2255 | dst[ndst].st_name = bitmap_weight(info->strmap, | 2249 | dst[ndst++].st_name = s - mod->core_strtab; |
2256 | dst[ndst].st_name); | 2250 | s += strlcpy(s, &mod->strtab[src->st_name], KSYM_NAME_LEN) + 1; |
2257 | ++ndst; | ||
2258 | } | 2251 | } |
2259 | mod->core_num_syms = ndst; | 2252 | mod->core_num_syms = ndst; |
2260 | |||
2261 | mod->core_strtab = s = mod->module_core + info->stroffs; | ||
2262 | for (*s = 0, i = 1; i < info->sechdrs[info->index.str].sh_size; ++i) | ||
2263 | if (test_bit(i, info->strmap)) | ||
2264 | *++s = mod->strtab[i]; | ||
2265 | } | 2253 | } |
2266 | #else | 2254 | #else |
2267 | static inline void layout_symtab(struct module *mod, struct load_info *info) | 2255 | static inline void layout_symtab(struct module *mod, struct load_info *info) |
@@ -2751,27 +2739,18 @@ static struct module *layout_and_allocate(struct load_info *info) | |||
2751 | this is done generically; there doesn't appear to be any | 2739 | this is done generically; there doesn't appear to be any |
2752 | special cases for the architectures. */ | 2740 | special cases for the architectures. */ |
2753 | layout_sections(mod, info); | 2741 | layout_sections(mod, info); |
2754 | |||
2755 | info->strmap = kzalloc(BITS_TO_LONGS(info->sechdrs[info->index.str].sh_size) | ||
2756 | * sizeof(long), GFP_KERNEL); | ||
2757 | if (!info->strmap) { | ||
2758 | err = -ENOMEM; | ||
2759 | goto free_percpu; | ||
2760 | } | ||
2761 | layout_symtab(mod, info); | 2742 | layout_symtab(mod, info); |
2762 | 2743 | ||
2763 | /* Allocate and move to the final place */ | 2744 | /* Allocate and move to the final place */ |
2764 | err = move_module(mod, info); | 2745 | err = move_module(mod, info); |
2765 | if (err) | 2746 | if (err) |
2766 | goto free_strmap; | 2747 | goto free_percpu; |
2767 | 2748 | ||
2768 | /* Module has been copied to its final place now: return it. */ | 2749 | /* Module has been copied to its final place now: return it. */ |
2769 | mod = (void *)info->sechdrs[info->index.mod].sh_addr; | 2750 | mod = (void *)info->sechdrs[info->index.mod].sh_addr; |
2770 | kmemleak_load_module(mod, info); | 2751 | kmemleak_load_module(mod, info); |
2771 | return mod; | 2752 | return mod; |
2772 | 2753 | ||
2773 | free_strmap: | ||
2774 | kfree(info->strmap); | ||
2775 | free_percpu: | 2754 | free_percpu: |
2776 | percpu_modfree(mod); | 2755 | percpu_modfree(mod); |
2777 | out: | 2756 | out: |
@@ -2781,7 +2760,6 @@ out: | |||
2781 | /* mod is no longer valid after this! */ | 2760 | /* mod is no longer valid after this! */ |
2782 | static void module_deallocate(struct module *mod, struct load_info *info) | 2761 | static void module_deallocate(struct module *mod, struct load_info *info) |
2783 | { | 2762 | { |
2784 | kfree(info->strmap); | ||
2785 | percpu_modfree(mod); | 2763 | percpu_modfree(mod); |
2786 | module_free(mod, mod->module_init); | 2764 | module_free(mod, mod->module_init); |
2787 | module_free(mod, mod->module_core); | 2765 | module_free(mod, mod->module_core); |
@@ -2911,8 +2889,7 @@ static struct module *load_module(void __user *umod, | |||
2911 | if (err < 0) | 2889 | if (err < 0) |
2912 | goto unlink; | 2890 | goto unlink; |
2913 | 2891 | ||
2914 | /* Get rid of temporary copy and strmap. */ | 2892 | /* Get rid of temporary copy. */ |
2915 | kfree(info.strmap); | ||
2916 | free_copy(&info); | 2893 | free_copy(&info); |
2917 | 2894 | ||
2918 | /* Done! */ | 2895 | /* Done! */ |