From 948f1923b56d4b2f8719fc861e746e92f56ebe6d Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Jun 03 2021 07:48:03 +0000 Subject: import devtoolset-10-binutils-2.35-5.el7 --- diff --git a/SOURCES/binutils-CVE-2021-20197.patch b/SOURCES/binutils-CVE-2021-20197.patch new file mode 100644 index 0000000..4e9be45 --- /dev/null +++ b/SOURCES/binutils-CVE-2021-20197.patch @@ -0,0 +1,778 @@ +diff -rup binutils.orig/bfd/bfd-in2.h binutils-2.35.1/bfd/bfd-in2.h +--- binutils.orig/bfd/bfd-in2.h 2021-01-29 11:14:51.848568548 +0000 ++++ binutils-2.35.1/bfd/bfd-in2.h 2021-01-29 11:15:33.431322133 +0000 +@@ -583,6 +583,8 @@ bfd *bfd_openr (const char *filename, co + + 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 -rup binutils.orig/bfd/opncls.c binutils-2.35.1/bfd/opncls.c +--- binutils.orig/bfd/opncls.c 2021-01-29 11:14:51.846568560 +0000 ++++ binutils-2.35.1/bfd/opncls.c 2021-01-29 11:15:33.431322133 +0000 +@@ -395,6 +395,39 @@ bfd_fdopenr (const char *filename, const + + /* + 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 -rup binutils.orig/binutils/ar.c binutils-2.35.1/binutils/ar.c +--- binutils.orig/binutils/ar.c 2021-01-29 11:14:51.344571539 +0000 ++++ binutils-2.35.1/binutils/ar.c 2021-01-29 11:15:56.174187367 +0000 +@@ -25,6 +25,7 @@ + + #include "sysdep.h" + #include "bfd.h" ++#include "libbfd.h" + #include "libiberty.h" + #include "progress.h" + #include "getopt.h" +@@ -1195,20 +1196,26 @@ write_archive (bfd *iarch) + bfd *obfd; + 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)); +- 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; + +@@ -1237,6 +1244,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); + +@@ -1246,7 +1261,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 -rup binutils.orig/binutils/arsup.c binutils-2.35.1/binutils/arsup.c +--- binutils.orig/binutils/arsup.c 2021-01-29 11:14:51.350571503 +0000 ++++ binutils-2.35.1/binutils/arsup.c 2021-01-29 11:15:56.174187367 +0000 +@@ -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 -rup binutils.orig/binutils/bucomm.c binutils-2.35.1/binutils/bucomm.c +--- binutils.orig/binutils/bucomm.c 2021-01-29 11:14:51.422571073 +0000 ++++ binutils-2.35.1/binutils/bucomm.c 2021-01-29 11:15:33.431322133 +0000 +@@ -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 -rup binutils.orig/binutils/bucomm.h binutils-2.35.1/binutils/bucomm.h +--- binutils.orig/binutils/bucomm.h 2021-01-29 11:14:51.350571503 +0000 ++++ binutils-2.35.1/binutils/bucomm.h 2021-01-29 11:15:56.174187367 +0000 +@@ -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 *); +@@ -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 -rup binutils.orig/binutils/objcopy.c binutils-2.35.1/binutils/objcopy.c +--- binutils.orig/binutils/objcopy.c 2021-01-29 11:14:51.342571551 +0000 ++++ binutils-2.35.1/binutils/objcopy.c 2021-01-29 11:15:56.175187361 +0000 +@@ -20,6 +20,7 @@ + + #include "sysdep.h" + #include "bfd.h" ++#include "libbfd.h" + #include "progress.h" + #include "getopt.h" + #include "libiberty.h" +@@ -3711,9 +3712,9 @@ set_long_section_mode (bfd *output_bfd, + /* The top-level control. */ + + static void +-copy_file (const char *input_filename, const char *output_filename, +- const char *input_target, const char *output_target, +- const bfd_arch_info_type *input_arch) ++copy_file (const char *input_filename, const char *output_filename, int ofd, ++ struct stat *in_stat, const char *input_target, ++ const char *output_target, const bfd_arch_info_type *input_arch) + { + bfd *ibfd; + char **obj_matching; +@@ -3732,7 +3733,7 @@ copy_file (const char *input_filename, c + /* 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; +@@ -3786,9 +3787,14 @@ copy_file (const char *input_filename, c + 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; +@@ -3816,13 +3822,19 @@ copy_file (const char *input_filename, c + 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); + +@@ -4786,6 +4798,8 @@ strip_main (int argc, char *argv[]) + int hold_status = status; + struct stat statbuf; + char *tmpname; ++ int tmpfd = -1; ++ int copyfd = -1; + + if (get_file_size (argv[i]) < 1) + { +@@ -4793,18 +4807,18 @@ 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]); ++ tmpname = make_tempname (argv[i], &tmpfd); + 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")); +@@ -4813,7 +4827,8 @@ strip_main (int argc, char *argv[]) + } + + status = 0; +- copy_file (argv[i], tmpname, input_target, output_target, NULL); ++ copy_file (argv[i], tmpname, tmpfd, &statbuf, input_target, ++ output_target, NULL); + if (status == 0) + { + if (preserve_dates) +@@ -4821,12 +4836,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); + } +@@ -5033,7 +5054,8 @@ 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; ++ int copyfd = -1; + struct stat statbuf; + const bfd_arch_info_type *input_arch = NULL; + +@@ -5870,34 +5892,43 @@ 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 + || filename_cmp (input_filename, output_filename) == 0) +- tmpname = make_tempname (input_filename); ++ tmpname = make_tempname (input_filename, &tmpfd); + 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, 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) + 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 -rup binutils.orig/binutils/rename.c binutils-2.35.1/binutils/rename.c +--- binutils.orig/binutils/rename.c 2021-01-29 11:14:51.422571073 +0000 ++++ binutils-2.35.1/binutils/rename.c 2021-01-29 11:15:56.175187361 +0000 +@@ -131,17 +131,55 @@ set_times (const char *destination, cons + #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 ch + 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 ch + 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; +diff -rup binutils.orig/binutils/ar.c binutils-2.35.1/binutils/ar.c +--- binutils.orig/binutils/ar.c 2021-02-02 13:01:42.257734944 +0000 ++++ binutils-2.35.1/binutils/ar.c 2021-02-02 13:11:13.340958352 +0000 +@@ -25,7 +25,6 @@ + + #include "sysdep.h" + #include "bfd.h" +-#include "libbfd.h" + #include "libiberty.h" + #include "progress.h" + #include "getopt.h" +@@ -1082,7 +1081,7 @@ open_output_file (bfd * abfd) + output_filename, base); + output_filename = base; + } +- ++ + if (output_dir) + { + size_t len = strlen (output_dir); +@@ -1099,7 +1098,7 @@ open_output_file (bfd * abfd) + + if (verbose) + printf ("x - %s\n", output_filename); +- ++ + FILE * ostream = fopen (output_filename, FOPEN_WB); + if (ostream == NULL) + { +@@ -1198,10 +1197,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) +@@ -1246,11 +1243,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 (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); +@@ -1261,7 +1256,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); +Only in binutils-2.35.1/binutils/: ar.c.orig +Only in binutils-2.35.1/binutils/: ar.c.rej +diff -rup binutils.orig/binutils/arsup.c binutils-2.35.1/binutils/arsup.c +--- binutils.orig/binutils/arsup.c 2021-02-02 13:01:42.208735269 +0000 ++++ binutils-2.35.1/binutils/arsup.c 2021-02-02 13:11:55.725678308 +0000 +@@ -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; +- +- /* 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) ++ real_name = xstrdup (name); ++ temp_name = make_tempname (real_name, &real_ofd); ++ ++ 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,18 @@ 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)); +- if (lstat (real_name, &target_stat) != 0) +- skip_stat = TRUE; ++ ofd = dup (ofd); + #endif +- + bfd_close (obfd); + +- smart_rename (ofilename, real_name, ofd, ++ if (ofd == -1 || fstat (ofd, &target_stat) != 0) ++ skip_stat = TRUE; ++ ++ smart_rename (temp_name, real_name, ofd, + skip_stat ? NULL : &target_stat, 0); + obfd = 0; +- free (ofilename); ++ free (temp_name); ++ free (real_name); + } + } + +Only in binutils-2.35.1/binutils/: arsup.c.orig +Only in binutils-2.35.1/binutils/: arsup.c.rej +diff -rup binutils.orig/binutils/objcopy.c binutils-2.35.1/binutils/objcopy.c +--- binutils.orig/binutils/objcopy.c 2021-02-02 13:01:42.214735229 +0000 ++++ binutils-2.35.1/binutils/objcopy.c 2021-02-02 13:13:27.613071192 +0000 +@@ -20,7 +20,6 @@ + + #include "sysdep.h" + #include "bfd.h" +-#include "libbfd.h" + #include "progress.h" + #include "getopt.h" + #include "libiberty.h" +@@ -3733,7 +3732,7 @@ copy_file (const char *input_filename, c + /* 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 || bfd_stat (ibfd, in_stat) != 0) + { + bfd_nonfatal_message (input_filename, NULL, NULL, NULL); + status = 1; +Only in binutils-2.35.1/binutils/: objcopy.c.orig +Only in binutils-2.35.1/binutils/: objcopy.c.rej +--- binutils.orig/binutils/arsup.c 2021-02-04 10:42:03.265729780 +0000 ++++ binutils-2.35.1/binutils/arsup.c 2021-02-04 10:45:48.439166658 +0000 +@@ -357,8 +357,21 @@ ar_save (void) + #endif + bfd_close (obfd); + +- if (ofd == -1 || fstat (ofd, &target_stat) != 0) +- skip_stat = TRUE; ++ 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); +--- binutils.orig/binutils/rename.c 2021-02-08 11:02:58.767933783 +0000 ++++ binutils-2.35.1/binutils/rename.c 2021-02-08 11:20:37.539179363 +0000 +@@ -179,7 +179,10 @@ smart_rename (const char *from, const ch + int preserve_dates ATTRIBUTE_UNUSED) + { + int ret = 0; +- bfd_boolean exists = target_stat != NULL; ++ struct stat to_stat; ++ bfd_boolean exists; ++ ++ exists = lstat (to, &to_stat) == 0; + + #if defined (_WIN32) && !defined (__CYGWIN32__) + /* Win32, unlike unix, will not erase `to' in `rename(from, to)' but +@@ -214,16 +217,16 @@ smart_rename (const char *from, const ch + external change. */ + if (! exists + || (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) ++ && !S_ISLNK (to_stat.st_mode) ++ && S_ISREG (to_stat.st_mode) ++ && (to_stat.st_mode & S_IWUSR) ++ && to_stat.st_nlink == 1) + ) + { + ret = rename (from, to); + if (ret == 0) + { +- if (exists) ++ if (exists && target_stat != NULL) + try_preserve_permissions (fd, target_stat); + } + else +@@ -239,7 +242,7 @@ smart_rename (const char *from, const ch + if (ret != 0) + non_fatal (_("unable to copy file '%s'; reason: %s"), to, strerror (errno)); + +- if (preserve_dates) ++ if (preserve_dates && target_stat != NULL) + set_times (to, target_stat); + unlink (from); + } diff --git a/SPECS/binutils.spec b/SPECS/binutils.spec index cd58c72..50a1891 100644 --- a/SPECS/binutils.spec +++ b/SPECS/binutils.spec @@ -4,7 +4,7 @@ Summary: A GNU collection of binary utilities Name: %{?scl_prefix}%{?cross}binutils%{?_with_debug:-debug} Version: 2.35 -Release: 3%{?dist} +Release: 5%{?dist} License: GPLv3+ URL: https://sourceware.org/binutils @@ -250,6 +250,10 @@ Patch25: binutils-aarch64-plt-sh_entsize.patch Patch26: binutils-add-sym-cache-to-elf-link-hash.patch Patch27: binutils-elf-add-objects.patch +# Purpose: Remove a vulnerability in the smart_rename function. +# Lifetime: Fixed in 2.36 +Patch28: binutils-CVE-2021-20197.patch + #---------------------------------------------------------------------------- Provides: bundled(libiberty) @@ -771,7 +775,7 @@ rm -rf %{buildroot} %{_bindir}/%{?cross}ld.bfd %{ld_bfd_priority} %{alternatives_cmdline} --install %{_bindir}/%{?cross}ld %{?cross}ld \ %{_bindir}/%{?cross}ld.gold %{ld_gold_priority} -%endif # both ld.gold and ld.bfd +%endif %if %{isnative} /sbin/ldconfig @@ -782,8 +786,8 @@ rm -rf %{buildroot} /sbin/install-info --info-dir=%{_infodir} %{_infodir}/gprof.info.gz /sbin/install-info --info-dir=%{_infodir} %{_infodir}/ld.info.gz /sbin/install-info --info-dir=%{_infodir} %{_infodir}/standards.info.gz -%endif # with docs -%endif # isnative +%endif +%endif exit 0 @@ -795,7 +799,7 @@ if [ $1 = 0 ]; then %{alternatives_cmdline} --remove %{?cross}ld %{_bindir}/%{?cross}ld.bfd %{alternatives_cmdline} --remove %{?cross}ld %{_bindir}/%{?cross}ld.gold fi -%endif # both ld.gold and ld.bfd +%endif %if %{isnative} if [ $1 = 0 ]; then @@ -808,7 +812,7 @@ if [ $1 = 0 ]; then /sbin/install-info --quiet --delete --info-dir=%{_infodir} %{_infodir}/standards.info.gz fi fi -%endif # isnative +%endif exit 0 @@ -881,6 +885,12 @@ exit 0 #---------------------------------------------------------------------------- %changelog +* Mon Feb 08 2021 Nick Clifton - 2.35-5 +- Extend vulnerability fix again. (#1925779) + +* Fri Jan 29 2021 Nick Clifton - 2.35-4 +- Fix a vulnerability in the smart_rename function. (#1920643) + * Tue Aug 11 2020 Nick Clifton - 2.35-3 - Fix building with LTO enabled. - Set the sh_entsize field of the AArch64's PLT section to 0. (PR 26312)