diff options
| -rw-r--r-- | kernel/module.c | 129 |
1 files changed, 72 insertions, 57 deletions
diff --git a/kernel/module.c b/kernel/module.c index 12905ed44393..19ddcb0dba36 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -2082,7 +2082,8 @@ static void *module_alloc_update_bounds(unsigned long size) | |||
| 2082 | 2082 | ||
| 2083 | #ifdef CONFIG_DEBUG_KMEMLEAK | 2083 | #ifdef CONFIG_DEBUG_KMEMLEAK |
| 2084 | static void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr, | 2084 | static void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr, |
| 2085 | Elf_Shdr *sechdrs, char *secstrings) | 2085 | const Elf_Shdr *sechdrs, |
| 2086 | const char *secstrings) | ||
| 2086 | { | 2087 | { |
| 2087 | unsigned int i; | 2088 | unsigned int i; |
| 2088 | 2089 | ||
| @@ -2102,7 +2103,8 @@ static void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr, | |||
| 2102 | } | 2103 | } |
| 2103 | #else | 2104 | #else |
| 2104 | static inline void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr, | 2105 | static inline void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr, |
| 2105 | Elf_Shdr *sechdrs, char *secstrings) | 2106 | Elf_Shdr *sechdrs, |
| 2107 | const char *secstrings) | ||
| 2106 | { | 2108 | { |
| 2107 | } | 2109 | } |
| 2108 | #endif | 2110 | #endif |
| @@ -2172,6 +2174,70 @@ static void find_module_sections(struct module *mod, Elf_Ehdr *hdr, | |||
| 2172 | #endif | 2174 | #endif |
| 2173 | } | 2175 | } |
| 2174 | 2176 | ||
| 2177 | static struct module *move_module(struct module *mod, | ||
| 2178 | Elf_Ehdr *hdr, Elf_Shdr *sechdrs, | ||
| 2179 | const char *secstrings, unsigned modindex) | ||
| 2180 | { | ||
| 2181 | int i; | ||
| 2182 | void *ptr; | ||
| 2183 | |||
| 2184 | /* Do the allocs. */ | ||
| 2185 | ptr = module_alloc_update_bounds(mod->core_size); | ||
| 2186 | /* | ||
| 2187 | * The pointer to this block is stored in the module structure | ||
| 2188 | * which is inside the block. Just mark it as not being a | ||
| 2189 | * leak. | ||
| 2190 | */ | ||
| 2191 | kmemleak_not_leak(ptr); | ||
| 2192 | if (!ptr) | ||
| 2193 | return ERR_PTR(-ENOMEM); | ||
| 2194 | |||
| 2195 | memset(ptr, 0, mod->core_size); | ||
| 2196 | mod->module_core = ptr; | ||
| 2197 | |||
| 2198 | ptr = module_alloc_update_bounds(mod->init_size); | ||
| 2199 | /* | ||
| 2200 | * The pointer to this block is stored in the module structure | ||
| 2201 | * which is inside the block. This block doesn't need to be | ||
| 2202 | * scanned as it contains data and code that will be freed | ||
| 2203 | * after the module is initialized. | ||
| 2204 | */ | ||
| 2205 | kmemleak_ignore(ptr); | ||
| 2206 | if (!ptr && mod->init_size) { | ||
| 2207 | module_free(mod, mod->module_core); | ||
| 2208 | return ERR_PTR(-ENOMEM); | ||
| 2209 | } | ||
| 2210 | memset(ptr, 0, mod->init_size); | ||
| 2211 | mod->module_init = ptr; | ||
| 2212 | |||
| 2213 | /* Transfer each section which specifies SHF_ALLOC */ | ||
| 2214 | DEBUGP("final section addresses:\n"); | ||
| 2215 | for (i = 0; i < hdr->e_shnum; i++) { | ||
| 2216 | void *dest; | ||
| 2217 | |||
| 2218 | if (!(sechdrs[i].sh_flags & SHF_ALLOC)) | ||
| 2219 | continue; | ||
| 2220 | |||
| 2221 | if (sechdrs[i].sh_entsize & INIT_OFFSET_MASK) | ||
| 2222 | dest = mod->module_init | ||
| 2223 | + (sechdrs[i].sh_entsize & ~INIT_OFFSET_MASK); | ||
| 2224 | else | ||
| 2225 | dest = mod->module_core + sechdrs[i].sh_entsize; | ||
| 2226 | |||
| 2227 | if (sechdrs[i].sh_type != SHT_NOBITS) | ||
| 2228 | memcpy(dest, (void *)sechdrs[i].sh_addr, | ||
| 2229 | sechdrs[i].sh_size); | ||
| 2230 | /* Update sh_addr to point to copy in image. */ | ||
| 2231 | sechdrs[i].sh_addr = (unsigned long)dest; | ||
| 2232 | DEBUGP("\t0x%lx %s\n", | ||
| 2233 | sechdrs[i].sh_addr, secstrings + sechdrs[i].sh_name); | ||
| 2234 | } | ||
| 2235 | /* Module has been moved. */ | ||
| 2236 | mod = (void *)sechdrs[modindex].sh_addr; | ||
| 2237 | kmemleak_load_module(mod, hdr, sechdrs, secstrings); | ||
| 2238 | return mod; | ||
| 2239 | } | ||
| 2240 | |||
| 2175 | /* Allocate and load the module: note that size of section 0 is always | 2241 | /* Allocate and load the module: note that size of section 0 is always |
| 2176 | zero, and we rely on this for optional sections. */ | 2242 | zero, and we rely on this for optional sections. */ |
| 2177 | static noinline struct module *load_module(void __user *umod, | 2243 | static noinline struct module *load_module(void __user *umod, |
| @@ -2188,7 +2254,6 @@ static noinline struct module *load_module(void __user *umod, | |||
| 2188 | unsigned int modindex, versindex, infoindex, pcpuindex; | 2254 | unsigned int modindex, versindex, infoindex, pcpuindex; |
| 2189 | struct module *mod; | 2255 | struct module *mod; |
| 2190 | long err = 0; | 2256 | long err = 0; |
| 2191 | void *ptr = NULL; /* Stops spurious gcc warning */ | ||
| 2192 | unsigned long symoffs, stroffs, *strmap; | 2257 | unsigned long symoffs, stroffs, *strmap; |
| 2193 | void __percpu *percpu; | 2258 | void __percpu *percpu; |
| 2194 | struct _ddebug *debug = NULL; | 2259 | struct _ddebug *debug = NULL; |
| @@ -2342,61 +2407,12 @@ static noinline struct module *load_module(void __user *umod, | |||
| 2342 | symoffs = layout_symtab(mod, sechdrs, symindex, strindex, hdr, | 2407 | symoffs = layout_symtab(mod, sechdrs, symindex, strindex, hdr, |
| 2343 | secstrings, &stroffs, strmap); | 2408 | secstrings, &stroffs, strmap); |
| 2344 | 2409 | ||
| 2345 | /* Do the allocs. */ | 2410 | /* Allocate and move to the final place */ |
| 2346 | ptr = module_alloc_update_bounds(mod->core_size); | 2411 | mod = move_module(mod, hdr, sechdrs, secstrings, modindex); |
| 2347 | /* | 2412 | if (IS_ERR(mod)) { |
| 2348 | * The pointer to this block is stored in the module structure | 2413 | err = PTR_ERR(mod); |
| 2349 | * which is inside the block. Just mark it as not being a | ||
| 2350 | * leak. | ||
| 2351 | */ | ||
| 2352 | kmemleak_not_leak(ptr); | ||
| 2353 | if (!ptr) { | ||
| 2354 | err = -ENOMEM; | ||
| 2355 | goto free_percpu; | 2414 | goto free_percpu; |
| 2356 | } | 2415 | } |
| 2357 | memset(ptr, 0, mod->core_size); | ||
| 2358 | mod->module_core = ptr; | ||
| 2359 | |||
| 2360 | ptr = module_alloc_update_bounds(mod->init_size); | ||
| 2361 | /* | ||
| 2362 | * The pointer to this block is stored in the module structure | ||
| 2363 | * which is inside the block. This block doesn't need to be | ||
| 2364 | * scanned as it contains data and code that will be freed | ||
| 2365 | * after the module is initialized. | ||
| 2366 | */ | ||
| 2367 | kmemleak_ignore(ptr); | ||
| 2368 | if (!ptr && mod->init_size) { | ||
| 2369 | err = -ENOMEM; | ||
| 2370 | goto free_core; | ||
| 2371 | } | ||
| 2372 | memset(ptr, 0, mod->init_size); | ||
| 2373 | mod->module_init = ptr; | ||
| 2374 | |||
| 2375 | /* Transfer each section which specifies SHF_ALLOC */ | ||
| 2376 | DEBUGP("final section addresses:\n"); | ||
| 2377 | for (i = 0; i < hdr->e_shnum; i++) { | ||
| 2378 | void *dest; | ||
| 2379 | |||
| 2380 | if (!(sechdrs[i].sh_flags & SHF_ALLOC)) | ||
| 2381 | continue; | ||
| 2382 | |||
| 2383 | if (sechdrs[i].sh_entsize & INIT_OFFSET_MASK) | ||
| 2384 | dest = mod->module_init | ||
| 2385 | + (sechdrs[i].sh_entsize & ~INIT_OFFSET_MASK); | ||
| 2386 | else | ||
| 2387 | dest = mod->module_core + sechdrs[i].sh_entsize; | ||
| 2388 | |||
| 2389 | if (sechdrs[i].sh_type != SHT_NOBITS) | ||
| 2390 | memcpy(dest, (void *)sechdrs[i].sh_addr, | ||
| 2391 | sechdrs[i].sh_size); | ||
| 2392 | /* Update sh_addr to point to copy in image. */ | ||
| 2393 | sechdrs[i].sh_addr = (unsigned long)dest; | ||
| 2394 | DEBUGP("\t0x%lx %s\n", | ||
| 2395 | sechdrs[i].sh_addr, secstrings + sechdrs[i].sh_name); | ||
| 2396 | } | ||
| 2397 | /* Module has been moved. */ | ||
| 2398 | mod = (void *)sechdrs[modindex].sh_addr; | ||
| 2399 | kmemleak_load_module(mod, hdr, sechdrs, secstrings); | ||
| 2400 | 2416 | ||
| 2401 | #if defined(CONFIG_MODULE_UNLOAD) | 2417 | #if defined(CONFIG_MODULE_UNLOAD) |
| 2402 | mod->refptr = alloc_percpu(struct module_ref); | 2418 | mod->refptr = alloc_percpu(struct module_ref); |
| @@ -2580,7 +2596,6 @@ static noinline struct module *load_module(void __user *umod, | |||
| 2580 | free_init: | 2596 | free_init: |
| 2581 | #endif | 2597 | #endif |
| 2582 | module_free(mod, mod->module_init); | 2598 | module_free(mod, mod->module_init); |
| 2583 | free_core: | ||
| 2584 | module_free(mod, mod->module_core); | 2599 | module_free(mod, mod->module_core); |
| 2585 | /* mod will be freed with core. Don't access it beyond this line! */ | 2600 | /* mod will be freed with core. Don't access it beyond this line! */ |
| 2586 | free_percpu: | 2601 | free_percpu: |
