diff options
Diffstat (limited to 'kernel/module.c')
-rw-r--r-- | kernel/module.c | 235 |
1 files changed, 99 insertions, 136 deletions
diff --git a/kernel/module.c b/kernel/module.c index 0d8d21ee792c..3d256681ab64 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -132,6 +132,29 @@ static unsigned int find_sec(Elf_Ehdr *hdr, | |||
132 | return 0; | 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 | /* Provided by the linker */ | 158 | /* Provided by the linker */ |
136 | extern const struct kernel_symbol __start___ksymtab[]; | 159 | extern const struct kernel_symbol __start___ksymtab[]; |
137 | extern const struct kernel_symbol __stop___ksymtab[]; | 160 | extern const struct kernel_symbol __stop___ksymtab[]; |
@@ -1789,32 +1812,20 @@ static inline void add_kallsyms(struct module *mod, | |||
1789 | } | 1812 | } |
1790 | #endif /* CONFIG_KALLSYMS */ | 1813 | #endif /* CONFIG_KALLSYMS */ |
1791 | 1814 | ||
1792 | #ifdef CONFIG_DYNAMIC_PRINTK_DEBUG | 1815 | static void dynamic_printk_setup(struct mod_debug *debug, unsigned int num) |
1793 | static void dynamic_printk_setup(Elf_Shdr *sechdrs, unsigned int verboseindex) | ||
1794 | { | 1816 | { |
1795 | struct mod_debug *debug_info; | 1817 | #ifdef CONFIG_DYNAMIC_PRINTK_DEBUG |
1796 | unsigned long pos, end; | 1818 | unsigned int i; |
1797 | unsigned int num_verbose; | ||
1798 | |||
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 | 1819 | ||
1804 | for (; pos < end; pos += sizeof(struct mod_debug)) { | 1820 | for (i = 0; i < num; i++) { |
1805 | debug_info = (struct mod_debug *)pos; | 1821 | register_dynamic_debug_module(debug[i].modname, |
1806 | register_dynamic_debug_module(debug_info->modname, | 1822 | debug[i].type, |
1807 | debug_info->type, debug_info->logical_modname, | 1823 | debug[i].logical_modname, |
1808 | debug_info->flag_names, debug_info->hash, | 1824 | debug[i].flag_names, |
1809 | debug_info->hash2); | 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 | #endif /* CONFIG_DYNAMIC_PRINTK_DEBUG */ | 1827 | #endif /* CONFIG_DYNAMIC_PRINTK_DEBUG */ |
1828 | } | ||
1818 | 1829 | ||
1819 | static void *module_alloc_update_bounds(unsigned long size) | 1830 | static void *module_alloc_update_bounds(unsigned long size) |
1820 | { | 1831 | { |
@@ -1843,37 +1854,14 @@ static noinline struct module *load_module(void __user *umod, | |||
1843 | unsigned int i; | 1854 | unsigned int i; |
1844 | unsigned int symindex = 0; | 1855 | unsigned int symindex = 0; |
1845 | unsigned int strindex = 0; | 1856 | unsigned int strindex = 0; |
1846 | unsigned int setupindex; | 1857 | unsigned int modindex, versindex, infoindex, pcpuindex; |
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; | ||
1859 | unsigned int unwindex = 0; | 1858 | unsigned int unwindex = 0; |
1860 | #ifdef CONFIG_UNUSED_SYMBOLS | 1859 | unsigned int num_kp, num_mcount; |
1861 | unsigned int unusedindex; | 1860 | struct kernel_param *kp; |
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; | ||
1872 | struct module *mod; | 1861 | struct module *mod; |
1873 | long err = 0; | 1862 | long err = 0; |
1874 | void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ | 1863 | void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */ |
1875 | void *mseg; | 1864 | unsigned long *mseg; |
1876 | struct exception_table_entry *extable; | ||
1877 | mm_segment_t old_fs; | 1865 | mm_segment_t old_fs; |
1878 | 1866 | ||
1879 | DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n", | 1867 | DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n", |
@@ -1937,6 +1925,7 @@ static noinline struct module *load_module(void __user *umod, | |||
1937 | err = -ENOEXEC; | 1925 | err = -ENOEXEC; |
1938 | goto free_hdr; | 1926 | goto free_hdr; |
1939 | } | 1927 | } |
1928 | /* This is temporary: point mod into copy of data. */ | ||
1940 | mod = (void *)sechdrs[modindex].sh_addr; | 1929 | mod = (void *)sechdrs[modindex].sh_addr; |
1941 | 1930 | ||
1942 | if (symindex == 0) { | 1931 | if (symindex == 0) { |
@@ -1946,22 +1935,6 @@ static noinline struct module *load_module(void __user *umod, | |||
1946 | goto free_hdr; | 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 | versindex = find_sec(hdr, sechdrs, secstrings, "__versions"); | 1938 | versindex = find_sec(hdr, sechdrs, secstrings, "__versions"); |
1966 | infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo"); | 1939 | infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo"); |
1967 | pcpuindex = find_pcpusec(hdr, sechdrs, secstrings); | 1940 | pcpuindex = find_pcpusec(hdr, sechdrs, secstrings); |
@@ -2117,42 +2090,57 @@ static noinline struct module *load_module(void __user *umod, | |||
2117 | if (err < 0) | 2090 | if (err < 0) |
2118 | goto cleanup; | 2091 | goto cleanup; |
2119 | 2092 | ||
2120 | /* Set up EXPORTed & EXPORT_GPLed symbols (section 0 is 0 length) */ | 2093 | /* Now we've got everything in the final locations, we can |
2121 | mod->num_syms = sechdrs[exportindex].sh_size / sizeof(*mod->syms); | 2094 | * find optional sections. */ |
2122 | mod->syms = (void *)sechdrs[exportindex].sh_addr; | 2095 | kp = section_objs(hdr, sechdrs, secstrings, "__param", sizeof(*kp), |
2123 | if (crcindex) | 2096 | &num_kp); |
2124 | mod->crcs = (void *)sechdrs[crcindex].sh_addr; | 2097 | mod->syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab", |
2125 | mod->num_gpl_syms = sechdrs[gplindex].sh_size / sizeof(*mod->gpl_syms); | 2098 | sizeof(*mod->syms), &mod->num_syms); |
2126 | mod->gpl_syms = (void *)sechdrs[gplindex].sh_addr; | 2099 | mod->crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab"); |
2127 | if (gplcrcindex) | 2100 | mod->gpl_syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab_gpl", |
2128 | mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr; | 2101 | sizeof(*mod->gpl_syms), |
2129 | mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size / | 2102 | &mod->num_gpl_syms); |
2130 | sizeof(*mod->gpl_future_syms); | 2103 | mod->gpl_crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab_gpl"); |
2131 | mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr; | 2104 | mod->gpl_future_syms = section_objs(hdr, sechdrs, secstrings, |
2132 | if (gplfuturecrcindex) | 2105 | "__ksymtab_gpl_future", |
2133 | mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr; | 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 | #ifdef CONFIG_UNUSED_SYMBOLS | 2111 | #ifdef CONFIG_UNUSED_SYMBOLS |
2136 | mod->num_unused_syms = sechdrs[unusedindex].sh_size / | 2112 | mod->unused_syms = section_objs(hdr, sechdrs, secstrings, |
2137 | sizeof(*mod->unused_syms); | 2113 | "__ksymtab_unused", |
2138 | mod->num_unused_gpl_syms = sechdrs[unusedgplindex].sh_size / | 2114 | sizeof(*mod->unused_syms), |
2139 | sizeof(*mod->unused_gpl_syms); | 2115 | &mod->num_unused_syms); |
2140 | mod->unused_syms = (void *)sechdrs[unusedindex].sh_addr; | 2116 | mod->unused_crcs = section_addr(hdr, sechdrs, secstrings, |
2141 | if (unusedcrcindex) | 2117 | "__kcrctab_unused"); |
2142 | mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr; | 2118 | mod->unused_gpl_syms = section_objs(hdr, sechdrs, secstrings, |
2143 | mod->unused_gpl_syms = (void *)sechdrs[unusedgplindex].sh_addr; | 2119 | "__ksymtab_unused_gpl", |
2144 | if (unusedgplcrcindex) | 2120 | sizeof(*mod->unused_gpl_syms), |
2145 | mod->unused_gpl_crcs | 2121 | &mod->num_unused_gpl_syms); |
2146 | = (void *)sechdrs[unusedgplcrcindex].sh_addr; | 2122 | mod->unused_gpl_crcs = section_addr(hdr, sechdrs, secstrings, |
2123 | "__kcrctab_unused_gpl"); | ||
2124 | #endif | ||
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); | ||
2147 | #endif | 2135 | #endif |
2148 | 2136 | ||
2149 | #ifdef CONFIG_MODVERSIONS | 2137 | #ifdef CONFIG_MODVERSIONS |
2150 | if ((mod->num_syms && !crcindex) | 2138 | if ((mod->num_syms && !mod->crcs) |
2151 | || (mod->num_gpl_syms && !gplcrcindex) | 2139 | || (mod->num_gpl_syms && !mod->gpl_crcs) |
2152 | || (mod->num_gpl_future_syms && !gplfuturecrcindex) | 2140 | || (mod->num_gpl_future_syms && !mod->gpl_future_crcs) |
2153 | #ifdef CONFIG_UNUSED_SYMBOLS | 2141 | #ifdef CONFIG_UNUSED_SYMBOLS |
2154 | || (mod->num_unused_syms && !unusedcrcindex) | 2142 | || (mod->num_unused_syms && !mod->unused_crcs) |
2155 | || (mod->num_unused_gpl_syms && !unusedgplcrcindex) | 2143 | || (mod->num_unused_gpl_syms && !mod->unused_gpl_crcs) |
2156 | #endif | 2144 | #endif |
2157 | ) { | 2145 | ) { |
2158 | printk(KERN_WARNING "%s: No versions for exported symbols.\n", mod->name); | 2146 | printk(KERN_WARNING "%s: No versions for exported symbols.\n", mod->name); |
@@ -2161,16 +2149,6 @@ static noinline struct module *load_module(void __user *umod, | |||
2161 | goto cleanup; | 2149 | goto cleanup; |
2162 | } | 2150 | } |
2163 | #endif | 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 | |||
2172 | mcountindex = find_sec(hdr, sechdrs, secstrings, | ||
2173 | "__mcount_loc"); | ||
2174 | 2152 | ||
2175 | /* Now do relocations. */ | 2153 | /* Now do relocations. */ |
2176 | for (i = 1; i < hdr->e_shnum; i++) { | 2154 | for (i = 1; i < hdr->e_shnum; i++) { |
@@ -2193,28 +2171,16 @@ static noinline struct module *load_module(void __user *umod, | |||
2193 | if (err < 0) | 2171 | if (err < 0) |
2194 | goto cleanup; | 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 | |||
2207 | 2174 | ||
2208 | /* Find duplicate symbols */ | 2175 | /* Find duplicate symbols */ |
2209 | err = verify_export_symbols(mod); | 2176 | err = verify_export_symbols(mod); |
2210 | |||
2211 | if (err < 0) | 2177 | if (err < 0) |
2212 | goto cleanup; | 2178 | goto cleanup; |
2213 | 2179 | ||
2214 | /* Set up and sort exception table */ | 2180 | /* Set up and sort exception table */ |
2215 | mod->num_exentries = sechdrs[exindex].sh_size / sizeof(*mod->extable); | 2181 | mod->extable = section_objs(hdr, sechdrs, secstrings, "__ex_table", |
2216 | mod->extable = extable = (void *)sechdrs[exindex].sh_addr; | 2182 | sizeof(*mod->extable), &mod->num_exentries); |
2217 | sort_extable(extable, extable + mod->num_exentries); | 2183 | sort_extable(mod->extable, mod->extable + mod->num_exentries); |
2218 | 2184 | ||
2219 | /* Finally, copy percpu area over. */ | 2185 | /* Finally, copy percpu area over. */ |
2220 | percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr, | 2186 | percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr, |
@@ -2223,11 +2189,17 @@ static noinline struct module *load_module(void __user *umod, | |||
2223 | add_kallsyms(mod, sechdrs, symindex, strindex, secstrings); | 2189 | add_kallsyms(mod, sechdrs, symindex, strindex, secstrings); |
2224 | 2190 | ||
2225 | if (!mod->taints) { | 2191 | if (!mod->taints) { |
2192 | struct mod_debug *debug; | ||
2193 | unsigned int num_debug; | ||
2194 | |||
2226 | #ifdef CONFIG_MARKERS | 2195 | #ifdef CONFIG_MARKERS |
2227 | marker_update_probe_range(mod->markers, | 2196 | marker_update_probe_range(mod->markers, |
2228 | mod->markers + mod->num_markers); | 2197 | mod->markers + mod->num_markers); |
2229 | #endif | 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 | #ifdef CONFIG_TRACEPOINTS | 2203 | #ifdef CONFIG_TRACEPOINTS |
2232 | tracepoint_update_probe_range(mod->tracepoints, | 2204 | tracepoint_update_probe_range(mod->tracepoints, |
2233 | mod->tracepoints + mod->num_tracepoints); | 2205 | mod->tracepoints + mod->num_tracepoints); |
@@ -2235,8 +2207,9 @@ static noinline struct module *load_module(void __user *umod, | |||
2235 | } | 2207 | } |
2236 | 2208 | ||
2237 | /* sechdrs[0].sh_size is always zero */ | 2209 | /* sechdrs[0].sh_size is always zero */ |
2238 | mseg = (void *)sechdrs[mcountindex].sh_addr; | 2210 | mseg = section_objs(hdr, sechdrs, secstrings, "__mcount_loc", |
2239 | ftrace_init_module(mseg, mseg + sechdrs[mcountindex].sh_size); | 2211 | sizeof(*mseg), &num_mcount); |
2212 | ftrace_init_module(mseg, mseg + num_mcount); | ||
2240 | 2213 | ||
2241 | err = module_finalize(hdr, sechdrs, mod); | 2214 | err = module_finalize(hdr, sechdrs, mod); |
2242 | if (err < 0) | 2215 | if (err < 0) |
@@ -2261,7 +2234,7 @@ static noinline struct module *load_module(void __user *umod, | |||
2261 | set_fs(old_fs); | 2234 | set_fs(old_fs); |
2262 | 2235 | ||
2263 | mod->args = args; | 2236 | mod->args = args; |
2264 | if (obsparmindex) | 2237 | if (section_addr(hdr, sechdrs, secstrings, "__obsparm")) |
2265 | printk(KERN_WARNING "%s: Ignoring obsolete parameters\n", | 2238 | printk(KERN_WARNING "%s: Ignoring obsolete parameters\n", |
2266 | mod->name); | 2239 | mod->name); |
2267 | 2240 | ||
@@ -2270,21 +2243,11 @@ static noinline struct module *load_module(void __user *umod, | |||
2270 | * strong_try_module_get() will fail. */ | 2243 | * strong_try_module_get() will fail. */ |
2271 | stop_machine(__link_module, mod, NULL); | 2244 | stop_machine(__link_module, mod, NULL); |
2272 | 2245 | ||
2273 | /* Size of section 0 is 0, so this works well if no params */ | 2246 | err = parse_args(mod->name, mod->args, kp, num_kp, NULL); |
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); | ||
2280 | if (err < 0) | 2247 | if (err < 0) |
2281 | goto unlink; | 2248 | goto unlink; |
2282 | 2249 | ||
2283 | err = mod_sysfs_setup(mod, | 2250 | err = mod_sysfs_setup(mod, kp, num_kp); |
2284 | (struct kernel_param *) | ||
2285 | sechdrs[setupindex].sh_addr, | ||
2286 | sechdrs[setupindex].sh_size | ||
2287 | / sizeof(struct kernel_param)); | ||
2288 | if (err < 0) | 2251 | if (err < 0) |
2289 | goto unlink; | 2252 | goto unlink; |
2290 | add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); | 2253 | add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); |