diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/module.c | 246 |
1 files changed, 125 insertions, 121 deletions
diff --git a/kernel/module.c b/kernel/module.c index 031bf26af8ea..679e4c88ed9e 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -164,131 +164,140 @@ static const struct kernel_symbol *lookup_symbol(const char *name, | |||
164 | return NULL; | 164 | return NULL; |
165 | } | 165 | } |
166 | 166 | ||
167 | static void printk_unused_warning(const char *name) | 167 | static bool always_ok(bool gplok, bool warn, const char *name) |
168 | { | 168 | { |
169 | printk(KERN_WARNING "Symbol %s is marked as UNUSED, " | 169 | return true; |
170 | "however this module is using it.\n", name); | ||
171 | printk(KERN_WARNING "This symbol will go away in the future.\n"); | ||
172 | printk(KERN_WARNING "Please evalute if this is the right api to use, " | ||
173 | "and if it really is, submit a report the linux kernel " | ||
174 | "mailinglist together with submitting your code for " | ||
175 | "inclusion.\n"); | ||
176 | } | 170 | } |
177 | 171 | ||
178 | /* Find a symbol, return value, crc and module which owns it */ | 172 | static bool printk_unused_warning(bool gplok, bool warn, const char *name) |
179 | static unsigned long __find_symbol(const char *name, | ||
180 | struct module **owner, | ||
181 | const unsigned long **crc, | ||
182 | int gplok) | ||
183 | { | 173 | { |
184 | struct module *mod; | 174 | if (warn) { |
185 | const struct kernel_symbol *ks; | 175 | printk(KERN_WARNING "Symbol %s is marked as UNUSED, " |
186 | 176 | "however this module is using it.\n", name); | |
187 | /* Core kernel first. */ | 177 | printk(KERN_WARNING |
188 | *owner = NULL; | 178 | "This symbol will go away in the future.\n"); |
189 | ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab); | 179 | printk(KERN_WARNING |
190 | if (ks) { | 180 | "Please evalute if this is the right api to use and if " |
191 | *crc = symversion(__start___kcrctab, (ks - __start___ksymtab)); | 181 | "it really is, submit a report the linux kernel " |
192 | return ks->value; | 182 | "mailinglist together with submitting your code for " |
183 | "inclusion.\n"); | ||
193 | } | 184 | } |
194 | if (gplok) { | 185 | return true; |
195 | ks = lookup_symbol(name, __start___ksymtab_gpl, | 186 | } |
196 | __stop___ksymtab_gpl); | 187 | |
197 | if (ks) { | 188 | static bool gpl_only_unused_warning(bool gplok, bool warn, const char *name) |
198 | *crc = symversion(__start___kcrctab_gpl, | 189 | { |
199 | (ks - __start___ksymtab_gpl)); | 190 | if (!gplok) |
200 | return ks->value; | 191 | return false; |
201 | } | 192 | return printk_unused_warning(gplok, warn, name); |
202 | } | 193 | } |
203 | ks = lookup_symbol(name, __start___ksymtab_gpl_future, | 194 | |
204 | __stop___ksymtab_gpl_future); | 195 | static bool gpl_only(bool gplok, bool warn, const char *name) |
205 | if (ks) { | 196 | { |
206 | if (!gplok) { | 197 | return gplok; |
207 | printk(KERN_WARNING "Symbol %s is being used " | 198 | } |
208 | "by a non-GPL module, which will not " | 199 | |
209 | "be allowed in the future\n", name); | 200 | static bool warn_if_not_gpl(bool gplok, bool warn, const char *name) |
210 | printk(KERN_WARNING "Please see the file " | 201 | { |
211 | "Documentation/feature-removal-schedule.txt " | 202 | if (!gplok && warn) { |
212 | "in the kernel source tree for more " | 203 | printk(KERN_WARNING "Symbol %s is being used " |
213 | "details.\n"); | 204 | "by a non-GPL module, which will not " |
214 | } | 205 | "be allowed in the future\n", name); |
215 | *crc = symversion(__start___kcrctab_gpl_future, | 206 | printk(KERN_WARNING "Please see the file " |
216 | (ks - __start___ksymtab_gpl_future)); | 207 | "Documentation/feature-removal-schedule.txt " |
217 | return ks->value; | 208 | "in the kernel source tree for more details.\n"); |
218 | } | 209 | } |
210 | return true; | ||
211 | } | ||
219 | 212 | ||
220 | ks = lookup_symbol(name, __start___ksymtab_unused, | 213 | struct symsearch { |
221 | __stop___ksymtab_unused); | 214 | const struct kernel_symbol *start, *stop; |
222 | if (ks) { | 215 | const unsigned long *crcs; |
223 | printk_unused_warning(name); | 216 | bool (*check)(bool gplok, bool warn, const char *name); |
224 | *crc = symversion(__start___kcrctab_unused, | 217 | }; |
225 | (ks - __start___ksymtab_unused)); | 218 | |
226 | return ks->value; | 219 | /* Look through this array of symbol tables for a symbol match which |
220 | * passes the check function. */ | ||
221 | static const struct kernel_symbol *search_symarrays(const struct symsearch *arr, | ||
222 | unsigned int num, | ||
223 | const char *name, | ||
224 | bool gplok, | ||
225 | bool warn, | ||
226 | const unsigned long **crc) | ||
227 | { | ||
228 | unsigned int i; | ||
229 | const struct kernel_symbol *ks; | ||
230 | |||
231 | for (i = 0; i < num; i++) { | ||
232 | ks = lookup_symbol(name, arr[i].start, arr[i].stop); | ||
233 | if (!ks || !arr[i].check(gplok, warn, name)) | ||
234 | continue; | ||
235 | |||
236 | if (crc) | ||
237 | *crc = symversion(arr[i].crcs, ks - arr[i].start); | ||
238 | return ks; | ||
227 | } | 239 | } |
240 | return NULL; | ||
241 | } | ||
228 | 242 | ||
229 | if (gplok) | 243 | /* Find a symbol, return value, (optional) crc and (optional) module |
230 | ks = lookup_symbol(name, __start___ksymtab_unused_gpl, | 244 | * which owns it */ |
231 | __stop___ksymtab_unused_gpl); | 245 | static unsigned long find_symbol(const char *name, |
246 | struct module **owner, | ||
247 | const unsigned long **crc, | ||
248 | bool gplok, | ||
249 | bool warn) | ||
250 | { | ||
251 | struct module *mod; | ||
252 | const struct kernel_symbol *ks; | ||
253 | const struct symsearch arr[] = { | ||
254 | { __start___ksymtab, __stop___ksymtab, __start___kcrctab, | ||
255 | always_ok }, | ||
256 | { __start___ksymtab_gpl, __stop___ksymtab_gpl, | ||
257 | __start___kcrctab_gpl, gpl_only }, | ||
258 | { __start___ksymtab_gpl_future, __stop___ksymtab_gpl_future, | ||
259 | __start___kcrctab_gpl_future, warn_if_not_gpl }, | ||
260 | { __start___ksymtab_unused, __stop___ksymtab_unused, | ||
261 | __start___kcrctab_unused, printk_unused_warning }, | ||
262 | { __start___ksymtab_unused_gpl, __stop___ksymtab_unused_gpl, | ||
263 | __start___kcrctab_unused_gpl, gpl_only_unused_warning }, | ||
264 | }; | ||
265 | |||
266 | /* Core kernel first. */ | ||
267 | ks = search_symarrays(arr, ARRAY_SIZE(arr), name, gplok, warn, crc); | ||
232 | if (ks) { | 268 | if (ks) { |
233 | printk_unused_warning(name); | 269 | if (owner) |
234 | *crc = symversion(__start___kcrctab_unused_gpl, | 270 | *owner = NULL; |
235 | (ks - __start___ksymtab_unused_gpl)); | ||
236 | return ks->value; | 271 | return ks->value; |
237 | } | 272 | } |
238 | 273 | ||
239 | /* Now try modules. */ | 274 | /* Now try modules. */ |
240 | list_for_each_entry(mod, &modules, list) { | 275 | list_for_each_entry(mod, &modules, list) { |
241 | *owner = mod; | 276 | struct symsearch arr[] = { |
242 | ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms); | 277 | { mod->syms, mod->syms + mod->num_syms, mod->crcs, |
278 | always_ok }, | ||
279 | { mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms, | ||
280 | mod->gpl_crcs, gpl_only }, | ||
281 | { mod->gpl_future_syms, | ||
282 | mod->gpl_future_syms + mod->num_gpl_future_syms, | ||
283 | mod->gpl_future_crcs, warn_if_not_gpl }, | ||
284 | { mod->unused_syms, | ||
285 | mod->unused_syms + mod->num_unused_syms, | ||
286 | mod->unused_crcs, printk_unused_warning }, | ||
287 | { mod->unused_gpl_syms, | ||
288 | mod->unused_gpl_syms + mod->num_unused_gpl_syms, | ||
289 | mod->unused_gpl_crcs, gpl_only_unused_warning }, | ||
290 | }; | ||
291 | |||
292 | ks = search_symarrays(arr, ARRAY_SIZE(arr), | ||
293 | name, gplok, warn, crc); | ||
243 | if (ks) { | 294 | if (ks) { |
244 | *crc = symversion(mod->crcs, (ks - mod->syms)); | 295 | if (owner) |
245 | return ks->value; | 296 | *owner = mod; |
246 | } | ||
247 | |||
248 | if (gplok) { | ||
249 | ks = lookup_symbol(name, mod->gpl_syms, | ||
250 | mod->gpl_syms + mod->num_gpl_syms); | ||
251 | if (ks) { | ||
252 | *crc = symversion(mod->gpl_crcs, | ||
253 | (ks - mod->gpl_syms)); | ||
254 | return ks->value; | ||
255 | } | ||
256 | } | ||
257 | ks = lookup_symbol(name, mod->unused_syms, mod->unused_syms + mod->num_unused_syms); | ||
258 | if (ks) { | ||
259 | printk_unused_warning(name); | ||
260 | *crc = symversion(mod->unused_crcs, (ks - mod->unused_syms)); | ||
261 | return ks->value; | ||
262 | } | ||
263 | |||
264 | if (gplok) { | ||
265 | ks = lookup_symbol(name, mod->unused_gpl_syms, | ||
266 | mod->unused_gpl_syms + mod->num_unused_gpl_syms); | ||
267 | if (ks) { | ||
268 | printk_unused_warning(name); | ||
269 | *crc = symversion(mod->unused_gpl_crcs, | ||
270 | (ks - mod->unused_gpl_syms)); | ||
271 | return ks->value; | ||
272 | } | ||
273 | } | ||
274 | ks = lookup_symbol(name, mod->gpl_future_syms, | ||
275 | (mod->gpl_future_syms + | ||
276 | mod->num_gpl_future_syms)); | ||
277 | if (ks) { | ||
278 | if (!gplok) { | ||
279 | printk(KERN_WARNING "Symbol %s is being used " | ||
280 | "by a non-GPL module, which will not " | ||
281 | "be allowed in the future\n", name); | ||
282 | printk(KERN_WARNING "Please see the file " | ||
283 | "Documentation/feature-removal-schedule.txt " | ||
284 | "in the kernel source tree for more " | ||
285 | "details.\n"); | ||
286 | } | ||
287 | *crc = symversion(mod->gpl_future_crcs, | ||
288 | (ks - mod->gpl_future_syms)); | ||
289 | return ks->value; | 297 | return ks->value; |
290 | } | 298 | } |
291 | } | 299 | } |
300 | |||
292 | DEBUGP("Failed to find symbol %s\n", name); | 301 | DEBUGP("Failed to find symbol %s\n", name); |
293 | return -ENOENT; | 302 | return -ENOENT; |
294 | } | 303 | } |
@@ -777,10 +786,9 @@ static void print_unload_info(struct seq_file *m, struct module *mod) | |||
777 | void __symbol_put(const char *symbol) | 786 | void __symbol_put(const char *symbol) |
778 | { | 787 | { |
779 | struct module *owner; | 788 | struct module *owner; |
780 | const unsigned long *crc; | ||
781 | 789 | ||
782 | preempt_disable(); | 790 | preempt_disable(); |
783 | if (IS_ERR_VALUE(__find_symbol(symbol, &owner, &crc, 1))) | 791 | if (IS_ERR_VALUE(find_symbol(symbol, &owner, NULL, true, false))) |
784 | BUG(); | 792 | BUG(); |
785 | module_put(owner); | 793 | module_put(owner); |
786 | preempt_enable(); | 794 | preempt_enable(); |
@@ -924,13 +932,10 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs, | |||
924 | struct module *mod) | 932 | struct module *mod) |
925 | { | 933 | { |
926 | const unsigned long *crc; | 934 | const unsigned long *crc; |
927 | struct module *owner; | ||
928 | 935 | ||
929 | if (IS_ERR_VALUE(__find_symbol("struct_module", | 936 | if (IS_ERR_VALUE(find_symbol("struct_module", NULL, &crc, true, false))) |
930 | &owner, &crc, 1))) | ||
931 | BUG(); | 937 | BUG(); |
932 | return check_version(sechdrs, versindex, "struct_module", mod, | 938 | return check_version(sechdrs, versindex, "struct_module", mod, crc); |
933 | crc); | ||
934 | } | 939 | } |
935 | 940 | ||
936 | /* First part is kernel version, which we ignore. */ | 941 | /* First part is kernel version, which we ignore. */ |
@@ -974,8 +979,8 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs, | |||
974 | unsigned long ret; | 979 | unsigned long ret; |
975 | const unsigned long *crc; | 980 | const unsigned long *crc; |
976 | 981 | ||
977 | ret = __find_symbol(name, &owner, &crc, | 982 | ret = find_symbol(name, &owner, &crc, |
978 | !(mod->taints & TAINT_PROPRIETARY_MODULE)); | 983 | !(mod->taints & TAINT_PROPRIETARY_MODULE), true); |
979 | if (!IS_ERR_VALUE(ret)) { | 984 | if (!IS_ERR_VALUE(ret)) { |
980 | /* use_module can fail due to OOM, | 985 | /* use_module can fail due to OOM, |
981 | or module initialization or unloading */ | 986 | or module initialization or unloading */ |
@@ -1376,10 +1381,9 @@ void *__symbol_get(const char *symbol) | |||
1376 | { | 1381 | { |
1377 | struct module *owner; | 1382 | struct module *owner; |
1378 | unsigned long value; | 1383 | unsigned long value; |
1379 | const unsigned long *crc; | ||
1380 | 1384 | ||
1381 | preempt_disable(); | 1385 | preempt_disable(); |
1382 | value = __find_symbol(symbol, &owner, &crc, 1); | 1386 | value = find_symbol(symbol, &owner, NULL, true, true); |
1383 | if (IS_ERR_VALUE(value)) | 1387 | if (IS_ERR_VALUE(value)) |
1384 | value = 0; | 1388 | value = 0; |
1385 | else if (strong_try_module_get(owner)) | 1389 | else if (strong_try_module_get(owner)) |
@@ -1402,16 +1406,16 @@ static int verify_export_symbols(struct module *mod) | |||
1402 | const unsigned long *crc; | 1406 | const unsigned long *crc; |
1403 | 1407 | ||
1404 | for (i = 0; i < mod->num_syms; i++) | 1408 | for (i = 0; i < mod->num_syms; i++) |
1405 | if (!IS_ERR_VALUE(__find_symbol(mod->syms[i].name, | 1409 | if (!IS_ERR_VALUE(find_symbol(mod->syms[i].name, |
1406 | &owner, &crc, 1))) { | 1410 | &owner, &crc, true, false))) { |
1407 | name = mod->syms[i].name; | 1411 | name = mod->syms[i].name; |
1408 | ret = -ENOEXEC; | 1412 | ret = -ENOEXEC; |
1409 | goto dup; | 1413 | goto dup; |
1410 | } | 1414 | } |
1411 | 1415 | ||
1412 | for (i = 0; i < mod->num_gpl_syms; i++) | 1416 | for (i = 0; i < mod->num_gpl_syms; i++) |
1413 | if (!IS_ERR_VALUE(__find_symbol(mod->gpl_syms[i].name, | 1417 | if (!IS_ERR_VALUE(find_symbol(mod->gpl_syms[i].name, |
1414 | &owner, &crc, 1))) { | 1418 | &owner, &crc, true, false))) { |
1415 | name = mod->gpl_syms[i].name; | 1419 | name = mod->gpl_syms[i].name; |
1416 | ret = -ENOEXEC; | 1420 | ret = -ENOEXEC; |
1417 | goto dup; | 1421 | goto dup; |