aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/module.c122
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
1806static char *get_modinfo(Elf_Shdr *sechdrs, 1806static 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
2112static 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
2147free_hdr:
2148 vfree(hdr);
2149 return err;
2150}
2151
2152static 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
2112static void find_module_sections(struct module *mod, Elf_Ehdr *hdr, 2179static 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);