From: Alan Modra Date: Thu, 27 Aug 2020 12:14:41 +0000 (+0930) Subject: PR26469 UBSAN: elflink.c:8742 shift exponent 6148914691236511722 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=4b69ce9b9121090ac42cf8fa20b949bbd9afff95;p=binutils-gdb.git PR26469 UBSAN: elflink.c:8742 shift exponent 6148914691236511722 PR 26469 * elflink.c: Include limits.h. (CHAR_BIT): Provide fallback define. (set_symbol_value): Correct complex reloc comment. (undefined_reference): Set bfd_error. (BINARY_OP_HEAD, BINARY_OP_TAIL): Split out from.. (BINARY_OP): ..this. (eval_symbol): Limit shifts. Force unsigned for left shift. Catch divide by zero. * configure.ac (AC_CHECK_HEADERS): Combine, sort and add limits.h. * configure: Regenerate. * config.in: Regenerate. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 6d3ba691da9..1d783f73830 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,18 @@ +2020-08-27 Alan Modra + + PR 26469 + * elflink.c: Include limits.h. + (CHAR_BIT): Provide fallback define. + (set_symbol_value): Correct complex reloc comment. + (undefined_reference): Set bfd_error. + (BINARY_OP_HEAD, BINARY_OP_TAIL): Split out from.. + (BINARY_OP): ..this. + (eval_symbol): Limit shifts. Force unsigned for left shift. + Catch divide by zero. + * configure.ac (AC_CHECK_HEADERS): Combine, sort and add limits.h. + * configure: Regenerate. + * config.in: Regenerate. + 2020-08-27 Alan Modra PR 26462 diff --git a/bfd/config.in b/bfd/config.in index c7be6c51764..18fb8aeb50c 100644 --- a/bfd/config.in +++ b/bfd/config.in @@ -143,6 +143,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + /* Define to 1 if the system has the type `long double'. */ #undef HAVE_LONG_DOUBLE diff --git a/bfd/configure b/bfd/configure index ece16566824..a9c4fd93669 100755 --- a/bfd/configure +++ b/bfd/configure @@ -13531,20 +13531,9 @@ $as_echo "$bfd_cv_build_exeext" >&6; } fi -for ac_header in alloca.h stddef.h string.h strings.h stdlib.h time.h unistd.h wchar.h wctype.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - -for ac_header in fcntl.h sys/file.h sys/time.h sys/stat.h sys/resource.h +for ac_header in alloca.h fcntl.h limits.h stddef.h stdlib.h string.h \ + strings.h sys/file.h sys/resource.h sys/stat.h sys/time.h \ + time.h unistd.h wchar.h wctype.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" diff --git a/bfd/configure.ac b/bfd/configure.ac index ae2de131873..f62659acd7f 100644 --- a/bfd/configure.ac +++ b/bfd/configure.ac @@ -243,8 +243,9 @@ AC_SUBST(BFD_HOSTPTR_T) BFD_CC_FOR_BUILD -AC_CHECK_HEADERS(alloca.h stddef.h string.h strings.h stdlib.h time.h unistd.h wchar.h wctype.h) -AC_CHECK_HEADERS(fcntl.h sys/file.h sys/time.h sys/stat.h sys/resource.h) +AC_CHECK_HEADERS(alloca.h fcntl.h limits.h stddef.h stdlib.h string.h \ + strings.h sys/file.h sys/resource.h sys/stat.h sys/time.h \ + time.h unistd.h wchar.h wctype.h) GCC_HEADER_STDINT(bfd_stdint.h) AC_HEADER_TIME AC_HEADER_DIRENT @@ -1104,7 +1105,6 @@ AC_MSG_RESULT($bfd_file_ptr) AC_SUBST(bfd_file_ptr) AC_SUBST(bfd_ufile_ptr) -dnl AC_CHECK_HEADERS(sys/mman.h) AC_FUNC_MMAP AC_CHECK_FUNCS(madvise mprotect) case ${want_mmap}+${ac_cv_func_mmap_fixed_mapped} in diff --git a/bfd/elflink.c b/bfd/elflink.c index 17a423270ec..5c085b14b79 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -32,6 +32,13 @@ #include "plugin.h" #endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif + /* This struct is used to pass information to routines called via elf_link_hash_traverse which must return failure. */ @@ -8427,12 +8434,12 @@ struct elf_outext_info implementation of them consists of two parts: complex symbols, and the relocations themselves. - The relocations are use a reserved elf-wide relocation type code (R_RELC + The relocations use a reserved elf-wide relocation type code (R_RELC external / BFD_RELOC_RELC internal) and an encoding of relocation field information (start bit, end bit, word width, etc) into the addend. This information is extracted from CGEN-generated operand tables within gas. - Complex symbols are mangled symbols (BSF_RELC external / STT_RELC + Complex symbols are mangled symbols (STT_RELC external / BSF_RELC internal) representing prefix-notation expressions, including but not limited to those sorts of expressions normally encoded as addends in the addend field. The symbol mangling format is: @@ -8607,6 +8614,7 @@ undefined_reference (const char *reftype, const char *name) /* xgettext:c-format */ _bfd_error_handler (_("undefined %s reference in complex symbol: %s"), reftype, name); + bfd_set_error (bfd_error_bad_value); } static bfd_boolean @@ -8715,7 +8723,7 @@ eval_symbol (bfd_vma *result, return TRUE; \ } -#define BINARY_OP(op) \ +#define BINARY_OP_HEAD(op) \ if (strncmp (sym, #op, strlen (#op)) == 0) \ { \ sym += strlen (#op); \ @@ -8728,18 +8736,33 @@ eval_symbol (bfd_vma *result, ++*symp; \ if (!eval_symbol (&b, symp, input_bfd, flinfo, dot, \ isymbuf, locsymcount, signed_p)) \ - return FALSE; \ + return FALSE; +#define BINARY_OP_TAIL(op) \ if (signed_p) \ *result = ((bfd_signed_vma) a) op ((bfd_signed_vma) b); \ else \ *result = a op b; \ return TRUE; \ } +#define BINARY_OP(op) BINARY_OP_HEAD(op) BINARY_OP_TAIL(op) default: UNARY_OP (0-); - BINARY_OP (<<); - BINARY_OP (>>); + BINARY_OP_HEAD (<<); + if (b >= sizeof (a) * CHAR_BIT) + { + *result = 0; + return TRUE; + } + signed_p = 0; + BINARY_OP_TAIL (<<); + BINARY_OP_HEAD (>>); + if (b >= sizeof (a) * CHAR_BIT) + { + *result = signed_p && (bfd_signed_vma) a < 0 ? -1 : 0; + return TRUE; + } + BINARY_OP_TAIL (>>); BINARY_OP (==); BINARY_OP (!=); BINARY_OP (<=); @@ -8749,8 +8772,22 @@ eval_symbol (bfd_vma *result, UNARY_OP (~); UNARY_OP (!); BINARY_OP (*); - BINARY_OP (/); - BINARY_OP (%); + BINARY_OP_HEAD (/); + if (b == 0) + { + _bfd_error_handler (_("division by zero")); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + BINARY_OP_TAIL (/); + BINARY_OP_HEAD (%); + if (b == 0) + { + _bfd_error_handler (_("division by zero")); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + BINARY_OP_TAIL (%); BINARY_OP (^); BINARY_OP (|); BINARY_OP (&);