|
Message-ID: <20200211123932.GA29598@linux-8ccs> Date: Tue, 11 Feb 2020 13:39:32 +0100 From: Jessica Yu <jeyu@...nel.org> To: Kees Cook <keescook@...omium.org> Cc: Kristen Carlson Accardi <kristen@...ux.intel.com>, tglx@...utronix.de, mingo@...hat.com, bp@...en8.de, hpa@...or.com, arjan@...ux.intel.com, rick.p.edgecombe@...el.com, x86@...nel.org, linux-kernel@...r.kernel.org, kernel-hardening@...ts.openwall.com Subject: Re: [RFC PATCH 10/11] module: Reorder functions +++ Kees Cook [06/02/20 04:41 -0800]: >On Wed, Feb 05, 2020 at 02:39:49PM -0800, Kristen Carlson Accardi wrote: >> If a module has functions split out into separate text sections >> (i.e. compiled with the -ffunction-sections flag), reorder the >> functions to provide some code diversification to modules. >> >> Signed-off-by: Kristen Carlson Accardi <kristen@...ux.intel.com> > >Probably a good idea to add Jessica to CC in next version: > Jessica Yu <jeyu@...nel.org> Thanks :) >Reviewed-by: Kees Cook <keescook@...omium.org> > >-Kees > >> --- >> kernel/module.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ >> 1 file changed, 85 insertions(+) >> >> diff --git a/kernel/module.c b/kernel/module.c >> index b56f3224b161..231563e95e61 100644 >> --- a/kernel/module.c >> +++ b/kernel/module.c >> @@ -53,6 +53,8 @@ >> #include <linux/bsearch.h> >> #include <linux/dynamic_debug.h> >> #include <linux/audit.h> >> +#include <linux/random.h> >> +#include <asm/setup.h> >> #include <uapi/linux/module.h> >> #include "module-internal.h" >> >> @@ -3245,6 +3247,87 @@ static int find_module_sections(struct module *mod, struct load_info *info) >> return 0; >> } >> >> +/* >> + * shuffle_text_list() >> + * Use a Fisher Yates algorithm to shuffle a list of text sections. >> + */ >> +static void shuffle_text_list(Elf_Shdr **list, int size) >> +{ >> + int i; >> + unsigned int j; >> + Elf_Shdr *temp; >> + >> + for (i = size - 1; i > 0; i--) { >> + /* >> + * TBD - seed. We need to be able to use a known >> + * seed so that we can non-randomly randomize for >> + * debugging. >> + */ >> + >> + // pick a random index from 0 to i >> + get_random_bytes(&j, sizeof(j)); >> + j = j % (i + 1); >> + >> + temp = list[i]; >> + list[i] = list[j]; >> + list[j] = temp; >> + } >> +} >> + >> +/* >> + * randomize_text() >> + * Look through the core section looking for executable code sections. >> + * Store sections in an array and then shuffle the sections >> + * to reorder the functions. >> + */ >> +static void randomize_text(struct module *mod, struct load_info *info) >> +{ >> + int i; >> + int num_text_sections = 0; >> + Elf_Shdr **text_list; >> + int size = 0; >> + int max_sections = info->hdr->e_shnum; >> + unsigned int sec = find_sec(info, ".text"); >> + >> + if (!IS_ENABLED(CONFIG_FG_KASLR) || !kaslr_enabled()) >> + return; Maybe put this conditional before the call to randomize_text() in move_module()? Just for code readability reasons (i.e., we only call randomize_text() when CONFIG_FG_KASLR || kaslr_enabled()). But this is just a matter of preference. >> + >> + if (sec == 0) >> + return; >> + >> + text_list = kmalloc_array(max_sections, sizeof(*text_list), GFP_KERNEL); >> + if (text_list == NULL) >> + return; >> + >> + for (i = 0; i < max_sections; i++) { >> + Elf_Shdr *shdr = &info->sechdrs[i]; >> + const char *sname = info->secstrings + shdr->sh_name; >> + >> + if (!(shdr->sh_flags & SHF_ALLOC) || >> + !(shdr->sh_flags & SHF_EXECINSTR) || >> + strstarts(sname, ".init")) >> + continue; >> + >> + text_list[num_text_sections] = shdr; >> + num_text_sections++; >> + } >> + >> + shuffle_text_list(text_list, num_text_sections); >> + >> + for (i = 0; i < num_text_sections; i++) { >> + Elf_Shdr *shdr = text_list[i]; >> + unsigned int infosec; >> + const char *sname; >> + >> + sname = info->secstrings + shdr->sh_name; sname doesn't appear to be used after this (?) >> + infosec = shdr->sh_info; >> + >> + shdr->sh_entsize = get_offset(mod, &size, shdr, infosec); get_offset() expects a section index as the last argument, but sh_info is 0 for text sections (SHT_PROGBITS). It's really only used in arch_mod_section_prepend() though, which is only defined for parisc. We could perhaps save the section index in sh_info in the previous for loop (hacky, I have to double check if this is actually safe, but it seems sh_info only has signficance for SHT_REL* and SHT_SYMTAB sections). >> + } >> + >> + kfree(text_list); >> +} >> + >> static int move_module(struct module *mod, struct load_info *info) >> { >> int i; >> @@ -3282,6 +3365,8 @@ static int move_module(struct module *mod, struct load_info *info) >> } else >> mod->init_layout.base = NULL; >> >> + randomize_text(mod, info); Hm, I wonder if we should not incorporate the randomize_text() logic into layout_sections() instead of move_module(), since logically speaking layout_sections() determines all the section offsets and stores them in sh_entsize, whereas move_module() does all the allocations and copying to final destination. Just a thought. Thanks! Jessica
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.