diff --git a/patch-2.7.6-CVE-2019-13636-symlinks.patch b/patch-2.7.6-CVE-2019-13636-symlinks.patch new file mode 100644 index 0000000..bf3e603 --- /dev/null +++ b/patch-2.7.6-CVE-2019-13636-symlinks.patch @@ -0,0 +1,102 @@ +commit dce4683cbbe107a95f1f0d45fabc304acfb5d71a +Author: Andreas Gruenbacher +Date: Mon Jul 15 16:21:48 2019 +0200 + + Don't follow symlinks unless --follow-symlinks is given + + * src/inp.c (plan_a, plan_b), src/util.c (copy_to_fd, copy_file, + append_to_file): Unless the --follow-symlinks option is given, open files with + the O_NOFOLLOW flag to avoid following symlinks. So far, we were only doing + that consistently for input files. + * src/util.c (create_backup): When creating empty backup files, (re)create them + with O_CREAT | O_EXCL to avoid following symlinks in that case as well. + +diff --git a/src/inp.c b/src/inp.c +index 32d0919..22d7473 100644 +--- a/src/inp.c ++++ b/src/inp.c +@@ -238,8 +238,13 @@ plan_a (char const *filename) + { + if (S_ISREG (instat.st_mode)) + { +- int ifd = safe_open (filename, O_RDONLY|binary_transput, 0); ++ int flags = O_RDONLY | binary_transput; + size_t buffered = 0, n; ++ int ifd; ++ ++ if (! follow_symlinks) ++ flags |= O_NOFOLLOW; ++ ifd = safe_open (filename, flags, 0); + if (ifd < 0) + pfatal ("can't open file %s", quotearg (filename)); + +@@ -340,6 +345,7 @@ plan_a (char const *filename) + static void + plan_b (char const *filename) + { ++ int flags = O_RDONLY | binary_transput; + int ifd; + FILE *ifp; + int c; +@@ -353,7 +359,9 @@ plan_b (char const *filename) + + if (instat.st_size == 0) + filename = NULL_DEVICE; +- if ((ifd = safe_open (filename, O_RDONLY | binary_transput, 0)) < 0 ++ if (! follow_symlinks) ++ flags |= O_NOFOLLOW; ++ if ((ifd = safe_open (filename, flags, 0)) < 0 + || ! (ifp = fdopen (ifd, binary_transput ? "rb" : "r"))) + pfatal ("Can't open file %s", quotearg (filename)); + if (TMPINNAME_needs_removal) +diff --git a/src/util.c b/src/util.c +index 1cc08ba..fb38307 100644 +--- a/src/util.c ++++ b/src/util.c +@@ -388,7 +388,7 @@ create_backup (char const *to, const struct stat *to_st, bool leave_original) + + try_makedirs_errno = ENOENT; + safe_unlink (bakname); +- while ((fd = safe_open (bakname, O_CREAT | O_WRONLY | O_TRUNC, 0666)) < 0) ++ while ((fd = safe_open (bakname, O_CREAT | O_EXCL | O_WRONLY | O_TRUNC, 0666)) < 0) + { + if (errno != try_makedirs_errno) + pfatal ("Can't create file %s", quotearg (bakname)); +@@ -579,10 +579,13 @@ create_file (char const *file, int open_flags, mode_t mode, + static void + copy_to_fd (const char *from, int tofd) + { ++ int from_flags = O_RDONLY | O_BINARY; + int fromfd; + ssize_t i; + +- if ((fromfd = safe_open (from, O_RDONLY | O_BINARY, 0)) < 0) ++ if (! follow_symlinks) ++ from_flags |= O_NOFOLLOW; ++ if ((fromfd = safe_open (from, from_flags, 0)) < 0) + pfatal ("Can't reopen file %s", quotearg (from)); + while ((i = read (fromfd, buf, bufsize)) != 0) + { +@@ -625,6 +628,8 @@ copy_file (char const *from, char const *to, struct stat *tost, + else + { + assert (S_ISREG (mode)); ++ if (! follow_symlinks) ++ to_flags |= O_NOFOLLOW; + tofd = create_file (to, O_WRONLY | O_BINARY | to_flags, mode, + to_dir_known_to_exist); + copy_to_fd (from, tofd); +@@ -640,9 +645,12 @@ copy_file (char const *from, char const *to, struct stat *tost, + void + append_to_file (char const *from, char const *to) + { ++ int to_flags = O_WRONLY | O_APPEND | O_BINARY; + int tofd; + +- if ((tofd = safe_open (to, O_WRONLY | O_BINARY | O_APPEND, 0)) < 0) ++ if (! follow_symlinks) ++ to_flags |= O_NOFOLLOW; ++ if ((tofd = safe_open (to, to_flags, 0)) < 0) + pfatal ("Can't reopen file %s", quotearg (to)); + copy_to_fd (from, tofd); + if (close (tofd) != 0) diff --git a/patch-2.7.6-abort_when_cleaning_up_fails.patch b/patch-2.7.6-abort_when_cleaning_up_fails.patch new file mode 100644 index 0000000..56dbda8 --- /dev/null +++ b/patch-2.7.6-abort_when_cleaning_up_fails.patch @@ -0,0 +1,46 @@ +commit b7b028a77bd855f6f56b17c8837fc1cca77b469d +Author: Andreas Gruenbacher +Date: Fri Jun 28 00:30:25 2019 +0200 + + Abort when cleaning up fails + + When a fatal error triggers during cleanup, another attempt will be made to + clean up, which will likely lead to the same fatal error. So instead, bail out + when that happens. + src/patch.c (cleanup): Bail out when called recursively. + (main): There is no need to call output_files() before cleanup() as cleanup() + already does that. + +diff --git a/src/patch.c b/src/patch.c +index 4616a48..02fd982 100644 +--- a/src/patch.c ++++ b/src/patch.c +@@ -685,7 +685,6 @@ main (int argc, char **argv) + } + if (outstate.ofp && (ferror (outstate.ofp) || fclose (outstate.ofp) != 0)) + write_fatal (); +- output_files (NULL); + cleanup (); + delete_files (); + if (somefailed) +@@ -1991,7 +1990,6 @@ void + fatal_exit (int sig) + { + cleanup (); +- + if (sig) + exit_with_signal (sig); + +@@ -2011,6 +2009,12 @@ remove_if_needed (char const *name, bool *needs_removal) + static void + cleanup (void) + { ++ static bool already_cleaning_up; ++ ++ if (already_cleaning_up) ++ return; ++ already_cleaning_up = true; ++ + remove_if_needed (TMPINNAME, &TMPINNAME_needs_removal); + remove_if_needed (TMPOUTNAME, &TMPOUTNAME_needs_removal); + remove_if_needed (TMPPATNAME, &TMPPATNAME_needs_removal); diff --git a/patch-2.7.6-avoid_invalid_memory_access.patch b/patch-2.7.6-avoid_invalid_memory_access.patch new file mode 100644 index 0000000..39b59d1 --- /dev/null +++ b/patch-2.7.6-avoid_invalid_memory_access.patch @@ -0,0 +1,21 @@ +commit 15b158db3ae11cb835f2eb8d2eb48e09d1a4af48 +Author: Andreas Gruenbacher +Date: Mon Jul 15 19:10:02 2019 +0200 + + Avoid invalid memory access in context format diffs + + * src/pch.c (another_hunk): Avoid invalid memory access in context format + diffs. + +diff --git a/src/pch.c b/src/pch.c +index a500ad9..cb54e03 100644 +--- a/src/pch.c ++++ b/src/pch.c +@@ -1328,6 +1328,7 @@ another_hunk (enum diff difftype, bool rev) + ptrn_prefix_context = context; + ptrn_suffix_context = context; + if (repl_beginning ++ || p_end <= 0 + || (p_end + != p_ptrn_lines + 1 + (p_Char[p_end - 1] == '\n'))) + { diff --git a/patch-2.7.6-crash-RLIMIT_NOFILE.patch b/patch-2.7.6-crash-RLIMIT_NOFILE.patch new file mode 100644 index 0000000..c0f4fe1 --- /dev/null +++ b/patch-2.7.6-crash-RLIMIT_NOFILE.patch @@ -0,0 +1,84 @@ +commit 61d7788b83b302207a67b82786f4fd79e3538f30 +Author: Andreas Gruenbacher +Date: Thu Jun 27 11:10:43 2019 +0200 + + Don't crash when RLIMIT_NOFILE is set to RLIM_INFINITY + + * src/safe.c (min_cached_fds): Define minimum number of cached dir file + descriptors. + (max_cached_fds): Change type to rlim_t to allow storing RLIM_INFINITY. + (init_dirfd_cache): Set max_cached_fds to RLIM_INFINITY when RLIMIT_NOFILE is + RLIM_INFINITY. Set the initial hash table size to min_cached_fds, independent + of RLIMIT_NOFILE: patches commonly only affect one or a few files, so a small + hash table will usually suffice; if needed, the hash table will grow. + (insert_cached_dirfd): Don't shrink the cache when max_cached_fds is + RLIM_INFINITY. + +diff --git a/src/safe.c b/src/safe.c +index 5a7202f..f147b0e 100644 +--- a/src/safe.c ++++ b/src/safe.c +@@ -67,7 +67,8 @@ struct cached_dirfd { + }; + + static Hash_table *cached_dirfds = NULL; +-static size_t max_cached_fds; ++static rlim_t min_cached_fds = 8; ++static rlim_t max_cached_fds; + LIST_HEAD (lru_list); + + static size_t hash_cached_dirfd (const void *entry, size_t table_size) +@@ -98,11 +99,17 @@ static void init_dirfd_cache (void) + { + struct rlimit nofile; + +- max_cached_fds = 8; + if (getrlimit (RLIMIT_NOFILE, &nofile) == 0) +- max_cached_fds = MAX (nofile.rlim_cur / 4, max_cached_fds); ++ { ++ if (nofile.rlim_cur == RLIM_INFINITY) ++ max_cached_fds = RLIM_INFINITY; ++ else ++ max_cached_fds = MAX (nofile.rlim_cur / 4, min_cached_fds); ++ } ++ else ++ max_cached_fds = min_cached_fds; + +- cached_dirfds = hash_initialize (max_cached_fds, ++ cached_dirfds = hash_initialize (min_cached_fds, + NULL, + hash_cached_dirfd, + compare_cached_dirfds, +@@ -148,20 +155,23 @@ static void insert_cached_dirfd (struct cached_dirfd *entry, int keepfd) + if (cached_dirfds == NULL) + init_dirfd_cache (); + +- /* Trim off the least recently used entries */ +- while (hash_get_n_entries (cached_dirfds) >= max_cached_fds) ++ if (max_cached_fds != RLIM_INFINITY) + { +- struct cached_dirfd *last = +- list_entry (lru_list.prev, struct cached_dirfd, lru_link); +- if (&last->lru_link == &lru_list) +- break; +- if (last->fd == keepfd) ++ /* Trim off the least recently used entries */ ++ while (hash_get_n_entries (cached_dirfds) >= max_cached_fds) + { +- last = list_entry (last->lru_link.prev, struct cached_dirfd, lru_link); ++ struct cached_dirfd *last = ++ list_entry (lru_list.prev, struct cached_dirfd, lru_link); + if (&last->lru_link == &lru_list) + break; ++ if (last->fd == keepfd) ++ { ++ last = list_entry (last->lru_link.prev, struct cached_dirfd, lru_link); ++ if (&last->lru_link == &lru_list) ++ break; ++ } ++ remove_cached_dirfd (last); + } +- remove_cached_dirfd (last); + } + + /* Only insert if the parent still exists. */ diff --git a/patch-2.7.6-failed_assertion.patch b/patch-2.7.6-failed_assertion.patch new file mode 100644 index 0000000..f3d9022 --- /dev/null +++ b/patch-2.7.6-failed_assertion.patch @@ -0,0 +1,29 @@ +commit 76e775847f4954b63dc72afe34d9d921c6688b31 +Author: Andreas Gruenbacher +Date: Tue Jul 16 01:16:28 2019 +0200 + + Fix failed assertion 'outstate->after_newline' + + The assertion triggers when the -o FILE option is used, more than one output + file is written into FILE, and one of those files (except the last one) ends in + the middle of a line. + * src/patch.c (main): Fix the case described above. + +diff --git a/src/patch.c b/src/patch.c +index 02fd982..3794319 100644 +--- a/src/patch.c ++++ b/src/patch.c +@@ -369,6 +369,13 @@ main (int argc, char **argv) + /* outstate.ofp now owns the file descriptor */ + outfd = -1; + } ++ else ++ { ++ /* When writing to a single output file (-o FILE), always pretend ++ that the output file ends in a newline. Otherwise, when another ++ file is written to the same output file, apply_hunk will fail. */ ++ outstate.after_newline = true; ++ } + + /* find out where all the lines are */ + if (!skip_rest_of_patch) { diff --git a/patch-2.7.6-git-style.patch b/patch-2.7.6-git-style.patch deleted file mode 100644 index eeee233..0000000 --- a/patch-2.7.6-git-style.patch +++ /dev/null @@ -1,70 +0,0 @@ -diff -up patch-2.7.6/src/patch.c.git-style patch-2.7.6/src/patch.c ---- patch-2.7.6/src/patch.c.git-style 2018-02-03 13:41:49.000000000 +0100 -+++ patch-2.7.6/src/patch.c 2018-10-11 15:01:08.709406802 +0200 -@@ -1938,8 +1938,12 @@ output_files (struct stat const *st) - { - gl_list_iterator_t iter; - const void *elt; -+ gl_list_t files; - -- iter = gl_list_iterator (files_to_output); -+ files = files_to_output; -+ init_files_to_output (); -+ -+ iter = gl_list_iterator (files); - while (gl_list_iterator_next (&iter, &elt, NULL)) - { - const struct file_to_output *file_to_output = elt; -@@ -1957,8 +1961,8 @@ output_files (struct stat const *st) - /* Free the list up to here. */ - for (;;) - { -- const void *elt2 = gl_list_get_at (files_to_output, 0); -- gl_list_remove_at (files_to_output, 0); -+ const void *elt2 = gl_list_get_at (files, 0); -+ gl_list_remove_at (files, 0); - if (elt == elt2) - break; - } -@@ -1967,7 +1971,7 @@ output_files (struct stat const *st) - } - } - gl_list_iterator_free (&iter); -- gl_list_clear (files_to_output); -+ gl_list_clear (files); - } - - /* Fatal exit with cleanup. */ -diff -up patch-2.7.6/tests/git-error.git-style patch-2.7.6/tests/git-error ---- patch-2.7.6/tests/git-error.git-style 2018-10-11 15:00:09.349200685 +0200 -+++ patch-2.7.6/tests/git-error 2018-10-11 15:00:09.349200685 +0200 -@@ -0,0 +1,29 @@ -+# Copyright (C) 2018 Free Software Foundation, Inc. -+# -+# Copying and distribution of this file, with or without modification, -+# in any medium, are permitted without royalty provided the copyright -+# notice and this notice are preserved. -+ -+. $srcdir/test-lib.sh -+ -+require cat -+use_local_patch -+use_tmpdir -+ -+cat > f.diff < +Date: Thu Jun 27 11:02:02 2019 +0200 + + Improve support for memory leak detection + + When building with the address sanitizer on, free some more resources before + exiting. (This is unnecessary when not looking for memory leaks.) + * src/patch.c (init_files_to_delete): Add dispose function for freeing + filenames. + +diff --git a/src/patch.c b/src/patch.c +index 81c7a02..4616a48 100644 +--- a/src/patch.c ++++ b/src/patch.c +@@ -36,6 +36,10 @@ + #include + #include + ++#ifdef __SANITIZE_ADDRESS__ ++# define FREE_BEFORE_EXIT ++#endif ++ + /* procedures */ + + static FILE *create_output_file (char const *, int); +@@ -1777,10 +1781,20 @@ struct file_to_delete { + + static gl_list_t files_to_delete; + ++#ifdef FREE_BEFORE_EXIT ++void dispose_file_to_delete (const void *elt) ++{ ++ free ((void *) elt); ++} ++#else ++#define dispose_file_to_delete NULL ++#endif ++ + static void + init_files_to_delete (void) + { +- files_to_delete = gl_list_create_empty (GL_LINKED_LIST, NULL, NULL, NULL, true); ++ files_to_delete = gl_list_create_empty (GL_LINKED_LIST, NULL, NULL, ++ dispose_file_to_delete, true); + } + + static void diff --git a/patch.spec b/patch.spec index 58d8052..3c20e27 100644 --- a/patch.spec +++ b/patch.spec @@ -3,14 +3,19 @@ Summary: Utility for modifying/upgrading files Name: patch Version: 2.7.6 -Release: 9%{?dist} +Release: 10%{?dist} License: GPLv3+ URL: http://www.gnu.org/software/patch/patch.html Source: ftp://ftp.gnu.org/gnu/patch/patch-%{version}.tar.xz Patch1: patch-CVE-2018-1000156.patch Patch2: patch-2.7.6-CVE-2018-6952.patch -Patch3: patch-2.7.6-git-style.patch +Patch3: patch-2.7.6-abort_when_cleaning_up_fails.patch Patch4: patch-2.7.6-CVE-2018-17942.patch +Patch5: patch-2.7.6-improve_support_for_memory_leak_detection.patch +Patch6: patch-2.7.6-crash-RLIMIT_NOFILE.patch +Patch7: patch-2.7.6-CVE-2019-13636-symlinks.patch +Patch8: patch-2.7.6-avoid_invalid_memory_access.patch +Patch9: patch-2.7.6-failed_assertion.patch Patch100: patch-selinux.patch BuildRequires: gcc @@ -37,11 +42,14 @@ applications. %patch1 -p1 -b .CVE-2018-1000156 # CVE-2018-6952, Double free of memory %patch2 -p1 -b .CVE-2018-6952 -# Fix error handling with git-style patches -# http://lists.gnu.org/archive/html/bug-patch/2018-10/msg00000.html -%patch3 -p1 -b .git-style +%patch3 -p1 -b .abort_when_cleaning_up_fails # CVE-2018-17942 gnulib: heap-based buffer overflow %patch4 -p1 -b .gnulib_buffer_overflow +%patch5 -p1 -b .improve_support_for_memory_leak_detection +%patch6 -p1 -b .crash-RLIMIT_NOFILE +%patch7 -p1 -b .CVE-2019-13636-symlinks +%patch8 -p1 -b .avoid_invalid_memory_access +%patch9 -p1 -b .failed_assertion # SELinux support. %patch100 -p1 -b .selinux @@ -67,6 +75,14 @@ rm -rf $RPM_BUILD_ROOT %{_mandir}/*/* %changelog +* Wed Jul 24 2019 Than Ngo - 2.7.6-10 +- backported patch, abort when cleaning up fails +- backported patch, improve support for memory leak detection +- backported patch, don't crash when RLIMIT_NOFILE is set to RLIM_INFINITY +- backported patch, CVE-2019-13636, don't follow symlinks unless --follow-symlinks is given +- backported patch, avoid invalid memory accessin context format diffs +- backported patch, fix failed assertion + * Fri Feb 01 2019 Fedora Release Engineering - 2.7.6-9 - Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild