From 7a2104f1299b67f7625ccd74a7444258890c8202 Mon Sep 17 00:00:00 2001 From: zou_lin77 <422351577@qq.com> Date: Sat, 9 Jan 2021 15:06:20 +0800 Subject: [PATCH 1/6] fix CVE-2020-16592 --- ...23-Use-after-free-in-bfd_hash_lookup.patch | 56 +++++++++++++++++++ binutils.spec | 11 +++- 2 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 backport-CVE-2020-16592-PR25823-Use-after-free-in-bfd_hash_lookup.patch diff --git a/backport-CVE-2020-16592-PR25823-Use-after-free-in-bfd_hash_lookup.patch b/backport-CVE-2020-16592-PR25823-Use-after-free-in-bfd_hash_lookup.patch new file mode 100644 index 0000000..d91f559 --- /dev/null +++ b/backport-CVE-2020-16592-PR25823-Use-after-free-in-bfd_hash_lookup.patch @@ -0,0 +1,56 @@ +From 7ecb51549ab1ec22aba5aaf34b70323cf0b8509a Mon Sep 17 00:00:00 2001 +From: Alan Modra +Date: Wed, 15 Apr 2020 18:58:11 +0930 +Subject: [PATCH] PR25823, Use after free in bfd_hash_lookup + + PR 25823 + * peXXigen.c (_bfd_XXi_swap_sym_in ): Don't use a + pointer into strings that may be freed for section name, always + allocate a new string. +--- + bfd/peXXigen.c | 20 ++++++++++---------- + 1 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/bfd/peXXigen.c b/bfd/peXXigen.c +index b9eeb77..8aa5914 100644 +--- a/bfd/peXXigen.c ++++ b/bfd/peXXigen.c +@@ -177,25 +177,25 @@ _bfd_XXi_swap_sym_in (bfd * abfd, void * ext1, void * in1) + int unused_section_number = 0; + asection *sec; + flagword flags; ++ size_t name_len; ++ char *sec_name; + + for (sec = abfd->sections; sec; sec = sec->next) + if (unused_section_number <= sec->target_index) + unused_section_number = sec->target_index + 1; + +- if (name == namebuf) ++ name_len = strlen (name) + 1; ++ sec_name = bfd_alloc (abfd, name_len); ++ if (sec_name == NULL) + { +- name = (const char *) bfd_alloc (abfd, strlen (namebuf) + 1); +- if (name == NULL) +- { +- _bfd_error_handler (_("%pB: out of memory creating name for empty section"), +- abfd); +- return; +- } +- strcpy ((char *) name, namebuf); ++ _bfd_error_handler (_("%pB: out of memory creating name " ++ "for empty section"), abfd); ++ return; + } ++ memcpy (sec_name, name, name_len); + + flags = SEC_HAS_CONTENTS | SEC_ALLOC | SEC_DATA | SEC_LOAD; +- sec = bfd_make_section_anyway_with_flags (abfd, name, flags); ++ sec = bfd_make_section_anyway_with_flags (abfd, sec_name, flags); + if (sec == NULL) + { + _bfd_error_handler (_("%pB: unable to create fake empty section"), +-- +1.8.3.1 + diff --git a/binutils.spec b/binutils.spec index 14fdb34..977298f 100644 --- a/binutils.spec +++ b/binutils.spec @@ -1,7 +1,7 @@ Summary: Binary utilities Name: binutils Version: 2.34 -Release: 4 +Release: 5 License: GPLv3+ URL: https://sourceware.org/binutils @@ -33,7 +33,8 @@ Patch16: asan-more-readelf-leaks.patch Patch17: Re-asan-more-readelf-leaks.patch Patch18: readelf-leak-in-process_archive.patch Patch19: metag-uninitialized-memory-read.patch -Patch20: Fix-a-potential-use-of-an-uninitialised-value-in-the.patch +Patch20: Fix-a-potential-use-of-an-uninitialised-value-in-the.patch +Patch21: backport-CVE-2020-16592-PR25823-Use-after-free-in-bfd_hash_lookup.patch Provides: bundled(libiberty) @@ -319,6 +320,12 @@ fi %{_infodir}/bfd*info* %changelog +* Sat Jan 9 2021 zoulin - 2.34-5 +- Type:CVE +- ID:NA +- SUG:NA +- DESC:fix CVE-2020-16592 + * Wed Sep 23 2020 zoulin - 2.34-4 - Type:bugfix - ID:NA -- Gitee From 9cf9486e693e20b818c12c1589c6e115e12f4222 Mon Sep 17 00:00:00 2001 From: yang_zhuang_zhuang <1162011203@qq.com> Date: Thu, 28 Jan 2021 11:29:47 +0800 Subject: [PATCH 2/6] Fix static library file conflicts when install both binutils and binutils-devel --- binutils.spec | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/binutils.spec b/binutils.spec index 977298f..ef69ab4 100644 --- a/binutils.spec +++ b/binutils.spec @@ -1,7 +1,7 @@ Summary: Binary utilities Name: binutils Version: 2.34 -Release: 5 +Release: 6 License: GPLv3+ URL: https://sourceware.org/binutils @@ -300,6 +300,8 @@ fi %ghost %{_bindir}/ld %{_libdir}/lib*.so %{_libdir}/libctf* +%exclude %{_libdir}/libctf.a +%exclude %{_libdir}/libctf-nobfd.a %exclude %{_libdir}/libbfd.so %exclude %{_libdir}/libopcodes.so @@ -320,6 +322,12 @@ fi %{_infodir}/bfd*info* %changelog +* Thu Jan 28 2021 yangzhuangzhuang - 2.34-6 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:Fix static library file conflicts when install both binutils and binutils-devel + * Sat Jan 9 2021 zoulin - 2.34-5 - Type:CVE - ID:NA -- Gitee From ae4d24605b9acd7ba585db1779e0c4994415550a Mon Sep 17 00:00:00 2001 From: Liquor <1692257904@qq.com> Date: Mon, 22 Mar 2021 15:11:56 +0800 Subject: [PATCH 3/6] move the test to %check phase --- binutils.spec | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/binutils.spec b/binutils.spec index ef69ab4..0cb3ba4 100644 --- a/binutils.spec +++ b/binutils.spec @@ -1,7 +1,7 @@ Summary: Binary utilities Name: binutils Version: 2.34 -Release: 6 +Release: 7 License: GPLv3+ URL: https://sourceware.org/binutils @@ -146,6 +146,7 @@ export LDFLAGS=$RPM_LD_FLAGS %make_build %{_smp_mflags} tooldir=%{_prefix} all %make_build %{_smp_mflags} tooldir=%{_prefix} info +%check make -k check < /dev/null || : cat {gas/testsuite/gas,ld/ld,binutils/binutils}.sum for file in {gas/testsuite/gas,ld/ld,binutils/binutils}.{sum,log} @@ -161,16 +162,6 @@ rm -f binutils-%{_target_platform}.tar.bz2 binutils-%{_target_platform}-*.{sum,l make prefix=%{buildroot}%{_prefix} infodir=%{buildroot}%{_infodir} install-info -# Rebuild static libraries with -g -fPIC. -for library in libiberty opcodes -do - %make_build -C $library clean - %make_build CFLAGS="-g -fPIC $RPM_OPT_FLAGS" -C $library -done -%make_build -C bfd clean -%make_build CFLAGS="-g -fPIC $RPM_OPT_FLAGS -fvisibility=hidden" -C bfd - - for library in bfd/libbfd.a libiberty/libiberty.a opcodes/libopcodes.a do install -m 644 $library %{buildroot}%{_libdir} @@ -322,6 +313,12 @@ fi %{_infodir}/bfd*info* %changelog +* Mon Mar 22 2021 lirui - 2.34-7 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:move the test to %check phase + * Thu Jan 28 2021 yangzhuangzhuang - 2.34-6 - Type:bugfix - ID:NA -- Gitee From 71d129cb9e7e8ec75c1849579ab5d7814d04ccca Mon Sep 17 00:00:00 2001 From: panxiaohe Date: Tue, 23 Mar 2021 11:27:14 +0800 Subject: [PATCH 4/6] fix CVE-2020-0551 --- ...t-CVE-2020-0551-i386-Generate-lfence.patch | 547 ++++++++++++++++++ binutils.spec | 9 +- 2 files changed, 555 insertions(+), 1 deletion(-) create mode 100644 backport-CVE-2020-0551-i386-Generate-lfence.patch diff --git a/backport-CVE-2020-0551-i386-Generate-lfence.patch b/backport-CVE-2020-0551-i386-Generate-lfence.patch new file mode 100644 index 0000000..dd59d6b --- /dev/null +++ b/backport-CVE-2020-0551-i386-Generate-lfence.patch @@ -0,0 +1,547 @@ +From ae531041c7c5956672342f89c486a011c84f027f Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Wed, 11 Mar 2020 09:46:19 -0700 +Subject: [PATCH] i386: Generate lfence with load/indirect branch/ret + [CVE-2020-0551] + +Add 3 command-line options to generate lfence for load, indirect near +branch and ret to help mitigate: + +https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00334.html +http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-0551 + +1. -mlfence-after-load=[no|yes]: + -mlfence-after-load=yes generates lfence after load instructions. +2. -mlfence-before-indirect-branch=[none|all|memory|register]: + a. -mlfence-before-indirect-branch=all generates lfence before indirect + near branches via register and a warning before indirect near branches + via memory. + b. -mlfence-before-indirect-branch=memory issue a warning before + indirect near branches via memory. + c. -mlfence-before-indirect-branch=register generates lfence before + indirect near branches via register. +Note that lfence won't be generated before indirect near branches via +register with -mlfence-after-load=yes since lfence will be generated +after loading branch target register. +3. -mlfence-before-ret=[none|or|not] + a. -mlfence-before-ret=or generates or with lfence before ret. + b. -mlfence-before-ret=not generates not with lfence before ret. + +A warning will be issued and lfence won't be generated before indirect +near branch and ret if the previous item is a prefix or a constant +directive, which may be used to hardcode an instruction, since there +is no clear instruction boundary. + + * config/tc-i386.c (lfence_after_load): New. + (lfence_before_indirect_branch_kind): New. + (lfence_before_indirect_branch): New. + (lfence_before_ret_kind): New. + (lfence_before_ret): New. + (last_insn): New. + (load_insn_p): New. + (insert_lfence_after): New. + (insert_lfence_before): New. + (md_assemble): Call insert_lfence_before and insert_lfence_after. + Set last_insn. + (OPTION_MLFENCE_AFTER_LOAD): New. + (OPTION_MLFENCE_BEFORE_INDIRECT_BRANCH): New. + (OPTION_MLFENCE_BEFORE_RET): New. + (md_longopts): Add -mlfence-after-load=, + -mlfence-before-indirect-branch= and -mlfence-before-ret=. + (md_parse_option): Handle -mlfence-after-load=, + -mlfence-before-indirect-branch= and -mlfence-before-ret=. + (md_show_usage): Display -mlfence-after-load=, + -mlfence-before-indirect-branch= and -mlfence-before-ret=. + (i386_cons_align): New. + * config/tc-i386.h (i386_cons_align): New. + (md_cons_align): New. + * doc/c-i386.texi: Document -mlfence-after-load=, + -mlfence-before-indirect-branch= and -mlfence-before-ret=. +--- + gas/config/tc-i386.c | 366 ++++++++++++++++++++++++++++++++++++++++++- + gas/doc/c-i386.texi | 43 +++++ + 2 files changed, 408 insertions(+), 1 deletion(-) + +diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c +index b020f39c863..09063f784b7 100644 +--- a/gas/config/tc-i386.c ++++ b/gas/config/tc-i386.c +@@ -629,7 +629,29 @@ static int omit_lock_prefix = 0; + "lock addl $0, (%{re}sp)". */ + static int avoid_fence = 0; + +-/* Type of the previous instruction. */ ++/* 1 if lfence should be inserted after every load. */ ++static int lfence_after_load = 0; ++ ++/* Non-zero if lfence should be inserted before indirect branch. */ ++static enum lfence_before_indirect_branch_kind ++ { ++ lfence_branch_none = 0, ++ lfence_branch_register, ++ lfence_branch_memory, ++ lfence_branch_all ++ } ++lfence_before_indirect_branch; ++ ++/* Non-zero if lfence should be inserted before ret. */ ++static enum lfence_before_ret_kind ++ { ++ lfence_before_ret_none = 0, ++ lfence_before_ret_not, ++ lfence_before_ret_or ++ } ++lfence_before_ret; ++ ++/* Types of previous instruction is .byte or prefix. */ + static struct + { + segT seg; +@@ -4311,6 +4333,283 @@ optimize_encoding (void) + } + } + ++/* Return non-zero for load instruction. */ ++ ++static int ++load_insn_p (void) ++{ ++ unsigned int dest; ++ int any_vex_p = is_any_vex_encoding (&i.tm); ++ unsigned int base_opcode = i.tm.base_opcode | 1; ++ ++ if (!any_vex_p) ++ { ++ /* lea */ ++ if (i.tm.base_opcode == 0x8d) ++ return 0; ++ ++ /* pop */ ++ if ((i.tm.base_opcode & ~7) == 0x58 ++ || (i.tm.base_opcode == 0x8f && i.tm.extension_opcode == 0)) ++ return 1; ++ ++ /* movs, cmps, lods, scas. */ ++ if ((i.tm.base_opcode | 0xb) == 0xaf) ++ return 1; ++ ++ /* outs */ ++ if (base_opcode == 0x6f) ++ return 1; ++ } ++ ++ /* No memory operand. */ ++ if (!i.mem_operands) ++ return 0; ++ ++ if (any_vex_p) ++ { ++ /* vldmxcsr. */ ++ if (i.tm.base_opcode == 0xae ++ && i.tm.opcode_modifier.vex ++ && i.tm.opcode_modifier.vexopcode == VEX0F ++ && i.tm.extension_opcode == 2) ++ return 1; ++ } ++ else ++ { ++ /* test, not, neg, mul, imul, div, idiv. */ ++ if ((i.tm.base_opcode == 0xf6 || i.tm.base_opcode == 0xf7) ++ && i.tm.extension_opcode != 1) ++ return 1; ++ ++ /* inc, dec. */ ++ if (base_opcode == 0xff && i.tm.extension_opcode <= 1) ++ return 1; ++ ++ /* add, or, adc, sbb, and, sub, xor, cmp. */ ++ if (i.tm.base_opcode >= 0x80 && i.tm.base_opcode <= 0x83) ++ return 1; ++ ++ /* bt, bts, btr, btc. */ ++ if (i.tm.base_opcode == 0xfba ++ && (i.tm.extension_opcode >= 4 && i.tm.extension_opcode <= 7)) ++ return 1; ++ ++ /* rol, ror, rcl, rcr, shl/sal, shr, sar. */ ++ if ((base_opcode == 0xc1 ++ || (i.tm.base_opcode >= 0xd0 && i.tm.base_opcode <= 0xd3)) ++ && i.tm.extension_opcode != 6) ++ return 1; ++ ++ /* cmpxchg8b, cmpxchg16b, xrstors. */ ++ if (i.tm.base_opcode == 0xfc7 ++ && (i.tm.extension_opcode == 1 || i.tm.extension_opcode == 3)) ++ return 1; ++ ++ /* fxrstor, ldmxcsr, xrstor. */ ++ if (i.tm.base_opcode == 0xfae ++ && (i.tm.extension_opcode == 1 ++ || i.tm.extension_opcode == 2 ++ || i.tm.extension_opcode == 5)) ++ return 1; ++ ++ /* lgdt, lidt, lmsw. */ ++ if (i.tm.base_opcode == 0xf01 ++ && (i.tm.extension_opcode == 2 ++ || i.tm.extension_opcode == 3 ++ || i.tm.extension_opcode == 6)) ++ return 1; ++ ++ /* vmptrld */ ++ if (i.tm.base_opcode == 0xfc7 ++ && i.tm.extension_opcode == 6) ++ return 1; ++ ++ /* Check for x87 instructions. */ ++ if (i.tm.base_opcode >= 0xd8 && i.tm.base_opcode <= 0xdf) ++ { ++ /* Skip fst, fstp, fstenv, fstcw. */ ++ if (i.tm.base_opcode == 0xd9 ++ && (i.tm.extension_opcode == 2 ++ || i.tm.extension_opcode == 3 ++ || i.tm.extension_opcode == 6 ++ || i.tm.extension_opcode == 7)) ++ return 0; ++ ++ /* Skip fisttp, fist, fistp, fstp. */ ++ if (i.tm.base_opcode == 0xdb ++ && (i.tm.extension_opcode == 1 ++ || i.tm.extension_opcode == 2 ++ || i.tm.extension_opcode == 3 ++ || i.tm.extension_opcode == 7)) ++ return 0; ++ ++ /* Skip fisttp, fst, fstp, fsave, fstsw. */ ++ if (i.tm.base_opcode == 0xdd ++ && (i.tm.extension_opcode == 1 ++ || i.tm.extension_opcode == 2 ++ || i.tm.extension_opcode == 3 ++ || i.tm.extension_opcode == 6 ++ || i.tm.extension_opcode == 7)) ++ return 0; ++ ++ /* Skip fisttp, fist, fistp, fbstp, fistp. */ ++ if (i.tm.base_opcode == 0xdf ++ && (i.tm.extension_opcode == 1 ++ || i.tm.extension_opcode == 2 ++ || i.tm.extension_opcode == 3 ++ || i.tm.extension_opcode == 6 ++ || i.tm.extension_opcode == 7)) ++ return 0; ++ ++ return 1; ++ } ++ } ++ ++ dest = i.operands - 1; ++ ++ /* Check fake imm8 operand and 3 source operands. */ ++ if ((i.tm.opcode_modifier.immext ++ || i.tm.opcode_modifier.vexsources == VEX3SOURCES) ++ && i.types[dest].bitfield.imm8) ++ dest--; ++ ++ /* add, or, adc, sbb, and, sub, xor, cmp, test, xchg, xadd */ ++ if (!any_vex_p ++ && (base_opcode == 0x1 ++ || base_opcode == 0x9 ++ || base_opcode == 0x11 ++ || base_opcode == 0x19 ++ || base_opcode == 0x21 ++ || base_opcode == 0x29 ++ || base_opcode == 0x31 ++ || base_opcode == 0x39 ++ || (i.tm.base_opcode >= 0x84 && i.tm.base_opcode <= 0x87) ++ || base_opcode == 0xfc1)) ++ return 1; ++ ++ /* Check for load instruction. */ ++ return (i.types[dest].bitfield.class != ClassNone ++ || i.types[dest].bitfield.instance == Accum); ++} ++ ++/* Output lfence, 0xfaee8, after instruction. */ ++ ++static void ++insert_lfence_after (void) ++{ ++ if (lfence_after_load && load_insn_p ()) ++ { ++ char *p = frag_more (3); ++ *p++ = 0xf; ++ *p++ = 0xae; ++ *p = 0xe8; ++ } ++} ++ ++/* Output lfence, 0xfaee8, before instruction. */ ++ ++static void ++insert_lfence_before (void) ++{ ++ char *p; ++ ++ if (is_any_vex_encoding (&i.tm)) ++ return; ++ ++ if (i.tm.base_opcode == 0xff ++ && (i.tm.extension_opcode == 2 || i.tm.extension_opcode == 4)) ++ { ++ /* Insert lfence before indirect branch if needed. */ ++ ++ if (lfence_before_indirect_branch == lfence_branch_none) ++ return; ++ ++ if (i.operands != 1) ++ abort (); ++ ++ if (i.reg_operands == 1) ++ { ++ /* Indirect branch via register. Don't insert lfence with ++ -mlfence-after-load=yes. */ ++ if (lfence_after_load ++ || lfence_before_indirect_branch == lfence_branch_memory) ++ return; ++ } ++ else if (i.mem_operands == 1 ++ && lfence_before_indirect_branch != lfence_branch_register) ++ { ++ as_warn (_("indirect `%s` with memory operand should be avoided"), ++ i.tm.name); ++ return; ++ } ++ else ++ return; ++ ++ if (last_insn.kind != last_insn_other ++ && last_insn.seg == now_seg) ++ { ++ as_warn_where (last_insn.file, last_insn.line, ++ _("`%s` skips -mlfence-before-indirect-branch on `%s`"), ++ last_insn.name, i.tm.name); ++ return; ++ } ++ ++ p = frag_more (3); ++ *p++ = 0xf; ++ *p++ = 0xae; ++ *p = 0xe8; ++ return; ++ } ++ ++ /* Output or/not and lfence before ret. */ ++ if (lfence_before_ret != lfence_before_ret_none ++ && (i.tm.base_opcode == 0xc2 ++ || i.tm.base_opcode == 0xc3 ++ || i.tm.base_opcode == 0xca ++ || i.tm.base_opcode == 0xcb)) ++ { ++ if (last_insn.kind != last_insn_other ++ && last_insn.seg == now_seg) ++ { ++ as_warn_where (last_insn.file, last_insn.line, ++ _("`%s` skips -mlfence-before-ret on `%s`"), ++ last_insn.name, i.tm.name); ++ return; ++ } ++ if (lfence_before_ret == lfence_before_ret_or) ++ { ++ /* orl: 0x830c2400. */ ++ p = frag_more ((flag_code == CODE_64BIT ? 1 : 0) + 4 + 3); ++ if (flag_code == CODE_64BIT) ++ *p++ = 0x48; ++ *p++ = 0x83; ++ *p++ = 0xc; ++ *p++ = 0x24; ++ *p++ = 0x0; ++ } ++ else ++ { ++ p = frag_more ((flag_code == CODE_64BIT ? 2 : 0) + 6 + 3); ++ /* notl: 0xf71424. */ ++ if (flag_code == CODE_64BIT) ++ *p++ = 0x48; ++ *p++ = 0xf7; ++ *p++ = 0x14; ++ *p++ = 0x24; ++ /* notl: 0xf71424. */ ++ if (flag_code == CODE_64BIT) ++ *p++ = 0x48; ++ *p++ = 0xf7; ++ *p++ = 0x14; ++ *p++ = 0x24; ++ } ++ *p++ = 0xf; ++ *p++ = 0xae; ++ *p = 0xe8; ++ } ++} ++ + /* This is the guts of the machine-dependent assembler. LINE points to a + machine dependent instruction. This function is supposed to emit + the frags/bytes it assembles to. */ +@@ -4628,9 +4927,13 @@ md_assemble (char *line) + if (i.rex != 0) + add_prefix (REX_OPCODE | i.rex); + ++ insert_lfence_before (); ++ + /* We are ready to output the insn. */ + output_insn (); + ++ insert_lfence_after (); ++ + last_insn.seg = now_seg; + + if (i.tm.opcode_modifier.isprefix) +@@ -12250,6 +12553,9 @@ const char *md_shortopts = "qnO::"; + #define OPTION_MALIGN_BRANCH_PREFIX_SIZE (OPTION_MD_BASE + 28) + #define OPTION_MALIGN_BRANCH (OPTION_MD_BASE + 29) + #define OPTION_MBRANCHES_WITH_32B_BOUNDARIES (OPTION_MD_BASE + 30) ++#define OPTION_MLFENCE_AFTER_LOAD (OPTION_MD_BASE + 31) ++#define OPTION_MLFENCE_BEFORE_INDIRECT_BRANCH (OPTION_MD_BASE + 32) ++#define OPTION_MLFENCE_BEFORE_RET (OPTION_MD_BASE + 33) + + struct option md_longopts[] = + { +@@ -12289,6 +12595,10 @@ struct option md_longopts[] = + {"malign-branch-prefix-size", required_argument, NULL, OPTION_MALIGN_BRANCH_PREFIX_SIZE}, + {"malign-branch", required_argument, NULL, OPTION_MALIGN_BRANCH}, + {"mbranches-within-32B-boundaries", no_argument, NULL, OPTION_MBRANCHES_WITH_32B_BOUNDARIES}, ++ {"mlfence-after-load", required_argument, NULL, OPTION_MLFENCE_AFTER_LOAD}, ++ {"mlfence-before-indirect-branch", required_argument, NULL, ++ OPTION_MLFENCE_BEFORE_INDIRECT_BRANCH}, ++ {"mlfence-before-ret", required_argument, NULL, OPTION_MLFENCE_BEFORE_RET}, + {"mamd64", no_argument, NULL, OPTION_MAMD64}, + {"mintel64", no_argument, NULL, OPTION_MINTEL64}, + {NULL, no_argument, NULL, 0} +@@ -12668,6 +12978,41 @@ md_parse_option (int c, const char *arg) + as_fatal (_("invalid -mfence-as-lock-add= option: `%s'"), arg); + break; + ++ case OPTION_MLFENCE_AFTER_LOAD: ++ if (strcasecmp (arg, "yes") == 0) ++ lfence_after_load = 1; ++ else if (strcasecmp (arg, "no") == 0) ++ lfence_after_load = 0; ++ else ++ as_fatal (_("invalid -mlfence-after-load= option: `%s'"), arg); ++ break; ++ ++ case OPTION_MLFENCE_BEFORE_INDIRECT_BRANCH: ++ if (strcasecmp (arg, "all") == 0) ++ lfence_before_indirect_branch = lfence_branch_all; ++ else if (strcasecmp (arg, "memory") == 0) ++ lfence_before_indirect_branch = lfence_branch_memory; ++ else if (strcasecmp (arg, "register") == 0) ++ lfence_before_indirect_branch = lfence_branch_register; ++ else if (strcasecmp (arg, "none") == 0) ++ lfence_before_indirect_branch = lfence_branch_none; ++ else ++ as_fatal (_("invalid -mlfence-before-indirect-branch= option: `%s'"), ++ arg); ++ break; ++ ++ case OPTION_MLFENCE_BEFORE_RET: ++ if (strcasecmp (arg, "or") == 0) ++ lfence_before_ret = lfence_before_ret_or; ++ else if (strcasecmp (arg, "not") == 0) ++ lfence_before_ret = lfence_before_ret_not; ++ else if (strcasecmp (arg, "none") == 0) ++ lfence_before_ret = lfence_before_ret_none; ++ else ++ as_fatal (_("invalid -mlfence-before-ret= option: `%s'"), ++ arg); ++ break; ++ + case OPTION_MRELAX_RELOCATIONS: + if (strcasecmp (arg, "yes") == 0) + generate_relax_relocations = 1; +@@ -13025,6 +13370,15 @@ md_show_usage (FILE *stream) + -mbranches-within-32B-boundaries\n\ + align branches within 32 byte boundary\n")); + fprintf (stream, _("\ ++ -mlfence-after-load=[no|yes] (default: no)\n\ ++ generate lfence after load\n")); ++ fprintf (stream, _("\ ++ -mlfence-before-indirect-branch=[none|all|register|memory] (default: none)\n\ ++ generate lfence before indirect near branch\n")); ++ fprintf (stream, _("\ ++ -mlfence-before-ret=[none|or|not] (default: none)\n\ ++ generate lfence before ret\n")); ++ fprintf (stream, _("\ + -mamd64 accept only AMD64 ISA [default]\n")); + fprintf (stream, _("\ + -mintel64 accept only Intel64 ISA\n")); +@@ -13254,6 +13608,16 @@ i386_cons_align (int ignore ATTRIBUTE_UNUSED) + last_insn.kind = last_insn_directive; + last_insn.name = "constant directive"; + last_insn.file = as_where (&last_insn.line); ++ if (lfence_before_ret != lfence_before_ret_none) ++ { ++ if (lfence_before_indirect_branch != lfence_branch_none) ++ as_warn (_("constant directive skips -mlfence-before-ret " ++ "and -mlfence-before-indirect-branch")); ++ else ++ as_warn (_("constant directive skips -mlfence-before-ret")); ++ } ++ else if (lfence_before_indirect_branch != lfence_branch_none) ++ as_warn (_("constant directive skips -mlfence-before-indirect-branch")); + } + } + +diff --git a/gas/doc/c-i386.texi b/gas/doc/c-i386.texi +index c536759cb38..1dd99f91bb0 100644 +--- a/gas/doc/c-i386.texi ++++ b/gas/doc/c-i386.texi +@@ -464,6 +464,49 @@ on an instruction. It is equivalent to + @option{-malign-branch-prefix-size=5}. + The default doesn't align branches. + ++@cindex @samp{-mlfence-after-load=} option, i386 ++@cindex @samp{-mlfence-after-load=} option, x86-64 ++@item -mlfence-after-load=@var{no} ++@itemx -mlfence-after-load=@var{yes} ++These options control whether the assembler should generate lfence ++after load instructions. @option{-mlfence-after-load=@var{yes}} will ++generate lfence. @option{-mlfence-after-load=@var{no}} will not generate ++lfence, which is the default. ++ ++@cindex @samp{-mlfence-before-indirect-branch=} option, i386 ++@cindex @samp{-mlfence-before-indirect-branch=} option, x86-64 ++@item -mlfence-before-indirect-branch=@var{none} ++@item -mlfence-before-indirect-branch=@var{all} ++@item -mlfence-before-indirect-branch=@var{register} ++@itemx -mlfence-before-indirect-branch=@var{memory} ++These options control whether the assembler should generate lfence ++after indirect near branch instructions. ++@option{-mlfence-before-indirect-branch=@var{all}} will generate lfence ++after indirect near branch via register and issue a warning before ++indirect near branch via memory. ++@option{-mlfence-before-indirect-branch=@var{register}} will generate ++lfence after indirect near branch via register. ++@option{-mlfence-before-indirect-branch=@var{memory}} will issue a ++warning before indirect near branch via memory. ++@option{-mlfence-before-indirect-branch=@var{none}} will not generate ++lfence nor issue warning, which is the default. Note that lfence won't ++be generated before indirect near branch via register with ++@option{-mlfence-after-load=@var{yes}} since lfence will be generated ++after loading branch target register. ++ ++@cindex @samp{-mlfence-before-ret=} option, i386 ++@cindex @samp{-mlfence-before-ret=} option, x86-64 ++@item -mlfence-before-ret=@var{none} ++@item -mlfence-before-ret=@var{or} ++@itemx -mlfence-before-ret=@var{not} ++These options control whether the assembler should generate lfence ++before ret. @option{-mlfence-before-ret=@var{or}} will generate ++generate or instruction with lfence. ++@option{-mlfence-before-ret=@var{not}} will generate not instruction ++with lfence. ++@option{-mlfence-before-ret=@var{none}} will not generate lfence, ++which is the default. ++ + @cindex @samp{-mx86-used-note=} option, i386 + @cindex @samp{-mx86-used-note=} option, x86-64 + @item -mx86-used-note=@var{no} diff --git a/binutils.spec b/binutils.spec index 0cb3ba4..afdcd80 100644 --- a/binutils.spec +++ b/binutils.spec @@ -1,7 +1,7 @@ Summary: Binary utilities Name: binutils Version: 2.34 -Release: 7 +Release: 8 License: GPLv3+ URL: https://sourceware.org/binutils @@ -35,6 +35,7 @@ Patch18: readelf-leak-in-process_archive.patch Patch19: metag-uninitialized-memory-read.patch Patch20: Fix-a-potential-use-of-an-uninitialised-value-in-the.patch Patch21: backport-CVE-2020-16592-PR25823-Use-after-free-in-bfd_hash_lookup.patch +Patch22: backport-CVE-2020-0551-i386-Generate-lfence.patch Provides: bundled(libiberty) @@ -313,6 +314,12 @@ fi %{_infodir}/bfd*info* %changelog +* Tue Mar 23 2021 panxiaohe - 2.34-8 +- Type:CVE +- ID:NA +- SUG:NA +- DESC:fix CVE-2020-0551 + * Mon Mar 22 2021 lirui - 2.34-7 - Type:bugfix - ID:NA -- Gitee From cc3cc4a9a2026dd0ed8232e628081d4212025c27 Mon Sep 17 00:00:00 2001 From: lirui Date: Fri, 16 Apr 2021 14:37:42 +0800 Subject: [PATCH 5/6] fix CVE-2021-20197 --- backport-0001-CVE-2021-20197.patch | 287 ++++++++++++++ backport-0002-CVE-2021-20197.patch | 96 +++++ backport-0003-CVE-2021-20197.patch | 368 ++++++++++++++++++ backport-0004-CVE-2021-20197.patch | 193 +++++++++ ...-build-problem-when-using-FreeBSD-12.patch | 57 +++ binutils.spec | 13 +- 6 files changed, 1013 insertions(+), 1 deletion(-) create mode 100644 backport-0001-CVE-2021-20197.patch create mode 100644 backport-0002-CVE-2021-20197.patch create mode 100644 backport-0003-CVE-2021-20197.patch create mode 100644 backport-0004-CVE-2021-20197.patch create mode 100644 backport-Fix-a-build-problem-when-using-FreeBSD-12.patch diff --git a/backport-0001-CVE-2021-20197.patch b/backport-0001-CVE-2021-20197.patch new file mode 100644 index 0000000..e3a9dd4 --- /dev/null +++ b/backport-0001-CVE-2021-20197.patch @@ -0,0 +1,287 @@ +From 365f5fb6d0f0da83817431a275e99e6f6babbe04 Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Mon, 7 Dec 2020 20:48:23 +0530 +Subject: [PATCH] binutils: Use file descriptors from make_tempname + +The purpose of creating a temporary file securely using mkstemp is +defeated if it is closed in make_tempname and reopened later for use; +it is as good as using mktemp. Get the file descriptor instead and +then use it to create the BFD object. + +bfd/ + + * opncls.c (bfd_fdopenw): New function. + * bfd-in2.h: Regenerate. + +binutils/ + + * bucomm.c (make_tempname): Add argument to return file + descriptor. + * bucomm.h (make_tempname): Likewise. + * ar.c: Include libbfd.h. + (write_archive): Adjust for change in make_tempname. Call + bfd_fdopenw instead of bfd_openw. + * objcopy.c: Include libbfd.h. + (copy_file): New argument OFD. Use bfd_fdopenw instead of + bfd_openw. + (strip_main): Adjust for change in make_tempname and + copy_file. + (copy_main): Likewise. +--- + bfd/ChangeLog | 6 ++++++ + bfd/bfd-in2.h | 2 ++ + bfd/opncls.c | 33 +++++++++++++++++++++++++++++++++ + binutils/ChangeLog | 17 +++++++++++++++++ + binutils/ar.c | 11 ++++++++--- + binutils/bucomm.c | 4 ++-- + binutils/bucomm.h | 2 +- + binutils/objcopy.c | 30 ++++++++++++++++++++++-------- + 8 files changed, 91 insertions(+), 14 deletions(-) + +diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h +index 935ba53..48e3d9b 100644 +--- a/bfd/bfd-in2.h ++++ b/bfd/bfd-in2.h +@@ -588,6 +588,8 @@ bfd *bfd_openr (const char *filename, const char *target); + + bfd *bfd_fdopenr (const char *filename, const char *target, int fd); + ++bfd *bfd_fdopenw (const char *filename, const char *target, int fd); ++ + bfd *bfd_openstreamr (const char * filename, const char * target, + void * stream); + +diff --git a/bfd/opncls.c b/bfd/opncls.c +index c2a1d2f..f7696b6 100644 +--- a/bfd/opncls.c ++++ b/bfd/opncls.c +@@ -395,6 +395,39 @@ bfd_fdopenr (const char *filename, const char *target, int fd) + + /* + FUNCTION ++ bfd_fdopenw ++ ++SYNOPSIS ++ bfd *bfd_fdopenw (const char *filename, const char *target, int fd); ++ ++DESCRIPTION ++ <> is exactly like <> with the exception that ++ the resulting BFD is suitable for output. ++*/ ++ ++bfd * ++bfd_fdopenw (const char *filename, const char *target, int fd) ++{ ++ bfd *out = bfd_fdopenr (filename, target, fd); ++ ++ if (out != NULL) ++ { ++ if (!bfd_write_p (out)) ++ { ++ close (fd); ++ _bfd_delete_bfd (out); ++ out = NULL; ++ bfd_set_error (bfd_error_invalid_operation); ++ } ++ else ++ out->direction = write_direction; ++ } ++ ++ return out; ++} ++ ++/* ++FUNCTION + bfd_openstreamr + + SYNOPSIS +diff --git a/binutils/ar.c b/binutils/ar.c +index 7d279d6..2253242 100644 +--- a/binutils/ar.c ++++ b/binutils/ar.c +@@ -25,6 +25,7 @@ + + #include "sysdep.h" + #include "bfd.h" ++#include "libbfd.h" + #include "libiberty.h" + #include "progress.h" + #include "getopt.h" +@@ -1252,20 +1253,24 @@ write_archive (bfd *iarch) + bfd *obfd; + char *old_name, *new_name; + bfd *contents_head = iarch->archive_next; ++ int ofd = -1; + + old_name = (char *) xmalloc (strlen (bfd_get_filename (iarch)) + 1); + strcpy (old_name, bfd_get_filename (iarch)); +- new_name = make_tempname (old_name); ++ new_name = make_tempname (old_name, &ofd); + + if (new_name == NULL) + bfd_fatal (_("could not create temporary file whilst writing archive")); + + output_filename = new_name; + +- obfd = bfd_openw (new_name, bfd_get_target (iarch)); ++ obfd = bfd_fdopenw (new_name, bfd_get_target (iarch), ofd); + + if (obfd == NULL) +- bfd_fatal (old_name); ++ { ++ close (ofd); ++ bfd_fatal (old_name); ++ } + + output_bfd = obfd; + +diff --git a/binutils/bucomm.c b/binutils/bucomm.c +index 9e6a028..5324420 100644 +--- a/binutils/bucomm.c ++++ b/binutils/bucomm.c +@@ -532,7 +532,7 @@ template_in_dir (const char *path) + as FILENAME. */ + + char * +-make_tempname (const char *filename) ++make_tempname (const char *filename, int *ofd) + { + char *tmpname = template_in_dir (filename); + int fd; +@@ -550,7 +550,7 @@ make_tempname (const char *filename) + free (tmpname); + return NULL; + } +- close (fd); ++ *ofd = fd; + return tmpname; + } + +diff --git a/binutils/bucomm.h b/binutils/bucomm.h +index d831834..afb8e09 100644 +--- a/binutils/bucomm.h ++++ b/binutils/bucomm.h +@@ -51,7 +51,7 @@ int display_info (void); + + void print_arelt_descr (FILE *, bfd *, bfd_boolean, bfd_boolean); + +-char *make_tempname (const char *); ++char *make_tempname (const char *, int *); + char *make_tempdir (const char *); + + bfd_vma parse_vma (const char *, const char *); +diff --git a/binutils/objcopy.c b/binutils/objcopy.c +index ca35df0..2eb083c 100644 +--- a/binutils/objcopy.c ++++ b/binutils/objcopy.c +@@ -20,6 +20,7 @@ + + #include "sysdep.h" + #include "bfd.h" ++#include "libbfd.h" + #include "progress.h" + #include "getopt.h" + #include "libiberty.h" +@@ -3727,7 +3728,7 @@ set_long_section_mode (bfd *output_bfd, bfd *input_bfd, enum long_section_name_h + /* The top-level control. */ + + static void +-copy_file (const char *input_filename, const char *output_filename, ++copy_file (const char *input_filename, const char *output_filename, int ofd, + const char *input_target, const char *output_target, + const bfd_arch_info_type *input_arch) + { +@@ -3802,9 +3803,14 @@ copy_file (const char *input_filename, const char *output_filename, + else + force_output_target = TRUE; + +- obfd = bfd_openw (output_filename, output_target); ++ if (ofd >= 0) ++ obfd = bfd_fdopenw (output_filename, output_target, ofd); ++ else ++ obfd = bfd_openw (output_filename, output_target); ++ + if (obfd == NULL) + { ++ close (ofd); + bfd_nonfatal_message (output_filename, NULL, NULL, NULL); + status = 1; + return; +@@ -3832,13 +3838,19 @@ copy_file (const char *input_filename, const char *output_filename, + if (output_target == NULL) + output_target = bfd_get_target (ibfd); + +- obfd = bfd_openw (output_filename, output_target); ++ if (ofd >= 0) ++ obfd = bfd_fdopenw (output_filename, output_target, ofd); ++ else ++ obfd = bfd_openw (output_filename, output_target); ++ + if (obfd == NULL) + { ++ close (ofd); + bfd_nonfatal_message (output_filename, NULL, NULL, NULL); + status = 1; + return; + } ++ + /* This is a no-op on non-Coff targets. */ + set_long_section_mode (obfd, ibfd, long_section_names); + +@@ -4802,6 +4814,7 @@ strip_main (int argc, char *argv[]) + int hold_status = status; + struct stat statbuf; + char *tmpname; ++ int tmpfd = -1; + + if (get_file_size (argv[i]) < 1) + { +@@ -4816,7 +4829,7 @@ strip_main (int argc, char *argv[]) + + if (output_file == NULL + || filename_cmp (argv[i], output_file) == 0) +- tmpname = make_tempname (argv[i]); ++ tmpname = make_tempname (argv[i], &tmpfd); + else + tmpname = output_file; + +@@ -4829,7 +4842,7 @@ strip_main (int argc, char *argv[]) + } + + status = 0; +- copy_file (argv[i], tmpname, input_target, output_target, NULL); ++ copy_file (argv[i], tmpname, tmpfd, input_target, output_target, NULL); + if (status == 0) + { + if (preserve_dates) +@@ -5049,7 +5062,7 @@ copy_main (int argc, char *argv[]) + bfd_boolean formats_info = FALSE; + bfd_boolean use_globalize = FALSE; + bfd_boolean use_keep_global = FALSE; +- int c; ++ int c, tmpfd = -1; + struct stat statbuf; + const bfd_arch_info_type *input_arch = NULL; + +@@ -5895,7 +5908,7 @@ copy_main (int argc, char *argv[]) + are the same, then create a temp and rename the result into the input. */ + if (output_filename == NULL + || filename_cmp (input_filename, output_filename) == 0) +- tmpname = make_tempname (input_filename); ++ tmpname = make_tempname (input_filename, &tmpfd); + else + tmpname = output_filename; + +@@ -5903,7 +5916,8 @@ copy_main (int argc, char *argv[]) + fatal (_("warning: could not create temporary file whilst copying '%s', (error: %s)"), + input_filename, strerror (errno)); + +- copy_file (input_filename, tmpname, input_target, output_target, input_arch); ++ copy_file (input_filename, tmpname, tmpfd, input_target, output_target, ++ input_arch); + if (status == 0) + { + if (preserve_dates) +-- +1.8.3.1 + diff --git a/backport-0002-CVE-2021-20197.patch b/backport-0002-CVE-2021-20197.patch new file mode 100644 index 0000000..abea8f4 --- /dev/null +++ b/backport-0002-CVE-2021-20197.patch @@ -0,0 +1,96 @@ +From 1a1c3b4cc17687091cff5a368bd6f13742bcfdf8 Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Mon, 7 Dec 2020 20:48:28 +0530 +Subject: [PATCH] objcopy: Get input file stat after BFD open + +Get file state from the descriptor opened by copy_file for the input +BFD. This ensures continuity in the view of the input file through +the descriptor. At the moment it is only to preserve timestamps +recorded at the point that we opened the file for input but in the +next patch this state will also be used to preserve ownership and +permissions wherever applicable. + +binutils/ + + * objcopy.c (copy_file): New argument IN_STAT. Return stat of + ibfd through it. + (strip_main): Remove redundant stat calls. adjust copy_file + calls. + (copy_main): Likewise. +--- + binutils/ChangeLog | 9 +++++++++ + binutils/objcopy.c | 23 +++++++---------------- + 2 files changed, 16 insertions(+), 16 deletions(-) + +diff --git a/binutils/objcopy.c b/binutils/objcopy.c +index 2eb083c..b6cf6ea 100644 +--- a/binutils/objcopy.c ++++ b/binutils/objcopy.c +@@ -3729,8 +3729,8 @@ set_long_section_mode (bfd *output_bfd, bfd *input_bfd, enum long_section_name_h + + static void + copy_file (const char *input_filename, const char *output_filename, int ofd, +- const char *input_target, const char *output_target, +- const bfd_arch_info_type *input_arch) ++ struct stat *in_stat, const char *input_target, ++ const char *output_target, const bfd_arch_info_type *input_arch) + { + bfd *ibfd; + char **obj_matching; +@@ -3749,7 +3749,7 @@ copy_file (const char *input_filename, const char *output_filename, int ofd, + /* To allow us to do "strip *" without dying on the first + non-object file, failures are nonfatal. */ + ibfd = bfd_openr (input_filename, input_target); +- if (ibfd == NULL) ++ if (ibfd == NULL || fstat (fileno (ibfd->iostream), in_stat) != 0) + { + bfd_nonfatal_message (input_filename, NULL, NULL, NULL); + status = 1; +@@ -4822,11 +4822,6 @@ strip_main (int argc, char *argv[]) + continue; + } + +- if (preserve_dates) +- /* No need to check the return value of stat(). +- It has already been checked in get_file_size(). */ +- stat (argv[i], &statbuf); +- + if (output_file == NULL + || filename_cmp (argv[i], output_file) == 0) + tmpname = make_tempname (argv[i], &tmpfd); +@@ -4842,7 +4837,8 @@ strip_main (int argc, char *argv[]) + } + + status = 0; +- copy_file (argv[i], tmpname, tmpfd, input_target, output_target, NULL); ++ copy_file (argv[i], tmpname, tmpfd, &statbuf, input_target, ++ output_target, NULL); + if (status == 0) + { + if (preserve_dates) +@@ -5899,11 +5895,6 @@ copy_main (int argc, char *argv[]) + convert_efi_target (efi); + } + +- if (preserve_dates) +- if (stat (input_filename, & statbuf) < 0) +- fatal (_("warning: could not locate '%s'. System error message: %s"), +- input_filename, strerror (errno)); +- + /* If there is no destination file, or the source and destination files + are the same, then create a temp and rename the result into the input. */ + if (output_filename == NULL +@@ -5916,8 +5907,8 @@ copy_main (int argc, char *argv[]) + fatal (_("warning: could not create temporary file whilst copying '%s', (error: %s)"), + input_filename, strerror (errno)); + +- copy_file (input_filename, tmpname, tmpfd, input_target, output_target, +- input_arch); ++ copy_file (input_filename, tmpname, tmpfd, &statbuf, input_target, ++ output_target, input_arch); + if (status == 0) + { + if (preserve_dates) +-- +1.8.3.1 + diff --git a/backport-0003-CVE-2021-20197.patch b/backport-0003-CVE-2021-20197.patch new file mode 100644 index 0000000..4e2e2c7 --- /dev/null +++ b/backport-0003-CVE-2021-20197.patch @@ -0,0 +1,368 @@ +From 014cc7f849e8209623fc99264814bce7b3b6faf2 Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Mon, 7 Dec 2020 20:48:33 +0530 +Subject: [PATCH] binutils: Make smart_rename safe too + +smart_rename is capable of handling symlinks by copying and it also +tries to preserve ownership and permissions of files when they're +overwritten during the rename. This is useful in objcopy where the +file properties need to be preserved. + +However because smart_rename does this using file names, it leaves a +race window between renames and permission fixes. This change removes +this race window by using file descriptors from the original BFDs that +were used to manipulate these files wherever possible. + +The file that is to be renamed is also passed as a file descriptor so +that we use fchown/fchmod on the file descriptor, thus making sure +that we only modify the file we have opened to write. Further, in +case the file is to be overwritten (as is the case in ar or objcopy), +the permissions that need to be restored are taken from the file +descriptor that was opened for input so that integrity of the file +status is maintained all the way through to the rename. + +binutils/ + + * rename.c + * ar.c + (write_archive) [!defined (_WIN32) || defined (__CYGWIN32__)]: + Initialize TARGET_STAT and OFD to pass to SMART_RENAME. + * arsup.c + (ar_save) [defined (_WIN32) || defined (__CYGWIN32__)]: + Likewise. + * bucomm.h (smart_rename): Add new arguments to declaration. + * objcopy.c + (strip_main)[defined (_WIN32) || defined (__CYGWIN32__)]: + Initialize COPYFD and pass to SMART_RENAME. + (copy_main) [defined (_WIN32) || defined (__CYGWIN32__)]: + Likewise. + * rename.c (try_preserve_permissions): New function. + (smart_rename): Use it and add new arguments. +--- + binutils/ChangeLog | 18 ++++++++++ + binutils/ar.c | 12 ++++++- + binutils/arsup.c | 14 +++++++- + binutils/bucomm.h | 3 +- + binutils/objcopy.c | 42 +++++++++++++++++----- + binutils/rename.c | 101 +++++++++++++++++++++++++++++++++++++---------------- + 6 files changed, 148 insertions(+), 42 deletions(-) + +diff --git a/binutils/ar.c b/binutils/ar.c +index 2253242..6598dd9 100644 +--- a/binutils/ar.c ++++ b/binutils/ar.c +@@ -1254,6 +1254,8 @@ write_archive (bfd *iarch) + char *old_name, *new_name; + bfd *contents_head = iarch->archive_next; + int ofd = -1; ++ struct stat target_stat; ++ bfd_boolean skip_stat = FALSE; + + old_name = (char *) xmalloc (strlen (bfd_get_filename (iarch)) + 1); + strcpy (old_name, bfd_get_filename (iarch)); +@@ -1299,6 +1301,14 @@ write_archive (bfd *iarch) + if (!bfd_set_archive_head (obfd, contents_head)) + bfd_fatal (old_name); + ++#if !defined (_WIN32) || defined (__CYGWIN32__) ++ ofd = dup (ofd); ++ if (iarch == NULL || iarch->iostream == NULL) ++ skip_stat = TRUE; ++ else if (ofd == -1 || fstat (fileno (iarch->iostream), &target_stat) != 0) ++ bfd_fatal (old_name); ++#endif ++ + if (!bfd_close (obfd)) + bfd_fatal (old_name); + +@@ -1308,7 +1318,7 @@ write_archive (bfd *iarch) + /* We don't care if this fails; we might be creating the archive. */ + bfd_close (iarch); + +- if (smart_rename (new_name, old_name, 0) != 0) ++ if (smart_rename (new_name, old_name, ofd, skip_stat ? NULL : &target_stat, 0) != 0) + xexit (1); + free (old_name); + free (new_name); +diff --git a/binutils/arsup.c b/binutils/arsup.c +index a668f27..8b4437f 100644 +--- a/binutils/arsup.c ++++ b/binutils/arsup.c +@@ -345,13 +345,25 @@ ar_save (void) + else + { + char *ofilename = xstrdup (bfd_get_filename (obfd)); ++ bfd_boolean skip_stat = FALSE; ++ struct stat target_stat; ++ int ofd = -1; + + if (deterministic > 0) + obfd->flags |= BFD_DETERMINISTIC_OUTPUT; + ++#if !defined (_WIN32) || defined (__CYGWIN32__) ++ /* It's OK to fail; at worst it will result in SMART_RENAME using a slow ++ copy fallback to write the output. */ ++ ofd = dup (fileno (obfd->iostream)); ++ if (lstat (real_name, &target_stat) != 0) ++ skip_stat = TRUE; ++#endif ++ + bfd_close (obfd); + +- smart_rename (ofilename, real_name, 0); ++ smart_rename (ofilename, real_name, ofd, ++ skip_stat ? NULL : &target_stat, 0); + obfd = 0; + free (ofilename); + } +diff --git a/binutils/bucomm.h b/binutils/bucomm.h +index afb8e09..9613b92 100644 +--- a/binutils/bucomm.h ++++ b/binutils/bucomm.h +@@ -71,7 +71,8 @@ extern void print_version (const char *); + /* In rename.c. */ + extern void set_times (const char *, const struct stat *); + +-extern int smart_rename (const char *, const char *, int); ++extern int smart_rename (const char *, const char *, int, struct stat *, int); ++ + + /* In libiberty. */ + void *xmalloc (size_t); +diff --git a/binutils/objcopy.c b/binutils/objcopy.c +index b6cf6ea..04ba95e 100644 +--- a/binutils/objcopy.c ++++ b/binutils/objcopy.c +@@ -4815,6 +4815,7 @@ strip_main (int argc, char *argv[]) + struct stat statbuf; + char *tmpname; + int tmpfd = -1; ++ int copyfd = -1; + + if (get_file_size (argv[i]) < 1) + { +@@ -4828,7 +4829,12 @@ strip_main (int argc, char *argv[]) + else + tmpname = output_file; + +- if (tmpname == NULL) ++ if (tmpname == NULL ++#if !defined (_WIN32) || defined (__CYGWIN32__) ++ /* Retain a copy of TMPFD since we will need it for SMART_RENAME. */ ++ || (tmpfd >= 0 && (copyfd = dup (tmpfd)) == -1) ++#endif ++ ) + { + bfd_nonfatal_message (argv[i], NULL, NULL, + _("could not create temporary file to hold stripped copy")); +@@ -4846,12 +4852,18 @@ strip_main (int argc, char *argv[]) + if (output_file != tmpname) + status = (smart_rename (tmpname, + output_file ? output_file : argv[i], +- preserve_dates) != 0); ++ copyfd, &statbuf, preserve_dates) != 0); + if (status == 0) + status = hold_status; + } + else +- unlink_if_ordinary (tmpname); ++ { ++#if !defined (_WIN32) || defined (__CYGWIN32__) ++ if (copyfd >= 0) ++ close (copyfd); ++#endif ++ unlink_if_ordinary (tmpname); ++ } + if (output_file != tmpname) + free (tmpname); + } +@@ -5059,6 +5071,7 @@ copy_main (int argc, char *argv[]) + bfd_boolean use_globalize = FALSE; + bfd_boolean use_keep_global = FALSE; + int c, tmpfd = -1; ++ int copyfd = -1; + struct stat statbuf; + const bfd_arch_info_type *input_arch = NULL; + +@@ -5903,9 +5916,16 @@ copy_main (int argc, char *argv[]) + else + tmpname = output_filename; + +- if (tmpname == NULL) +- fatal (_("warning: could not create temporary file whilst copying '%s', (error: %s)"), +- input_filename, strerror (errno)); ++ if (tmpname == NULL ++#if !defined (_WIN32) || defined (__CYGWIN32__) ++ /* Retain a copy of TMPFD since we will need it for SMART_RENAME. */ ++ || (tmpfd >= 0 && (copyfd = dup (tmpfd)) == -1) ++#endif ++ ) ++ { ++ fatal (_("warning: could not create temporary file whilst copying '%s', (error: %s)"), ++ input_filename, strerror (errno)); ++ } + + copy_file (input_filename, tmpname, tmpfd, &statbuf, input_target, + output_target, input_arch); +@@ -5914,11 +5934,17 @@ copy_main (int argc, char *argv[]) + if (preserve_dates) + set_times (tmpname, &statbuf); + if (tmpname != output_filename) +- status = (smart_rename (tmpname, input_filename, ++ status = (smart_rename (tmpname, input_filename, copyfd, &statbuf, + preserve_dates) != 0); + } + else +- unlink_if_ordinary (tmpname); ++ { ++#if !defined (_WIN32) || defined (__CYGWIN32__) ++ if (copyfd >= 0) ++ close (copyfd); ++#endif ++ unlink_if_ordinary (tmpname); ++ } + + if (tmpname != output_filename) + free (tmpname); +diff --git a/binutils/rename.c b/binutils/rename.c +index bf3b68d..6b9165e 100644 +--- a/binutils/rename.c ++++ b/binutils/rename.c +@@ -131,17 +131,55 @@ set_times (const char *destination, const struct stat *statbuf) + #endif + #endif + +-/* Rename FROM to TO, copying if TO is a link. +- Return 0 if ok, -1 if error. */ ++#if !defined (_WIN32) || defined (__CYGWIN32__) ++/* Try to preserve the permission bits and ownership of an existing file when ++ rename overwrites it. FD is the file being renamed and TARGET_STAT has the ++ status of the file that was overwritten. */ ++static void ++try_preserve_permissions (int fd, struct stat *target_stat) ++{ ++ struct stat from_stat; ++ int ret = 0; ++ ++ if (fstat (fd, &from_stat) != 0) ++ return; ++ ++ int from_mode = from_stat.st_mode & 0777; ++ int to_mode = target_stat->st_mode & 0777; ++ ++ /* Fix up permissions before we potentially lose ownership with fchown. ++ Clear the setxid bits because in case the fchown below fails then we don't ++ want to end up with a sxid file owned by the invoking user. If the user ++ hasn't changed or if fchown succeeded, we add back the sxid bits at the ++ end. */ ++ if (from_mode != to_mode) ++ fchmod (fd, to_mode); ++ ++ /* Fix up ownership, this will clear the setxid bits. */ ++ if (from_stat.st_uid != target_stat->st_uid ++ || from_stat.st_gid != target_stat->st_gid) ++ ret = fchown (fd, target_stat->st_uid, target_stat->st_gid); ++ ++ /* Fix up the sxid bits if either the fchown wasn't needed or it ++ succeeded. */ ++ if (ret == 0) ++ fchmod (fd, target_stat->st_mode & 07777); ++} ++#endif ++ ++/* Rename FROM to TO, copying if TO is either a link or is not a regular file. ++ FD is an open file descriptor pointing to FROM that we can use to safely fix ++ up permissions of the file after renaming. TARGET_STAT has the file status ++ that is used to fix up permissions and timestamps after rename. Return 0 if ++ ok, -1 if error and FD is closed before returning. */ + + int +-smart_rename (const char *from, const char *to, int preserve_dates ATTRIBUTE_UNUSED) ++smart_rename (const char *from, const char *to, int fd ATTRIBUTE_UNUSED, ++ struct stat *target_stat ATTRIBUTE_UNUSED, ++ int preserve_dates ATTRIBUTE_UNUSED) + { +- bfd_boolean exists; +- struct stat s; + int ret = 0; +- +- exists = lstat (to, &s) == 0; ++ bfd_boolean exists = target_stat != NULL; + + #if defined (_WIN32) && !defined (__CYGWIN32__) + /* Win32, unlike unix, will not erase `to' in `rename(from, to)' but +@@ -158,36 +196,35 @@ smart_rename (const char *from, const char *to, int preserve_dates ATTRIBUTE_UNU + unlink (from); + } + #else +- /* Use rename only if TO is not a symbolic link and has +- only one hard link, and we have permission to write to it. */ ++ /* Avoid a full copy and use rename if we can fix up permissions of the ++ file after renaming, i.e.: ++ ++ - TO is not a symbolic link ++ - TO is a regular file with only one hard link ++ - We have permission to write to TO ++ - FD is available to safely fix up permissions to be the same as the file ++ we overwrote with the rename. ++ ++ Note though that the actual file on disk that TARGET_STAT describes may ++ have changed and we're only trying to preserve the status we know about. ++ At no point do we try to interact with the new file changes, so there can ++ only be two outcomes, i.e. either the external file change survives ++ without knowledge of our change (if it happens after the rename syscall) ++ or our rename and permissions fixup survive without any knowledge of the ++ external change. */ + if (! exists +- || (!S_ISLNK (s.st_mode) +- && S_ISREG (s.st_mode) +- && (s.st_mode & S_IWUSR) +- && s.st_nlink == 1) ++ || (fd >= 0 ++ && !S_ISLNK (target_stat->st_mode) ++ && S_ISREG (target_stat->st_mode) ++ && (target_stat->st_mode & S_IWUSR) ++ && target_stat->st_nlink == 1) + ) + { + ret = rename (from, to); + if (ret == 0) + { + if (exists) +- { +- /* Try to preserve the permission bits and ownership of +- TO. First get the mode right except for the setuid +- bit. Then change the ownership. Then fix the setuid +- bit. We do the chmod before the chown because if the +- chown succeeds, and we are a normal user, we won't be +- able to do the chmod afterward. We don't bother to +- fix the setuid bit first because that might introduce +- a fleeting security problem, and because the chown +- will clear the setuid bit anyhow. We only fix the +- setuid bit if the chown succeeds, because we don't +- want to introduce an unexpected setuid file owned by +- the user running objcopy. */ +- chmod (to, s.st_mode & 0777); +- if (chown (to, s.st_uid, s.st_gid) >= 0) +- chmod (to, s.st_mode & 07777); +- } ++ try_preserve_permissions (fd, target_stat); + } + else + { +@@ -203,9 +240,11 @@ smart_rename (const char *from, const char *to, int preserve_dates ATTRIBUTE_UNU + non_fatal (_("unable to copy file '%s'; reason: %s"), to, strerror (errno)); + + if (preserve_dates) +- set_times (to, &s); ++ set_times (to, target_stat); + unlink (from); + } ++ if (fd >= 0) ++ close (fd); + #endif /* _WIN32 && !__CYGWIN32__ */ + + return ret; +-- +1.8.3.1 + diff --git a/backport-0004-CVE-2021-20197.patch b/backport-0004-CVE-2021-20197.patch new file mode 100644 index 0000000..39a16ec --- /dev/null +++ b/backport-0004-CVE-2021-20197.patch @@ -0,0 +1,193 @@ +From 95b91a043aeaeb546d2fea556d84a2de1e917770 Mon Sep 17 00:00:00 2001 +From: Alan Modra +Date: Mon, 1 Feb 2021 02:04:41 +1030 +Subject: [PATCH] pr27270 and pr27284, ar segfaults and wrong file mode + + PR 27270 + PR 27284 + PR 26945 + * ar.c: Don't include libbfd.h. + (write_archive): Replace xmalloc+strcpy with xstrdup. Use + bfd_stat rather than fstat on iostream. Move stat and fd tests + outside of _WIN32 ifdef. Delete skip_stat variable. + * arsup.c (temp_name, real_ofd): New static variables. + (ar_open): Use make_tempname and bfd_fdopenw. + (ar_save): Adjust to suit ar_open changes. Move stat output + of _WIN32 ifdef. + * objcopy.c: Don't include libbfd.h. + (copy_file): Use bfd_stat. +--- + binutils/ChangeLog | 16 ++++++++++++++++ + binutils/ar.c | 13 ++++--------- + binutils/arsup.c | 46 +++++++++++++++++++++++++++++----------------- + binutils/objcopy.c | 3 +-- + 4 files changed, 50 insertions(+), 28 deletions(-) + +diff --git a/binutils/ar.c b/binutils/ar.c +index 24ff092..0ecfa33 100644 +--- a/binutils/ar.c ++++ b/binutils/ar.c +@@ -25,7 +25,6 @@ + + #include "sysdep.h" + #include "bfd.h" +-#include "libbfd.h" + #include "libiberty.h" + #include "progress.h" + #include "getopt.h" +@@ -1255,10 +1254,8 @@ write_archive (bfd *iarch) + bfd *contents_head = iarch->archive_next; + int ofd = -1; + struct stat target_stat; +- bfd_boolean skip_stat = FALSE; + +- old_name = (char *) xmalloc (strlen (bfd_get_filename (iarch)) + 1); +- strcpy (old_name, bfd_get_filename (iarch)); ++ old_name = xstrdup (bfd_get_filename (iarch)); + new_name = make_tempname (old_name, &ofd); + + if (new_name == NULL) +@@ -1303,11 +1300,9 @@ write_archive (bfd *iarch) + + #if !defined (_WIN32) || defined (__CYGWIN32__) + ofd = dup (ofd); +- if (iarch == NULL || iarch->iostream == NULL) +- skip_stat = TRUE; +- else if (ofd == -1 || fstat (fileno ((FILE *) iarch->iostream), &target_stat) != 0) +- bfd_fatal (old_name); + #endif ++ if (ofd == -1 || bfd_stat (iarch, &target_stat) != 0) ++ bfd_fatal (old_name); + + if (!bfd_close (obfd)) + bfd_fatal (old_name); +@@ -1318,7 +1313,7 @@ write_archive (bfd *iarch) + /* We don't care if this fails; we might be creating the archive. */ + bfd_close (iarch); + +- if (smart_rename (new_name, old_name, ofd, skip_stat ? NULL : &target_stat, 0) != 0) ++ if (smart_rename (new_name, old_name, ofd, &target_stat, 0) != 0) + xexit (1); + free (old_name); + free (new_name); +diff --git a/binutils/arsup.c b/binutils/arsup.c +index 837011b..a60629f 100644 +--- a/binutils/arsup.c ++++ b/binutils/arsup.c +@@ -42,6 +42,8 @@ extern int deterministic; + + static bfd *obfd; + static char *real_name; ++static char *temp_name; ++static int real_ofd; + static FILE *outfile; + + static void +@@ -149,27 +151,24 @@ maybequit (void) + void + ar_open (char *name, int t) + { +- char *tname; +- const char *bname = lbasename (name); +- real_name = name; ++ real_name = xstrdup (name); ++ temp_name = make_tempname (real_name, &real_ofd); + +- /* Prepend tmp- to the beginning, to avoid file-name clashes after +- truncation on filesystems with limited namespaces (DOS). */ +- if (asprintf (&tname, "%.*stmp-%s", (int) (bname - name), name, bname) == -1) ++ if (temp_name == NULL) + { +- fprintf (stderr, _("%s: Can't allocate memory for temp name (%s)\n"), ++ fprintf (stderr, _("%s: Can't open temporary file (%s)\n"), + program_name, strerror(errno)); + maybequit (); + return; + } + +- obfd = bfd_openw (tname, NULL); ++ obfd = bfd_fdopenw (temp_name, NULL, real_ofd); + + if (!obfd) + { + fprintf (stderr, + _("%s: Can't open output archive %s\n"), +- program_name, tname); ++ program_name, temp_name); + + maybequit (); + } +@@ -344,10 +343,9 @@ ar_save (void) + } + else + { +- char *ofilename = xstrdup (bfd_get_filename (obfd)); + bfd_boolean skip_stat = FALSE; + struct stat target_stat; +- int ofd = -1; ++ int ofd = real_ofd; + + if (deterministic > 0) + obfd->flags |= BFD_DETERMINISTIC_OUTPUT; +@@ -355,17 +353,31 @@ ar_save (void) + #if !defined (_WIN32) || defined (__CYGWIN32__) + /* It's OK to fail; at worst it will result in SMART_RENAME using a slow + copy fallback to write the output. */ +- ofd = dup (fileno ((FILE *) obfd->iostream)); +- if (lstat (real_name, &target_stat) != 0) +- skip_stat = TRUE; ++ ofd = dup (ofd); + #endif +- + bfd_close (obfd); + +- smart_rename (ofilename, real_name, ofd, ++ if (lstat (real_name, &target_stat) != 0) ++ { ++ /* The temp file created in ar_open has mode 0600 as per mkstemp. ++ Create the real empty output file here so smart_rename will ++ update the mode according to the process umask. */ ++ obfd = bfd_openw (real_name, NULL); ++ if (obfd == NULL ++ || bfd_stat (obfd, &target_stat) != 0) ++ skip_stat = TRUE; ++ if (obfd != NULL) ++ { ++ bfd_set_format (obfd, bfd_archive); ++ bfd_close (obfd); ++ } ++ } ++ ++ smart_rename (temp_name, real_name, ofd, + skip_stat ? NULL : &target_stat, 0); + obfd = 0; +- free (ofilename); ++ free (temp_name); ++ free (real_name); + } + } + +diff --git a/binutils/objcopy.c b/binutils/objcopy.c +index 39a1ccb..0e1047e 100644 +--- a/binutils/objcopy.c ++++ b/binutils/objcopy.c +@@ -20,7 +20,6 @@ + + #include "sysdep.h" + #include "bfd.h" +-#include "libbfd.h" + #include "progress.h" + #include "getopt.h" + #include "libiberty.h" +@@ -3768,7 +3767,7 @@ copy_file (const char *input_filename, const char *output_filename, int ofd, + /* To allow us to do "strip *" without dying on the first + non-object file, failures are nonfatal. */ + ibfd = bfd_openr (input_filename, input_target); +- if (ibfd == NULL || fstat (fileno ((FILE *) ibfd->iostream), in_stat) != 0) ++ if (ibfd == NULL || bfd_stat (ibfd, in_stat) != 0) + { + bfd_nonfatal_message (input_filename, NULL, NULL, NULL); + status = 1; +-- +1.8.3.1 + diff --git a/backport-Fix-a-build-problem-when-using-FreeBSD-12.patch b/backport-Fix-a-build-problem-when-using-FreeBSD-12.patch new file mode 100644 index 0000000..36671d6 --- /dev/null +++ b/backport-Fix-a-build-problem-when-using-FreeBSD-12.patch @@ -0,0 +1,57 @@ +From b143e2d506bee1020752597f979d5af174edc36d Mon Sep 17 00:00:00 2001 +From: Sebastian Huber +Date: Fri, 11 Dec 2020 13:27:45 +0000 +Subject: [PATCH] Fix a build problem when using FreeBSD 12. + + * ar.c (write_archive): Cast iostream pointer to FILE *. + * arsup.c (ar_save): Likewise. + * objcopy.c (copy_file): Likewise. +--- + binutils/ChangeLog | 6 ++++++ + binutils/ar.c | 2 +- + binutils/arsup.c | 2 +- + binutils/objcopy.c | 2 +- + 4 files changed, 9 insertions(+), 3 deletions(-) + +diff --git a/binutils/ar.c b/binutils/ar.c +index 6598dd9..8329223 100644 +--- a/binutils/ar.c ++++ b/binutils/ar.c +@@ -1305,7 +1305,7 @@ write_archive (bfd *iarch) + ofd = dup (ofd); + if (iarch == NULL || iarch->iostream == NULL) + skip_stat = TRUE; +- else if (ofd == -1 || fstat (fileno (iarch->iostream), &target_stat) != 0) ++ else if (ofd == -1 || fstat (fileno ((FILE *) iarch->iostream), &target_stat) != 0) + bfd_fatal (old_name); + #endif + +diff --git a/binutils/arsup.c b/binutils/arsup.c +index 8b4437f..dad4174 100644 +--- a/binutils/arsup.c ++++ b/binutils/arsup.c +@@ -355,7 +355,7 @@ ar_save (void) + #if !defined (_WIN32) || defined (__CYGWIN32__) + /* It's OK to fail; at worst it will result in SMART_RENAME using a slow + copy fallback to write the output. */ +- ofd = dup (fileno (obfd->iostream)); ++ ofd = dup (fileno ((FILE *) obfd->iostream)); + if (lstat (real_name, &target_stat) != 0) + skip_stat = TRUE; + #endif +diff --git a/binutils/objcopy.c b/binutils/objcopy.c +index 06ecf3e..0ea3ea1 100644 +--- a/binutils/objcopy.c ++++ b/binutils/objcopy.c +@@ -3745,7 +3745,7 @@ copy_file (const char *input_filename, const char *output_filename, int ofd, + /* To allow us to do "strip *" without dying on the first + non-object file, failures are nonfatal. */ + ibfd = bfd_openr (input_filename, input_target); +- if (ibfd == NULL || fstat (fileno (ibfd->iostream), in_stat) != 0) ++ if (ibfd == NULL || fstat (fileno ((FILE *) ibfd->iostream), in_stat) != 0) + { + bfd_nonfatal_message (input_filename, NULL, NULL, NULL); + status = 1; +-- +1.8.3.1 + diff --git a/binutils.spec b/binutils.spec index afdcd80..20bb2b8 100644 --- a/binutils.spec +++ b/binutils.spec @@ -1,7 +1,7 @@ Summary: Binary utilities Name: binutils Version: 2.34 -Release: 8 +Release: 9 License: GPLv3+ URL: https://sourceware.org/binutils @@ -36,6 +36,11 @@ Patch19: metag-uninitialized-memory-read.patch Patch20: Fix-a-potential-use-of-an-uninitialised-value-in-the.patch Patch21: backport-CVE-2020-16592-PR25823-Use-after-free-in-bfd_hash_lookup.patch Patch22: backport-CVE-2020-0551-i386-Generate-lfence.patch +Patch23: backport-0001-CVE-2021-20197.patch +Patch24: backport-0002-CVE-2021-20197.patch +Patch25: backport-0003-CVE-2021-20197.patch +Patch26: backport-Fix-a-build-problem-when-using-FreeBSD-12.patch +Patch27: backport-0004-CVE-2021-20197.patch Provides: bundled(libiberty) @@ -314,6 +319,12 @@ fi %{_infodir}/bfd*info* %changelog +* Fri Apr 16 2021 lirui - 2.34-9 +- Type:CVE +- ID:NA +- SUG:NA +- DESC:fix CVE-2021-20197 + * Tue Mar 23 2021 panxiaohe - 2.34-8 - Type:CVE - ID:NA -- Gitee From 26cd446e6bc339d68e2d0f83a05a6fa99bd10c66 Mon Sep 17 00:00:00 2001 From: lirui Date: Fri, 23 Apr 2021 11:38:09 +0800 Subject: [PATCH 6/6] fix CVE-2021-3487 --- backport-CVE-2021-3487.patch | 76 ++++++++++++++++++++++++++++++++++++ binutils.spec | 9 ++++- 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 backport-CVE-2021-3487.patch diff --git a/backport-CVE-2021-3487.patch b/backport-CVE-2021-3487.patch new file mode 100644 index 0000000..fc6e002 --- /dev/null +++ b/backport-CVE-2021-3487.patch @@ -0,0 +1,76 @@ +From 647cebce12a6b0a26960220caff96ff38978cf24 Mon Sep 17 00:00:00 2001 +From: Nick Clifton +Date: Thu, 26 Nov 2020 17:08:33 +0000 +Subject: [PATCH] Prevent a memory allocation failure when parsing corrupt + DWARF debug sections. + + PR 26946 + * dwarf2.c (read_section): Check for debug sections with excessive + sizes. +--- + bfd/ChangeLog | 6 ++++++ + bfd/dwarf2.c | 25 +++++++++++++++++++------ + 2 files changed, 25 insertions(+), 6 deletions(-) + +diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c +index 977bf43..8bbfc81 100644 +--- a/bfd/dwarf2.c ++++ b/bfd/dwarf2.c +@@ -531,22 +531,24 @@ read_section (bfd * abfd, + bfd_byte ** section_buffer, + bfd_size_type * section_size) + { +- asection *msec; + const char *section_name = sec->uncompressed_name; + bfd_byte *contents = *section_buffer; +- bfd_size_type amt; + + /* The section may have already been read. */ + if (contents == NULL) + { ++ bfd_size_type amt; ++ asection *msec; ++ ufile_ptr filesize; ++ + msec = bfd_get_section_by_name (abfd, section_name); +- if (! msec) ++ if (msec == NULL) + { + section_name = sec->compressed_name; + if (section_name != NULL) + msec = bfd_get_section_by_name (abfd, section_name); + } +- if (! msec) ++ if (msec == NULL) + { + _bfd_error_handler (_("DWARF error: can't find %s section."), + sec->uncompressed_name); +@@ -554,12 +556,23 @@ read_section (bfd * abfd, + return FALSE; + } + +- *section_size = msec->rawsize ? msec->rawsize : msec->size; ++ amt = bfd_get_section_limit_octets (abfd, msec); ++ filesize = bfd_get_file_size (abfd); ++ if (amt >= filesize) ++ { ++ /* PR 26946 */ ++ _bfd_error_handler (_("DWARF error: section %s is larger than its filesize! (0x%lx vs 0x%lx)"), ++ section_name, (long) amt, (long) filesize); ++ bfd_set_error (bfd_error_bad_value); ++ return FALSE; ++ } ++ *section_size = amt; + /* Paranoia - alloc one extra so that we can make sure a string + section is NUL terminated. */ +- amt = *section_size + 1; ++ amt += 1; + if (amt == 0) + { ++ /* Paranoia - this should never happen. */ + bfd_set_error (bfd_error_no_memory); + return FALSE; + } +-- +1.8.3.1 + diff --git a/binutils.spec b/binutils.spec index 20bb2b8..fc13516 100644 --- a/binutils.spec +++ b/binutils.spec @@ -1,7 +1,7 @@ Summary: Binary utilities Name: binutils Version: 2.34 -Release: 9 +Release: 10 License: GPLv3+ URL: https://sourceware.org/binutils @@ -41,6 +41,7 @@ Patch24: backport-0002-CVE-2021-20197.patch Patch25: backport-0003-CVE-2021-20197.patch Patch26: backport-Fix-a-build-problem-when-using-FreeBSD-12.patch Patch27: backport-0004-CVE-2021-20197.patch +Patch28: backport-CVE-2021-3487.patch Provides: bundled(libiberty) @@ -319,6 +320,12 @@ fi %{_infodir}/bfd*info* %changelog +* Fri Apr 23 2021 lirui - 2.34-10 +- Type:CVE +- ID:NA +- SUG:NA +- DESC:fix CVE-2021-3487 + * Fri Apr 16 2021 lirui - 2.34-9 - Type:CVE - ID:NA -- Gitee