diff options
| -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); |
