diff options
author | Mikhail Kashkarov <m.kashkarov@partner.samsung.com> | 2019-04-15 14:15:49 +0300 |
---|---|---|
committer | Slava Barinov <v.barinov@samsung.com> | 2019-12-16 15:28:16 +0300 |
commit | 793d9e3fde1a643df92c4bb8c52415844921a2e9 (patch) | |
tree | ae0749c19724720ab14621336b06bc50c7f80996 | |
parent | 3ba82f954de75b2236040c068470aa4331983f3b (diff) | |
download | binutils-793d9e3fde1a643df92c4bb8c52415844921a2e9.tar.gz binutils-793d9e3fde1a643df92c4bb8c52415844921a2e9.tar.bz2 binutils-793d9e3fde1a643df92c4bb8c52415844921a2e9.zip |
Add .note.gnu.property runtime verification and merge support
- Define annobin .note.gnu.property bits for sanitization/CxxABI checks
- New configure option --enable-annobin-verification=warn|strict to enable
runtime verification support for gnu property notes.
- Add merging support for compilation flags annobin gnu notes.
- Add readelf section text for compiler properties.
Change-Id: I452029baca753f6a97ef4b7297ef9a8905a7b79c
-rw-r--r-- | bfd/config.in | 6 | ||||
-rwxr-xr-x | bfd/configure | 33 | ||||
-rw-r--r-- | bfd/configure.ac | 21 | ||||
-rw-r--r-- | bfd/elf-bfd.h | 1 | ||||
-rw-r--r-- | bfd/elf-properties.c | 166 | ||||
-rw-r--r-- | binutils/readelf.c | 26 | ||||
-rw-r--r-- | include/elf/common.h | 11 | ||||
-rw-r--r-- | packaging/binutils-aarch64.spec | 2 | ||||
-rw-r--r-- | packaging/binutils-armv7hl.spec | 2 | ||||
-rw-r--r-- | packaging/binutils-armv7l.spec | 2 | ||||
-rw-r--r-- | packaging/binutils.spec | 2 |
11 files changed, 270 insertions, 2 deletions
diff --git a/bfd/config.in b/bfd/config.in index be572969fc0..01c38b7c4c1 100644 --- a/bfd/config.in +++ b/bfd/config.in @@ -13,6 +13,12 @@ /* Define to 1 if you want to enable -z separate-code in ELF linker by default. */ #undef DEFAULT_LD_Z_SEPARATE_CODE +/* Define to enable annobin runtime checks for static linker (warnings only) + */ +#undef ENABLE_ANNOBIN_VERIFICATION + +/* Define to enable annobin runtime strict checks (error mode) */ +#undef ENABLE_ANNOBIN_VERIFICATION_STRICT /* Define to 1 if translation of program messages to the user's native language is requested. */ diff --git a/bfd/configure b/bfd/configure index a292a2ed280..50e4bd35196 100755 --- a/bfd/configure +++ b/bfd/configure @@ -832,6 +832,7 @@ with_mmap enable_secureplt enable_separate_code enable_leading_mingw64_underscores +enable_annobin_verification with_separate_debug_dir with_pkgversion with_bugurl @@ -1490,6 +1491,9 @@ Optional Features: --enable-separate-code enable -z separate-code in ELF linker by default --enable-leading-mingw64-underscores Enable leading underscores on 64 bit mingw targets + --enable-annobin-verification[=warn|strict] + enable runtime checks with dynamic notes generated + by annobin plugin --enable-werror treat compile warnings as errors --enable-build-warnings enable build-time compiler warnings --enable-maintainer-mode @@ -11728,7 +11732,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11731 "configure" +#line 11735 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11834,7 +11838,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11837 "configure" +#line 11841 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -12507,6 +12511,31 @@ $as_echo "#define USE_MINGW64_LEADING_UNDERSCORES 1" >>confdefs.h fi +# Check whether --enable-annobin_verification was given. +if test "${enable_annobin_verification+set}" = set; then : + enableval=$enable_annobin_verification; case "${enableval}" in + yes | warn | "" ) annobin_verification=warn ;; + strict ) annobin_verification=strict ;; + no) annobin_verification=no ;; + *) annobin_verification=no ;; + esac +else + annobin_verification=no +fi + +if test "$annobin_verification" = "yes" || + test "$annobin_verification" = "warn" || + test "$annobin_verification" = "strict"; then + +$as_echo "#define ENABLE_ANNOBIN_VERIFICATION 1" >>confdefs.h + + if test "$annobin_verification" = "strict"; then + +$as_echo "#define ENABLE_ANNOBIN_VERIFICATION_STRICT 1" >>confdefs.h + + fi +fi + DEBUGDIR=${libdir}/debug # Check whether --with-separate-debug-dir was given. diff --git a/bfd/configure.ac b/bfd/configure.ac index 39702ce1315..a492b262c63 100644 --- a/bfd/configure.ac +++ b/bfd/configure.ac @@ -126,6 +126,27 @@ AS_IF([ test x"$enable_leading_mingw64_underscores" = xyes ], [AC_DEFINE(USE_MINGW64_LEADING_UNDERSCORES, 1, [Define if we should use leading underscore on 64 bit mingw targets])]) +AC_ARG_ENABLE(annobin_verification, +[AS_HELP_STRING([[--enable-annobin-verification[=warn|strict]]], +[enable runtime checks with dynamic notes generated by annobin plugin])], +[case "${enableval}" in + yes | warn | "" ) annobin_verification=warn ;; + strict ) annobin_verification=strict ;; + no) annobin_verification=no ;; + *) annobin_verification=no ;; + esac], +[annobin_verification=no]) +if test "$annobin_verification" = "yes" || + test "$annobin_verification" = "warn" || + test "$annobin_verification" = "strict"; then + AC_DEFINE(ENABLE_ANNOBIN_VERIFICATION, 1, + [Define to enable annobin runtime checks for static linker (warnings only)]) + if test "$annobin_verification" = "strict"; then + AC_DEFINE(ENABLE_ANNOBIN_VERIFICATION_STRICT, 1, + [Define to enable annobin runtime strict checks (error mode)]) + fi +fi + DEBUGDIR=${libdir}/debug AC_ARG_WITH(separate-debug-dir, AS_HELP_STRING([--with-separate-debug-dir=DIR], diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 521d35debb0..7905b37c5ee 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -831,6 +831,7 @@ typedef struct elf_property /* Add a new one if elf_property_kind is updated. */ } u; enum elf_property_kind pr_kind; + const char *filename; } elf_property; typedef struct elf_property_list diff --git a/bfd/elf-properties.c b/bfd/elf-properties.c index 198eece0843..b510b21fc02 100644 --- a/bfd/elf-properties.c +++ b/bfd/elf-properties.c @@ -69,6 +69,7 @@ _bfd_elf_get_property (bfd *abfd, unsigned int type, unsigned int datasz) memset (p, 0, sizeof (*p)); p->property.pr_type = type; p->property.pr_datasz = datasz; + p->property.filename = abfd->filename; p->next = *lastp; *lastp = p; return &p->property; @@ -177,6 +178,26 @@ bad_size: prop->pr_kind = property_number; goto next; + case GNU_PROPERTY_COMPILER_FLAGS: + /* Note that annobin uses 4-byte alignment even on 64-bit targets. */ + if (!((datasz == 4) || (datasz == 8))) + { + _bfd_error_handler + (_("warning: %B: corrupt compiler flags: 0x%x\n"), + abfd, datasz); + /* Clear all properties. */ + elf_properties (abfd) = NULL; + return FALSE; + } + prop = _bfd_elf_get_property (abfd, type, datasz); + if (datasz == 8) + prop->u.number = bfd_h_get_64 (abfd, ptr); + else + prop->u.number = bfd_h_get_32 (abfd, ptr); + + prop->pr_kind = property_number; + goto next; + default: break; } @@ -193,6 +214,110 @@ next: return TRUE; } +/* If validation bits are set - compare bit flags for equality. */ +inline static bfd_boolean +elf_gnu_property_validate_flag (bfd_vma anum, + bfd_vma bnum, + bfd_vma validation_bit_flag, + bfd_vma validation_bit) +{ + if ((anum & validation_bit_flag) && (bnum & validation_bit_flag) + && ((anum & validation_bit) != (bnum & validation_bit))) + { + return FALSE; + } + return TRUE; +} + +static bfd_boolean +elf_validate_compiler_flags_properties (elf_property *aprop, + elf_property *bprop) +{ + bfd_boolean is_flag_set; + + /* Sanity check to verify correct usage. */ + BFD_ASSERT(aprop); + BFD_ASSERT(bprop); + + if (aprop->pr_type != bprop->pr_type) + return TRUE; + + BFD_ASSERT(aprop->pr_type == GNU_PROPERTY_COMPILER_FLAGS); + + /* Return TRUE if compiler flags are identical (likely?). */ + if (aprop->u.number == bprop->u.number) + return TRUE; + + if (!elf_gnu_property_validate_flag(aprop->u.number, + bprop->u.number, + GNU_PROPERTY_SANITIZE_VALIDATION, + GNU_PROPERTY_SANITIZE_ADDRESS)) + { + is_flag_set = bprop->u.number & GNU_PROPERTY_SANITIZE_ADDRESS; + _bfd_error_handler + (_("%s: ERROR: Validation failed, linking %s object with previous %s"), + bprop->filename, is_flag_set ? "sanitized" : "unsanitized", + !is_flag_set ? "sanitized" : "unsanitized"); + return FALSE; + } + + if (!elf_gnu_property_validate_flag(aprop->u.number, + bprop->u.number, + GNU_PROPERTY_USECXX_VALIDATION, + GNU_PROPERTY_USECXX11_ABI)) + { + is_flag_set = bprop->u.number & GNU_PROPERTY_USECXX11_ABI; + _bfd_error_handler + (_("ERROR: Validation failed, linking %s ABI object with %s ABI"), + bprop->filename, is_flag_set ? "pre-cxx11" : "cxx11", + !is_flag_set ? "pre-cxx11" : "cxx11"); + return FALSE; + } + + return TRUE; +} + + +/* Merge bprop into aprop according compiler-flags properties, return TRUE if */ +/* aprop is updated. */ +static bfd_boolean +elf_merge_gnu_properties_compiler_flags (elf_property *aprop, + elf_property *bprop) +{ + bfd_boolean is_updated = FALSE; + /* Likely that objects have the same properties. */ + if (aprop->u.number == bprop->u.number) { + return FALSE; + } + + /* Validation bit + no-validation bit = validation bit. */ + if ((aprop->u.number ^ bprop->u.number) & GNU_PROPERTY_SANITIZE_VALIDATION) + { + aprop->u.number |= GNU_PROPERTY_SANITIZE_VALIDATION; + is_updated = TRUE; + } + /* Sanitized object + unsanitized results = sanitized final object. */ + if ((aprop->u.number ^ bprop->u.number) & GNU_PROPERTY_SANITIZE_ADDRESS) + { + aprop->u.number |= GNU_PROPERTY_SANITIZE_ADDRESS; + is_updated = TRUE; + } + + if ((aprop->u.number ^ bprop->u.number) & GNU_PROPERTY_USECXX_VALIDATION) + { + aprop->u.number |= GNU_PROPERTY_USECXX_VALIDATION; + is_updated = TRUE; + } + + if ((aprop->u.number ^ bprop->u.number) & GNU_PROPERTY_USECXX11_ABI) + { + aprop->u.number |= GNU_PROPERTY_USECXX11_ABI; + is_updated = TRUE; + } + + return is_updated; +} + /* Merge GNU property BPROP with APROP. If APROP isn't NULL, return TRUE if APROP is updated. Otherwise, return TRUE if BPROP should be merged with ABFD. */ @@ -227,6 +352,44 @@ elf_merge_gnu_properties (struct bfd_link_info *info, bfd *abfd, bfd *bbfd, /* Return TRUE if APROP is NULL to indicate that BPROP should be added to ABFD. */ return aprop == NULL; + /* FALLTHROUGH */ + + case GNU_PROPERTY_COMPILER_FLAGS: + { + bfd_boolean is_updated; + if (aprop != NULL && bprop != NULL) + { +#ifdef ENABLE_ANNOBIN_VERIFICATION + if (!elf_validate_compiler_flags_properties (aprop, bprop)) + { + _bfd_error_handler(_("ERROR: Linking failed due to incompatible " + "compilation flags used to generate objects\n")); + /* Strict mode, abort. */ +#ifdef ENABLE_ANNOBIN_VERIFICATION_STRICT + _exit (EXIT_FAILURE); +#endif + } +#endif + is_updated = elf_merge_gnu_properties_compiler_flags (aprop, bprop); + } + else + { + is_updated = FALSE; + /* aprop or bprop is NULL, warn for missing GNU_PROPERTY_COMPILER_FLAGS. + + This is too noisy since glibc's crt{i,n}.o are compiled with + predefined flags (without annobin support), so we'll have at + least 2x of the following warning for every linking. May be + enabled after we verified crt* compilation with plugins. */ + /* if (bprop == NULL) + _bfd_error_handler + (_("WARNING: not found (generated by annobin gcc plugin), " + "runtime verification may be incomplete"), + NOTE_GNU_PROPERTY_SECTION_NAME); */ + } + return is_updated; + } + /* FALLTHROUGH */ default: /* Never should happen. */ @@ -601,6 +764,9 @@ _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info) NOTE_GNU_PROPERTY_SECTION_NAME); BFD_ASSERT (sec != NULL); + if (!sec) + return; + /* Update stack size in .note.gnu.property with -z stack-size=N if N > 0. */ if (info->stacksize > 0) diff --git a/binutils/readelf.c b/binutils/readelf.c index 0962877ad8f..7f22c58dbe5 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -17750,6 +17750,20 @@ decode_aarch64_feature_1_and (unsigned int bitmask) } static void +decode_compiler_flags_notes (unsigned long bitmask) +{ + printf("%#lx [", bitmask); + + printf("%c%ccxx11, ", bitmask & GNU_PROPERTY_USECXX_VALIDATION ? '=' : '~', + bitmask & GNU_PROPERTY_USECXX11_ABI ? '+' : '!'); + + printf("%c%casan", bitmask & GNU_PROPERTY_SANITIZE_VALIDATION ? '=' : '~', + bitmask & GNU_PROPERTY_SANITIZE_ADDRESS ? '+' : '!'); + + printf("]"); +} + +static void print_gnu_property_note (Filedata * filedata, Elf_Internal_Note * pnote) { unsigned char * ptr = (unsigned char *) pnote->descdata; @@ -17914,6 +17928,18 @@ print_gnu_property_note (Filedata * filedata, Elf_Internal_Note * pnote) printf (_("<corrupt length: %#x> "), datasz); goto next; + case GNU_PROPERTY_COMPILER_FLAGS: + printf ("compilations flags: "); + if ((datasz != 4) && (datasz != 8)) + printf (_("<corrupt length: %#x> "), datasz); + else + { + unsigned long bitmask_flags; + bitmask_flags = (unsigned long) byte_get (ptr, size); + decode_compiler_flags_notes (bitmask_flags); + } + goto next; + default: break; } diff --git a/include/elf/common.h b/include/elf/common.h index 75c4fb7e9d7..182818eb865 100644 --- a/include/elf/common.h +++ b/include/elf/common.h @@ -741,6 +741,17 @@ /* Values used in GNU .note.gnu.property notes (NT_GNU_PROPERTY_TYPE_0). */ #define GNU_PROPERTY_STACK_SIZE 1 #define GNU_PROPERTY_NO_COPY_ON_PROTECTED 2 +#define GNU_PROPERTY_COMPILER_FLAGS 32 + +/* Bit masks for compiler flags: */ +/* Pre/post cxx11 ABI. */ +#define GNU_PROPERTY_USECXX_VALIDATION (1U << 0) +#define GNU_PROPERTY_USECXX11_ABI (1U << 1) +/* Sanitizer flags. */ +#define GNU_PROPERTY_SANITIZE_VALIDATION (1U << 2) +#define GNU_PROPERTY_SANITIZE_ADDRESS (1U << 3) +#define GNU_PROPERTY_SANITIZE_UNDEFINED (1U << 4) +#define GNU_PROPERTY_SANITIZE_THREAD (1U << 5) /* Processor-specific semantics, lo */ #define GNU_PROPERTY_LOPROC 0xc0000000 diff --git a/packaging/binutils-aarch64.spec b/packaging/binutils-aarch64.spec index 4c3e55f33a4..3460085f172 100644 --- a/packaging/binutils-aarch64.spec +++ b/packaging/binutils-aarch64.spec @@ -104,6 +104,8 @@ cd build-dir --with-pic \ --build=%{host_arch} --target=%{target_arch} \ --host=%{host_arch} \ + %{?annobin_verification: --enable-annobin-verification=warn } \ + %{?annobin_verification_strict: --enable-annobin-verification=strict } \ %{?cross: \ --enable-targets=%{target_arch} \ --enable-64-bit-bfd \ diff --git a/packaging/binutils-armv7hl.spec b/packaging/binutils-armv7hl.spec index c1b09e30a3a..ecdde918eff 100644 --- a/packaging/binutils-armv7hl.spec +++ b/packaging/binutils-armv7hl.spec @@ -104,6 +104,8 @@ cd build-dir --with-pic \ --build=%{host_arch} --target=%{target_arch} \ --host=%{host_arch} \ + %{?annobin_verification: --enable-annobin-verification=warn } \ + %{?annobin_verification_strict: --enable-annobin-verification=strict } \ %{?cross: \ --enable-targets=%{target_arch} \ --enable-64-bit-bfd \ diff --git a/packaging/binutils-armv7l.spec b/packaging/binutils-armv7l.spec index 422c4536229..bedf7a15abb 100644 --- a/packaging/binutils-armv7l.spec +++ b/packaging/binutils-armv7l.spec @@ -104,6 +104,8 @@ cd build-dir --with-pic \ --build=%{host_arch} --target=%{target_arch} \ --host=%{host_arch} \ + %{?annobin_verification: --enable-annobin-verification=warn } \ + %{?annobin_verification_strict: --enable-annobin-verification=strict } \ %{?cross: \ --enable-targets=%{target_arch} \ --enable-64-bit-bfd \ diff --git a/packaging/binutils.spec b/packaging/binutils.spec index 7f2479d63cd..f98fd941720 100644 --- a/packaging/binutils.spec +++ b/packaging/binutils.spec @@ -101,6 +101,8 @@ cd build-dir --with-pic \ --build=%{host_arch} --target=%{target_arch} \ --host=%{host_arch} \ + %{?annobin_verification: --enable-annobin-verification=warn } \ + %{?annobin_verification_strict: --enable-annobin-verification=strict } \ %{?cross: \ --enable-targets=%{target_arch} \ --enable-64-bit-bfd \ |