diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2010-08-05 14:59:06 -0400 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2010-08-04 23:29:06 -0400 |
commit | 8b5f61a795fe37be090b0fd18b6b7271db9298e0 (patch) | |
tree | 4440e449af9207b25e62b4d8ad0dc16500720e65 /kernel/module.c | |
parent | 3264d3f9dd532ed9c3eb9491619e3f485b72747f (diff) |
module: refactor out section header rewriting
Put all the "rewrite and check section headers" in one place. This
adds another iteration over the sections, but it's far clearer. We
iterate once for every find_section() so we already iterate over many
times.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'kernel/module.c')
-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, |