The current implementation of try_module_get() requires the module to exist and be live as a precondition. While this may seem intuitive at first glance, enforcing the precondition can be tricky, considering that modules can be unloaded at any time if not previously taken. For instance, the caller could be preempted just before calling try_module_get(), and while preempted, the module could be unloaded and freed. More subtly, the module could also be unloaded at any point while executing try_module_get() before incrementing the refount with atomic_inc_not_zero(). Neglecting the precondition that the module must exist and be live can cause unexpected race conditions that can lead to crashes. However, ensuring that the precondition is met may require additional locking that increases the complexity of the code and can make it more error-prone. This patch adds a slower yet safer implementation of try_module_get() that checks if the module is valid by looking into the mod_tree before taking the module's refcount. This new function can be safely called on stale and invalid module pointers, relieving developers from the burden of ensuring that the module exists and is live before attempting to take it. The tree lookup and refcount increment are executed after taking the module_mutex to prevent the module from being unloaded after looking up the tree. Signed-off-by: Marco Pagani <marpagan@xxxxxxxxxx> --- include/linux/module.h | 15 +++++++++++++++ kernel/module/main.c | 27 +++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/include/linux/module.h b/include/linux/module.h index 08364d5cbc07..86b6ea43d204 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -695,6 +695,19 @@ extern void __module_get(struct module *module); */ extern bool try_module_get(struct module *module); +/** + * try_module_get_safe() - safely take the refcount of a module. + * @module: address of the module to be taken. + * + * Safer version of try_module_get(). Check first if the module exists and is alive, + * and then take its reference count. + * + * Return: + * * %true - module exists and its refcount has been incremented or module is NULL. + * * %false - module does not exist. + */ +extern bool try_module_get_safe(struct module *module); + /** * module_put() - release a reference count to a module * @module: the module we should release a reference count for @@ -815,6 +828,8 @@ static inline bool try_module_get(struct module *module) return true; } +#define try_module_get_safe(module) try_module_get(module) + static inline void module_put(struct module *module) { } diff --git a/kernel/module/main.c b/kernel/module/main.c index 98fedfdb8db5..22376b69778c 100644 --- a/kernel/module/main.c +++ b/kernel/module/main.c @@ -842,6 +842,33 @@ bool try_module_get(struct module *module) } EXPORT_SYMBOL(try_module_get); +bool try_module_get_safe(struct module *module) +{ + struct module *mod; + bool ret = true; + + if (!module) + goto out; + + mutex_lock(&module_mutex); + + /* + * Check if the address points to a valid live module and take + * the refcount only if it points to the module struct. + */ + mod = __module_address((unsigned long)module); + if (mod && mod == module && module_is_live(mod)) + __module_get(mod); + else + ret = false; + + mutex_unlock(&module_mutex); + +out: + return ret; +} +EXPORT_SYMBOL(try_module_get_safe); + void module_put(struct module *module) { int ret; base-commit: 4515d08a742c76612b65d2f47a87d12860519842 -- 2.43.0