Skip to content

Commit 0be964b

Browse files
Peter Zijlstrarustyrussell
authored andcommitted
module: Sanitize RCU usage and locking
Currently the RCU usage in module is an inconsistent mess of RCU and RCU-sched, this is broken for CONFIG_PREEMPT where synchronize_rcu() does not imply synchronize_sched(). Most usage sites use preempt_{dis,en}able() which is RCU-sched, but (most of) the modification sites use synchronize_rcu(). With the exception of the module bug list, which actually uses RCU. Convert everything over to RCU-sched. Furthermore add lockdep asserts to all sites, because it's not at all clear to me the required locking is observed, esp. on exported functions. Cc: Rusty Russell <[email protected]> Acked-by: "Paul E. McKenney" <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Rusty Russell <[email protected]>
1 parent bed831f commit 0be964b

File tree

3 files changed

+47
-12
lines changed

3 files changed

+47
-12
lines changed

include/linux/module.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -421,14 +421,22 @@ struct symsearch {
421421
bool unused;
422422
};
423423

424-
/* Search for an exported symbol by name. */
424+
/*
425+
* Search for an exported symbol by name.
426+
*
427+
* Must be called with module_mutex held or preemption disabled.
428+
*/
425429
const struct kernel_symbol *find_symbol(const char *name,
426430
struct module **owner,
427431
const unsigned long **crc,
428432
bool gplok,
429433
bool warn);
430434

431-
/* Walk the exported symbol table */
435+
/*
436+
* Walk the exported symbol table
437+
*
438+
* Must be called with module_mutex held or preemption disabled.
439+
*/
432440
bool each_symbol_section(bool (*fn)(const struct symsearch *arr,
433441
struct module *owner,
434442
void *data), void *data);

kernel/module.c

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,22 @@ static LIST_HEAD(modules);
105105
struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
106106
#endif /* CONFIG_KGDB_KDB */
107107

108+
static void module_assert_mutex(void)
109+
{
110+
lockdep_assert_held(&module_mutex);
111+
}
112+
113+
static void module_assert_mutex_or_preempt(void)
114+
{
115+
#ifdef CONFIG_LOCKDEP
116+
if (unlikely(!debug_locks))
117+
return;
118+
119+
WARN_ON(!rcu_read_lock_sched_held() &&
120+
!lockdep_is_held(&module_mutex));
121+
#endif
122+
}
123+
108124
#ifdef CONFIG_MODULE_SIG
109125
#ifdef CONFIG_MODULE_SIG_FORCE
110126
static bool sig_enforce = true;
@@ -318,6 +334,8 @@ bool each_symbol_section(bool (*fn)(const struct symsearch *arr,
318334
#endif
319335
};
320336

337+
module_assert_mutex_or_preempt();
338+
321339
if (each_symbol_in_section(arr, ARRAY_SIZE(arr), NULL, fn, data))
322340
return true;
323341

@@ -457,6 +475,8 @@ static struct module *find_module_all(const char *name, size_t len,
457475
{
458476
struct module *mod;
459477

478+
module_assert_mutex();
479+
460480
list_for_each_entry(mod, &modules, list) {
461481
if (!even_unformed && mod->state == MODULE_STATE_UNFORMED)
462482
continue;
@@ -1860,8 +1880,8 @@ static void free_module(struct module *mod)
18601880
list_del_rcu(&mod->list);
18611881
/* Remove this module from bug list, this uses list_del_rcu */
18621882
module_bug_cleanup(mod);
1863-
/* Wait for RCU synchronizing before releasing mod->list and buglist. */
1864-
synchronize_rcu();
1883+
/* Wait for RCU-sched synchronizing before releasing mod->list and buglist. */
1884+
synchronize_sched();
18651885
mutex_unlock(&module_mutex);
18661886

18671887
/* This may be NULL, but that's OK */
@@ -3133,11 +3153,11 @@ static noinline int do_init_module(struct module *mod)
31333153
mod->init_text_size = 0;
31343154
/*
31353155
* We want to free module_init, but be aware that kallsyms may be
3136-
* walking this with preempt disabled. In all the failure paths,
3137-
* we call synchronize_rcu/synchronize_sched, but we don't want
3138-
* to slow down the success path, so use actual RCU here.
3156+
* walking this with preempt disabled. In all the failure paths, we
3157+
* call synchronize_sched(), but we don't want to slow down the success
3158+
* path, so use actual RCU here.
31393159
*/
3140-
call_rcu(&freeinit->rcu, do_free_init);
3160+
call_rcu_sched(&freeinit->rcu, do_free_init);
31413161
mutex_unlock(&module_mutex);
31423162
wake_up_all(&module_wq);
31433163

@@ -3395,8 +3415,8 @@ static int load_module(struct load_info *info, const char __user *uargs,
33953415
/* Unlink carefully: kallsyms could be walking list. */
33963416
list_del_rcu(&mod->list);
33973417
wake_up_all(&module_wq);
3398-
/* Wait for RCU synchronizing before releasing mod->list. */
3399-
synchronize_rcu();
3418+
/* Wait for RCU-sched synchronizing before releasing mod->list. */
3419+
synchronize_sched();
34003420
mutex_unlock(&module_mutex);
34013421
free_module:
34023422
/* Free lock-classes; relies on the preceding sync_rcu() */
@@ -3663,6 +3683,8 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *,
36633683
unsigned int i;
36643684
int ret;
36653685

3686+
module_assert_mutex();
3687+
36663688
list_for_each_entry(mod, &modules, list) {
36673689
if (mod->state == MODULE_STATE_UNFORMED)
36683690
continue;
@@ -3837,6 +3859,8 @@ struct module *__module_address(unsigned long addr)
38373859
if (addr < module_addr_min || addr > module_addr_max)
38383860
return NULL;
38393861

3862+
module_assert_mutex_or_preempt();
3863+
38403864
list_for_each_entry_rcu(mod, &modules, list) {
38413865
if (mod->state == MODULE_STATE_UNFORMED)
38423866
continue;

lib/bug.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ static const struct bug_entry *module_find_bug(unsigned long bugaddr)
6666
struct module *mod;
6767
const struct bug_entry *bug = NULL;
6868

69-
rcu_read_lock();
69+
rcu_read_lock_sched();
7070
list_for_each_entry_rcu(mod, &module_bug_list, bug_list) {
7171
unsigned i;
7272

@@ -77,7 +77,7 @@ static const struct bug_entry *module_find_bug(unsigned long bugaddr)
7777
}
7878
bug = NULL;
7979
out:
80-
rcu_read_unlock();
80+
rcu_read_unlock_sched();
8181

8282
return bug;
8383
}
@@ -88,6 +88,8 @@ void module_bug_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
8888
char *secstrings;
8989
unsigned int i;
9090

91+
lockdep_assert_held(&module_mutex);
92+
9193
mod->bug_table = NULL;
9294
mod->num_bugs = 0;
9395

@@ -113,6 +115,7 @@ void module_bug_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
113115

114116
void module_bug_cleanup(struct module *mod)
115117
{
118+
lockdep_assert_held(&module_mutex);
116119
list_del_rcu(&mod->bug_list);
117120
}
118121

0 commit comments

Comments
 (0)