diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2010-08-05 14:59:03 -0400 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2010-08-04 23:29:04 -0400 |
commit | 40dd2560ec2df21036db9ec8b971f92d98fd1969 (patch) | |
tree | a5785afb92619379172c9ee5b05501e075cc7bff /kernel/module.c | |
parent | 65b8a9b4d5525348e55cf63a43517610ee8e0970 (diff) |
module: refactor load_module part 3
Extract out the allocation and copying in from userspace, and the
first set of modinfo checks.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'kernel/module.c')
-rw-r--r-- | kernel/module.c | 122 |
1 files changed, 75 insertions, 47 deletions
diff --git a/kernel/module.c b/kernel/module.c index 19ddcb0dba36..d8faf35cba84 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -1803,7 +1803,7 @@ static char *next_string(char *string, unsigned long *secsize) | |||
1803 | return string; | 1803 | return string; |
1804 | } | 1804 | } |
1805 | 1805 | ||
1806 | static char *get_modinfo(Elf_Shdr *sechdrs, | 1806 | static char *get_modinfo(const Elf_Shdr *sechdrs, |
1807 | unsigned int info, | 1807 | unsigned int info, |
1808 | const char *tag) | 1808 | const char *tag) |
1809 | { | 1809 | { |
@@ -2109,6 +2109,73 @@ static inline void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr, | |||
2109 | } | 2109 | } |
2110 | #endif | 2110 | #endif |
2111 | 2111 | ||
2112 | static int copy_and_check(Elf_Ehdr **hdrp, | ||
2113 | const void __user *umod, unsigned long len) | ||
2114 | { | ||
2115 | int err; | ||
2116 | Elf_Ehdr *hdr; | ||
2117 | |||
2118 | if (len < sizeof(*hdr)) | ||
2119 | return -ENOEXEC; | ||
2120 | |||
2121 | /* Suck in entire file: we'll want most of it. */ | ||
2122 | /* vmalloc barfs on "unusual" numbers. Check here */ | ||
2123 | if (len > 64 * 1024 * 1024 || (hdr = *hdrp = vmalloc(len)) == NULL) | ||
2124 | return -ENOMEM; | ||
2125 | |||
2126 | if (copy_from_user(hdr, umod, len) != 0) { | ||
2127 | err = -EFAULT; | ||
2128 | goto free_hdr; | ||
2129 | } | ||
2130 | |||
2131 | /* Sanity checks against insmoding binaries or wrong arch, | ||
2132 | weird elf version */ | ||
2133 | if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0 | ||
2134 | || hdr->e_type != ET_REL | ||
2135 | || !elf_check_arch(hdr) | ||
2136 | || hdr->e_shentsize != sizeof(Elf_Shdr)) { | ||
2137 | err = -ENOEXEC; | ||
2138 | goto free_hdr; | ||
2139 | } | ||
2140 | |||
2141 | if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) { | ||
2142 | err = -ENOEXEC; | ||
2143 | goto free_hdr; | ||
2144 | } | ||
2145 | return 0; | ||
2146 | |||
2147 | free_hdr: | ||
2148 | vfree(hdr); | ||
2149 | return err; | ||
2150 | } | ||
2151 | |||
2152 | static int check_modinfo(struct module *mod, | ||
2153 | const Elf_Shdr *sechdrs, | ||
2154 | unsigned int infoindex, unsigned int versindex) | ||
2155 | { | ||
2156 | const char *modmagic = get_modinfo(sechdrs, infoindex, "vermagic"); | ||
2157 | int err; | ||
2158 | |||
2159 | /* This is allowed: modprobe --force will invalidate it. */ | ||
2160 | if (!modmagic) { | ||
2161 | err = try_to_force_load(mod, "bad vermagic"); | ||
2162 | if (err) | ||
2163 | return err; | ||
2164 | } else if (!same_magic(modmagic, vermagic, versindex)) { | ||
2165 | printk(KERN_ERR "%s: version magic '%s' should be '%s'\n", | ||
2166 | mod->name, modmagic, vermagic); | ||
2167 | return -ENOEXEC; | ||
2168 | } | ||
2169 | |||
2170 | if (get_modinfo(sechdrs, infoindex, "staging")) { | ||
2171 | add_taint_module(mod, TAINT_CRAP); | ||
2172 | printk(KERN_WARNING "%s: module is from the staging directory," | ||
2173 | " the quality is unknown, you have been warned.\n", | ||
2174 | mod->name); | ||
2175 | } | ||
2176 | return 0; | ||
2177 | } | ||
2178 | |||
2112 | static void find_module_sections(struct module *mod, Elf_Ehdr *hdr, | 2179 | static void find_module_sections(struct module *mod, Elf_Ehdr *hdr, |
2113 | Elf_Shdr *sechdrs, const char *secstrings) | 2180 | Elf_Shdr *sechdrs, const char *secstrings) |
2114 | { | 2181 | { |
@@ -2246,14 +2313,13 @@ static noinline struct module *load_module(void __user *umod, | |||
2246 | { | 2313 | { |
2247 | Elf_Ehdr *hdr; | 2314 | Elf_Ehdr *hdr; |
2248 | Elf_Shdr *sechdrs; | 2315 | Elf_Shdr *sechdrs; |
2249 | char *secstrings, *args, *modmagic, *strtab = NULL; | 2316 | char *secstrings, *args, *strtab = NULL; |
2250 | char *staging; | ||
2251 | unsigned int i; | 2317 | unsigned int i; |
2252 | unsigned int symindex = 0; | 2318 | unsigned int symindex = 0; |
2253 | unsigned int strindex = 0; | 2319 | unsigned int strindex = 0; |
2254 | unsigned int modindex, versindex, infoindex, pcpuindex; | 2320 | unsigned int modindex, versindex, infoindex, pcpuindex; |
2255 | struct module *mod; | 2321 | struct module *mod; |
2256 | long err = 0; | 2322 | long err; |
2257 | unsigned long symoffs, stroffs, *strmap; | 2323 | unsigned long symoffs, stroffs, *strmap; |
2258 | void __percpu *percpu; | 2324 | void __percpu *percpu; |
2259 | struct _ddebug *debug = NULL; | 2325 | struct _ddebug *debug = NULL; |
@@ -2263,31 +2329,10 @@ static noinline struct module *load_module(void __user *umod, | |||
2263 | 2329 | ||
2264 | DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n", | 2330 | DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n", |
2265 | umod, len, uargs); | 2331 | umod, len, uargs); |
2266 | if (len < sizeof(*hdr)) | ||
2267 | return ERR_PTR(-ENOEXEC); | ||
2268 | |||
2269 | /* Suck in entire file: we'll want most of it. */ | ||
2270 | /* vmalloc barfs on "unusual" numbers. Check here */ | ||
2271 | if (len > 64 * 1024 * 1024 || (hdr = vmalloc(len)) == NULL) | ||
2272 | return ERR_PTR(-ENOMEM); | ||
2273 | |||
2274 | if (copy_from_user(hdr, umod, len) != 0) { | ||
2275 | err = -EFAULT; | ||
2276 | goto free_hdr; | ||
2277 | } | ||
2278 | |||
2279 | /* Sanity checks against insmoding binaries or wrong arch, | ||
2280 | weird elf version */ | ||
2281 | if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0 | ||
2282 | || hdr->e_type != ET_REL | ||
2283 | || !elf_check_arch(hdr) | ||
2284 | || hdr->e_shentsize != sizeof(*sechdrs)) { | ||
2285 | err = -ENOEXEC; | ||
2286 | goto free_hdr; | ||
2287 | } | ||
2288 | 2332 | ||
2289 | if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) | 2333 | err = copy_and_check(&hdr, umod, len); |
2290 | goto truncated; | 2334 | if (err) |
2335 | return ERR_PTR(err); | ||
2291 | 2336 | ||
2292 | /* Convenience variables */ | 2337 | /* Convenience variables */ |
2293 | sechdrs = (void *)hdr + hdr->e_shoff; | 2338 | sechdrs = (void *)hdr + hdr->e_shoff; |
@@ -2347,26 +2392,9 @@ static noinline struct module *load_module(void __user *umod, | |||
2347 | goto free_hdr; | 2392 | goto free_hdr; |
2348 | } | 2393 | } |
2349 | 2394 | ||
2350 | modmagic = get_modinfo(sechdrs, infoindex, "vermagic"); | 2395 | err = check_modinfo(mod, sechdrs, infoindex, versindex); |
2351 | /* This is allowed: modprobe --force will invalidate it. */ | 2396 | if (err) |
2352 | if (!modmagic) { | ||
2353 | err = try_to_force_load(mod, "bad vermagic"); | ||
2354 | if (err) | ||
2355 | goto free_hdr; | ||
2356 | } else if (!same_magic(modmagic, vermagic, versindex)) { | ||
2357 | printk(KERN_ERR "%s: version magic '%s' should be '%s'\n", | ||
2358 | mod->name, modmagic, vermagic); | ||
2359 | err = -ENOEXEC; | ||
2360 | goto free_hdr; | 2397 | goto free_hdr; |
2361 | } | ||
2362 | |||
2363 | staging = get_modinfo(sechdrs, infoindex, "staging"); | ||
2364 | if (staging) { | ||
2365 | add_taint_module(mod, TAINT_CRAP); | ||
2366 | printk(KERN_WARNING "%s: module is from the staging directory," | ||
2367 | " the quality is unknown, you have been warned.\n", | ||
2368 | mod->name); | ||
2369 | } | ||
2370 | 2398 | ||
2371 | /* Now copy in args */ | 2399 | /* Now copy in args */ |
2372 | args = strndup_user(uargs, ~0UL >> 1); | 2400 | args = strndup_user(uargs, ~0UL >> 1); |