From ac55f50329e4e4c22ad31d3e1bd9d175d94be227 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Thu, 11 Mar 2021 14:30:48 +0000 Subject: [PATCH] Extend vulnerability fix yet again. Resolves: #1925779 --- binutils-CVE-2021-20197.patch | 419 ++++++++++++++++++++++++++++++++++ binutils.spec | 5 +- 2 files changed, 423 insertions(+), 1 deletion(-) diff --git a/binutils-CVE-2021-20197.patch b/binutils-CVE-2021-20197.patch index a1af8e9..d6ec23a 100644 --- a/binutils-CVE-2021-20197.patch +++ b/binutils-CVE-2021-20197.patch @@ -331,3 +331,422 @@ diff -rup binutils.orig/binutils/rename.c binutils-2.36.1/binutils/rename.c unlink (from); } #endif /* _WIN32 && !__CYGWIN32__ */ +diff -rup binutils.orig/binutils/ar.c binutils-2.36.1/binutils/ar.c +--- binutils.orig/binutils/ar.c 2021-03-11 12:57:40.206766885 +0000 ++++ binutils-2.36.1/binutils/ar.c 2021-03-11 12:59:42.874957119 +0000 +@@ -1252,21 +1252,21 @@ write_archive (bfd *iarch) + bfd *obfd; + char *old_name, *new_name; + bfd *contents_head = iarch->archive_next; +- int ofd = -1; ++ int tmpfd = -1; + + old_name = xstrdup (bfd_get_filename (iarch)); +- new_name = make_tempname (old_name, &ofd); ++ new_name = make_tempname (old_name, &tmpfd); + + if (new_name == NULL) + bfd_fatal (_("could not create temporary file whilst writing archive")); + + output_filename = new_name; + +- obfd = bfd_fdopenw (new_name, bfd_get_target (iarch), ofd); ++ obfd = bfd_fdopenw (new_name, bfd_get_target (iarch), tmpfd); + + if (obfd == NULL) + { +- close (ofd); ++ close (tmpfd); + bfd_fatal (old_name); + } + +@@ -1297,6 +1297,7 @@ write_archive (bfd *iarch) + if (!bfd_set_archive_head (obfd, contents_head)) + bfd_fatal (old_name); + ++ tmpfd = dup (tmpfd); + if (!bfd_close (obfd)) + bfd_fatal (old_name); + +@@ -1306,7 +1307,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, NULL) != 0) ++ if (smart_rename (new_name, old_name, tmpfd, NULL, FALSE) != 0) + xexit (1); + free (old_name); + free (new_name); +diff -rup binutils.orig/binutils/arsup.c binutils-2.36.1/binutils/arsup.c +--- binutils.orig/binutils/arsup.c 2021-03-11 12:57:40.190766990 +0000 ++++ binutils-2.36.1/binutils/arsup.c 2021-03-11 13:00:35.897607109 +0000 +@@ -43,7 +43,7 @@ extern int deterministic; + static bfd *obfd; + static char *real_name; + static char *temp_name; +-static int real_ofd; ++static int temp_fd; + static FILE *outfile; + + static void +@@ -152,7 +152,7 @@ void + ar_open (char *name, int t) + { + real_name = xstrdup (name); +- temp_name = make_tempname (real_name, &real_ofd); ++ temp_name = make_tempname (real_name, &temp_fd); + + if (temp_name == NULL) + { +@@ -162,7 +162,7 @@ ar_open (char *name, int t) + return; + } + +- obfd = bfd_fdopenw (temp_name, NULL, real_ofd); ++ obfd = bfd_fdopenw (temp_name, NULL, temp_fd); + + if (!obfd) + { +@@ -348,6 +348,7 @@ ar_save (void) + if (deterministic > 0) + obfd->flags |= BFD_DETERMINISTIC_OUTPUT; + ++ temp_fd = dup (temp_fd); + bfd_close (obfd); + + if (stat (real_name, &target_stat) != 0) +@@ -363,11 +364,10 @@ ar_save (void) + } + } + +- smart_rename (temp_name, real_name, NULL); ++ smart_rename (temp_name, real_name, temp_fd, NULL, FALSE); + obfd = NULL; + free (temp_name); + free (real_name); +- temp_name = real_name = NULL; + } + } + +diff -rup binutils.orig/binutils/bucomm.h binutils-2.36.1/binutils/bucomm.h +--- binutils.orig/binutils/bucomm.h 2021-03-11 12:57:40.205766891 +0000 ++++ binutils-2.36.1/binutils/bucomm.h 2021-03-11 12:59:03.082219804 +0000 +@@ -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 *, struct stat *); ++extern int smart_rename (const char *, const char *, int, ++ struct stat *, bfd_boolean); + + /* In libiberty. */ + void *xmalloc (size_t); +diff -rup binutils.orig/binutils/objcopy.c binutils-2.36.1/binutils/objcopy.c +--- binutils.orig/binutils/objcopy.c 2021-03-11 12:57:40.196766951 +0000 ++++ binutils-2.36.1/binutils/objcopy.c 2021-03-11 13:02:43.321765939 +0000 +@@ -4822,6 +4822,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) + { +@@ -4831,7 +4832,11 @@ strip_main (int argc, char *argv[]) + + if (output_file == NULL + || filename_cmp (argv[i], output_file) == 0) +- tmpname = make_tempname (argv[i], &tmpfd); ++ { ++ tmpname = make_tempname (argv[i], &tmpfd); ++ if (tmpfd >= 0) ++ copyfd = dup (tmpfd); ++ } + else + tmpname = output_file; + +@@ -4849,14 +4854,18 @@ strip_main (int argc, char *argv[]) + if (status == 0) + { + if (output_file != tmpname) +- status = (smart_rename (tmpname, +- output_file ? output_file : argv[i], +- preserve_dates ? &statbuf : NULL) != 0); ++ status = smart_rename (tmpname, ++ output_file ? output_file : argv[i], ++ copyfd, &statbuf, preserve_dates) != 0; + if (status == 0) + status = hold_status; + } + else +- unlink_if_ordinary (tmpname); ++ { ++ if (copyfd >= 0) ++ close (copyfd); ++ unlink_if_ordinary (tmpname); ++ } + if (output_file != tmpname) + free (tmpname); + } +@@ -5063,7 +5072,9 @@ copy_main (int argc, char *argv[]) + bfd_boolean formats_info = FALSE; + bfd_boolean use_globalize = FALSE; + bfd_boolean use_keep_global = FALSE; +- int c, tmpfd = -1; ++ int c; ++ int tmpfd = -1; ++ int copyfd; + struct stat statbuf; + const bfd_arch_info_type *input_arch = NULL; + +@@ -5901,27 +5912,38 @@ copy_main (int argc, char *argv[]) + } + + /* 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. */ ++ are the same, then create a temp and copy the result into the input. */ ++ copyfd = -1; + if (output_filename == NULL + || filename_cmp (input_filename, output_filename) == 0) +- tmpname = make_tempname (input_filename, &tmpfd); ++ { ++ tmpname = make_tempname (input_filename, &tmpfd); ++ if (tmpfd >= 0) ++ copyfd = dup (tmpfd); ++ } + else + tmpname = output_filename; + + if (tmpname == NULL) +- fatal (_("warning: could not create temporary file whilst copying '%s', (error: %s)"), +- input_filename, strerror (errno)); ++ { ++ 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); + if (status == 0) + { + if (tmpname != output_filename) +- status = (smart_rename (tmpname, input_filename, +- preserve_dates ? &statbuf : NULL) != 0); ++ status = smart_rename (tmpname, input_filename, copyfd, ++ &statbuf, preserve_dates) != 0; + } + else +- unlink_if_ordinary (tmpname); ++ { ++ if (copyfd >= 0) ++ close (copyfd); ++ unlink_if_ordinary (tmpname); ++ } + + if (tmpname != output_filename) + free (tmpname); +diff -rup binutils.orig/binutils/rename.c binutils-2.36.1/binutils/rename.c +--- binutils.orig/binutils/rename.c 2021-03-11 12:57:40.206766885 +0000 ++++ binutils-2.36.1/binutils/rename.c 2021-03-11 12:58:47.306323943 +0000 +@@ -24,36 +24,29 @@ + + #ifdef HAVE_GOOD_UTIME_H + #include +-#else /* ! HAVE_GOOD_UTIME_H */ +-#ifdef HAVE_UTIMES ++#elif defined HAVE_UTIMES + #include +-#endif /* HAVE_UTIMES */ +-#endif /* ! HAVE_GOOD_UTIME_H */ +- +-#if ! defined (_WIN32) || defined (__CYGWIN32__) +-static int simple_copy (const char *, const char *); ++#endif + + /* The number of bytes to copy at once. */ + #define COPY_BUF 8192 + +-/* Copy file FROM to file TO, performing no translations. ++/* Copy file FROMFD to file TO, performing no translations. + Return 0 if ok, -1 if error. */ + + static int +-simple_copy (const char *from, const char *to) ++simple_copy (int fromfd, const char *to, ++ struct stat *target_stat ATTRIBUTE_UNUSED) + { +- int fromfd, tofd, nread; ++ int tofd, nread; + int saved; + char buf[COPY_BUF]; + +- fromfd = open (from, O_RDONLY | O_BINARY); +- if (fromfd < 0) ++ if (fromfd < 0 ++ || lseek (fromfd, 0, SEEK_SET) != 0) + return -1; +-#ifdef O_CREAT +- tofd = open (to, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0777); +-#else +- tofd = creat (to, 0777); +-#endif ++ ++ tofd = open (to, O_WRONLY | O_TRUNC | O_BINARY); + if (tofd < 0) + { + saved = errno; +@@ -61,6 +54,7 @@ simple_copy (const char *from, const cha + errno = saved; + return -1; + } ++ + while ((nread = read (fromfd, buf, sizeof buf)) > 0) + { + if (write (tofd, buf, nread) != nread) +@@ -72,7 +66,16 @@ simple_copy (const char *from, const cha + return -1; + } + } ++ + saved = errno; ++ ++#if !defined (_WIN32) || defined (__CYGWIN32__) ++ /* Writing to a setuid/setgid file may clear S_ISUID and S_ISGID. ++ Try to restore them, ignoring failure. */ ++ if (target_stat != NULL) ++ fchmod (tofd, target_stat->st_mode); ++#endif ++ + close (fromfd); + close (tofd); + if (nread < 0) +@@ -82,7 +85,6 @@ simple_copy (const char *from, const cha + } + return 0; + } +-#endif /* __CYGWIN32__ or not _WIN32 */ + + /* Set the times of the file DESTINATION to be the same as those in + STATBUF. */ +@@ -91,87 +93,52 @@ void + set_times (const char *destination, const struct stat *statbuf) + { + int result; +- +- { + #ifdef HAVE_GOOD_UTIME_H +- struct utimbuf tb; ++ struct utimbuf tb; + +- tb.actime = statbuf->st_atime; +- tb.modtime = statbuf->st_mtime; +- result = utime (destination, &tb); +-#else /* ! HAVE_GOOD_UTIME_H */ +-#ifndef HAVE_UTIMES +- long tb[2]; +- +- tb[0] = statbuf->st_atime; +- tb[1] = statbuf->st_mtime; +- result = utime (destination, tb); +-#else /* HAVE_UTIMES */ +- struct timeval tv[2]; +- +- tv[0].tv_sec = statbuf->st_atime; +- tv[0].tv_usec = 0; +- tv[1].tv_sec = statbuf->st_mtime; +- tv[1].tv_usec = 0; +- result = utimes (destination, tv); +-#endif /* HAVE_UTIMES */ +-#endif /* ! HAVE_GOOD_UTIME_H */ +- } ++ tb.actime = statbuf->st_atime; ++ tb.modtime = statbuf->st_mtime; ++ result = utime (destination, &tb); ++#elif defined HAVE_UTIMES ++ struct timeval tv[2]; ++ ++ tv[0].tv_sec = statbuf->st_atime; ++ tv[0].tv_usec = 0; ++ tv[1].tv_sec = statbuf->st_mtime; ++ tv[1].tv_usec = 0; ++ result = utimes (destination, tv); ++#else ++ long tb[2]; ++ ++ tb[0] = statbuf->st_atime; ++ tb[1] = statbuf->st_mtime; ++ result = utime (destination, tb); ++#endif + + if (result != 0) + non_fatal (_("%s: cannot set time: %s"), destination, strerror (errno)); + } + +-/* Rename FROM to TO, copying if TO exists. TARGET_STAT has the file status +- that, if non-NULL, is used to fix up timestamps after rename. Return 0 if +- ok, -1 if error. */ ++/* Copy FROM to TO. TARGET_STAT has the file status that, if non-NULL, ++ is used to fix up timestamps. Return 0 if ok, -1 if error. ++ At one time this function renamed files, but file permissions are ++ tricky to update given the number of different schemes used by ++ various systems. So now we just copy. */ + + int +-smart_rename (const char *from, const char *to, +- struct stat *target_stat ATTRIBUTE_UNUSED) ++smart_rename (const char *from, const char *to, int fromfd, ++ struct stat *target_stat, bfd_boolean preserve_dates) + { +- int ret = 0; +- struct stat to_stat; +- bfd_boolean exists; ++ int ret; + +- exists = lstat (to, &to_stat) == 0; +- +-#if defined (_WIN32) && !defined (__CYGWIN32__) +- /* Win32, unlike unix, will not erase `to' in `rename(from, to)' but +- fail instead. Also, chown is not present. */ +- +- if (exists) +- remove (to); +- +- ret = rename (from, to); ++ ret = simple_copy (fromfd, to, target_stat); + if (ret != 0) +- { +- /* We have to clean up here. */ +- non_fatal (_("unable to rename '%s'; reason: %s"), to, strerror (errno)); +- unlink (from); +- } +-#else +- /* Avoid a full copy and use rename if TO does not exist. */ +- if (!exists) +- { +- if ((ret = rename (from, to)) != 0) +- { +- /* We have to clean up here. */ +- non_fatal (_("unable to rename '%s'; reason: %s"), to, strerror (errno)); +- unlink (from); +- } +- } +- else +- { +- ret = simple_copy (from, to); +- if (ret != 0) +- non_fatal (_("unable to copy file '%s'; reason: %s"), to, strerror (errno)); +- +- if (target_stat != NULL) +- set_times (to, target_stat); +- unlink (from); +- } +-#endif /* _WIN32 && !__CYGWIN32__ */ ++ non_fatal (_("unable to copy file '%s'; reason: %s"), ++ to, strerror (errno)); ++ ++ if (preserve_dates) ++ set_times (to, target_stat); ++ unlink (from); + + return ret; + } diff --git a/binutils.spec b/binutils.spec index bc4af2d..319d717 100644 --- a/binutils.spec +++ b/binutils.spec @@ -39,7 +39,7 @@ Summary: A GNU collection of binary utilities Name: binutils%{?name_cross}%{?_with_debug:-debug} Version: 2.36.1 -Release: 6%{?dist} +Release: 7%{?dist} License: GPLv3+ URL: https://sourceware.org/binutils @@ -860,6 +860,9 @@ exit 0 #---------------------------------------------------------------------------- %changelog +* Thu Mar 11 2021 Nick Clifton - 2.36.1-7 +- Extend vulnerability fix yet again. (#1925779) + * Mon Feb 22 2021 Nick Clifton - 2.36.1-6 - Fix merging ppc64le notes (again). (#1928936)