module_assert_mutex_or_preempt() is not needed in find_symbol(). The function checks for RCU-sched or the module_mutex to be acquired. The list_for_each_entry_rcu() below does the same check. Remove module_assert_mutex_or_preempt() from try_add_tainted_module(). Use RCU protection to invoke find_symbol() and update callers.
Showing the changes to kernel/module (2 of 2 files). Show all
Unified · Split
| @@ -331,7 +331,7 @@ static bool find_exported_symbol_in_section(const struct symsearch *syms, · 330 unmodified lines | ||
| 331 | 331 | |
| 332 | 332 | /* |
| 333 | 333 | * Find an exported symbol and return it, along with, (optional) crc and |
| 334 | − * (optional) module which owns it. Needs preempt disabled or module_mutex. | |
| 334 | + * (optional) module which owns it. Needs RCU or module_mutex. | |
| 335 | 335 | */ |
| 336 | 336 | bool find_symbol(struct find_symbol_arg *fsa) |
| 337 | 337 | { |
| @@ -345,8 +345,6 @@ bool find_symbol(struct find_symbol_arg *fsa) · 7 unmodified lines | ||
| 345 | 345 | struct module *mod; |
| 346 | 346 | unsigned int i; |
| 347 | 347 | |
| 348 | − module_assert_mutex_or_preempt(); | |
| 349 | − | |
| 350 | 348 | for (i = 0; i < ARRAY_SIZE(arr); i++) |
| 351 | 349 | if (find_exported_symbol_in_section(&arr[i], NULL, fsa)) |
| 352 | 350 | return true; |
| @@ -812,10 +810,9 @@ void __symbol_put(const char *symbol) · 459 unmodified lines | ||
| 812 | 810 | .gplok = true, |
| 813 | 811 | }; |
| 814 | 812 | |
| 815 | − preempt_disable(); | |
| 813 | + guard(rcu)(); | |
| 816 | 814 | BUG_ON(!find_symbol(&fsa)); |
| 817 | 815 | module_put(fsa.owner); |
| 818 | − preempt_enable(); | |
| 819 | 816 | } |
| 820 | 817 | EXPORT_SYMBOL(__symbol_put); |
| 821 | 818 | |
| @@ -1369,21 +1366,18 @@ void *__symbol_get(const char *symbol) · 547 unmodified lines | ||
| 1369 | 1366 | .warn = true, |
| 1370 | 1367 | }; |
| 1371 | 1368 | |
| 1372 | − preempt_disable(); | |
| 1373 | − if (!find_symbol(&fsa)) | |
| 1374 | − goto fail; | |
| 1375 | − if (fsa.license != GPL_ONLY) { | |
| 1376 | − pr_warn("failing symbol_get of non-GPLONLY symbol %s.\n", | |
| 1377 | − symbol); | |
| 1378 | − goto fail; | |
| 1369 | + scoped_guard(rcu) { | |
| 1370 | + if (!find_symbol(&fsa)) | |
| 1371 | + return NULL; | |
| 1372 | + if (fsa.license != GPL_ONLY) { | |
| 1373 | + pr_warn("failing symbol_get of non-GPLONLY symbol %s.\n", | |
| 1374 | + symbol); | |
| 1375 | + return NULL; | |
| 1376 | + } | |
| 1377 | + if (strong_try_module_get(fsa.owner)) | |
| 1378 | + return NULL; | |
| 1379 | 1379 | } |
| 1380 | − if (strong_try_module_get(fsa.owner)) | |
| 1381 | − goto fail; | |
| 1382 | − preempt_enable(); | |
| 1383 | 1380 | return (void *)kernel_symbol_value(fsa.sym); |
| 1384 | −fail: | |
| 1385 | − preempt_enable(); | |
| 1386 | − return NULL; | |
| 1387 | 1381 | } |
| 1388 | 1382 | EXPORT_SYMBOL_GPL(__symbol_get); |
| 1389 | 1383 | |
| @@ -79,17 +79,17 @@ int check_modstruct_version(const struct load_info *info, · 78 unmodified lines | ||
| 79 | 79 | .name = "module_layout", |
| 80 | 80 | .gplok = true, |
| 81 | 81 | }; |
| 82 | + bool have_symbol; | |
| 82 | 83 | |
| 83 | 84 | /* |
| 84 | 85 | * Since this should be found in kernel (which can't be removed), no |
| 85 | − * locking is necessary -- use preempt_disable() to placate lockdep. | |
| 86 | + * locking is necessary. Regardless use a RCU read section to keep | |
| 87 | + * lockdep happy. | |
| 86 | 88 | */ |
| 87 | − preempt_disable(); | |
| 88 | − if (!find_symbol(&fsa)) { | |
| 89 | − preempt_enable(); | |
| 90 | − BUG(); | |
| 91 | − } | |
| 92 | − preempt_enable(); | |
| 89 | + scoped_guard(rcu) | |
| 90 | + have_symbol = find_symbol(&fsa); | |
| 91 | + BUG_ON(!have_symbol); | |
| 92 | + | |
| 93 | 93 | return check_version(info, "module_layout", mod, fsa.crc); |
| 94 | 94 | } |
| 95 | 95 | |