diff options
Diffstat (limited to 'binutils')
-rw-r--r-- | binutils/ChangeLog | 18 | ||||
-rw-r--r-- | binutils/doc/binutils.texi | 34 | ||||
-rw-r--r-- | binutils/elfedit.c | 256 |
3 files changed, 298 insertions, 10 deletions
diff --git a/binutils/ChangeLog b/binutils/ChangeLog index bdbee0f..f484f92 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,21 @@ +2018-11-06 H.J. Lu <hongjiu.lu@intel.com> + + * doc/binutils.texi: Document --enable-x86-feature and + --disable-x86-feature options for elfedit. + * elfedit.c: Include "config.h" and <sys/mman.h>. + (enable_x86_features): New. + (disable_x86_features): Likewise. + (update_gnu_property): Likewise. + (elf_x86_feature): Likewise. + (process_file): Call update_gnu_property on ET_EXEC or ET_DYN + file. + (command_line_switch): Add OPTION_ENABLE_X86_FEATURE and + OPTION_DISABLE_X86_FEATURE. + (options): Add--enable-x86-feature and --disable-x86-feature. + (usage): Likewise. + (main): Handle OPTION_ENABLE_X86_FEATURE and + OPTION_DISABLE_X86_FEATURE. + 2018-11-03 H.J. Lu <hongjiu.lu@intel.com> * elfedit.c (update_elf_header): Move EI_MAG? check to ... diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi index 6edd7b1..6cfda45 100644 --- a/binutils/doc/binutils.texi +++ b/binutils/doc/binutils.texi @@ -42,7 +42,7 @@ section entitled ``GNU Free Documentation License''. * size: (binutils)size. List section sizes and total size. * strings: (binutils)strings. List printable strings from files. * strip: (binutils)strip. Discard symbols. -* elfedit: (binutils)elfedit. Update the ELF header of ELF files. +* elfedit: (binutils)elfedit. Update ELF header and property of ELF files. * windmc: (binutils)windmc. Generator for Windows message resources. * windres: (binutils)windres. Manipulate Windows resources. @end direntry @@ -111,7 +111,7 @@ List printable strings from files Discard symbols @item elfedit -Update the ELF header of ELF files. +Update the ELF header and program property of ELF files. @item c++filt Demangle encoded C++ symbols (on MS-DOS, this program is named @@ -151,7 +151,7 @@ in the section entitled ``GNU Free Documentation License''. * windres:: Manipulate Windows resources * dlltool:: Create files needed to build and use DLLs * readelf:: Display the contents of ELF format files -* elfedit:: Update the ELF header of ELF files +* elfedit:: Update ELF header and property of ELF files * Common Options:: Command-line options for all utilities * Selecting the Target System:: How these utilities determine the target * Reporting Bugs:: Reporting Bugs @@ -4725,7 +4725,7 @@ objdump(1), and the Info entries for @file{binutils}. @cindex Update ELF header @kindex elfedit -@c man title elfedit Update the ELF header of ELF files. +@c man title elfedit Update ELF header and program property of ELF files. @smallexample @c man begin SYNOPSIS elfedit @@ -4735,6 +4735,8 @@ elfedit [@option{--input-mach=}@var{machine}] @option{--output-mach=}@var{machine} @option{--output-type=}@var{type} @option{--output-osabi=}@var{osabi} + @option{--enable-x86-feature=}@var{feature} + @option{--disable-x86-feature=}@var{feature} [@option{-v}|@option{--version}] [@option{-h}|@option{--help}] @var{elffile}@dots{} @@ -4743,9 +4745,10 @@ elfedit [@option{--input-mach=}@var{machine}] @c man begin DESCRIPTION elfedit -@command{elfedit} updates the ELF header of ELF files which have -the matching ELF machine and file types. The options control how and -which fields in the ELF header should be updated. +@command{elfedit} updates the ELF header and program property of ELF +files which have the matching ELF machine and file types. The options +control how and which fields in the ELF header and program property +should be updated. @var{elffile}@dots{} are the ELF files to be updated. 32-bit and 64-bit ELF files are supported, as are archives containing ELF files. @@ -4755,7 +4758,9 @@ which fields in the ELF header should be updated. The long and short forms of options, shown here as alternatives, are equivalent. At least one of the @option{--output-mach}, -@option{--output-type} and @option{--output-osabi} options must be given. +@option{--output-type}, @option{--output-osabi}, +@option{--enable-x86-feature} and @option{--disable-x86-feature} +options must be given. @table @env @@ -4795,6 +4800,19 @@ The supported ELF OSABIs are, @var{none}, @var{HPUX}, @var{NetBSD}, Change the ELF OSABI in the ELF header to @var{osabi}. The supported ELF OSABI are the same as @option{--input-osabi}. +@item --enable-x86-feature=@var{feature} +Set the @var{feature} bit in program property in @var{exec} or @var{dyn} +ELF files with machine types of @var{i386} or @var{x86-64}. The +supported features are, @var{ibt} and @var{shstk}. + +@item --disable-x86-feature=@var{feature} +Clear the @var{feature} bit in program property in @var{exec} or +@var{dyn} ELF files with machine types of @var{i386} or @var{x86-64}. +The supported features are the same as @option{--enable-x86-feature}. + +Note: @option{--enable-x86-feature} and @option{--disable-x86-feature} +are available only on hosts with @samp{mmap} support. + @item -v @itemx --version Display the version number of @command{elfedit}. diff --git a/binutils/elfedit.c b/binutils/elfedit.c index a9f7c9d..98d4fd7 100644 --- a/binutils/elfedit.c +++ b/binutils/elfedit.c @@ -18,6 +18,7 @@ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "config.h" #include "sysdep.h" #include <assert.h> @@ -65,6 +66,217 @@ enum elfclass static enum elfclass input_elf_class = ELF_CLASS_UNKNOWN; static enum elfclass output_elf_class = ELF_CLASS_BOTH; +#ifdef HAVE_MMAP +#include <sys/mman.h> + +static unsigned int enable_x86_features; +static unsigned int disable_x86_features; + +static int +update_gnu_property (const char *file_name, FILE *file) +{ + char *map; + Elf_Internal_Phdr *phdrs; + struct stat st_buf; + unsigned int i; + int ret; + + if (!enable_x86_features && !disable_x86_features) + return 0; + + if (elf_header.e_machine != EM_386 + && elf_header.e_machine != EM_X86_64) + { + error (_("%s: Not an i386 nor x86-64 ELF file\n"), file_name); + return 0; + } + + if (fstat (fileno (file), &st_buf) < 0) + { + error (_("%s: stat () failed\n"), file_name); + return 1; + } + + map = mmap (NULL, st_buf.st_size, PROT_READ | PROT_WRITE, + MAP_SHARED, fileno (file), 0); + if (map == MAP_FAILED) + { + error (_("%s: mmap () failed\n"), file_name); + return 0; + } + + phdrs = xmalloc (elf_header.e_phnum * sizeof (*phdrs)); + + if (elf_header.e_ident[EI_CLASS] == ELFCLASS32) + { + Elf32_External_Phdr *phdrs32 + = (Elf32_External_Phdr *) (map + elf_header.e_phoff); + for (i = 0; i < elf_header.e_phnum; i++) + { + phdrs[i].p_type = BYTE_GET (phdrs32[i].p_type); + phdrs[i].p_offset = BYTE_GET (phdrs32[i].p_offset); + phdrs[i].p_vaddr = BYTE_GET (phdrs32[i].p_vaddr); + phdrs[i].p_paddr = BYTE_GET (phdrs32[i].p_paddr); + phdrs[i].p_filesz = BYTE_GET (phdrs32[i].p_filesz); + phdrs[i].p_memsz = BYTE_GET (phdrs32[i].p_memsz); + phdrs[i].p_flags = BYTE_GET (phdrs32[i].p_flags); + phdrs[i].p_align = BYTE_GET (phdrs32[i].p_align); + } + } + else + { + Elf64_External_Phdr *phdrs64 + = (Elf64_External_Phdr *) (map + elf_header.e_phoff); + for (i = 0; i < elf_header.e_phnum; i++) + { + phdrs[i].p_type = BYTE_GET (phdrs64[i].p_type); + phdrs[i].p_offset = BYTE_GET (phdrs64[i].p_offset); + phdrs[i].p_vaddr = BYTE_GET (phdrs64[i].p_vaddr); + phdrs[i].p_paddr = BYTE_GET (phdrs64[i].p_paddr); + phdrs[i].p_filesz = BYTE_GET (phdrs64[i].p_filesz); + phdrs[i].p_memsz = BYTE_GET (phdrs64[i].p_memsz); + phdrs[i].p_flags = BYTE_GET (phdrs64[i].p_flags); + phdrs[i].p_align = BYTE_GET (phdrs64[i].p_align); + } + } + + ret = 0; + for (i = 0; i < elf_header.e_phnum; i++) + if (phdrs[i].p_type == PT_NOTE) + { + size_t offset = phdrs[i].p_offset; + size_t size = phdrs[i].p_filesz; + size_t align = phdrs[i].p_align; + char *buf = map + offset; + char *p = buf; + + while (p < buf + size) + { + Elf_External_Note *xnp = (Elf_External_Note *) p; + Elf_Internal_Note in; + + if (offsetof (Elf_External_Note, name) > buf - p + size) + { + ret = 1; + goto out; + } + + in.type = BYTE_GET (xnp->type); + in.namesz = BYTE_GET (xnp->namesz); + in.namedata = xnp->name; + if (in.namesz > buf - in.namedata + size) + { + ret = 1; + goto out; + } + + in.descsz = BYTE_GET (xnp->descsz); + in.descdata = p + ELF_NOTE_DESC_OFFSET (in.namesz, align); + in.descpos = offset + (in.descdata - buf); + if (in.descsz != 0 + && (in.descdata >= buf + size + || in.descsz > buf - in.descdata + size)) + { + ret = 1; + goto out; + } + + if (in.namesz == sizeof "GNU" + && strcmp (in.namedata, "GNU") == 0 + && in.type == NT_GNU_PROPERTY_TYPE_0) + { + unsigned char *ptr; + unsigned char *ptr_end; + + if (in.descsz < 8 || (in.descsz % align) != 0) + { + ret = 1; + goto out; + } + + ptr = (unsigned char *) in.descdata; + ptr_end = ptr + in.descsz; + + do + { + unsigned int type = byte_get (ptr, 4); + unsigned int datasz = byte_get (ptr + 4, 4); + unsigned int bitmask, old_bitmask; + + ptr += 8; + if ((ptr + datasz) > ptr_end) + { + ret = 1; + goto out; + } + + if (type == GNU_PROPERTY_X86_FEATURE_1_AND) + { + if (datasz != 4) + { + ret = 1; + goto out; + } + + old_bitmask = byte_get (ptr, 4); + bitmask = old_bitmask; + if (enable_x86_features) + bitmask |= enable_x86_features; + if (disable_x86_features) + bitmask &= ~disable_x86_features; + if (old_bitmask != bitmask) + BYTE_PUT (ptr, bitmask); + goto out; + } + + ptr += ELF_ALIGN_UP (datasz, align); + } + while ((ptr_end - ptr) >= 8); + } + + p += ELF_NOTE_NEXT_OFFSET (in.namesz, in.descsz, align); + } + } + +out: + if (ret != 0) + error (_("%s: Invalid PT_NOTE segment\n"), file_name); + + free (phdrs); + munmap (map, st_buf.st_size); + + return ret; +} + +/* Set enable_x86_features and disable_x86_features for a feature + string, FEATURE. */ + +static int +elf_x86_feature (const char *feature, int enable) +{ + unsigned int x86_feature; + if (strcasecmp (feature, "ibt") == 0) + x86_feature = GNU_PROPERTY_X86_FEATURE_1_IBT; + else if (strcasecmp (feature, "shstk") == 0) + x86_feature = GNU_PROPERTY_X86_FEATURE_1_SHSTK; + else + return -1; + + if (enable) + { + enable_x86_features |= x86_feature; + disable_x86_features &= ~x86_feature; + } + else + { + disable_x86_features |= x86_feature; + enable_x86_features &= ~x86_feature; + } + + return 0; +} +#endif + /* Return ELF class for a machine type, MACH. */ static enum elfclass @@ -533,6 +745,12 @@ process_file (const char *file_name) rewind (file); archive_file_size = archive_file_offset = 0; ret = process_object (file_name, file); +#ifdef HAVE_MMAP + if (!ret + && (elf_header.e_type == ET_EXEC + || elf_header.e_type == ET_DYN)) + ret = update_gnu_property (file_name, file); +#endif } fclose (file); @@ -632,7 +850,11 @@ enum command_line_switch OPTION_INPUT_TYPE, OPTION_OUTPUT_TYPE, OPTION_INPUT_OSABI, - OPTION_OUTPUT_OSABI + OPTION_OUTPUT_OSABI, +#ifdef HAVE_MMAP + OPTION_ENABLE_X86_FEATURE, + OPTION_DISABLE_X86_FEATURE, +#endif }; static struct option options[] = @@ -643,6 +865,12 @@ static struct option options[] = {"output-type", required_argument, 0, OPTION_OUTPUT_TYPE}, {"input-osabi", required_argument, 0, OPTION_INPUT_OSABI}, {"output-osabi", required_argument, 0, OPTION_OUTPUT_OSABI}, +#ifdef HAVE_MMAP + {"enable-x86-feature", + required_argument, 0, OPTION_ENABLE_X86_FEATURE}, + {"disable-x86-feature", + required_argument, 0, OPTION_DISABLE_X86_FEATURE}, +#endif {"version", no_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, {0, no_argument, 0, 0} @@ -661,7 +889,15 @@ usage (FILE *stream, int exit_status) --input-type <type> Set input file type to <type>\n\ --output-type <type> Set output file type to <type>\n\ --input-osabi <osabi> Set input OSABI to <osabi>\n\ - --output-osabi <osabi> Set output OSABI to <osabi>\n\ + --output-osabi <osabi> Set output OSABI to <osabi>\n")); +#ifdef HAVE_MMAP + fprintf (stream, _("\ + --enable-x86-feature <feature>\n\ + Enable x86 feature <feature>\n\ + --disable-x86-feature <feature>\n\ + Disable x86 feature <feature>\n")); +#endif + fprintf (stream, _("\ -h --help Display this information\n\ -v --version Display the version number of %s\n\ "), @@ -734,6 +970,18 @@ main (int argc, char ** argv) return 1; break; +#ifdef HAVE_MMAP + case OPTION_ENABLE_X86_FEATURE: + if (elf_x86_feature (optarg, 1) < 0) + return 1; + break; + + case OPTION_DISABLE_X86_FEATURE: + if (elf_x86_feature (optarg, 0) < 0) + return 1; + break; +#endif + case 'h': usage (stdout, 0); @@ -748,6 +996,10 @@ main (int argc, char ** argv) if (optind == argc || (output_elf_machine == -1 +#ifdef HAVE_MMAP + && ! enable_x86_features + && ! disable_x86_features +#endif && output_elf_type == -1 && output_elf_osabi == -1)) usage (stderr, 1); |