Commit 5e458cc0f4770eea45d3c07110f01b3a94c72aa5
1 parent
2515ddc6db
Exists in
master
and in
20 other branches
module: simplify load_module.
Linus' recent catch of stack overflow in load_module lead me to look at the code. A couple of helpers to get a section address and get objects from a section can help clean things up a little. (And in case you're wondering, the stack size also dropped from 328 to 284 bytes). Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Showing 2 changed files with 100 additions and 137 deletions Side-by-side Diff
include/linux/module.h
kernel/module.c
... | ... | @@ -132,6 +132,29 @@ |
132 | 132 | return 0; |
133 | 133 | } |
134 | 134 | |
135 | +/* Find a module section, or NULL. */ | |
136 | +static void *section_addr(Elf_Ehdr *hdr, Elf_Shdr *shdrs, | |
137 | + const char *secstrings, const char *name) | |
138 | +{ | |
139 | + /* Section 0 has sh_addr 0. */ | |
140 | + return (void *)shdrs[find_sec(hdr, shdrs, secstrings, name)].sh_addr; | |
141 | +} | |
142 | + | |
143 | +/* Find a module section, or NULL. Fill in number of "objects" in section. */ | |
144 | +static void *section_objs(Elf_Ehdr *hdr, | |
145 | + Elf_Shdr *sechdrs, | |
146 | + const char *secstrings, | |
147 | + const char *name, | |
148 | + size_t object_size, | |
149 | + unsigned int *num) | |
150 | +{ | |
151 | + unsigned int sec = find_sec(hdr, sechdrs, secstrings, name); | |
152 | + | |
153 | + /* Section 0 has sh_addr 0 and sh_size 0. */ | |
154 | + *num = sechdrs[sec].sh_size / object_size; | |
155 | + return (void *)sechdrs[sec].sh_addr; | |
156 | +} | |
157 | + | |
135 | 158 | /* Provided by the linker */ |
136 | 159 | extern const struct kernel_symbol __start___ksymtab[]; |
137 | 160 | extern const struct kernel_symbol __stop___ksymtab[]; |
138 | 161 | |
139 | 162 | |
140 | 163 | |
141 | 164 | |
... | ... | @@ -1789,32 +1812,20 @@ |
1789 | 1812 | } |
1790 | 1813 | #endif /* CONFIG_KALLSYMS */ |
1791 | 1814 | |
1792 | -#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG | |
1793 | -static void dynamic_printk_setup(Elf_Shdr *sechdrs, unsigned int verboseindex) | |
1815 | +static void dynamic_printk_setup(struct mod_debug *debug, unsigned int num) | |
1794 | 1816 | { |
1795 | - struct mod_debug *debug_info; | |
1796 | - unsigned long pos, end; | |
1797 | - unsigned int num_verbose; | |
1817 | +#ifdef CONFIG_DYNAMIC_PRINTK_DEBUG | |
1818 | + unsigned int i; | |
1798 | 1819 | |
1799 | - pos = sechdrs[verboseindex].sh_addr; | |
1800 | - num_verbose = sechdrs[verboseindex].sh_size / | |
1801 | - sizeof(struct mod_debug); | |
1802 | - end = pos + (num_verbose * sizeof(struct mod_debug)); | |
1803 | - | |
1804 | - for (; pos < end; pos += sizeof(struct mod_debug)) { | |
1805 | - debug_info = (struct mod_debug *)pos; | |
1806 | - register_dynamic_debug_module(debug_info->modname, | |
1807 | - debug_info->type, debug_info->logical_modname, | |
1808 | - debug_info->flag_names, debug_info->hash, | |
1809 | - debug_info->hash2); | |
1820 | + for (i = 0; i < num; i++) { | |
1821 | + register_dynamic_debug_module(debug[i].modname, | |
1822 | + debug[i].type, | |
1823 | + debug[i].logical_modname, | |
1824 | + debug[i].flag_names, | |
1825 | + debug[i].hash, debug[i].hash2); | |
1810 | 1826 | } |
1811 | -} | |
1812 | -#else | |
1813 | -static inline void dynamic_printk_setup(Elf_Shdr *sechdrs, | |
1814 | - unsigned int verboseindex) | |
1815 | -{ | |
1816 | -} | |
1817 | 1827 | #endif /* CONFIG_DYNAMIC_PRINTK_DEBUG */ |
1828 | +} | |
1818 | 1829 | |
1819 | 1830 | static void *module_alloc_update_bounds(unsigned long size) |
1820 | 1831 | { |
1821 | 1832 | |
1822 | 1833 | |
... | ... | @@ -1843,37 +1854,14 @@ |
1843 | 1854 | unsigned int i; |
1844 | 1855 | unsigned int symindex = 0; |
1845 | 1856 | unsigned int strindex = 0; |
1846 | - unsigned int setupindex; | |
1847 | - unsigned int exindex; | |
1848 | - unsigned int exportindex; | |
1849 | - unsigned int modindex; | |
1850 | - unsigned int obsparmindex; | |
1851 | - unsigned int infoindex; | |
1852 | - unsigned int gplindex; | |
1853 | - unsigned int crcindex; | |
1854 | - unsigned int gplcrcindex; | |
1855 | - unsigned int versindex; | |
1856 | - unsigned int pcpuindex; | |
1857 | - unsigned int gplfutureindex; | |
1858 | - unsigned int gplfuturecrcindex; | |
1857 | + unsigned int modindex, versindex, infoindex, pcpuindex; | |
1859 | 1858 | unsigned int unwindex = 0; |
1860 | -#ifdef CONFIG_UNUSED_SYMBOLS | |
1861 | - unsigned int unusedindex; | |
1862 | - unsigned int unusedcrcindex; | |
1863 | - unsigned int unusedgplindex; | |
1864 | - unsigned int unusedgplcrcindex; | |
1865 | -#endif | |
1866 | - unsigned int markersindex; | |
1867 | - unsigned int markersstringsindex; | |
1868 | - unsigned int verboseindex; | |
1869 | - unsigned int tracepointsindex; | |
1870 | - unsigned int tracepointsstringsindex; | |
1871 | - unsigned int mcountindex; | |
1859 | + unsigned int num_kp, num_mcount; | |
1860 | + struct kernel_param *kp; | |
1872 | 1861 | struct module *mod; |
1873 | 1862 | long err = 0; |
1874 | 1863 | void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ |
1875 | - void *mseg; | |
1876 | - struct exception_table_entry *extable; | |
1864 | + unsigned long *mseg; | |
1877 | 1865 | mm_segment_t old_fs; |
1878 | 1866 | |
1879 | 1867 | DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n", |
... | ... | @@ -1937,6 +1925,7 @@ |
1937 | 1925 | err = -ENOEXEC; |
1938 | 1926 | goto free_hdr; |
1939 | 1927 | } |
1928 | + /* This is temporary: point mod into copy of data. */ | |
1940 | 1929 | mod = (void *)sechdrs[modindex].sh_addr; |
1941 | 1930 | |
1942 | 1931 | if (symindex == 0) { |
... | ... | @@ -1946,22 +1935,6 @@ |
1946 | 1935 | goto free_hdr; |
1947 | 1936 | } |
1948 | 1937 | |
1949 | - /* Optional sections */ | |
1950 | - exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab"); | |
1951 | - gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl"); | |
1952 | - gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future"); | |
1953 | - crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab"); | |
1954 | - gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl"); | |
1955 | - gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future"); | |
1956 | -#ifdef CONFIG_UNUSED_SYMBOLS | |
1957 | - unusedindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused"); | |
1958 | - unusedgplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused_gpl"); | |
1959 | - unusedcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused"); | |
1960 | - unusedgplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused_gpl"); | |
1961 | -#endif | |
1962 | - setupindex = find_sec(hdr, sechdrs, secstrings, "__param"); | |
1963 | - exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table"); | |
1964 | - obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm"); | |
1965 | 1938 | versindex = find_sec(hdr, sechdrs, secstrings, "__versions"); |
1966 | 1939 | infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo"); |
1967 | 1940 | pcpuindex = find_pcpusec(hdr, sechdrs, secstrings); |
1968 | 1941 | |
1969 | 1942 | |
1970 | 1943 | |
1971 | 1944 | |
... | ... | @@ -2117,42 +2090,57 @@ |
2117 | 2090 | if (err < 0) |
2118 | 2091 | goto cleanup; |
2119 | 2092 | |
2120 | - /* Set up EXPORTed & EXPORT_GPLed symbols (section 0 is 0 length) */ | |
2121 | - mod->num_syms = sechdrs[exportindex].sh_size / sizeof(*mod->syms); | |
2122 | - mod->syms = (void *)sechdrs[exportindex].sh_addr; | |
2123 | - if (crcindex) | |
2124 | - mod->crcs = (void *)sechdrs[crcindex].sh_addr; | |
2125 | - mod->num_gpl_syms = sechdrs[gplindex].sh_size / sizeof(*mod->gpl_syms); | |
2126 | - mod->gpl_syms = (void *)sechdrs[gplindex].sh_addr; | |
2127 | - if (gplcrcindex) | |
2128 | - mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr; | |
2129 | - mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size / | |
2130 | - sizeof(*mod->gpl_future_syms); | |
2131 | - mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr; | |
2132 | - if (gplfuturecrcindex) | |
2133 | - mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr; | |
2093 | + /* Now we've got everything in the final locations, we can | |
2094 | + * find optional sections. */ | |
2095 | + kp = section_objs(hdr, sechdrs, secstrings, "__param", sizeof(*kp), | |
2096 | + &num_kp); | |
2097 | + mod->syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab", | |
2098 | + sizeof(*mod->syms), &mod->num_syms); | |
2099 | + mod->crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab"); | |
2100 | + mod->gpl_syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab_gpl", | |
2101 | + sizeof(*mod->gpl_syms), | |
2102 | + &mod->num_gpl_syms); | |
2103 | + mod->gpl_crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab_gpl"); | |
2104 | + mod->gpl_future_syms = section_objs(hdr, sechdrs, secstrings, | |
2105 | + "__ksymtab_gpl_future", | |
2106 | + sizeof(*mod->gpl_future_syms), | |
2107 | + &mod->num_gpl_future_syms); | |
2108 | + mod->gpl_future_crcs = section_addr(hdr, sechdrs, secstrings, | |
2109 | + "__kcrctab_gpl_future"); | |
2134 | 2110 | |
2135 | 2111 | #ifdef CONFIG_UNUSED_SYMBOLS |
2136 | - mod->num_unused_syms = sechdrs[unusedindex].sh_size / | |
2137 | - sizeof(*mod->unused_syms); | |
2138 | - mod->num_unused_gpl_syms = sechdrs[unusedgplindex].sh_size / | |
2139 | - sizeof(*mod->unused_gpl_syms); | |
2140 | - mod->unused_syms = (void *)sechdrs[unusedindex].sh_addr; | |
2141 | - if (unusedcrcindex) | |
2142 | - mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr; | |
2143 | - mod->unused_gpl_syms = (void *)sechdrs[unusedgplindex].sh_addr; | |
2144 | - if (unusedgplcrcindex) | |
2145 | - mod->unused_gpl_crcs | |
2146 | - = (void *)sechdrs[unusedgplcrcindex].sh_addr; | |
2112 | + mod->unused_syms = section_objs(hdr, sechdrs, secstrings, | |
2113 | + "__ksymtab_unused", | |
2114 | + sizeof(*mod->unused_syms), | |
2115 | + &mod->num_unused_syms); | |
2116 | + mod->unused_crcs = section_addr(hdr, sechdrs, secstrings, | |
2117 | + "__kcrctab_unused"); | |
2118 | + mod->unused_gpl_syms = section_objs(hdr, sechdrs, secstrings, | |
2119 | + "__ksymtab_unused_gpl", | |
2120 | + sizeof(*mod->unused_gpl_syms), | |
2121 | + &mod->num_unused_gpl_syms); | |
2122 | + mod->unused_gpl_crcs = section_addr(hdr, sechdrs, secstrings, | |
2123 | + "__kcrctab_unused_gpl"); | |
2147 | 2124 | #endif |
2148 | 2125 | |
2126 | +#ifdef CONFIG_MARKERS | |
2127 | + mod->markers = section_objs(hdr, sechdrs, secstrings, "__markers", | |
2128 | + sizeof(*mod->markers), &mod->num_markers); | |
2129 | +#endif | |
2130 | +#ifdef CONFIG_TRACEPOINTS | |
2131 | + mod->tracepoints = section_objs(hdr, sechdrs, secstrings, | |
2132 | + "__tracepoints", | |
2133 | + sizeof(*mod->tracepoints), | |
2134 | + &mod->num_tracepoints); | |
2135 | +#endif | |
2136 | + | |
2149 | 2137 | #ifdef CONFIG_MODVERSIONS |
2150 | - if ((mod->num_syms && !crcindex) | |
2151 | - || (mod->num_gpl_syms && !gplcrcindex) | |
2152 | - || (mod->num_gpl_future_syms && !gplfuturecrcindex) | |
2138 | + if ((mod->num_syms && !mod->crcs) | |
2139 | + || (mod->num_gpl_syms && !mod->gpl_crcs) | |
2140 | + || (mod->num_gpl_future_syms && !mod->gpl_future_crcs) | |
2153 | 2141 | #ifdef CONFIG_UNUSED_SYMBOLS |
2154 | - || (mod->num_unused_syms && !unusedcrcindex) | |
2155 | - || (mod->num_unused_gpl_syms && !unusedgplcrcindex) | |
2142 | + || (mod->num_unused_syms && !mod->unused_crcs) | |
2143 | + || (mod->num_unused_gpl_syms && !mod->unused_gpl_crcs) | |
2156 | 2144 | #endif |
2157 | 2145 | ) { |
2158 | 2146 | printk(KERN_WARNING "%s: No versions for exported symbols.\n", mod->name); |
2159 | 2147 | |
... | ... | @@ -2161,17 +2149,7 @@ |
2161 | 2149 | goto cleanup; |
2162 | 2150 | } |
2163 | 2151 | #endif |
2164 | - markersindex = find_sec(hdr, sechdrs, secstrings, "__markers"); | |
2165 | - markersstringsindex = find_sec(hdr, sechdrs, secstrings, | |
2166 | - "__markers_strings"); | |
2167 | - verboseindex = find_sec(hdr, sechdrs, secstrings, "__verbose"); | |
2168 | - tracepointsindex = find_sec(hdr, sechdrs, secstrings, "__tracepoints"); | |
2169 | - tracepointsstringsindex = find_sec(hdr, sechdrs, secstrings, | |
2170 | - "__tracepoints_strings"); | |
2171 | 2152 | |
2172 | - mcountindex = find_sec(hdr, sechdrs, secstrings, | |
2173 | - "__mcount_loc"); | |
2174 | - | |
2175 | 2153 | /* Now do relocations. */ |
2176 | 2154 | for (i = 1; i < hdr->e_shnum; i++) { |
2177 | 2155 | const char *strtab = (char *)sechdrs[strindex].sh_addr; |
2178 | 2156 | |
2179 | 2157 | |
2180 | 2158 | |
... | ... | @@ -2193,28 +2171,16 @@ |
2193 | 2171 | if (err < 0) |
2194 | 2172 | goto cleanup; |
2195 | 2173 | } |
2196 | -#ifdef CONFIG_MARKERS | |
2197 | - mod->markers = (void *)sechdrs[markersindex].sh_addr; | |
2198 | - mod->num_markers = | |
2199 | - sechdrs[markersindex].sh_size / sizeof(*mod->markers); | |
2200 | -#endif | |
2201 | -#ifdef CONFIG_TRACEPOINTS | |
2202 | - mod->tracepoints = (void *)sechdrs[tracepointsindex].sh_addr; | |
2203 | - mod->num_tracepoints = | |
2204 | - sechdrs[tracepointsindex].sh_size / sizeof(*mod->tracepoints); | |
2205 | -#endif | |
2206 | 2174 | |
2207 | - | |
2208 | 2175 | /* Find duplicate symbols */ |
2209 | 2176 | err = verify_export_symbols(mod); |
2210 | - | |
2211 | 2177 | if (err < 0) |
2212 | 2178 | goto cleanup; |
2213 | 2179 | |
2214 | 2180 | /* Set up and sort exception table */ |
2215 | - mod->num_exentries = sechdrs[exindex].sh_size / sizeof(*mod->extable); | |
2216 | - mod->extable = extable = (void *)sechdrs[exindex].sh_addr; | |
2217 | - sort_extable(extable, extable + mod->num_exentries); | |
2181 | + mod->extable = section_objs(hdr, sechdrs, secstrings, "__ex_table", | |
2182 | + sizeof(*mod->extable), &mod->num_exentries); | |
2183 | + sort_extable(mod->extable, mod->extable + mod->num_exentries); | |
2218 | 2184 | |
2219 | 2185 | /* Finally, copy percpu area over. */ |
2220 | 2186 | percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr, |
2221 | 2187 | |
... | ... | @@ -2223,11 +2189,17 @@ |
2223 | 2189 | add_kallsyms(mod, sechdrs, symindex, strindex, secstrings); |
2224 | 2190 | |
2225 | 2191 | if (!mod->taints) { |
2192 | + struct mod_debug *debug; | |
2193 | + unsigned int num_debug; | |
2194 | + | |
2226 | 2195 | #ifdef CONFIG_MARKERS |
2227 | 2196 | marker_update_probe_range(mod->markers, |
2228 | 2197 | mod->markers + mod->num_markers); |
2229 | 2198 | #endif |
2230 | - dynamic_printk_setup(sechdrs, verboseindex); | |
2199 | + debug = section_objs(hdr, sechdrs, secstrings, "__verbose", | |
2200 | + sizeof(*debug), &num_debug); | |
2201 | + dynamic_printk_setup(debug, num_debug); | |
2202 | + | |
2231 | 2203 | #ifdef CONFIG_TRACEPOINTS |
2232 | 2204 | tracepoint_update_probe_range(mod->tracepoints, |
2233 | 2205 | mod->tracepoints + mod->num_tracepoints); |
... | ... | @@ -2235,8 +2207,9 @@ |
2235 | 2207 | } |
2236 | 2208 | |
2237 | 2209 | /* sechdrs[0].sh_size is always zero */ |
2238 | - mseg = (void *)sechdrs[mcountindex].sh_addr; | |
2239 | - ftrace_init_module(mseg, mseg + sechdrs[mcountindex].sh_size); | |
2210 | + mseg = section_objs(hdr, sechdrs, secstrings, "__mcount_loc", | |
2211 | + sizeof(*mseg), &num_mcount); | |
2212 | + ftrace_init_module(mseg, mseg + num_mcount); | |
2240 | 2213 | |
2241 | 2214 | err = module_finalize(hdr, sechdrs, mod); |
2242 | 2215 | if (err < 0) |
... | ... | @@ -2261,7 +2234,7 @@ |
2261 | 2234 | set_fs(old_fs); |
2262 | 2235 | |
2263 | 2236 | mod->args = args; |
2264 | - if (obsparmindex) | |
2237 | + if (section_addr(hdr, sechdrs, secstrings, "__obsparm")) | |
2265 | 2238 | printk(KERN_WARNING "%s: Ignoring obsolete parameters\n", |
2266 | 2239 | mod->name); |
2267 | 2240 | |
2268 | 2241 | |
... | ... | @@ -2270,21 +2243,11 @@ |
2270 | 2243 | * strong_try_module_get() will fail. */ |
2271 | 2244 | stop_machine(__link_module, mod, NULL); |
2272 | 2245 | |
2273 | - /* Size of section 0 is 0, so this works well if no params */ | |
2274 | - err = parse_args(mod->name, mod->args, | |
2275 | - (struct kernel_param *) | |
2276 | - sechdrs[setupindex].sh_addr, | |
2277 | - sechdrs[setupindex].sh_size | |
2278 | - / sizeof(struct kernel_param), | |
2279 | - NULL); | |
2246 | + err = parse_args(mod->name, mod->args, kp, num_kp, NULL); | |
2280 | 2247 | if (err < 0) |
2281 | 2248 | goto unlink; |
2282 | 2249 | |
2283 | - err = mod_sysfs_setup(mod, | |
2284 | - (struct kernel_param *) | |
2285 | - sechdrs[setupindex].sh_addr, | |
2286 | - sechdrs[setupindex].sh_size | |
2287 | - / sizeof(struct kernel_param)); | |
2250 | + err = mod_sysfs_setup(mod, kp, num_kp); | |
2288 | 2251 | if (err < 0) |
2289 | 2252 | goto unlink; |
2290 | 2253 | add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); |