On Thu, May 21, 2020 at 09:56:37AM -0700, Kristen Carlson Accardi wrote:
> When reordering functions, the relative offsets for relocs that
> are either in the randomized sections, or refer to the randomized
> sections will need to be adjusted. Add code to detect whether a
> reloc satisifies these cases, and if so, add them to the appropriate
> reloc list.
> 
> Signed-off-by: Kristen Carlson Accardi <[email protected]>
> Reviewed-by: Tony Luck <[email protected]>
> Tested-by: Tony Luck <[email protected]>

I'm just down to bikeshedding here (see below).

> ---
>  arch/x86/boot/compressed/Makefile |  7 +++-
>  arch/x86/tools/relocs.c           | 55 ++++++++++++++++++++++++-------
>  arch/x86/tools/relocs.h           |  4 +--
>  arch/x86/tools/relocs_common.c    | 15 ++++++---
>  4 files changed, 62 insertions(+), 19 deletions(-)
> 
> diff --git a/arch/x86/boot/compressed/Makefile 
> b/arch/x86/boot/compressed/Makefile
> index 5f7c262bcc99..3a5a004498de 100644
> --- a/arch/x86/boot/compressed/Makefile
> +++ b/arch/x86/boot/compressed/Makefile
> @@ -117,6 +117,11 @@ $(obj)/vmlinux: $(vmlinux-objs-y) FORCE
>       $(call if_changed,check-and-link-vmlinux)
>  
>  OBJCOPYFLAGS_vmlinux.bin :=  -R .comment -S
> +
> +ifdef CONFIG_FG_KASLR
> +     RELOCS_ARGS += --fg-kaslr
> +endif
> +
>  $(obj)/vmlinux.bin: vmlinux FORCE
>       $(call if_changed,objcopy)
>  
> @@ -124,7 +129,7 @@ targets += $(patsubst $(obj)/%,%,$(vmlinux-objs-y)) 
> vmlinux.bin.all vmlinux.relo
>  
>  CMD_RELOCS = arch/x86/tools/relocs
>  quiet_cmd_relocs = RELOCS  $@
> -      cmd_relocs = $(CMD_RELOCS) $< > $@;$(CMD_RELOCS) --abs-relocs $<
> +      cmd_relocs = $(CMD_RELOCS) $(RELOCS_ARGS) $< > $@;$(CMD_RELOCS) 
> $(RELOCS_ARGS) --abs-relocs $<
>  $(obj)/vmlinux.relocs: vmlinux FORCE
>       $(call if_changed,relocs)
>  
> diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
> index a00dc133f109..bf51ff1854ff 100644
> --- a/arch/x86/tools/relocs.c
> +++ b/arch/x86/tools/relocs.c
> @@ -42,6 +42,8 @@ struct section {
>  };
>  static struct section *secs;
>  
> +static int fg_kaslr;

I find the shifting name for fg_kaslr, fgkaslr, and global fg_kaslr
confusing. I think it would call this one "fgkaslr_mode" to indicate
that it does control the mode of how the later functions behave.

> +
>  static const char * const sym_regex_kernel[S_NSYMTYPES] = {
>  /*
>   * Following symbols have been audited. There values are constant and do
> @@ -351,8 +353,8 @@ static int sym_index(Elf_Sym *sym)
>               return sym->st_shndx;
>  
>       /* calculate offset of sym from head of table. */
> -     offset = (unsigned long) sym - (unsigned long) symtab;
> -     index = offset/sizeof(*sym);
> +     offset = (unsigned long)sym - (unsigned long)symtab;
> +     index = offset / sizeof(*sym);
>  
>       return elf32_to_cpu(xsymtab[index]);
>  }
> @@ -500,22 +502,22 @@ static void read_symtabs(FILE *fp)
>                       sec->xsymtab = malloc(sec->shdr.sh_size);
>                       if (!sec->xsymtab) {
>                               die("malloc of %d bytes for xsymtab failed\n",
> -                                     sec->shdr.sh_size);
> +                                 sec->shdr.sh_size);
>                       }
>                       if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
>                               die("Seek to %d failed: %s\n",
> -                                     sec->shdr.sh_offset, strerror(errno));
> +                                 sec->shdr.sh_offset, strerror(errno));
>                       }
>                       if (fread(sec->xsymtab, 1, sec->shdr.sh_size, fp)
> -                                     != sec->shdr.sh_size) {
> +                         != sec->shdr.sh_size) {
>                               die("Cannot read extended symbol table: %s\n",
> -                                     strerror(errno));
> +                                 strerror(errno));
>                       }
>                       shxsymtabndx = i;
>                       continue;
>  
>               case SHT_SYMTAB:
> -                     num_syms = sec->shdr.sh_size/sizeof(Elf_Sym);
> +                     num_syms = sec->shdr.sh_size / sizeof(Elf_Sym);
>  
>                       sec->symtab = malloc(sec->shdr.sh_size);
>                       if (!sec->symtab) {

I would mention these whitespace/readability cleanups in the commit log.

> @@ -818,6 +820,32 @@ static int is_percpu_sym(ElfW(Sym) *sym, const char 
> *symname)
>               strncmp(symname, "init_per_cpu_", 13);
>  }
>  
> +static int is_function_section(struct section *sec)
> +{
> +     const char *name;
> +
> +     if (!fg_kaslr)
> +             return 0;
> +
> +     name = sec_name(sec->shdr.sh_info);
> +
> +     return(!strncmp(name, ".text.", 6));
> +}
> +
> +static int is_randomized_sym(ElfW(Sym) *sym)
> +{
> +     const char *name;
> +
> +     if (!fg_kaslr)
> +             return 0;
> +
> +     if (sym->st_shndx > shnum)
> +             return 0;
> +
> +     name = sec_name(sym_index(sym));
> +     return(!strncmp(name, ".text.", 6));
> +}
> +
>  static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
>                     const char *symname)
>  {
> @@ -842,13 +870,17 @@ static int do_reloc64(struct section *sec, Elf_Rel 
> *rel, ElfW(Sym) *sym,
>       case R_X86_64_PC32:
>       case R_X86_64_PLT32:
>               /*
> -              * PC relative relocations don't need to be adjusted unless
> -              * referencing a percpu symbol.
> +              * we need to keep pc relative relocations for sections which
> +              * might be randomized, and for the percpu section.
> +              * We also need to keep relocations for any offset which might
> +              * reference an address in a section which has been randomized.
>                *
>                * NB: R_X86_64_PLT32 can be treated as R_X86_64_PC32.
>                */
> -             if (is_percpu_sym(sym, symname))
> +             if (is_function_section(sec) || is_randomized_sym(sym) ||
> +                 is_percpu_sym(sym, symname))
>                       add_reloc(&relocs32neg, offset);
> +
>               break;
>  
>       case R_X86_64_PC64:
> @@ -1158,8 +1190,9 @@ static void print_reloc_info(void)
>  
>  void process(FILE *fp, int use_real_mode, int as_text,
>            int show_absolute_syms, int show_absolute_relocs,
> -          int show_reloc_info)
> +          int show_reloc_info, int fgkaslr)
>  {
> +     fg_kaslr = fgkaslr;

Then this becomes a bit more readable:

        fgkaslr_mode = fgkaslr;

>       regex_init(use_real_mode);
>       read_ehdr(fp);
>       read_shdrs(fp);
> diff --git a/arch/x86/tools/relocs.h b/arch/x86/tools/relocs.h
> index 43c83c0fd22c..05504052c846 100644
> --- a/arch/x86/tools/relocs.h
> +++ b/arch/x86/tools/relocs.h
> @@ -31,8 +31,8 @@ enum symtype {
>  
>  void process_32(FILE *fp, int use_real_mode, int as_text,
>               int show_absolute_syms, int show_absolute_relocs,
> -             int show_reloc_info);
> +             int show_reloc_info, int fg_kaslr);
>  void process_64(FILE *fp, int use_real_mode, int as_text,
>               int show_absolute_syms, int show_absolute_relocs,
> -             int show_reloc_info);
> +             int show_reloc_info, int fg_kaslr);

I think the prototype and declaration should have matching names:
fgkaslr in "process" and fg_kaslr here. I suggest just calling it
fgkaslr in all.

>  #endif /* RELOCS_H */
> diff --git a/arch/x86/tools/relocs_common.c b/arch/x86/tools/relocs_common.c
> index 6634352a20bc..1407db72367a 100644
> --- a/arch/x86/tools/relocs_common.c
> +++ b/arch/x86/tools/relocs_common.c
> @@ -12,14 +12,14 @@ void die(char *fmt, ...)
>  
>  static void usage(void)
>  {
> -     die("relocs [--abs-syms|--abs-relocs|--reloc-info|--text|--realmode]" \
> -         " vmlinux\n");
> +     die("relocs [--abs-syms|--abs-relocs|--reloc-info|--text|--realmode|" \
> +         "--fg-kaslr] vmlinux\n");
>  }
>  
>  int main(int argc, char **argv)
>  {
>       int show_absolute_syms, show_absolute_relocs, show_reloc_info;
> -     int as_text, use_real_mode;
> +     int as_text, use_real_mode, fg_kaslr;

And I think I'd call this one fgkaslr_opt to show it comes from the opt
parsing.

>       const char *fname;
>       FILE *fp;
>       int i;
> @@ -30,6 +30,7 @@ int main(int argc, char **argv)
>       show_reloc_info = 0;
>       as_text = 0;
>       use_real_mode = 0;
> +     fg_kaslr = 0;
>       fname = NULL;
>       for (i = 1; i < argc; i++) {
>               char *arg = argv[i];
> @@ -54,6 +55,10 @@ int main(int argc, char **argv)
>                               use_real_mode = 1;
>                               continue;
>                       }
> +                     if (strcmp(arg, "--fg-kaslr") == 0) {
> +                             fg_kaslr = 1;
> +                             continue;
> +                     }
>               }
>               else if (!fname) {
>                       fname = arg;
> @@ -75,11 +80,11 @@ int main(int argc, char **argv)
>       if (e_ident[EI_CLASS] == ELFCLASS64)
>               process_64(fp, use_real_mode, as_text,
>                          show_absolute_syms, show_absolute_relocs,
> -                        show_reloc_info);
> +                        show_reloc_info, fg_kaslr);
>       else
>               process_32(fp, use_real_mode, as_text,
>                          show_absolute_syms, show_absolute_relocs,
> -                        show_reloc_info);
> +                        show_reloc_info, fg_kaslr);
>       fclose(fp);
>       return 0;
>  }
> -- 
> 2.20.1
> 

With these changes, yeah, I think it's good to go.

Reviewed-by: Kees Cook <[email protected]>

-- 
Kees Cook

Reply via email to