Message ID | 20240221194052.927623-14-surenb@google.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | Memory allocation profiling | expand |
On 2/21/24 20:40, Suren Baghdasaryan wrote: > Skip freeing module's data section if there are non-zero allocation tags > because otherwise, once these allocations are freed, the access to their > code tag would cause UAF. > > Signed-off-by: Suren Baghdasaryan <surenb@google.com> I know that module unloading was never considered really supported etc. But should we printk something so the admin knows why it didn't unload, and can go check those outstanding allocations?
On Mon, Feb 26, 2024 at 8:58 AM Vlastimil Babka <vbabka@suse.cz> wrote: > > On 2/21/24 20:40, Suren Baghdasaryan wrote: > > Skip freeing module's data section if there are non-zero allocation tags > > because otherwise, once these allocations are freed, the access to their > > code tag would cause UAF. > > > > Signed-off-by: Suren Baghdasaryan <surenb@google.com> > > I know that module unloading was never considered really supported etc. > But should we printk something so the admin knows why it didn't unload, and > can go check those outstanding allocations? Yes, that sounds reasonable. I'll add a pr_warn() in the next version. Thanks! > > -- > To unsubscribe from this group and stop receiving emails from it, send an email to kernel-team+unsubscribe@android.com. >
On Mon, Feb 26, 2024 at 05:58:40PM +0100, Vlastimil Babka wrote: > On 2/21/24 20:40, Suren Baghdasaryan wrote: > > Skip freeing module's data section if there are non-zero allocation tags > > because otherwise, once these allocations are freed, the access to their > > code tag would cause UAF. > > > > Signed-off-by: Suren Baghdasaryan <surenb@google.com> > > I know that module unloading was never considered really supported etc. If its not supported then we should not have it on modules. Module loading and unloading should just work, otherwise then this should not work with modules and leave them in a zombie state. Luis
On Tue, Mar 12, 2024 at 11:23 AM Luis Chamberlain <mcgrof@kernel.org> wrote: > > On Mon, Feb 26, 2024 at 05:58:40PM +0100, Vlastimil Babka wrote: > > On 2/21/24 20:40, Suren Baghdasaryan wrote: > > > Skip freeing module's data section if there are non-zero allocation tags > > > because otherwise, once these allocations are freed, the access to their > > > code tag would cause UAF. > > > > > > Signed-off-by: Suren Baghdasaryan <surenb@google.com> > > > > I know that module unloading was never considered really supported etc. > > If its not supported then we should not have it on modules. Module > loading and unloading should just work, otherwise then this should not > work with modules and leave them in a zombie state. I replied on the v5 thread here: https://lore.kernel.org/all/20240306182440.2003814-13-surenb@google.com/ . Let's continue the discussion in that thread. Thanks! > > Luis
On Tue, Mar 12, 2024 at 11:23:45AM -0700, Luis Chamberlain wrote: > On Mon, Feb 26, 2024 at 05:58:40PM +0100, Vlastimil Babka wrote: > > On 2/21/24 20:40, Suren Baghdasaryan wrote: > > > Skip freeing module's data section if there are non-zero allocation tags > > > because otherwise, once these allocations are freed, the access to their > > > code tag would cause UAF. > > > > > > Signed-off-by: Suren Baghdasaryan <surenb@google.com> > > > > I know that module unloading was never considered really supported etc. > > If its not supported then we should not have it on modules. Module > loading and unloading should just work, otherwise then this should not > work with modules and leave them in a zombie state. Not have memory allocation profiling on modules?
diff --git a/include/linux/codetag.h b/include/linux/codetag.h index c44f5b83f24d..bfd0ba5c4185 100644 --- a/include/linux/codetag.h +++ b/include/linux/codetag.h @@ -35,7 +35,7 @@ struct codetag_type_desc { size_t tag_size; void (*module_load)(struct codetag_type *cttype, struct codetag_module *cmod); - void (*module_unload)(struct codetag_type *cttype, + bool (*module_unload)(struct codetag_type *cttype, struct codetag_module *cmod); }; @@ -71,10 +71,10 @@ codetag_register_type(const struct codetag_type_desc *desc); #if defined(CONFIG_CODE_TAGGING) && defined(CONFIG_MODULES) void codetag_load_module(struct module *mod); -void codetag_unload_module(struct module *mod); +bool codetag_unload_module(struct module *mod); #else static inline void codetag_load_module(struct module *mod) {} -static inline void codetag_unload_module(struct module *mod) {} +static inline bool codetag_unload_module(struct module *mod) { return true; } #endif #endif /* _LINUX_CODETAG_H */ diff --git a/kernel/module/main.c b/kernel/module/main.c index f400ba076cc7..658b631e76ad 100644 --- a/kernel/module/main.c +++ b/kernel/module/main.c @@ -1211,15 +1211,19 @@ static void *module_memory_alloc(unsigned int size, enum mod_mem_type type) return module_alloc(size); } -static void module_memory_free(void *ptr, enum mod_mem_type type) +static void module_memory_free(void *ptr, enum mod_mem_type type, + bool unload_codetags) { + if (!unload_codetags && mod_mem_type_is_core_data(type)) + return; + if (mod_mem_use_vmalloc(type)) vfree(ptr); else module_memfree(ptr); } -static void free_mod_mem(struct module *mod) +static void free_mod_mem(struct module *mod, bool unload_codetags) { for_each_mod_mem_type(type) { struct module_memory *mod_mem = &mod->mem[type]; @@ -1230,20 +1234,23 @@ static void free_mod_mem(struct module *mod) /* Free lock-classes; relies on the preceding sync_rcu(). */ lockdep_free_key_range(mod_mem->base, mod_mem->size); if (mod_mem->size) - module_memory_free(mod_mem->base, type); + module_memory_free(mod_mem->base, type, + unload_codetags); } /* MOD_DATA hosts mod, so free it at last */ lockdep_free_key_range(mod->mem[MOD_DATA].base, mod->mem[MOD_DATA].size); - module_memory_free(mod->mem[MOD_DATA].base, MOD_DATA); + module_memory_free(mod->mem[MOD_DATA].base, MOD_DATA, unload_codetags); } /* Free a module, remove from lists, etc. */ static void free_module(struct module *mod) { + bool unload_codetags; + trace_module_free(mod); - codetag_unload_module(mod); + unload_codetags = codetag_unload_module(mod); mod_sysfs_teardown(mod); /* @@ -1285,7 +1292,7 @@ static void free_module(struct module *mod) kfree(mod->args); percpu_modfree(mod); - free_mod_mem(mod); + free_mod_mem(mod, unload_codetags); } void *__symbol_get(const char *symbol) @@ -2298,7 +2305,7 @@ static int move_module(struct module *mod, struct load_info *info) return 0; out_enomem: for (t--; t >= 0; t--) - module_memory_free(mod->mem[t].base, t); + module_memory_free(mod->mem[t].base, t, true); return ret; } @@ -2428,7 +2435,7 @@ static void module_deallocate(struct module *mod, struct load_info *info) percpu_modfree(mod); module_arch_freeing_init(mod); - free_mod_mem(mod); + free_mod_mem(mod, true); } int __weak module_finalize(const Elf_Ehdr *hdr, diff --git a/lib/codetag.c b/lib/codetag.c index 9af22648dbfa..b13412ca57cc 100644 --- a/lib/codetag.c +++ b/lib/codetag.c @@ -5,6 +5,7 @@ #include <linux/module.h> #include <linux/seq_buf.h> #include <linux/slab.h> +#include <linux/vmalloc.h> struct codetag_type { struct list_head link; @@ -239,12 +240,13 @@ void codetag_load_module(struct module *mod) mutex_unlock(&codetag_lock); } -void codetag_unload_module(struct module *mod) +bool codetag_unload_module(struct module *mod) { struct codetag_type *cttype; + bool unload_ok = true; if (!mod) - return; + return true; mutex_lock(&codetag_lock); list_for_each_entry(cttype, &codetag_types, link) { @@ -261,7 +263,8 @@ void codetag_unload_module(struct module *mod) } if (found) { if (cttype->desc.module_unload) - cttype->desc.module_unload(cttype, cmod); + if (!cttype->desc.module_unload(cttype, cmod)) + unload_ok = false; cttype->count -= range_size(cttype, &cmod->range); idr_remove(&cttype->mod_idr, mod_id); @@ -270,4 +273,6 @@ void codetag_unload_module(struct module *mod) up_write(&cttype->mod_lock); } mutex_unlock(&codetag_lock); + + return unload_ok; }
Skip freeing module's data section if there are non-zero allocation tags because otherwise, once these allocations are freed, the access to their code tag would cause UAF. Signed-off-by: Suren Baghdasaryan <surenb@google.com> --- include/linux/codetag.h | 6 +++--- kernel/module/main.c | 23 +++++++++++++++-------- lib/codetag.c | 11 ++++++++--- 3 files changed, 26 insertions(+), 14 deletions(-)