Add .note.gnu.property runtime verification and merge support submit/tizen_5.5_base/20191030.000001 submit/tizen_base/20190724.060247 tizen_5.5.m2_release
authorMikhail Kashkarov <m.kashkarov@partner.samsung.com>
Mon, 15 Apr 2019 11:15:49 +0000 (14:15 +0300)
committerMikhail Kashkarov <m.kashkarov@partner.samsung.com>
Thu, 18 Jul 2019 11:22:08 +0000 (14:22 +0300)
- 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

bfd/config.in
bfd/configure
bfd/configure.ac
bfd/elf-bfd.h
bfd/elf-properties.c
binutils/readelf.c
include/elf/common.h
packaging/binutils-aarch64.spec
packaging/binutils-armv7hl.spec
packaging/binutils-armv7l.spec
packaging/binutils.spec

index 341afae..3c654d2 100644 (file)
 /* Name of host specific core header file to include in elf.c. */
 #undef CORE_HEADER
 
+/* 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. */
 #undef ENABLE_NLS
index 130678f..3162aff 100755 (executable)
@@ -793,6 +793,7 @@ enable_64_bit_archive
 with_mmap
 enable_secureplt
 enable_leading_mingw64_underscores
+enable_annobin_verification
 with_separate_debug_dir
 with_pkgversion
 with_bugurl
@@ -1447,6 +1448,9 @@ Optional Features:
   --enable-secureplt      Default to creating read-only plt entries
   --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  enable make rules and dependencies not useful
@@ -11427,7 +11431,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11430 "configure"
+#line 11434 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11533,7 +11537,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11536 "configure"
+#line 11540 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12181,6 +12185,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.
index 0ecbf08..0bd5008 100644 (file)
@@ -105,6 +105,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],
index b2f7bf4..b8b0c42 100644 (file)
@@ -779,6 +779,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
index a0456f8..95e66ff 100644 (file)
@@ -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;
@@ -163,6 +164,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;
            }
@@ -184,6 +205,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.  */
@@ -218,6 +343,44 @@ elf_merge_gnu_properties (bfd *abfd, elf_property *aprop,
       /* 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.  */
@@ -380,6 +543,9 @@ _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info)
       sec = bfd_get_section_by_name (first_pbfd,
                                     NOTE_GNU_PROPERTY_SECTION_NAME);
 
+      if (!sec)
+       return;
+
       /* Update stack size in .note.gnu.property with -z stack-size=N
         if N > 0.  */
       if (info->stacksize > 0)
index 5acc770..9212a8f 100644 (file)
@@ -15441,6 +15441,20 @@ decode_x86_isa (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 (Elf_Internal_Note * pnote)
 {
   unsigned char * ptr = (unsigned char *) pnote->descdata;
@@ -15526,6 +15540,18 @@ print_gnu_property_note (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;
            }
index 4d8e42e..ff3a08d 100644 (file)
 /* 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
index 4c3e55f..3460085 100644 (file)
@@ -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 \
index c1b09e3..ecdde91 100644 (file)
@@ -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 \
index 422c453..bedf7a1 100644 (file)
@@ -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 \
index 7f2479d..f98fd94 100644 (file)
@@ -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 \