diff options
| -rw-r--r-- | kernel/module.c | 70 |
1 files changed, 45 insertions, 25 deletions
diff --git a/kernel/module.c b/kernel/module.c index cb40a4e64a0e..91f3ebe230e3 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -2158,6 +2158,7 @@ struct load_info { | |||
| 2158 | } index; | 2158 | } index; |
| 2159 | }; | 2159 | }; |
| 2160 | 2160 | ||
| 2161 | /* Sets info->hdr and info->len. */ | ||
| 2161 | static int copy_and_check(struct load_info *info, const void __user *umod, unsigned long len) | 2162 | static int copy_and_check(struct load_info *info, const void __user *umod, unsigned long len) |
| 2162 | { | 2163 | { |
| 2163 | int err; | 2164 | int err; |
| @@ -2199,6 +2200,39 @@ free_hdr: | |||
| 2199 | return err; | 2200 | return err; |
| 2200 | } | 2201 | } |
| 2201 | 2202 | ||
| 2203 | static int rewrite_section_headers(struct load_info *info) | ||
| 2204 | { | ||
| 2205 | unsigned int i; | ||
| 2206 | |||
| 2207 | /* This should always be true, but let's be sure. */ | ||
| 2208 | info->sechdrs[0].sh_addr = 0; | ||
| 2209 | |||
| 2210 | for (i = 1; i < info->hdr->e_shnum; i++) { | ||
| 2211 | Elf_Shdr *shdr = &info->sechdrs[i]; | ||
| 2212 | if (shdr->sh_type != SHT_NOBITS | ||
| 2213 | && info->len < shdr->sh_offset + shdr->sh_size) { | ||
| 2214 | printk(KERN_ERR "Module len %lu truncated\n", | ||
| 2215 | info->len); | ||
| 2216 | return -ENOEXEC; | ||
| 2217 | } | ||
| 2218 | |||
| 2219 | /* Mark all sections sh_addr with their address in the | ||
| 2220 | temporary image. */ | ||
| 2221 | shdr->sh_addr = (size_t)info->hdr + shdr->sh_offset; | ||
| 2222 | |||
| 2223 | #ifndef CONFIG_MODULE_UNLOAD | ||
| 2224 | /* Don't load .exit sections */ | ||
| 2225 | if (strstarts(info->secstrings+shdr->sh_name, ".exit")) | ||
| 2226 | shdr->sh_flags &= ~(unsigned long)SHF_ALLOC; | ||
| 2227 | #endif | ||
| 2228 | /* Don't keep modinfo and version sections. */ | ||
| 2229 | if (!strcmp(info->secstrings+shdr->sh_name, "__versions") | ||
| 2230 | || !strcmp(info->secstrings+shdr->sh_name, ".modinfo")) | ||
| 2231 | shdr->sh_flags &= ~(unsigned long)SHF_ALLOC; | ||
| 2232 | } | ||
| 2233 | return 0; | ||
| 2234 | } | ||
| 2235 | |||
| 2202 | /* | 2236 | /* |
| 2203 | * Set up our basic convenience variables (pointers to section headers, | 2237 | * Set up our basic convenience variables (pointers to section headers, |
| 2204 | * search for module section index etc), and do some basic section | 2238 | * search for module section index etc), and do some basic section |
| @@ -2210,33 +2244,27 @@ free_hdr: | |||
| 2210 | static struct module *setup_load_info(struct load_info *info) | 2244 | static struct module *setup_load_info(struct load_info *info) |
| 2211 | { | 2245 | { |
| 2212 | unsigned int i; | 2246 | unsigned int i; |
| 2247 | int err; | ||
| 2213 | struct module *mod; | 2248 | struct module *mod; |
| 2214 | 2249 | ||
| 2215 | /* Set up the convenience variables */ | 2250 | /* Set up the convenience variables */ |
| 2216 | info->sechdrs = (void *)info->hdr + info->hdr->e_shoff; | 2251 | info->sechdrs = (void *)info->hdr + info->hdr->e_shoff; |
| 2217 | info->secstrings = (void *)info->hdr + info->sechdrs[info->hdr->e_shstrndx].sh_offset; | 2252 | info->secstrings = (void *)info->hdr |
| 2218 | info->sechdrs[0].sh_addr = 0; | 2253 | + info->sechdrs[info->hdr->e_shstrndx].sh_offset; |
| 2219 | |||
| 2220 | for (i = 1; i < info->hdr->e_shnum; i++) { | ||
| 2221 | if (info->sechdrs[i].sh_type != SHT_NOBITS | ||
| 2222 | && info->len < info->sechdrs[i].sh_offset + info->sechdrs[i].sh_size) | ||
| 2223 | goto truncated; | ||
| 2224 | 2254 | ||
| 2225 | /* Mark all sections sh_addr with their address in the | 2255 | err = rewrite_section_headers(info); |
| 2226 | temporary image. */ | 2256 | if (err) |
| 2227 | info->sechdrs[i].sh_addr = (size_t)info->hdr + info->sechdrs[i].sh_offset; | 2257 | return ERR_PTR(err); |
| 2228 | 2258 | ||
| 2229 | /* Internal symbols and strings. */ | 2259 | /* Find internal symbols and strings. */ |
| 2260 | for (i = 1; i < info->hdr->e_shnum; i++) { | ||
| 2230 | if (info->sechdrs[i].sh_type == SHT_SYMTAB) { | 2261 | if (info->sechdrs[i].sh_type == SHT_SYMTAB) { |
| 2231 | info->index.sym = i; | 2262 | info->index.sym = i; |
| 2232 | info->index.str = info->sechdrs[i].sh_link; | 2263 | info->index.str = info->sechdrs[i].sh_link; |
| 2233 | info->strtab = (char *)info->hdr + info->sechdrs[info->index.str].sh_offset; | 2264 | info->strtab = (char *)info->hdr |
| 2265 | + info->sechdrs[info->index.str].sh_offset; | ||
| 2266 | break; | ||
| 2234 | } | 2267 | } |
| 2235 | #ifndef CONFIG_MODULE_UNLOAD | ||
| 2236 | /* Don't load .exit sections */ | ||
| 2237 | if (strstarts(info->secstrings+info->sechdrs[i].sh_name, ".exit")) | ||
| 2238 | info->sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC; | ||
| 2239 | #endif | ||
| 2240 | } | 2268 | } |
| 2241 | 2269 | ||
| 2242 | info->index.mod = find_sec(info->hdr, info->sechdrs, info->secstrings, | 2270 | info->index.mod = find_sec(info->hdr, info->sechdrs, info->secstrings, |
| @@ -2258,19 +2286,11 @@ static struct module *setup_load_info(struct load_info *info) | |||
| 2258 | info->index.info = find_sec(info->hdr, info->sechdrs, info->secstrings, ".modinfo"); | 2286 | info->index.info = find_sec(info->hdr, info->sechdrs, info->secstrings, ".modinfo"); |
| 2259 | info->index.pcpu = find_pcpusec(info->hdr, info->sechdrs, info->secstrings); | 2287 | info->index.pcpu = find_pcpusec(info->hdr, info->sechdrs, info->secstrings); |
| 2260 | 2288 | ||
| 2261 | /* Don't keep modinfo and version sections. */ | ||
| 2262 | info->sechdrs[info->index.info].sh_flags &= ~(unsigned long)SHF_ALLOC; | ||
| 2263 | info->sechdrs[info->index.vers].sh_flags &= ~(unsigned long)SHF_ALLOC; | ||
| 2264 | |||
| 2265 | /* Check module struct version now, before we try to use module. */ | 2289 | /* Check module struct version now, before we try to use module. */ |
| 2266 | if (!check_modstruct_version(info->sechdrs, info->index.vers, mod)) | 2290 | if (!check_modstruct_version(info->sechdrs, info->index.vers, mod)) |
| 2267 | return ERR_PTR(-ENOEXEC); | 2291 | return ERR_PTR(-ENOEXEC); |
| 2268 | 2292 | ||
| 2269 | return mod; | 2293 | return mod; |
| 2270 | |||
| 2271 | truncated: | ||
| 2272 | printk(KERN_ERR "Module len %lu truncated\n", info->len); | ||
| 2273 | return ERR_PTR(-ENOEXEC); | ||
| 2274 | } | 2294 | } |
| 2275 | 2295 | ||
| 2276 | static int check_modinfo(struct module *mod, | 2296 | static int check_modinfo(struct module *mod, |
