diff options
author | Alan Modra <amodra@gmail.com> | 2020-08-27 21:44:41 +0930 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2020-08-27 22:05:00 +0930 |
commit | 4b69ce9b9121090ac42cf8fa20b949bbd9afff95 (patch) | |
tree | 196408e74cea24562bea850fc2ff4a8c6850e383 /bfd/elflink.c | |
parent | 6fbd4a8e8baa7fe5adcaa1c11c885f741fccd250 (diff) | |
download | binutils-4b69ce9b9121090ac42cf8fa20b949bbd9afff95.zip binutils-4b69ce9b9121090ac42cf8fa20b949bbd9afff95.tar.gz binutils-4b69ce9b9121090ac42cf8fa20b949bbd9afff95.tar.bz2 |
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.
Diffstat (limited to 'bfd/elflink.c')
-rw-r--r-- | bfd/elflink.c | 53 |
1 files changed, 45 insertions, 8 deletions
diff --git a/bfd/elflink.c b/bfd/elflink.c index 17a4232..5c085b1 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -32,6 +32,13 @@ #include "plugin.h" #endif +#ifdef HAVE_LIMITS_H +#include <limits.h> +#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 (&); |