diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b016cef --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/patch-2.7.6.tar.xz diff --git a/.patch.metadata b/.patch.metadata new file mode 100644 index 0000000..5380928 --- /dev/null +++ b/.patch.metadata @@ -0,0 +1 @@ +6f64fa75993bdb285ac4ed6eca6c9212725bff91 SOURCES/patch-2.7.6.tar.xz diff --git a/SOURCES/patch-2.7.6-CVE-2018-17942.patch b/SOURCES/patch-2.7.6-CVE-2018-17942.patch new file mode 100644 index 0000000..5eb224e --- /dev/null +++ b/SOURCES/patch-2.7.6-CVE-2018-17942.patch @@ -0,0 +1,14 @@ +diff -up patch-2.7.6/lib/vasnprintf.c.me patch-2.7.6/lib/vasnprintf.c +--- patch-2.7.6/lib/vasnprintf.c.me 2018-11-26 14:02:03.401718842 +0100 ++++ patch-2.7.6/lib/vasnprintf.c 2018-11-26 14:03:02.923913446 +0100 +@@ -860,7 +860,9 @@ convert_to_decimal (mpn_t a, size_t extr + size_t a_len = a.nlimbs; + /* 0.03345 is slightly larger than log(2)/(9*log(10)). */ + size_t c_len = 9 * ((size_t)(a_len * (GMP_LIMB_BITS * 0.03345f)) + 1); +- char *c_ptr = (char *) malloc (xsum (c_len, extra_zeroes)); ++ /* We need extra_zeroes bytes for zeroes, followed by c_len bytes for the ++ digits of a, followed by 1 byte for the terminating NUL. */ ++ char *c_ptr = (char *) malloc (xsum (xsum (extra_zeroes, c_len), 1)); + if (c_ptr != NULL) + { + char *d_ptr = c_ptr; diff --git a/SOURCES/patch-2.7.6-CVE-2018-6952-fix-swapping-fake-lines-in-pch_swap.patch b/SOURCES/patch-2.7.6-CVE-2018-6952-fix-swapping-fake-lines-in-pch_swap.patch new file mode 100644 index 0000000..257a300 --- /dev/null +++ b/SOURCES/patch-2.7.6-CVE-2018-6952-fix-swapping-fake-lines-in-pch_swap.patch @@ -0,0 +1,25 @@ +commit 9c986353e420ead6e706262bf204d6e03322c300 +Author: Andreas Gruenbacher +Date: Fri Aug 17 13:35:40 2018 +0200 + + Fix swapping fake lines in pch_swap + + * src/pch.c (pch_swap): Fix swapping p_bfake and p_efake when there is a + blank line in the middle of a context-diff hunk: that empty line stays + in the middle of the hunk and isn't swapped. + + Fixes: https://savannah.gnu.org/bugs/index.php?53133 + +diff --git a/src/pch.c b/src/pch.c +index e92bc64..a500ad9 100644 +--- a/src/pch.c ++++ b/src/pch.c +@@ -2122,7 +2122,7 @@ pch_swap (void) + } + if (p_efake >= 0) { /* fix non-freeable ptr range */ + if (p_efake <= i) +- n = p_end - i + 1; ++ n = p_end - p_ptrn_lines; + else + n = -i; + p_efake += n; diff --git a/SOURCES/patch-2.7.6-CVE-2019-13636-symlinks.patch b/SOURCES/patch-2.7.6-CVE-2019-13636-symlinks.patch new file mode 100644 index 0000000..bf3e603 --- /dev/null +++ b/SOURCES/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/SOURCES/patch-2.7.6-CVE-2019-13638-invoked-ed-directly-instead-of-using-the-shell.patch b/SOURCES/patch-2.7.6-CVE-2019-13638-invoked-ed-directly-instead-of-using-the-shell.patch new file mode 100644 index 0000000..4a9f2d6 --- /dev/null +++ b/SOURCES/patch-2.7.6-CVE-2019-13638-invoked-ed-directly-instead-of-using-the-shell.patch @@ -0,0 +1,33 @@ +commit 3fcd042d26d70856e826a42b5f93dc4854d80bf0 +Author: Andreas Gruenbacher +Date: Fri Apr 6 19:36:15 2018 +0200 + + Invoke ed directly instead of using the shell + + * src/pch.c (do_ed_script): Invoke ed directly instead of using a shell + command to avoid quoting vulnerabilities. + +diff --git a/src/pch.c b/src/pch.c +index 4fd5a05..16e001a 100644 +--- a/src/pch.c ++++ b/src/pch.c +@@ -2459,9 +2459,6 @@ do_ed_script (char const *inname, char const *outname, + *outname_needs_removal = true; + copy_file (inname, outname, 0, exclusive, instat.st_mode, true); + } +- sprintf (buf, "%s %s%s", editor_program, +- verbosity == VERBOSE ? "" : "- ", +- outname); + fflush (stdout); + + pid = fork(); +@@ -2470,7 +2467,8 @@ do_ed_script (char const *inname, char const *outname, + else if (pid == 0) + { + dup2 (tmpfd, 0); +- execl ("/bin/sh", "sh", "-c", buf, (char *) 0); ++ assert (outname[0] != '!' && outname[0] != '-'); ++ execlp (editor_program, editor_program, "-", outname, (char *) NULL); + _exit (2); + } + else diff --git a/SOURCES/patch-2.7.6-abort_when_cleaning_up_fails.patch b/SOURCES/patch-2.7.6-abort_when_cleaning_up_fails.patch new file mode 100644 index 0000000..56dbda8 --- /dev/null +++ b/SOURCES/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/SOURCES/patch-2.7.6-allow-input-files-to-be-missing-for-ed-style-patches.patch b/SOURCES/patch-2.7.6-allow-input-files-to-be-missing-for-ed-style-patches.patch new file mode 100644 index 0000000..34b8fb4 --- /dev/null +++ b/SOURCES/patch-2.7.6-allow-input-files-to-be-missing-for-ed-style-patches.patch @@ -0,0 +1,28 @@ +commit b5a91a01e5d0897facdd0f49d64b76b0f02b43e1 +Author: Andreas Gruenbacher +Date: Fri Apr 6 11:34:51 2018 +0200 + + Allow input files to be missing for ed-style patches + + * src/pch.c (do_ed_script): Allow input files to be missing so that new + files will be created as with non-ed-style patches. + +diff --git a/src/pch.c b/src/pch.c +index bc6278c..0c5cc26 100644 +--- a/src/pch.c ++++ b/src/pch.c +@@ -2394,9 +2394,11 @@ do_ed_script (char const *inname, char const *outname, + + if (! dry_run && ! skip_rest_of_patch) { + int exclusive = *outname_needs_removal ? 0 : O_EXCL; +- assert (! inerrno); +- *outname_needs_removal = true; +- copy_file (inname, outname, 0, exclusive, instat.st_mode, true); ++ if (inerrno != ENOENT) ++ { ++ *outname_needs_removal = true; ++ copy_file (inname, outname, 0, exclusive, instat.st_mode, true); ++ } + sprintf (buf, "%s %s%s", editor_program, + verbosity == VERBOSE ? "" : "- ", + outname); diff --git a/SOURCES/patch-2.7.6-avoid-invalid-memory-access-in-context-format-diffs.patch b/SOURCES/patch-2.7.6-avoid-invalid-memory-access-in-context-format-diffs.patch new file mode 100644 index 0000000..39b59d1 --- /dev/null +++ b/SOURCES/patch-2.7.6-avoid-invalid-memory-access-in-context-format-diffs.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/SOURCES/patch-2.7.6-avoid-set_file_attributes-sign-conversion-warnings.patch b/SOURCES/patch-2.7.6-avoid-set_file_attributes-sign-conversion-warnings.patch new file mode 100644 index 0000000..dd57034 --- /dev/null +++ b/SOURCES/patch-2.7.6-avoid-set_file_attributes-sign-conversion-warnings.patch @@ -0,0 +1,24 @@ +commit 3bbebbb29f6fbbf2988b9f2e75695b7c0b1f1c9b +Author: Andreas Gruenbacher +Date: Wed Feb 7 12:01:22 2018 +0100 + + Avoid set_file_attributes sign conversion warnings + + * src/util.c (set_file_attributes): Avoid sign conversion warnings when + assigning -1 to uid_t / gid_t. + +diff --git a/src/util.c b/src/util.c +index b1c7266..1cc08ba 100644 +--- a/src/util.c ++++ b/src/util.c +@@ -256,8 +256,8 @@ set_file_attributes (char const *to, enum file_attributes attr, + } + if (attr & FA_IDS) + { +- static uid_t euid = -1; +- static gid_t egid = -1; ++ static uid_t euid = (uid_t)-1; ++ static gid_t egid = (gid_t)-1; + uid_t uid; + uid_t gid; + diff --git a/SOURCES/patch-2.7.6-avoid-warnings-gcc8.patch b/SOURCES/patch-2.7.6-avoid-warnings-gcc8.patch new file mode 100644 index 0000000..5cc3366 --- /dev/null +++ b/SOURCES/patch-2.7.6-avoid-warnings-gcc8.patch @@ -0,0 +1,85 @@ +commit ae81be0024ea4eaf139b7ba57e9a8ce9e4a163ec +Author: Jim Meyering +Date: Fri Apr 6 17:17:11 2018 -0700 + + maint: avoid warnings from GCC8 + + Hi Andreas, + + I configured with --enable-gcc-warnings and bleeding-edge gcc + (version 8.0.1 20180406) and hit some warning-escalated-to-errors. + This fixes them: + + >From a71ddb200dbe7ac0f9258796b5a51979b2740e88 Mon Sep 17 00:00:00 2001 + From: Jim Meyering + Date: Fri, 6 Apr 2018 16:47:00 -0700 + Subject: [PATCH] maint: avoid warnings from GCC8 + + * src/common.h (FALLTHROUGH): Define. + * src/patch.c (abort_hunk_context): Use FALLTHROUGH macro in place of + a comment. This avoids a warning from -Wimplicit-fallthrough=. + * src/pch.c (do_ed_script): Add otherwise unnecessary initialization + to avoid warning from -Wmaybe-uninitialized. + (another_hunk): Use FALLTHROUGH macro here, too, twice. + +diff --git a/src/common.h b/src/common.h +index ec50b40..904a3f8 100644 +--- a/src/common.h ++++ b/src/common.h +@@ -218,3 +218,11 @@ bool merge_hunk (int hunk, struct outstate *, lin where, bool *); + #else + # define merge_hunk(hunk, outstate, where, somefailed) false + #endif ++ ++#ifndef FALLTHROUGH ++# if __GNUC__ < 7 ++# define FALLTHROUGH ((void) 0) ++# else ++# define FALLTHROUGH __attribute__ ((__fallthrough__)) ++# endif ++#endif +diff --git a/src/patch.c b/src/patch.c +index 0fe6d72..1ae91d9 100644 +--- a/src/patch.c ++++ b/src/patch.c +@@ -1381,7 +1381,7 @@ abort_hunk_context (bool header, bool reverse) + break; + case ' ': case '-': case '+': case '!': + fprintf (rejfp, "%c ", pch_char (i)); +- /* fall into */ ++ FALLTHROUGH; + case '\n': + pch_write_line (i, rejfp); + break; +diff --git a/src/pch.c b/src/pch.c +index 1055542..cda3dfa 100644 +--- a/src/pch.c ++++ b/src/pch.c +@@ -1735,7 +1735,7 @@ another_hunk (enum diff difftype, bool rev) + break; + case '=': + ch = ' '; +- /* FALL THROUGH */ ++ FALLTHROUGH; + case ' ': + if (fillsrc > p_ptrn_lines) { + free(s); +@@ -1756,7 +1756,7 @@ another_hunk (enum diff difftype, bool rev) + p_end = fillsrc-1; + return -1; + } +- /* FALL THROUGH */ ++ FALLTHROUGH; + case '+': + if (filldst > p_end) { + free(s); +@@ -2394,8 +2394,7 @@ do_ed_script (char const *inname, char const *outname, + size_t chars_read; + FILE *tmpfp = 0; + char const *tmpname; +- int tmpfd; +- pid_t pid; ++ int tmpfd = -1; /* placate gcc's -Wmaybe-uninitialized */ + int exclusive = *outname_needs_removal ? 0 : O_EXCL; + char const **ed_argv; + int stdin_dup, status; diff --git a/SOURCES/patch-2.7.6-check-of-return-value-of-fwrite.patch b/SOURCES/patch-2.7.6-check-of-return-value-of-fwrite.patch new file mode 100644 index 0000000..01242c0 --- /dev/null +++ b/SOURCES/patch-2.7.6-check-of-return-value-of-fwrite.patch @@ -0,0 +1,75 @@ +commit 1e9104c18019e7dc6b5590aea4b1d4f9d8ecfd56 +Author: Bruno Haible +Date: Sat Apr 7 12:21:04 2018 +0200 + + Fix check of return value of fwrite(). + + * src/patch.c (copy_till): Consider incomplete fwrite() write as an error. + * src/pch.c (pch_write_line, do_ed_script): Likewise. + +diff --git a/src/patch.c b/src/patch.c +index 1ae91d9..3fcaec5 100644 +--- a/src/patch.c ++++ b/src/patch.c +@@ -2,7 +2,7 @@ + + /* Copyright (C) 1984, 1985, 1986, 1987, 1988 Larry Wall + +- Copyright (C) 1989-1993, 1997-1999, 2002-2003, 2006, 2009-2012 Free Software ++ Copyright (C) 1989-1993, 1997-1999, 2002-2003, 2006, 2009-2018 Free Software + Foundation, Inc. + + This program is free software: you can redistribute it and/or modify +@@ -1641,7 +1641,7 @@ copy_till (struct outstate *outstate, lin lastline) + if (size) + { + if ((! outstate->after_newline && putc ('\n', fp) == EOF) +- || ! fwrite (s, sizeof *s, size, fp)) ++ || fwrite (s, sizeof *s, size, fp) < size) + write_fatal (); + outstate->after_newline = s[size - 1] == '\n'; + outstate->zero_output = false; +diff --git a/src/pch.c b/src/pch.c +index cda3dfa..79a3c99 100644 +--- a/src/pch.c ++++ b/src/pch.c +@@ -2279,8 +2279,11 @@ pfetch (lin line) + bool + pch_write_line (lin line, FILE *file) + { +- bool after_newline = (p_len[line] > 0) && (p_line[line][p_len[line] - 1] == '\n'); +- if (! fwrite (p_line[line], sizeof (*p_line[line]), p_len[line], file)) ++ bool after_newline = ++ (p_len[line] > 0) && (p_line[line][p_len[line] - 1] == '\n'); ++ ++ if (fwrite (p_line[line], sizeof (*p_line[line]), p_len[line], file) ++ < p_len[line]) + write_fatal (); + return after_newline; + } +@@ -2427,13 +2430,14 @@ do_ed_script (char const *inname, char const *outname, + ed_command_letter = get_ed_command_letter (buf); + if (ed_command_letter) { + if (tmpfp) +- if (! fwrite (buf, sizeof *buf, chars_read, tmpfp)) ++ if (fwrite (buf, sizeof *buf, chars_read, tmpfp) < chars_read) + write_fatal (); + if (ed_command_letter != 'd' && ed_command_letter != 's') { + p_pass_comments_through = true; + while ((chars_read = get_line ()) != 0) { + if (tmpfp) +- if (! fwrite (buf, sizeof *buf, chars_read, tmpfp)) ++ if (fwrite (buf, sizeof *buf, chars_read, tmpfp) ++ < chars_read) + write_fatal (); + if (chars_read == 2 && strEQ (buf, ".\n")) + break; +@@ -2448,7 +2452,7 @@ do_ed_script (char const *inname, char const *outname, + } + if (dry_run || skip_rest_of_patch) + return; +- if (fwrite ("w\nq\n", sizeof (char), (size_t) 4, tmpfp) == 0 ++ if (fwrite ("w\nq\n", sizeof (char), (size_t) 4, tmpfp) < (size_t) 4 + || fflush (tmpfp) != 0) + write_fatal (); + diff --git a/SOURCES/patch-2.7.6-cleanups-in-do_ed_script.patch b/SOURCES/patch-2.7.6-cleanups-in-do_ed_script.patch new file mode 100644 index 0000000..1fab381 --- /dev/null +++ b/SOURCES/patch-2.7.6-cleanups-in-do_ed_script.patch @@ -0,0 +1,91 @@ +commit 2a32bf09f5e9572da4be183bb0dbde8164351474 +Author: Andreas Gruenbacher +Date: Fri Apr 6 20:32:46 2018 +0200 + + Minor cleanups in do_ed_script + + * src/pch.c (do_ed_script): Minor cleanups. + +diff --git a/src/pch.c b/src/pch.c +index 1f14624..1055542 100644 +--- a/src/pch.c ++++ b/src/pch.c +@@ -2396,6 +2396,10 @@ do_ed_script (char const *inname, char const *outname, + char const *tmpname; + int tmpfd; + pid_t pid; ++ int exclusive = *outname_needs_removal ? 0 : O_EXCL; ++ char const **ed_argv; ++ int stdin_dup, status; ++ + + if (! dry_run && ! skip_rest_of_patch) + { +@@ -2443,7 +2447,7 @@ do_ed_script (char const *inname, char const *outname, + break; + } + } +- if (!tmpfp) ++ if (dry_run || skip_rest_of_patch) + return; + if (fwrite ("w\nq\n", sizeof (char), (size_t) 4, tmpfp) == 0 + || fflush (tmpfp) != 0) +@@ -2452,36 +2456,29 @@ do_ed_script (char const *inname, char const *outname, + if (lseek (tmpfd, 0, SEEK_SET) == -1) + pfatal ("Can't rewind to the beginning of file %s", quotearg (tmpname)); + +- if (! dry_run && ! skip_rest_of_patch) { +- int exclusive = *outname_needs_removal ? 0 : O_EXCL; +- char const **ed_argv; +- int stdin_dup, status; +- ++ if (inerrno != ENOENT) ++ { + *outname_needs_removal = true; +- if (inerrno != ENOENT) +- { +- *outname_needs_removal = true; +- copy_file (inname, outname, 0, exclusive, instat.st_mode, true); +- } +- fflush (stdout); +- +- if ((stdin_dup = dup (0)) == -1 +- || dup2 (tmpfd, 0) == -1) +- pfatal ("Failed to duplicate standard input"); +- assert (outname[0] != '!' && outname[0] != '-'); +- ed_argv = alloca (4 * sizeof * ed_argv); +- ed_argv[0] = editor_program; +- ed_argv[1] = "-"; +- ed_argv[2] = outname; +- ed_argv[3] = (char *) NULL; +- status = execute (editor_program, editor_program, (char **)ed_argv, +- false, false, false, false, true, false, NULL); +- if (status) +- fatal ("%s FAILED", editor_program); +- if (dup2 (stdin_dup, 0) == -1 +- || close (stdin_dup) == -1) +- pfatal ("Failed to duplicate standard input"); +- } ++ copy_file (inname, outname, 0, exclusive, instat.st_mode, true); ++ } ++ fflush (stdout); ++ ++ if ((stdin_dup = dup (0)) == -1 ++ || dup2 (tmpfd, 0) == -1) ++ pfatal ("Failed to duplicate standard input"); ++ assert (outname[0] != '!' && outname[0] != '-'); ++ ed_argv = alloca (4 * sizeof * ed_argv); ++ ed_argv[0] = editor_program; ++ ed_argv[1] = "-"; ++ ed_argv[2] = outname; ++ ed_argv[3] = (char *) NULL; ++ status = execute (editor_program, editor_program, (char **)ed_argv, ++ false, false, false, false, true, false, NULL); ++ if (status) ++ fatal ("%s FAILED", editor_program); ++ if (dup2 (stdin_dup, 0) == -1 ++ || close (stdin_dup) == -1) ++ pfatal ("Failed to duplicate standard input"); + + fclose (tmpfp); + safe_unlink (tmpname); diff --git a/SOURCES/patch-2.7.6-crash-RLIMIT_NOFILE.patch b/SOURCES/patch-2.7.6-crash-RLIMIT_NOFILE.patch new file mode 100644 index 0000000..c0f4fe1 --- /dev/null +++ b/SOURCES/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/SOURCES/patch-2.7.6-dont-leak-temporary-file-on-failed-ed-style-patch.patch b/SOURCES/patch-2.7.6-dont-leak-temporary-file-on-failed-ed-style-patch.patch new file mode 100644 index 0000000..d0c7869 --- /dev/null +++ b/SOURCES/patch-2.7.6-dont-leak-temporary-file-on-failed-ed-style-patch.patch @@ -0,0 +1,95 @@ +commit 19599883ffb6a450d2884f081f8ecf68edbed7ee +Author: Jean Delvare +Date: Thu May 3 14:31:55 2018 +0200 + + Don't leak temporary file on failed ed-style patch + + Now that we write ed-style patches to a temporary file before we + apply them, we need to ensure that the temporary file is removed + before we leave, even on fatal error. + + * src/pch.c (do_ed_script): Use global TMPEDNAME instead of local + tmpname. Don't unlink the file directly, instead tag it for removal + at exit time. + * src/patch.c (cleanup): Unlink TMPEDNAME at exit. + + This closes bug #53820: + https://savannah.gnu.org/bugs/index.php?53820 + + Fixes: 123eaff0d5d1 ("Fix arbitrary command execution in ed-style patches (CVE-2018-1000156)") + +diff --git a/src/common.h b/src/common.h +index 904a3f8..53c5e32 100644 +--- a/src/common.h ++++ b/src/common.h +@@ -94,10 +94,12 @@ XTERN char const *origsuff; + XTERN char const * TMPINNAME; + XTERN char const * TMPOUTNAME; + XTERN char const * TMPPATNAME; ++XTERN char const * TMPEDNAME; + + XTERN bool TMPINNAME_needs_removal; + XTERN bool TMPOUTNAME_needs_removal; + XTERN bool TMPPATNAME_needs_removal; ++XTERN bool TMPEDNAME_needs_removal; + + #ifdef DEBUGGING + XTERN int debug; +diff --git a/src/patch.c b/src/patch.c +index 3fcaec5..9146597 100644 +--- a/src/patch.c ++++ b/src/patch.c +@@ -1999,6 +1999,7 @@ cleanup (void) + remove_if_needed (TMPINNAME, &TMPINNAME_needs_removal); + remove_if_needed (TMPOUTNAME, &TMPOUTNAME_needs_removal); + remove_if_needed (TMPPATNAME, &TMPPATNAME_needs_removal); ++ remove_if_needed (TMPEDNAME, &TMPEDNAME_needs_removal); + remove_if_needed (TMPREJNAME, &TMPREJNAME_needs_removal); + output_files (NULL); + } +diff --git a/src/pch.c b/src/pch.c +index 79a3c99..1bb3153 100644 +--- a/src/pch.c ++++ b/src/pch.c +@@ -2396,7 +2396,6 @@ do_ed_script (char const *inname, char const *outname, + file_offset beginning_of_this_line; + size_t chars_read; + FILE *tmpfp = 0; +- char const *tmpname; + int tmpfd = -1; /* placate gcc's -Wmaybe-uninitialized */ + int exclusive = *outname_needs_removal ? 0 : O_EXCL; + char const **ed_argv; +@@ -2411,12 +2410,13 @@ do_ed_script (char const *inname, char const *outname, + invalid commands and treats the next line as a new command, which + can lead to arbitrary command execution. */ + +- tmpfd = make_tempfile (&tmpname, 'e', NULL, O_RDWR | O_BINARY, 0); ++ tmpfd = make_tempfile (&TMPEDNAME, 'e', NULL, O_RDWR | O_BINARY, 0); + if (tmpfd == -1) +- pfatal ("Can't create temporary file %s", quotearg (tmpname)); ++ pfatal ("Can't create temporary file %s", quotearg (TMPEDNAME)); ++ TMPEDNAME_needs_removal = true; + tmpfp = fdopen (tmpfd, "w+b"); + if (! tmpfp) +- pfatal ("Can't open stream for file %s", quotearg (tmpname)); ++ pfatal ("Can't open stream for file %s", quotearg (TMPEDNAME)); + } + + for (;;) { +@@ -2457,7 +2457,7 @@ do_ed_script (char const *inname, char const *outname, + write_fatal (); + + if (lseek (tmpfd, 0, SEEK_SET) == -1) +- pfatal ("Can't rewind to the beginning of file %s", quotearg (tmpname)); ++ pfatal ("Can't rewind to the beginning of file %s", quotearg (TMPEDNAME)); + + if (inerrno != ENOENT) + { +@@ -2484,7 +2484,6 @@ do_ed_script (char const *inname, char const *outname, + pfatal ("Failed to duplicate standard input"); + + fclose (tmpfp); +- safe_unlink (tmpname); + + if (ofp) + { diff --git a/SOURCES/patch-2.7.6-dont-leak-temporary-file-on-failed-multi-file-ed-style-patch.patch b/SOURCES/patch-2.7.6-dont-leak-temporary-file-on-failed-multi-file-ed-style-patch.patch new file mode 100644 index 0000000..959a59c --- /dev/null +++ b/SOURCES/patch-2.7.6-dont-leak-temporary-file-on-failed-multi-file-ed-style-patch.patch @@ -0,0 +1,71 @@ +commit 369dcccdfa6336e5a873d6d63705cfbe04c55727 +Author: Jean Delvare +Date: Mon May 7 15:14:45 2018 +0200 + + Don't leak temporary file on failed multi-file ed-style patch + + The previous fix worked fine with single-file ed-style patches, but + would still leak temporary files in the case of multi-file ed-style + patch. Fix that case as well, and extend the test case to check for + it. + + * src/patch.c (main): Unlink TMPEDNAME if needed before moving to + the next file in a patch. + + This closes bug #53820: + https://savannah.gnu.org/bugs/index.php?53820 + + Fixes: 123eaff0d5d1 ("Fix arbitrary command execution in ed-style patches (CVE-2018-1000156)") + Fixes: 19599883ffb6 ("Don't leak temporary file on failed ed-style patch") + +diff --git a/src/patch.c b/src/patch.c +index 9146597..81c7a02 100644 +--- a/src/patch.c ++++ b/src/patch.c +@@ -236,6 +236,7 @@ main (int argc, char **argv) + } + remove_if_needed (TMPOUTNAME, &TMPOUTNAME_needs_removal); + } ++ remove_if_needed (TMPEDNAME, &TMPEDNAME_needs_removal); + + if (! skip_rest_of_patch && ! file_type) + { +diff --git a/tests/ed-style b/tests/ed-style +index 6b6ef9d..504e6e5 100644 +--- a/tests/ed-style ++++ b/tests/ed-style +@@ -38,3 +38,34 @@ EOF + check 'cat foo' < ed3.diff < baz < +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/SOURCES/patch-2.7.6-fix-ed-style-test-failure.patch b/SOURCES/patch-2.7.6-fix-ed-style-test-failure.patch new file mode 100644 index 0000000..609516d --- /dev/null +++ b/SOURCES/patch-2.7.6-fix-ed-style-test-failure.patch @@ -0,0 +1,22 @@ +commit 458ac51a05426c1af9aa6bf1342ecf60728c19b4 +Author: Bruno Haible +Date: Sat Apr 7 12:34:03 2018 +0200 + + Fix 'ed-style' test failure. + + * tests/ed-style: Remove '?' line from expected output. + +diff --git a/tests/ed-style b/tests/ed-style +index d8c0689..6b6ef9d 100644 +--- a/tests/ed-style ++++ b/tests/ed-style +@@ -31,8 +31,7 @@ r !echo bar + ,p + EOF + +-check 'patch -e foo -i ed2.diff 2> /dev/null || echo "Status: $?"' < /dev/null 2> /dev/null || echo "Status: $?"' < +Date: Wed Feb 7 17:05:00 2018 +0100 + + Test suite: fix Korn shell incompatibility + + tests/merge: In a Korn shell, shift apparently fails when $# is 0. + +diff --git a/tests/merge b/tests/merge +index b628891..e950b92 100644 +--- a/tests/merge ++++ b/tests/merge +@@ -32,7 +32,7 @@ x2() { + shift + done > b.sed + echo "$body" | sed -f b.sed > b +- shift ++ test $# -eq 0 || shift + while test $# -gt 0 ; do + echo "$1" + shift diff --git a/SOURCES/patch-2.7.6-fix-segfault-with-mangled-rename-patch.patch b/SOURCES/patch-2.7.6-fix-segfault-with-mangled-rename-patch.patch new file mode 100644 index 0000000..c5bcba5 --- /dev/null +++ b/SOURCES/patch-2.7.6-fix-segfault-with-mangled-rename-patch.patch @@ -0,0 +1,24 @@ +commit f290f48a621867084884bfff87f8093c15195e6a +Author: Andreas Gruenbacher +Date: Mon Feb 12 16:48:24 2018 +0100 + + Fix segfault with mangled rename patch + + http://savannah.gnu.org/bugs/?53132 + * src/pch.c (intuit_diff_type): Ensure that two filenames are specified + for renames and copies (fix the existing check). + +diff --git a/src/pch.c b/src/pch.c +index ff9ed2c..bc6278c 100644 +--- a/src/pch.c ++++ b/src/pch.c +@@ -974,7 +974,8 @@ intuit_diff_type (bool need_header, mode_t *p_file_type) + if ((pch_rename () || pch_copy ()) + && ! inname + && ! ((i == OLD || i == NEW) && +- p_name[! reverse] && ++ p_name[reverse] && p_name[! reverse] && ++ name_is_valid (p_name[reverse]) && + name_is_valid (p_name[! reverse]))) + { + say ("Cannot %s file without two valid file names\n", pch_rename () ? "rename" : "copy"); diff --git a/SOURCES/patch-2.7.6-improve_support_for_memory_leak_detection.patch b/SOURCES/patch-2.7.6-improve_support_for_memory_leak_detection.patch new file mode 100644 index 0000000..fc92ff0 --- /dev/null +++ b/SOURCES/patch-2.7.6-improve_support_for_memory_leak_detection.patch @@ -0,0 +1,48 @@ +commit 2b584aec9e5f2806b1eccadcabe7e901fcfa0b0a +Author: Andreas Gruenbacher +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/SOURCES/patch-2.7.6-make-debug-output-more-useful.patch b/SOURCES/patch-2.7.6-make-debug-output-more-useful.patch new file mode 100644 index 0000000..69e79c2 --- /dev/null +++ b/SOURCES/patch-2.7.6-make-debug-output-more-useful.patch @@ -0,0 +1,40 @@ +commit ff81775f4eb6ab9a91b75e4031e8216654c0c76a +Author: Andreas Gruenbacher +Date: Fri Aug 17 10:31:22 2018 +0200 + + Make the (debug & 2) output more useful + + * src/pch.c (another_hunk): In the (debug & 2) output, fix how empty + lines that are not part of the patch context are printed. Also, add + newlines to lines that are missing them to keep the output readable. + +diff --git a/src/pch.c b/src/pch.c +index 1bb3153..e92bc64 100644 +--- a/src/pch.c ++++ b/src/pch.c +@@ -1916,8 +1916,13 @@ another_hunk (enum diff difftype, bool rev) + lin i; + + for (i = 0; i <= p_end + 1; i++) { +- fprintf (stderr, "%s %c", +- format_linenum (numbuf0, i), ++ fputs (format_linenum (numbuf0, i), stderr); ++ if (p_Char[i] == '\n') ++ { ++ fputc('\n', stderr); ++ continue; ++ } ++ fprintf (stderr, " %c", + p_Char[i]); + if (p_Char[i] == '*') + fprintf (stderr, " %s,%s\n", +@@ -1930,7 +1935,8 @@ another_hunk (enum diff difftype, bool rev) + else if (p_Char[i] != '^') + { + fputs(" |", stderr); +- pch_write_line (i, stderr); ++ if (! pch_write_line (i, stderr)) ++ fputc('\n', stderr); + } + else + fputc('\n', stderr); diff --git a/SOURCES/patch-2.7.6-skip-ed-test-when-the-ed-utility-is-not-installed.patch b/SOURCES/patch-2.7.6-skip-ed-test-when-the-ed-utility-is-not-installed.patch new file mode 100644 index 0000000..e9738ad --- /dev/null +++ b/SOURCES/patch-2.7.6-skip-ed-test-when-the-ed-utility-is-not-installed.patch @@ -0,0 +1,20 @@ +commit a5b442ce01b80a758606ede316f739426a12bc33 +Author: Andreas Gruenbacher +Date: Thu Jun 27 11:09:31 2019 +0200 + + Skip "ed" test when the ed utility is not installed + + * tests/ed-style: Require ed. + +diff --git a/tests/ed-style b/tests/ed-style +index 504e6e5..9907cb6 100644 +--- a/tests/ed-style ++++ b/tests/ed-style +@@ -7,6 +7,7 @@ + . $srcdir/test-lib.sh + + require cat ++require ed + use_local_patch + use_tmpdir + diff --git a/SOURCES/patch-2.7.6-switch-from-fork-execlp-to-execute.patch b/SOURCES/patch-2.7.6-switch-from-fork-execlp-to-execute.patch new file mode 100644 index 0000000..4212552 --- /dev/null +++ b/SOURCES/patch-2.7.6-switch-from-fork-execlp-to-execute.patch @@ -0,0 +1,1774 @@ +diff -up patch-2.7.6/lib/execute.c.switch-from-fork-execlp-to-execute patch-2.7.6/lib/execute.c +--- patch-2.7.6/lib/execute.c.switch-from-fork-execlp-to-execute 2019-07-29 14:40:53.264464824 +0200 ++++ patch-2.7.6/lib/execute.c 2019-07-29 14:40:53.264464824 +0200 +@@ -0,0 +1,273 @@ ++/* Creation of autonomous subprocesses. ++ Copyright (C) 2001-2004, 2006-2018 Free Software Foundation, Inc. ++ Written by Bruno Haible , 2001. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++ ++#include ++ ++/* Specification. */ ++#include "execute.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "error.h" ++#include "fatal-signal.h" ++#include "wait-process.h" ++#include "gettext.h" ++ ++#define _(str) gettext (str) ++ ++#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ ++ ++/* Native Windows API. */ ++# include ++# include "w32spawn.h" ++ ++#else ++ ++/* Unix API. */ ++# include ++ ++#endif ++ ++ ++#if defined EINTR && ((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__) ++ ++/* EINTR handling for close(), open(). ++ These functions can return -1/EINTR even though we don't have any ++ signal handlers set up, namely when we get interrupted via SIGSTOP. */ ++ ++static int ++nonintr_close (int fd) ++{ ++ int retval; ++ ++ do ++ retval = close (fd); ++ while (retval < 0 && errno == EINTR); ++ ++ return retval; ++} ++#define close nonintr_close ++ ++static int ++nonintr_open (const char *pathname, int oflag, mode_t mode) ++{ ++ int retval; ++ ++ do ++ retval = open (pathname, oflag, mode); ++ while (retval < 0 && errno == EINTR); ++ ++ return retval; ++} ++#undef open /* avoid warning on VMS */ ++#define open nonintr_open ++ ++#endif ++ ++ ++/* Execute a command, optionally redirecting any of the three standard file ++ descriptors to /dev/null. Return its exit code. ++ If it didn't terminate correctly, exit if exit_on_error is true, otherwise ++ return 127. ++ If slave_process is true, the child process will be terminated when its ++ creator receives a catchable fatal signal. */ ++int ++execute (const char *progname, ++ const char *prog_path, char **prog_argv, ++ bool ignore_sigpipe, ++ bool null_stdin, bool null_stdout, bool null_stderr, ++ bool slave_process, bool exit_on_error, ++ int *termsigp) ++{ ++#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ ++ ++ /* Native Windows API. */ ++ int orig_stdin; ++ int orig_stdout; ++ int orig_stderr; ++ int exitcode; ++ int nullinfd; ++ int nulloutfd; ++ ++ /* FIXME: Need to free memory allocated by prepare_spawn. */ ++ prog_argv = prepare_spawn (prog_argv); ++ ++ /* Save standard file handles of parent process. */ ++ if (null_stdin) ++ orig_stdin = dup_safer_noinherit (STDIN_FILENO); ++ if (null_stdout) ++ orig_stdout = dup_safer_noinherit (STDOUT_FILENO); ++ if (null_stderr) ++ orig_stderr = dup_safer_noinherit (STDERR_FILENO); ++ exitcode = -1; ++ ++ /* Create standard file handles of child process. */ ++ nullinfd = -1; ++ nulloutfd = -1; ++ if ((!null_stdin ++ || ((nullinfd = open ("NUL", O_RDONLY, 0)) >= 0 ++ && (nullinfd == STDIN_FILENO ++ || (dup2 (nullinfd, STDIN_FILENO) >= 0 ++ && close (nullinfd) >= 0)))) ++ && (!(null_stdout || null_stderr) ++ || ((nulloutfd = open ("NUL", O_RDWR, 0)) >= 0 ++ && (!null_stdout ++ || nulloutfd == STDOUT_FILENO ++ || dup2 (nulloutfd, STDOUT_FILENO) >= 0) ++ && (!null_stderr ++ || nulloutfd == STDERR_FILENO ++ || dup2 (nulloutfd, STDERR_FILENO) >= 0) ++ && ((null_stdout && nulloutfd == STDOUT_FILENO) ++ || (null_stderr && nulloutfd == STDERR_FILENO) ++ || close (nulloutfd) >= 0)))) ++ /* Use spawnvpe and pass the environment explicitly. This is needed if ++ the program has modified the environment using putenv() or [un]setenv(). ++ On Windows, programs have two environments, one in the "environment ++ block" of the process and managed through SetEnvironmentVariable(), and ++ one inside the process, in the location retrieved by the 'environ' ++ macro. When using spawnvp() without 'e', the child process inherits a ++ copy of the environment block - ignoring the effects of putenv() and ++ [un]setenv(). */ ++ { ++ exitcode = spawnvpe (P_WAIT, prog_path, (const char **) prog_argv, ++ (const char **) environ); ++ if (exitcode < 0 && errno == ENOEXEC) ++ { ++ /* prog is not a native executable. Try to execute it as a ++ shell script. Note that prepare_spawn() has already prepended ++ a hidden element "sh.exe" to prog_argv. */ ++ --prog_argv; ++ exitcode = spawnvpe (P_WAIT, prog_argv[0], (const char **) prog_argv, ++ (const char **) environ); ++ } ++ } ++ if (nulloutfd >= 0) ++ close (nulloutfd); ++ if (nullinfd >= 0) ++ close (nullinfd); ++ ++ /* Restore standard file handles of parent process. */ ++ if (null_stderr) ++ undup_safer_noinherit (orig_stderr, STDERR_FILENO); ++ if (null_stdout) ++ undup_safer_noinherit (orig_stdout, STDOUT_FILENO); ++ if (null_stdin) ++ undup_safer_noinherit (orig_stdin, STDIN_FILENO); ++ ++ if (termsigp != NULL) ++ *termsigp = 0; ++ ++ if (exitcode == -1) ++ { ++ if (exit_on_error || !null_stderr) ++ error (exit_on_error ? EXIT_FAILURE : 0, errno, ++ _("%s subprocess failed"), progname); ++ return 127; ++ } ++ ++ return exitcode; ++ ++#else ++ ++ /* Unix API. */ ++ /* Note about 127: Some errors during posix_spawnp() cause the function ++ posix_spawnp() to return an error code; some other errors cause the ++ subprocess to exit with return code 127. It is implementation ++ dependent which error is reported which way. We treat both cases as ++ equivalent. */ ++ sigset_t blocked_signals; ++ posix_spawn_file_actions_t actions; ++ bool actions_allocated; ++ posix_spawnattr_t attrs; ++ bool attrs_allocated; ++ int err; ++ pid_t child; ++ ++ if (slave_process) ++ { ++ sigprocmask (SIG_SETMASK, NULL, &blocked_signals); ++ block_fatal_signals (); ++ } ++ actions_allocated = false; ++ attrs_allocated = false; ++ if ((err = posix_spawn_file_actions_init (&actions)) != 0 ++ || (actions_allocated = true, ++ (null_stdin ++ && (err = posix_spawn_file_actions_addopen (&actions, ++ STDIN_FILENO, ++ "/dev/null", O_RDONLY, ++ 0)) ++ != 0) ++ || (null_stdout ++ && (err = posix_spawn_file_actions_addopen (&actions, ++ STDOUT_FILENO, ++ "/dev/null", O_RDWR, ++ 0)) ++ != 0) ++ || (null_stderr ++ && (err = posix_spawn_file_actions_addopen (&actions, ++ STDERR_FILENO, ++ "/dev/null", O_RDWR, ++ 0)) ++ != 0) ++ || (slave_process ++ && ((err = posix_spawnattr_init (&attrs)) != 0 ++ || (attrs_allocated = true, ++ (err = posix_spawnattr_setsigmask (&attrs, ++ &blocked_signals)) ++ != 0 ++ || (err = posix_spawnattr_setflags (&attrs, ++ POSIX_SPAWN_SETSIGMASK)) ++ != 0))) ++ || (err = posix_spawnp (&child, prog_path, &actions, ++ attrs_allocated ? &attrs : NULL, prog_argv, ++ environ)) ++ != 0)) ++ { ++ if (actions_allocated) ++ posix_spawn_file_actions_destroy (&actions); ++ if (attrs_allocated) ++ posix_spawnattr_destroy (&attrs); ++ if (slave_process) ++ unblock_fatal_signals (); ++ if (termsigp != NULL) ++ *termsigp = 0; ++ if (exit_on_error || !null_stderr) ++ error (exit_on_error ? EXIT_FAILURE : 0, err, ++ _("%s subprocess failed"), progname); ++ return 127; ++ } ++ posix_spawn_file_actions_destroy (&actions); ++ if (attrs_allocated) ++ posix_spawnattr_destroy (&attrs); ++ if (slave_process) ++ { ++ register_slave_subprocess (child); ++ unblock_fatal_signals (); ++ } ++ ++ return wait_subprocess (child, progname, ignore_sigpipe, null_stderr, ++ slave_process, exit_on_error, termsigp); ++ ++#endif ++} +diff -up patch-2.7.6/lib/execute.h.switch-from-fork-execlp-to-execute patch-2.7.6/lib/execute.h +--- patch-2.7.6/lib/execute.h.switch-from-fork-execlp-to-execute 2019-07-29 14:40:53.264464824 +0200 ++++ patch-2.7.6/lib/execute.h 2019-07-29 14:40:53.264464824 +0200 +@@ -0,0 +1,44 @@ ++/* Creation of autonomous subprocesses. ++ Copyright (C) 2001-2003, 2008-2018 Free Software Foundation, Inc. ++ Written by Bruno Haible , 2001. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#ifndef _EXECUTE_H ++#define _EXECUTE_H ++ ++#include ++ ++/* Execute a command, optionally redirecting any of the three standard file ++ descriptors to /dev/null. Return its exit code. ++ If it didn't terminate correctly, exit if exit_on_error is true, otherwise ++ return 127. ++ If ignore_sigpipe is true, consider a subprocess termination due to SIGPIPE ++ as equivalent to a success. This is suitable for processes whose only ++ purpose is to write to standard output. ++ If slave_process is true, the child process will be terminated when its ++ creator receives a catchable fatal signal. ++ If termsigp is not NULL, *termsig will be set to the signal that terminated ++ the subprocess (if supported by the platform: not on native Windows ++ platforms), otherwise 0. ++ It is recommended that no signal is blocked or ignored while execute() ++ is called. See pipe.h for the reason. */ ++extern int execute (const char *progname, ++ const char *prog_path, char **prog_argv, ++ bool ignore_sigpipe, ++ bool null_stdin, bool null_stdout, bool null_stderr, ++ bool slave_process, bool exit_on_error, ++ int *termsigp); ++ ++#endif /* _EXECUTE_H */ +diff -up patch-2.7.6/lib/fatal-signal.c.switch-from-fork-execlp-to-execute patch-2.7.6/lib/fatal-signal.c +--- patch-2.7.6/lib/fatal-signal.c.switch-from-fork-execlp-to-execute 2019-07-29 14:51:00.441882754 +0200 ++++ patch-2.7.6/lib/fatal-signal.c 2019-07-29 14:51:00.441882754 +0200 +@@ -0,0 +1,286 @@ ++/* Emergency actions in case of a fatal signal. ++ Copyright (C) 2003-2004, 2006-2018 Free Software Foundation, Inc. ++ Written by Bruno Haible , 2003. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++ ++#include ++ ++/* Specification. */ ++#include "fatal-signal.h" ++ ++#include ++#include ++#include ++#include ++ ++#include "sig-handler.h" ++#include "xalloc.h" ++ ++#define SIZEOF(a) (sizeof(a) / sizeof(a[0])) ++ ++/* ========================================================================= */ ++ ++ ++/* The list of fatal signals. ++ These are those signals whose default action is to terminate the process ++ without a core dump, except ++ SIGKILL - because it cannot be caught, ++ SIGALRM SIGUSR1 SIGUSR2 SIGPOLL SIGIO SIGLOST - because applications ++ often use them for their own purpose, ++ SIGPROF SIGVTALRM - because they are used for profiling, ++ SIGSTKFLT - because it is more similar to SIGFPE, SIGSEGV, SIGBUS, ++ SIGSYS - because it is more similar to SIGABRT, SIGSEGV, ++ SIGPWR - because it of too special use, ++ SIGRTMIN...SIGRTMAX - because they are reserved for application use. ++ plus ++ SIGXCPU, SIGXFSZ - because they are quite similar to SIGTERM. */ ++ ++static int fatal_signals[] = ++ { ++ /* ISO C 99 signals. */ ++#ifdef SIGINT ++ SIGINT, ++#endif ++#ifdef SIGTERM ++ SIGTERM, ++#endif ++ /* POSIX:2001 signals. */ ++#ifdef SIGHUP ++ SIGHUP, ++#endif ++#ifdef SIGPIPE ++ SIGPIPE, ++#endif ++ /* BSD signals. */ ++#ifdef SIGXCPU ++ SIGXCPU, ++#endif ++#ifdef SIGXFSZ ++ SIGXFSZ, ++#endif ++ /* Native Windows signals. */ ++#ifdef SIGBREAK ++ SIGBREAK, ++#endif ++ 0 ++ }; ++ ++#define num_fatal_signals (SIZEOF (fatal_signals) - 1) ++ ++/* Eliminate signals whose signal handler is SIG_IGN. */ ++ ++static void ++init_fatal_signals (void) ++{ ++ static bool fatal_signals_initialized = false; ++ if (!fatal_signals_initialized) ++ { ++ size_t i; ++ ++ for (i = 0; i < num_fatal_signals; i++) ++ { ++ struct sigaction action; ++ ++ if (sigaction (fatal_signals[i], NULL, &action) >= 0 ++ && get_handler (&action) == SIG_IGN) ++ fatal_signals[i] = -1; ++ } ++ ++ fatal_signals_initialized = true; ++ } ++} ++ ++ ++/* ========================================================================= */ ++ ++ ++typedef void (*action_t) (void); ++ ++/* Type of an entry in the actions array. ++ The 'action' field is accessed from within the fatal_signal_handler(), ++ therefore we mark it as 'volatile'. */ ++typedef struct ++{ ++ volatile action_t action; ++} ++actions_entry_t; ++ ++/* The registered cleanup actions. */ ++static actions_entry_t static_actions[32]; ++static actions_entry_t * volatile actions = static_actions; ++static sig_atomic_t volatile actions_count = 0; ++static size_t actions_allocated = SIZEOF (static_actions); ++ ++ ++/* The saved signal handlers. ++ Size 32 would not be sufficient: On HP-UX, SIGXCPU = 33, SIGXFSZ = 34. */ ++static struct sigaction saved_sigactions[64]; ++ ++ ++/* Uninstall the handlers. */ ++static void ++uninstall_handlers (void) ++{ ++ size_t i; ++ ++ for (i = 0; i < num_fatal_signals; i++) ++ if (fatal_signals[i] >= 0) ++ { ++ int sig = fatal_signals[i]; ++ if (saved_sigactions[sig].sa_handler == SIG_IGN) ++ saved_sigactions[sig].sa_handler = SIG_DFL; ++ sigaction (sig, &saved_sigactions[sig], NULL); ++ } ++} ++ ++ ++/* The signal handler. It gets called asynchronously. */ ++static void ++fatal_signal_handler (int sig) ++{ ++ for (;;) ++ { ++ /* Get the last registered cleanup action, in a reentrant way. */ ++ action_t action; ++ size_t n = actions_count; ++ if (n == 0) ++ break; ++ n--; ++ actions_count = n; ++ action = actions[n].action; ++ /* Execute the action. */ ++ action (); ++ } ++ ++ /* Now execute the signal's default action. ++ If the signal being delivered was blocked, the re-raised signal would be ++ delivered when this handler returns. But the way we install this handler, ++ no signal is blocked, and the re-raised signal is delivered already ++ during raise(). */ ++ uninstall_handlers (); ++ raise (sig); ++} ++ ++ ++/* Install the handlers. */ ++static void ++install_handlers (void) ++{ ++ size_t i; ++ struct sigaction action; ++ ++ action.sa_handler = &fatal_signal_handler; ++ /* If we get a fatal signal while executing fatal_signal_handler, enter ++ fatal_signal_handler recursively, since it is reentrant. Hence no ++ SA_RESETHAND. */ ++ action.sa_flags = SA_NODEFER; ++ sigemptyset (&action.sa_mask); ++ for (i = 0; i < num_fatal_signals; i++) ++ if (fatal_signals[i] >= 0) ++ { ++ int sig = fatal_signals[i]; ++ ++ if (!(sig < sizeof (saved_sigactions) / sizeof (saved_sigactions[0]))) ++ abort (); ++ sigaction (sig, &action, &saved_sigactions[sig]); ++ } ++} ++ ++ ++/* Register a cleanup function to be executed when a catchable fatal signal ++ occurs. */ ++void ++at_fatal_signal (action_t action) ++{ ++ static bool cleanup_initialized = false; ++ if (!cleanup_initialized) ++ { ++ init_fatal_signals (); ++ install_handlers (); ++ cleanup_initialized = true; ++ } ++ ++ if (actions_count == actions_allocated) ++ { ++ /* Extend the actions array. Note that we cannot use xrealloc(), ++ because then the cleanup() function could access an already ++ deallocated array. */ ++ actions_entry_t *old_actions = actions; ++ size_t old_actions_allocated = actions_allocated; ++ size_t new_actions_allocated = 2 * actions_allocated; ++ actions_entry_t *new_actions = ++ XNMALLOC (new_actions_allocated, actions_entry_t); ++ size_t k; ++ ++ /* Don't use memcpy() here, because memcpy takes non-volatile arguments ++ and is therefore not guaranteed to complete all memory stores before ++ the next statement. */ ++ for (k = 0; k < old_actions_allocated; k++) ++ new_actions[k] = old_actions[k]; ++ actions = new_actions; ++ actions_allocated = new_actions_allocated; ++ /* Now we can free the old actions array. */ ++ if (old_actions != static_actions) ++ free (old_actions); ++ } ++ /* The two uses of 'volatile' in the types above (and ISO C 99 section ++ 5.1.2.3.(5)) ensure that we increment the actions_count only after ++ the new action has been written to the memory location ++ actions[actions_count]. */ ++ actions[actions_count].action = action; ++ actions_count++; ++} ++ ++ ++/* ========================================================================= */ ++ ++ ++static sigset_t fatal_signal_set; ++ ++static void ++init_fatal_signal_set (void) ++{ ++ static bool fatal_signal_set_initialized = false; ++ if (!fatal_signal_set_initialized) ++ { ++ size_t i; ++ ++ init_fatal_signals (); ++ ++ sigemptyset (&fatal_signal_set); ++ for (i = 0; i < num_fatal_signals; i++) ++ if (fatal_signals[i] >= 0) ++ sigaddset (&fatal_signal_set, fatal_signals[i]); ++ ++ fatal_signal_set_initialized = true; ++ } ++} ++ ++/* Temporarily delay the catchable fatal signals. */ ++void ++block_fatal_signals (void) ++{ ++ init_fatal_signal_set (); ++ sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL); ++} ++ ++/* Stop delaying the catchable fatal signals. */ ++void ++unblock_fatal_signals (void) ++{ ++ init_fatal_signal_set (); ++ sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL); ++} +diff -up patch-2.7.6/lib/fatal-signal.h.switch-from-fork-execlp-to-execute patch-2.7.6/lib/fatal-signal.h +--- patch-2.7.6/lib/fatal-signal.h.switch-from-fork-execlp-to-execute 2019-07-29 14:51:09.977920729 +0200 ++++ patch-2.7.6/lib/fatal-signal.h 2019-07-29 14:51:09.977920729 +0200 +@@ -0,0 +1,76 @@ ++/* Emergency actions in case of a fatal signal. ++ Copyright (C) 2003-2004, 2009-2018 Free Software Foundation, Inc. ++ Written by Bruno Haible , 2003. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++ ++/* It is often useful to do some cleanup action when a usually fatal signal ++ terminates the process, like removing a temporary file or killing a ++ subprocess that may be stuck waiting for a device, pipe or network input. ++ Such signals are SIGHUP, SIGINT, SIGPIPE, SIGTERM, and possibly others. ++ The limitation of this facility is that it cannot work for SIGKILL. ++ ++ Signals with a SIG_IGN handler are considered to be non-fatal. The ++ functions in this file assume that when a SIG_IGN handler is installed ++ for a signal, it was installed before any functions in this file were ++ called and it stays so for the whole lifetime of the process. */ ++ ++/* Register a cleanup function to be executed when a catchable fatal signal ++ occurs. ++ ++ Restrictions for the cleanup function: ++ - The cleanup function can do all kinds of system calls. ++ - It can also access application dependent memory locations and data ++ structures provided they are in a consistent state. One way to ensure ++ this is through block_fatal_signals()/unblock_fatal_signals(), see ++ below. Another - more tricky - way to ensure this is the careful use ++ of 'volatile'. ++ However, ++ - malloc() and similarly complex facilities are not safe to be called ++ because they are not guaranteed to be in a consistent state. ++ - Also, the cleanup function must not block the catchable fatal signals ++ and leave them blocked upon return. ++ ++ The cleanup function is executed asynchronously. It is unspecified ++ whether during its execution the catchable fatal signals are blocked ++ or not. */ ++extern void at_fatal_signal (void (*function) (void)); ++ ++ ++/* Sometimes it is necessary to block the usually fatal signals while the ++ data structures being accessed by the cleanup action are being built or ++ reorganized. This is the case, for example, when a temporary file or ++ directory is created through mkstemp() or mkdtemp(), because these ++ functions create the temporary file or directory _before_ returning its ++ name to the application. */ ++ ++/* Temporarily delay the catchable fatal signals. ++ The signals will be blocked (= delayed) until the next call to ++ unblock_fatal_signals(). If the signals are already blocked, a further ++ call to block_fatal_signals() has no effect. */ ++extern void block_fatal_signals (void); ++ ++/* Stop delaying the catchable fatal signals. */ ++extern void unblock_fatal_signals (void); ++ ++ ++#ifdef __cplusplus ++} ++#endif +diff -up patch-2.7.6/lib/gnulib.mk.switch-from-fork-execlp-to-execute patch-2.7.6/lib/gnulib.mk +--- patch-2.7.6/lib/gnulib.mk.switch-from-fork-execlp-to-execute 2018-02-03 14:31:15.000000000 +0100 ++++ patch-2.7.6/lib/gnulib.mk 2019-07-29 14:49:33.437536285 +0200 +@@ -21,7 +21,7 @@ + # the same distribution terms as the rest of that program. + # + # Generated by gnulib-tool. +-# Reproduce by: gnulib-tool --import --local-dir=gl --lib=libpatch --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --makefile-name=gnulib.mk --no-conditional-dependencies --no-libtool --macro-prefix=gl argmatch backupfile clock-time diffseq dirname dup2 errno exitfail extensions faccessat fchmodat fchownat fcntl-h fstatat full-write getdate getopt-gnu gettime git-version-gen gitlog-to-changelog gnupload hash ignore-value intprops largefile linked-list maintainer-makefile malloc manywarnings memchr minmax mkdirat nstrftime openat progname quotearg readlinkat realloc renameat setenv signal size_max ssize_t stat-time stdbool stdlib symlinkat sys_stat tempname time unistd unlinkat update-copyright utimensat verror xalloc xlist xmemdup0 ++# Reproduce by: gnulib-tool --import --local-dir=gl --lib=libpatch --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --makefile-name=gnulib.mk --no-conditional-dependencies --no-libtool --macro-prefix=gl argmatch backupfile clock-time diffseq dirname dup2 errno execute exitfail extensions faccessat fchmodat fchownat fcntl-h fstatat full-write getdate getopt-gnu gettime git-version-gen gitlog-to-changelog gnupload hash ignore-value intprops largefile linked-list maintainer-makefile malloc manywarnings memchr minmax mkdirat nstrftime openat progname quotearg readlinkat realloc renameat setenv signal size_max ssize_t stat-time stdbool stdlib symlinkat sys_stat tempname time unistd unlinkat update-copyright utimensat verror xalloc xlist xmemdup0 wait-process fatal-signal + + + MOSTLYCLEANFILES += core *.stackdump +@@ -378,6 +378,12 @@ EXTRA_libpatch_a_SOURCES += euidaccess.c + + ## end gnulib module euidaccess + ++## begin gnulib module execute ++ ++libpatch_a_SOURCES += execute.h execute.c w32spawn.h ++ ++## end gnulib module execute ++ + ## begin gnulib module exitfail + + libpatch_a_SOURCES += exitfail.c +@@ -2481,6 +2487,28 @@ libpatch_a_SOURCES += verror.h verror.c + + ## end gnulib module verror + ++## begin gnulib module wait-process ++ ++libpatch_a_SOURCES += wait-process.h wait-process.c ++ ++## end gnulib module wait-process ++ ++## begin gnulib module fatal-signal ++ ++libpatch_a_SOURCES += fatal-signal.h fatal-signal.c ++ ++## end gnulib module fatal-signal ++ ++## begin gnulib module sigaction ++ ++libpatch_a_SOURCES += sig-handler.c ++ ++EXTRA_DIST += sig-handler.h sigaction.c ++ ++EXTRA_libpatch_a_SOURCES += sigaction.c ++ ++## end gnulib module sigaction ++ + ## begin gnulib module wchar + + BUILT_SOURCES += wchar.h +@@ -2694,6 +2722,7 @@ EXTRA_libpatch_a_SOURCES += xmemdup0.c + + ## end gnulib module xmemdup0 + ++ + ## begin gnulib module xsize + + libpatch_a_SOURCES += xsize.h xsize.c +diff -up patch-2.7.6/lib/sigaction.c.switch-from-fork-execlp-to-execute patch-2.7.6/lib/sigaction.c +--- patch-2.7.6/lib/sigaction.c.switch-from-fork-execlp-to-execute 2019-07-29 14:50:31.833768833 +0200 ++++ patch-2.7.6/lib/sigaction.c 2019-07-29 14:50:31.833768833 +0200 +@@ -0,0 +1,204 @@ ++/* POSIX compatible signal blocking. ++ Copyright (C) 2008-2018 Free Software Foundation, Inc. ++ Written by Eric Blake , 2008. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#include ++ ++/* Specification. */ ++#include ++ ++#include ++#include ++#include ++ ++/* This implementation of sigaction is tailored to native Windows behavior: ++ signal() has SysV semantics (ie. the handler is uninstalled before ++ it is invoked). This is an inherent data race if an asynchronous ++ signal is sent twice in a row before we can reinstall our handler, ++ but there's nothing we can do about it. Meanwhile, sigprocmask() ++ is not present, and while we can use the gnulib replacement to ++ provide critical sections, it too suffers from potential data races ++ in the face of an ill-timed asynchronous signal. And we compound ++ the situation by reading static storage in a signal handler, which ++ POSIX warns is not generically async-signal-safe. Oh well. ++ ++ Additionally: ++ - We don't implement SA_NOCLDSTOP or SA_NOCLDWAIT, because SIGCHLD ++ is not defined. ++ - We don't implement SA_ONSTACK, because sigaltstack() is not present. ++ - We ignore SA_RESTART, because blocking native Windows API calls are ++ not interrupted anyway when an asynchronous signal occurs, and the ++ MSVCRT runtime never sets errno to EINTR. ++ - We don't implement SA_SIGINFO because it is impossible to do so ++ portably. ++ ++ POSIX states that an application should not mix signal() and ++ sigaction(). We support the use of signal() within the gnulib ++ sigprocmask() substitute, but all other application code linked ++ with this module should stick with only sigaction(). */ ++ ++/* Check some of our assumptions. */ ++#if defined SIGCHLD || defined HAVE_SIGALTSTACK || defined HAVE_SIGINTERRUPT ++# error "Revisit the assumptions made in the sigaction module" ++#endif ++ ++/* Out-of-range substitutes make a good fallback for uncatchable ++ signals. */ ++#ifndef SIGKILL ++# define SIGKILL (-1) ++#endif ++#ifndef SIGSTOP ++# define SIGSTOP (-1) ++#endif ++ ++/* On native Windows, as of 2008, the signal SIGABRT_COMPAT is an alias ++ for the signal SIGABRT. Only one signal handler is stored for both ++ SIGABRT and SIGABRT_COMPAT. SIGABRT_COMPAT is not a signal of its own. */ ++#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ ++# undef SIGABRT_COMPAT ++# define SIGABRT_COMPAT 6 ++#endif ++ ++/* A signal handler. */ ++typedef void (*handler_t) (int signal); ++ ++/* Set of current actions. If sa_handler for an entry is NULL, then ++ that signal is not currently handled by the sigaction handler. */ ++static struct sigaction volatile action_array[NSIG] /* = 0 */; ++ ++/* Signal handler that is installed for signals. */ ++static void ++sigaction_handler (int sig) ++{ ++ handler_t handler; ++ sigset_t mask; ++ sigset_t oldmask; ++ int saved_errno = errno; ++ if (sig < 0 || NSIG <= sig || !action_array[sig].sa_handler) ++ { ++ /* Unexpected situation; be careful to avoid recursive abort. */ ++ if (sig == SIGABRT) ++ signal (SIGABRT, SIG_DFL); ++ abort (); ++ } ++ ++ /* Reinstall the signal handler when required; otherwise update the ++ bookkeeping so that the user's handler may call sigaction and get ++ accurate results. We know the signal isn't currently blocked, or ++ we wouldn't be in its handler, therefore we know that we are not ++ interrupting a sigaction() call. There is a race where any ++ asynchronous instance of the same signal occurring before we ++ reinstall the handler will trigger the default handler; oh ++ well. */ ++ handler = action_array[sig].sa_handler; ++ if ((action_array[sig].sa_flags & SA_RESETHAND) == 0) ++ signal (sig, sigaction_handler); ++ else ++ action_array[sig].sa_handler = NULL; ++ ++ /* Block appropriate signals. */ ++ mask = action_array[sig].sa_mask; ++ if ((action_array[sig].sa_flags & SA_NODEFER) == 0) ++ sigaddset (&mask, sig); ++ sigprocmask (SIG_BLOCK, &mask, &oldmask); ++ ++ /* Invoke the user's handler, then restore prior mask. */ ++ errno = saved_errno; ++ handler (sig); ++ saved_errno = errno; ++ sigprocmask (SIG_SETMASK, &oldmask, NULL); ++ errno = saved_errno; ++} ++ ++/* Change and/or query the action that will be taken on delivery of ++ signal SIG. If not NULL, ACT describes the new behavior. If not ++ NULL, OACT is set to the prior behavior. Return 0 on success, or ++ set errno and return -1 on failure. */ ++int ++sigaction (int sig, const struct sigaction *restrict act, ++ struct sigaction *restrict oact) ++{ ++ sigset_t mask; ++ sigset_t oldmask; ++ int saved_errno; ++ ++ if (sig < 0 || NSIG <= sig || sig == SIGKILL || sig == SIGSTOP ++ || (act && act->sa_handler == SIG_ERR)) ++ { ++ errno = EINVAL; ++ return -1; ++ } ++ ++#ifdef SIGABRT_COMPAT ++ if (sig == SIGABRT_COMPAT) ++ sig = SIGABRT; ++#endif ++ ++ /* POSIX requires sigaction() to be async-signal-safe. In other ++ words, if an asynchronous signal can occur while we are anywhere ++ inside this function, the user's handler could then call ++ sigaction() recursively and expect consistent results. We meet ++ this rule by using sigprocmask to block all signals before ++ modifying any data structure that could be read from a signal ++ handler; this works since we know that the gnulib sigprocmask ++ replacement does not try to use sigaction() from its handler. */ ++ if (!act && !oact) ++ return 0; ++ sigfillset (&mask); ++ sigprocmask (SIG_BLOCK, &mask, &oldmask); ++ if (oact) ++ { ++ if (action_array[sig].sa_handler) ++ *oact = action_array[sig]; ++ else ++ { ++ /* Safe to change the handler at will here, since all ++ signals are currently blocked. */ ++ oact->sa_handler = signal (sig, SIG_DFL); ++ if (oact->sa_handler == SIG_ERR) ++ goto failure; ++ signal (sig, oact->sa_handler); ++ oact->sa_flags = SA_RESETHAND | SA_NODEFER; ++ sigemptyset (&oact->sa_mask); ++ } ++ } ++ ++ if (act) ++ { ++ /* Safe to install the handler before updating action_array, ++ since all signals are currently blocked. */ ++ if (act->sa_handler == SIG_DFL || act->sa_handler == SIG_IGN) ++ { ++ if (signal (sig, act->sa_handler) == SIG_ERR) ++ goto failure; ++ action_array[sig].sa_handler = NULL; ++ } ++ else ++ { ++ if (signal (sig, sigaction_handler) == SIG_ERR) ++ goto failure; ++ action_array[sig] = *act; ++ } ++ } ++ sigprocmask (SIG_SETMASK, &oldmask, NULL); ++ return 0; ++ ++ failure: ++ saved_errno = errno; ++ sigprocmask (SIG_SETMASK, &oldmask, NULL); ++ errno = saved_errno; ++ return -1; ++} +diff -up patch-2.7.6/lib/sig-handler.c.switch-from-fork-execlp-to-execute patch-2.7.6/lib/sig-handler.c +--- patch-2.7.6/lib/sig-handler.c.switch-from-fork-execlp-to-execute 2019-07-29 14:50:17.265710820 +0200 ++++ patch-2.7.6/lib/sig-handler.c 2019-07-29 14:48:19.707242671 +0200 +@@ -0,0 +1,3 @@ ++#include ++#define SIG_HANDLER_INLINE _GL_EXTERN_INLINE ++#include "sig-handler.h" +diff -up patch-2.7.6/lib/sig-handler.h.switch-from-fork-execlp-to-execute patch-2.7.6/lib/sig-handler.h +--- patch-2.7.6/lib/sig-handler.h.switch-from-fork-execlp-to-execute 2019-07-29 14:50:12.249690845 +0200 ++++ patch-2.7.6/lib/sig-handler.h 2019-07-29 14:48:23.099256180 +0200 +@@ -0,0 +1,54 @@ ++/* Convenience declarations when working with . ++ ++ Copyright (C) 2008-2018 Free Software Foundation, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#ifndef _GL_SIG_HANDLER_H ++#define _GL_SIG_HANDLER_H ++ ++#include ++ ++#ifndef _GL_INLINE_HEADER_BEGIN ++ #error "Please include config.h first." ++#endif ++_GL_INLINE_HEADER_BEGIN ++#ifndef SIG_HANDLER_INLINE ++# define SIG_HANDLER_INLINE _GL_INLINE ++#endif ++ ++/* Convenience type when working with signal handlers. */ ++typedef void (*sa_handler_t) (int); ++ ++/* Return the handler of a signal, as a sa_handler_t value regardless ++ of its true type. The resulting function can be compared to ++ special values like SIG_IGN but it is not portable to call it. */ ++SIG_HANDLER_INLINE sa_handler_t _GL_ATTRIBUTE_PURE ++get_handler (struct sigaction const *a) ++{ ++#ifdef SA_SIGINFO ++ /* POSIX says that special values like SIG_IGN can only occur when ++ action.sa_flags does not contain SA_SIGINFO. But in Linux 2.4, ++ for example, sa_sigaction and sa_handler are aliases and a signal ++ is ignored if sa_sigaction (after casting) equals SIG_IGN. So ++ use (and cast) sa_sigaction in that case. */ ++ if (a->sa_flags & SA_SIGINFO) ++ return (sa_handler_t) a->sa_sigaction; ++#endif ++ return a->sa_handler; ++} ++ ++_GL_INLINE_HEADER_END ++ ++#endif /* _GL_SIG_HANDLER_H */ +diff -up patch-2.7.6/lib/w32spawn.h.switch-from-fork-execlp-to-execute patch-2.7.6/lib/w32spawn.h +--- patch-2.7.6/lib/w32spawn.h.switch-from-fork-execlp-to-execute 2019-07-29 14:40:53.265464828 +0200 ++++ patch-2.7.6/lib/w32spawn.h 2019-07-29 14:40:53.265464828 +0200 +@@ -0,0 +1,233 @@ ++/* Auxiliary functions for the creation of subprocesses. Native Windows API. ++ Copyright (C) 2001, 2003-2018 Free Software Foundation, Inc. ++ Written by Bruno Haible , 2003. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#ifndef __KLIBC__ ++/* Get declarations of the native Windows API functions. */ ++# define WIN32_LEAN_AND_MEAN ++# include ++#endif ++ ++/* Get _open_osfhandle(). */ ++#include ++ ++#include ++#include ++#include ++#include ++ ++/* Get _get_osfhandle(). */ ++# if GNULIB_MSVC_NOTHROW ++# include "msvc-nothrow.h" ++# else ++# include ++# endif ++ ++#include "cloexec.h" ++#include "xalloc.h" ++ ++/* Duplicates a file handle, making the copy uninheritable. ++ Returns -1 for a file handle that is equivalent to closed. */ ++static int ++dup_noinherit (int fd) ++{ ++ fd = dup_cloexec (fd); ++ if (fd < 0 && errno == EMFILE) ++ error (EXIT_FAILURE, errno, _("_open_osfhandle failed")); ++ ++ return fd; ++} ++ ++/* Returns a file descriptor equivalent to FD, except that the resulting file ++ descriptor is none of STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO. ++ FD must be open and non-inheritable. The result will be non-inheritable as ++ well. ++ If FD < 0, FD itself is returned. */ ++static int ++fd_safer_noinherit (int fd) ++{ ++ if (STDIN_FILENO <= fd && fd <= STDERR_FILENO) ++ { ++ /* The recursion depth is at most 3. */ ++ int nfd = fd_safer_noinherit (dup_noinherit (fd)); ++ int saved_errno = errno; ++ close (fd); ++ errno = saved_errno; ++ return nfd; ++ } ++ return fd; ++} ++ ++/* Duplicates a file handle, making the copy uninheritable and ensuring the ++ result is none of STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO. ++ Returns -1 for a file handle that is equivalent to closed. */ ++static int ++dup_safer_noinherit (int fd) ++{ ++ return fd_safer_noinherit (dup_noinherit (fd)); ++} ++ ++/* Undoes the effect of TEMPFD = dup_safer_noinherit (ORIGFD); */ ++static void ++undup_safer_noinherit (int tempfd, int origfd) ++{ ++ if (tempfd >= 0) ++ { ++ if (dup2 (tempfd, origfd) < 0) ++ error (EXIT_FAILURE, errno, _("cannot restore fd %d: dup2 failed"), ++ origfd); ++ close (tempfd); ++ } ++ else ++ { ++ /* origfd was closed or open to no handle at all. Set it to a closed ++ state. This is (nearly) equivalent to the original state. */ ++ close (origfd); ++ } ++} ++ ++/* Prepares an argument vector before calling spawn(). ++ Note that spawn() does not by itself call the command interpreter ++ (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : ++ ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); ++ GetVersionEx(&v); ++ v.dwPlatformId == VER_PLATFORM_WIN32_NT; ++ }) ? "cmd.exe" : "command.com"). ++ Instead it simply concatenates the arguments, separated by ' ', and calls ++ CreateProcess(). We must quote the arguments since Windows CreateProcess() ++ interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a ++ special way: ++ - Space and tab are interpreted as delimiters. They are not treated as ++ delimiters if they are surrounded by double quotes: "...". ++ - Unescaped double quotes are removed from the input. Their only effect is ++ that within double quotes, space and tab are treated like normal ++ characters. ++ - Backslashes not followed by double quotes are not special. ++ - But 2*n+1 backslashes followed by a double quote become ++ n backslashes followed by a double quote (n >= 0): ++ \" -> " ++ \\\" -> \" ++ \\\\\" -> \\" ++ - '*', '?' characters may get expanded through wildcard expansion in the ++ callee: By default, in the callee, the initialization code before main() ++ takes the result of GetCommandLine(), wildcard-expands it, and passes it ++ to main(). The exceptions to this rule are: ++ - programs that inspect GetCommandLine() and ignore argv, ++ - mingw programs that have a global variable 'int _CRT_glob = 0;', ++ - Cygwin programs, when invoked from a Cygwin program. ++ */ ++#ifndef __KLIBC__ ++# define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037*?" ++# define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" ++#else ++# define SHELL_SPECIAL_CHARS "" ++# define SHELL_SPACE_CHARS "" ++#endif ++static char ** ++prepare_spawn (char **argv) ++{ ++ size_t argc; ++ char **new_argv; ++ size_t i; ++ ++ /* Count number of arguments. */ ++ for (argc = 0; argv[argc] != NULL; argc++) ++ ; ++ ++ /* Allocate new argument vector. */ ++ new_argv = XNMALLOC (1 + argc + 1, char *); ++ ++ /* Add an element upfront that can be used when argv[0] turns out to be a ++ script, not a program. ++ On Unix, this would be "/bin/sh". On native Windows, "sh" is actually ++ "sh.exe". We have to omit the directory part and rely on the search in ++ PATH, because the mingw "mount points" are not visible inside Windows ++ CreateProcess(). */ ++ *new_argv++ = "sh.exe"; ++ ++ /* Put quoted arguments into the new argument vector. */ ++ for (i = 0; i < argc; i++) ++ { ++ const char *string = argv[i]; ++ ++ if (string[0] == '\0') ++ new_argv[i] = xstrdup ("\"\""); ++ else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) ++ { ++ bool quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); ++ size_t length; ++ unsigned int backslashes; ++ const char *s; ++ char *quoted_string; ++ char *p; ++ ++ length = 0; ++ backslashes = 0; ++ if (quote_around) ++ length++; ++ for (s = string; *s != '\0'; s++) ++ { ++ char c = *s; ++ if (c == '"') ++ length += backslashes + 1; ++ length++; ++ if (c == '\\') ++ backslashes++; ++ else ++ backslashes = 0; ++ } ++ if (quote_around) ++ length += backslashes + 1; ++ ++ quoted_string = (char *) xmalloc (length + 1); ++ ++ p = quoted_string; ++ backslashes = 0; ++ if (quote_around) ++ *p++ = '"'; ++ for (s = string; *s != '\0'; s++) ++ { ++ char c = *s; ++ if (c == '"') ++ { ++ unsigned int j; ++ for (j = backslashes + 1; j > 0; j--) ++ *p++ = '\\'; ++ } ++ *p++ = c; ++ if (c == '\\') ++ backslashes++; ++ else ++ backslashes = 0; ++ } ++ if (quote_around) ++ { ++ unsigned int j; ++ for (j = backslashes; j > 0; j--) ++ *p++ = '\\'; ++ *p++ = '"'; ++ } ++ *p = '\0'; ++ ++ new_argv[i] = quoted_string; ++ } ++ else ++ new_argv[i] = (char *) string; ++ } ++ new_argv[argc] = NULL; ++ ++ return new_argv; ++} +diff -up patch-2.7.6/lib/wait-process.c.switch-from-fork-execlp-to-execute patch-2.7.6/lib/wait-process.c +--- patch-2.7.6/lib/wait-process.c.switch-from-fork-execlp-to-execute 2019-07-29 14:50:49.937840928 +0200 ++++ patch-2.7.6/lib/wait-process.c 2019-07-29 14:45:17.196515863 +0200 +@@ -0,0 +1,361 @@ ++/* Waiting for a subprocess to finish. ++ Copyright (C) 2001-2003, 2005-2018 Free Software Foundation, Inc. ++ Written by Bruno Haible , 2001. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++ ++#include ++ ++/* Specification. */ ++#include "wait-process.h" ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "error.h" ++#include "fatal-signal.h" ++#include "xalloc.h" ++#include "gettext.h" ++ ++#define _(str) gettext (str) ++ ++#define SIZEOF(a) (sizeof(a) / sizeof(a[0])) ++ ++ ++#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ ++ ++# define WIN32_LEAN_AND_MEAN ++# include ++ ++/* The return value of spawnvp() is really a process handle as returned ++ by CreateProcess(). Therefore we can kill it using TerminateProcess. */ ++# define kill(pid,sig) TerminateProcess ((HANDLE) (pid), sig) ++ ++#endif ++ ++ ++/* Type of an entry in the slaves array. ++ The 'used' bit determines whether this entry is currently in use. ++ (If pid_t was an atomic type like sig_atomic_t, we could just set the ++ 'child' field to 0 when unregistering a slave process, and wouldn't need ++ the 'used' field.) ++ The 'used' and 'child' fields are accessed from within the cleanup_slaves() ++ action, therefore we mark them as 'volatile'. */ ++typedef struct ++{ ++ volatile sig_atomic_t used; ++ volatile pid_t child; ++} ++slaves_entry_t; ++ ++/* The registered slave subprocesses. */ ++static slaves_entry_t static_slaves[32]; ++static slaves_entry_t * volatile slaves = static_slaves; ++static sig_atomic_t volatile slaves_count = 0; ++static size_t slaves_allocated = SIZEOF (static_slaves); ++ ++/* The termination signal for slave subprocesses. ++ 2003-10-07: Terminator becomes Governator. */ ++#ifdef SIGHUP ++# define TERMINATOR SIGHUP ++#else ++# define TERMINATOR SIGTERM ++#endif ++ ++/* The cleanup action. It gets called asynchronously. */ ++static void ++cleanup_slaves (void) ++{ ++ for (;;) ++ { ++ /* Get the last registered slave. */ ++ size_t n = slaves_count; ++ if (n == 0) ++ break; ++ n--; ++ slaves_count = n; ++ /* Skip unused entries in the slaves array. */ ++ if (slaves[n].used) ++ { ++ pid_t slave = slaves[n].child; ++ ++ /* Kill the slave. */ ++ kill (slave, TERMINATOR); ++ } ++ } ++} ++ ++/* Register a subprocess as being a slave process. This means that the ++ subprocess will be terminated when its creator receives a catchable fatal ++ signal or exits normally. Registration ends when wait_subprocess() ++ notices that the subprocess has exited. */ ++void ++register_slave_subprocess (pid_t child) ++{ ++ static bool cleanup_slaves_registered = false; ++ if (!cleanup_slaves_registered) ++ { ++ atexit (cleanup_slaves); ++ at_fatal_signal (cleanup_slaves); ++ cleanup_slaves_registered = true; ++ } ++ ++ /* Try to store the new slave in an unused entry of the slaves array. */ ++ { ++ slaves_entry_t *s = slaves; ++ slaves_entry_t *s_end = s + slaves_count; ++ ++ for (; s < s_end; s++) ++ if (!s->used) ++ { ++ /* The two uses of 'volatile' in the slaves_entry_t type above ++ (and ISO C 99 section 5.1.2.3.(5)) ensure that we mark the ++ entry as used only after the child pid has been written to the ++ memory location s->child. */ ++ s->child = child; ++ s->used = 1; ++ return; ++ } ++ } ++ ++ if (slaves_count == slaves_allocated) ++ { ++ /* Extend the slaves array. Note that we cannot use xrealloc(), ++ because then the cleanup_slaves() function could access an already ++ deallocated array. */ ++ slaves_entry_t *old_slaves = slaves; ++ size_t new_slaves_allocated = 2 * slaves_allocated; ++ slaves_entry_t *new_slaves = ++ (slaves_entry_t *) ++ malloc (new_slaves_allocated * sizeof (slaves_entry_t)); ++ if (new_slaves == NULL) ++ { ++ /* xalloc_die() will call exit() which will invoke cleanup_slaves(). ++ Additionally we need to kill child, because it's not yet among ++ the slaves list. */ ++ kill (child, TERMINATOR); ++ xalloc_die (); ++ } ++ memcpy (new_slaves, old_slaves, ++ slaves_allocated * sizeof (slaves_entry_t)); ++ slaves = new_slaves; ++ slaves_allocated = new_slaves_allocated; ++ /* Now we can free the old slaves array. */ ++ if (old_slaves != static_slaves) ++ free (old_slaves); ++ } ++ /* The three uses of 'volatile' in the types above (and ISO C 99 section ++ 5.1.2.3.(5)) ensure that we increment the slaves_count only after the ++ new slave and its 'used' bit have been written to the memory locations ++ that make up slaves[slaves_count]. */ ++ slaves[slaves_count].child = child; ++ slaves[slaves_count].used = 1; ++ slaves_count++; ++} ++ ++/* Unregister a child from the list of slave subprocesses. */ ++static void ++unregister_slave_subprocess (pid_t child) ++{ ++ /* The easiest way to remove an entry from a list that can be used by ++ an asynchronous signal handler is just to mark it as unused. For this, ++ we rely on sig_atomic_t. */ ++ slaves_entry_t *s = slaves; ++ slaves_entry_t *s_end = s + slaves_count; ++ ++ for (; s < s_end; s++) ++ if (s->used && s->child == child) ++ s->used = 0; ++} ++ ++ ++/* Wait for a subprocess to finish. Return its exit code. ++ If it didn't terminate correctly, exit if exit_on_error is true, otherwise ++ return 127. */ ++int ++wait_subprocess (pid_t child, const char *progname, ++ bool ignore_sigpipe, bool null_stderr, ++ bool slave_process, bool exit_on_error, ++ int *termsigp) ++{ ++#if HAVE_WAITID && defined WNOWAIT && 0 ++ /* Commented out because waitid() without WEXITED and with WNOWAIT doesn't ++ work: On Solaris 7 and OSF/1 4.0, it returns -1 and sets errno = ECHILD, ++ and on HP-UX 10.20 it just hangs. */ ++ /* Use of waitid() with WNOWAIT avoids a race condition: If slave_process is ++ true, and this process sleeps a very long time between the return from ++ waitpid() and the execution of unregister_slave_subprocess(), and ++ meanwhile another process acquires the same PID as child, and then - still ++ before unregister_slave_subprocess() - this process gets a fatal signal, ++ it would kill the other totally unrelated process. */ ++ siginfo_t info; ++ ++ if (termsigp != NULL) ++ *termsigp = 0; ++ for (;;) ++ { ++ if (waitid (P_PID, child, &info, WEXITED | (slave_process ? WNOWAIT : 0)) ++ < 0) ++ { ++# ifdef EINTR ++ if (errno == EINTR) ++ continue; ++# endif ++ if (exit_on_error || !null_stderr) ++ error (exit_on_error ? EXIT_FAILURE : 0, errno, ++ _("%s subprocess"), progname); ++ return 127; ++ } ++ ++ /* info.si_code is set to one of CLD_EXITED, CLD_KILLED, CLD_DUMPED, ++ CLD_TRAPPED, CLD_STOPPED, CLD_CONTINUED. Loop until the program ++ terminates. */ ++ if (info.si_code == CLD_EXITED ++ || info.si_code == CLD_KILLED || info.si_code == CLD_DUMPED) ++ break; ++ } ++ ++ /* The child process has exited or was signalled. */ ++ ++ if (slave_process) ++ { ++ /* Unregister the child from the list of slave subprocesses, so that ++ later, when we exit, we don't kill a totally unrelated process which ++ may have acquired the same pid. */ ++ unregister_slave_subprocess (child); ++ ++ /* Now remove the zombie from the process list. */ ++ for (;;) ++ { ++ if (waitid (P_PID, child, &info, WEXITED) < 0) ++ { ++# ifdef EINTR ++ if (errno == EINTR) ++ continue; ++# endif ++ if (exit_on_error || !null_stderr) ++ error (exit_on_error ? EXIT_FAILURE : 0, errno, ++ _("%s subprocess"), progname); ++ return 127; ++ } ++ break; ++ } ++ } ++ ++ switch (info.si_code) ++ { ++ case CLD_KILLED: ++ case CLD_DUMPED: ++ if (termsigp != NULL) ++ *termsigp = info.si_status; /* TODO: or info.si_signo? */ ++# ifdef SIGPIPE ++ if (info.si_status == SIGPIPE && ignore_sigpipe) ++ return 0; ++# endif ++ if (exit_on_error || (!null_stderr && termsigp == NULL)) ++ error (exit_on_error ? EXIT_FAILURE : 0, 0, ++ _("%s subprocess got fatal signal %d"), ++ progname, info.si_status); ++ return 127; ++ case CLD_EXITED: ++ if (info.si_status == 127) ++ { ++ if (exit_on_error || !null_stderr) ++ error (exit_on_error ? EXIT_FAILURE : 0, 0, ++ _("%s subprocess failed"), progname); ++ return 127; ++ } ++ return info.si_status; ++ default: ++ abort (); ++ } ++#else ++ /* waitpid() is just as portable as wait() nowadays. */ ++ int status; ++ ++ if (termsigp != NULL) ++ *termsigp = 0; ++ status = 0; ++ for (;;) ++ { ++ int result = waitpid (child, &status, 0); ++ ++ if (result != child) ++ { ++# ifdef EINTR ++ if (errno == EINTR) ++ continue; ++# endif ++# if 0 /* defined ECHILD */ ++ if (errno == ECHILD) ++ { ++ /* Child process nonexistent?! Assume it terminated ++ successfully. */ ++ status = 0; ++ break; ++ } ++# endif ++ if (exit_on_error || !null_stderr) ++ error (exit_on_error ? EXIT_FAILURE : 0, errno, ++ _("%s subprocess"), progname); ++ return 127; ++ } ++ ++ /* One of WIFSIGNALED (status), WIFEXITED (status), WIFSTOPPED (status) ++ must always be true, since we did not specify WCONTINUED in the ++ waitpid() call. Loop until the program terminates. */ ++ if (!WIFSTOPPED (status)) ++ break; ++ } ++ ++ /* The child process has exited or was signalled. */ ++ ++ if (slave_process) ++ /* Unregister the child from the list of slave subprocesses, so that ++ later, when we exit, we don't kill a totally unrelated process which ++ may have acquired the same pid. */ ++ unregister_slave_subprocess (child); ++ ++ if (WIFSIGNALED (status)) ++ { ++ if (termsigp != NULL) ++ *termsigp = WTERMSIG (status); ++# ifdef SIGPIPE ++ if (WTERMSIG (status) == SIGPIPE && ignore_sigpipe) ++ return 0; ++# endif ++ if (exit_on_error || (!null_stderr && termsigp == NULL)) ++ error (exit_on_error ? EXIT_FAILURE : 0, 0, ++ _("%s subprocess got fatal signal %d"), ++ progname, (int) WTERMSIG (status)); ++ return 127; ++ } ++ if (!WIFEXITED (status)) ++ abort (); ++ if (WEXITSTATUS (status) == 127) ++ { ++ if (exit_on_error || !null_stderr) ++ error (exit_on_error ? EXIT_FAILURE : 0, 0, ++ _("%s subprocess failed"), progname); ++ return 127; ++ } ++ return WEXITSTATUS (status); ++#endif ++} +diff -up patch-2.7.6/lib/wait-process.h.switch-from-fork-execlp-to-execute patch-2.7.6/lib/wait-process.h +--- patch-2.7.6/lib/wait-process.h.switch-from-fork-execlp-to-execute 2019-07-29 14:50:46.505827261 +0200 ++++ patch-2.7.6/lib/wait-process.h 2019-07-29 14:45:20.715529876 +0200 +@@ -0,0 +1,74 @@ ++/* Waiting for a subprocess to finish. ++ Copyright (C) 2001-2003, 2006, 2008-2018 Free Software Foundation, Inc. ++ Written by Bruno Haible , 2001. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#ifndef _WAIT_PROCESS_H ++#define _WAIT_PROCESS_H ++ ++/* Get pid_t. */ ++#include ++#include ++#include ++ ++#include ++ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++ ++/* Wait for a subprocess to finish. Return its exit code. ++ If it didn't terminate correctly, exit if exit_on_error is true, otherwise ++ return 127. ++ Arguments: ++ - child is the pid of the subprocess. ++ - progname is the name of the program executed by the subprocess, used for ++ error messages. ++ - If ignore_sigpipe is true, consider a subprocess termination due to ++ SIGPIPE as equivalent to a success. This is suitable for processes whose ++ only purpose is to write to standard output. This flag can be safely set ++ to false when the process' standard output is known to go to DEV_NULL. ++ - If null_stderr is true, the usual error message to stderr will be omitted. ++ This is suitable when the subprocess does not fulfill an important task. ++ - slave_process should be set to true if the process has been launched as a ++ slave process. ++ - If exit_on_error is true, any error will cause the main process to exit ++ with an error status. ++ - If termsigp is not NULL: *termsig will be set to the signal that ++ terminated the subprocess (if supported by the platform: not on native ++ Windows platforms), otherwise 0, and the error message about the signal ++ that terminated the subprocess will be omitted. ++ Prerequisites: The signal handler for SIGCHLD should not be set to SIG_IGN, ++ otherwise this function will not work. */ ++extern int wait_subprocess (pid_t child, const char *progname, ++ bool ignore_sigpipe, bool null_stderr, ++ bool slave_process, bool exit_on_error, ++ int *termsigp); ++ ++/* Register a subprocess as being a slave process. This means that the ++ subprocess will be terminated when its creator receives a catchable fatal ++ signal or exits normally. Registration ends when wait_subprocess() ++ notices that the subprocess has exited. */ ++extern void register_slave_subprocess (pid_t child); ++ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++ ++#endif /* _WAIT_PROCESS_H */ +diff -up patch-2.7.6/src/pch.c.switch-from-fork-execlp-to-execute patch-2.7.6/src/pch.c +--- patch-2.7.6/src/pch.c.switch-from-fork-execlp-to-execute 2019-07-29 14:40:53.262464816 +0200 ++++ patch-2.7.6/src/pch.c 2019-07-29 15:01:10.338312098 +0200 +@@ -33,7 +33,8 @@ + # include + #endif + #include +-#include ++#include ++#include "execute.h" + + #define INITHUNKMAX 125 /* initial dynamic allocation size */ + +@@ -2453,6 +2463,9 @@ do_ed_script (char const *inname, char c + + if (! dry_run && ! skip_rest_of_patch) { + int exclusive = *outname_needs_removal ? 0 : O_EXCL; ++ char const **ed_argv; ++ int stdin_dup, status; ++ + *outname_needs_removal = true; + if (inerrno != ENOENT) + { +@@ -2461,24 +2474,22 @@ do_ed_script (char const *inname, char c + } + fflush (stdout); + +- pid = fork(); +- if (pid == -1) +- pfatal ("Can't fork"); +- else if (pid == 0) +- { +- dup2 (tmpfd, 0); +- assert (outname[0] != '!' && outname[0] != '-'); +- execlp (editor_program, editor_program, "-", outname, (char *) NULL); +- _exit (2); +- } +- else +- { +- int wstatus; +- if (waitpid (pid, &wstatus, 0) == -1 +- || ! WIFEXITED (wstatus) +- || WEXITSTATUS (wstatus) != 0) +- fatal ("%s FAILED", editor_program); +- } ++ if ((stdin_dup = dup (0)) == -1 ++ || dup2 (tmpfd, 0) == -1) ++ pfatal ("Failed to duplicate standard input"); ++ assert (outname[0] != '!' && outname[0] != '-'); ++ ed_argv = alloca (4 * sizeof * ed_argv); ++ ed_argv[0] = editor_program; ++ ed_argv[1] = "-"; ++ ed_argv[2] = outname; ++ ed_argv[3] = (char *) NULL; ++ status = execute (editor_program, editor_program, (char **)ed_argv, ++ false, false, false, false, true, false, NULL); ++ if (status) ++ fatal ("%s FAILED", editor_program); ++ if (dup2 (stdin_dup, 0) == -1 ++ || close (stdin_dup) == -1) ++ pfatal ("Failed to duplicate standard input"); + } + + fclose (tmpfp); diff --git a/SOURCES/patch-2.7.6-test-suite-compatibility-fixes.patch b/SOURCES/patch-2.7.6-test-suite-compatibility-fixes.patch new file mode 100644 index 0000000..ce3e36f --- /dev/null +++ b/SOURCES/patch-2.7.6-test-suite-compatibility-fixes.patch @@ -0,0 +1,124 @@ +commit f6bc5b14bd193859851d15a049bafb1007acd288 +Author: Andreas Gruenbacher +Date: Wed Feb 7 12:10:41 2018 +0100 + + Test suite compatibility fixes + + * tests/crlf-handling, tests/git-cleanup, tests/test-lib.sh: Use printf + instead of echo -e / echo -n for compatibility with systems that don't + support these echo options. + * tests/merge: Minor other cleanups. + +diff --git a/tests/crlf-handling b/tests/crlf-handling +index 239149c..c192cac 100644 +--- a/tests/crlf-handling ++++ b/tests/crlf-handling +@@ -14,7 +14,7 @@ use_local_patch + use_tmpdir + + lf2crlf() { +- while read l; do echo -e "$l\r"; done ++ while read l; do printf "%s\r\n" "$l"; done + } + + echo 1 > a +diff --git a/tests/git-cleanup b/tests/git-cleanup +index 2e3e4c6..ca527a1 100644 +--- a/tests/git-cleanup ++++ b/tests/git-cleanup +@@ -36,8 +36,8 @@ BAD PATCH + EOF + + echo 1 > f +-echo -n '' > g +-echo -n '' > h ++printf '' > g ++printf '' > h + + check 'patch -f -i 1.diff || echo status: $?' < a.sed +- echo "$body" | sed -f a.sed > b ++ done > b.sed ++ echo "$body" | sed -f b.sed > b + shift + while test $# -gt 0 ; do + echo "$1" + shift +- done > b.sed +- echo "$body" | sed -f b.sed > c +- rm -f a.sed b.sed ++ done > c.sed ++ echo "$body" | sed -f c.sed > c ++ rm -f b.sed c.sed + output=`diff -u a b | patch $ARGS -f c` + status=$? + echo "$output" | sed -e '/^$/d' -e '/^patching file c$/d' + cat c +- test $status == 0 || echo "Status: $status" ++ test $status = 0 || echo "Status: $status" + } + + x() { +- ARGS="$ARGS --merge" x2 "$@" ++ ARGS="--merge" x2 "$@" + echo +- ARGS="$ARGS --merge=diff3" x2 "$@" ++ ARGS="--merge=diff3" x2 "$@" + } + +-unset ARGS +- + # ============================================================== + + check 'x 3' <&3 ++ printf "\n\n" >&3 + gdbserver localhost:53153 $PATCH "$@" 2>&3 + else + $PATCH "$@" +@@ -113,22 +113,15 @@ cleanup() { + exit $status + } + +-if test -z "`echo -n`"; then +- if eval 'test -n "${BASH_LINENO[0]}" 2>/dev/null'; then +- eval ' +- _start_test() { +- echo -n "[${BASH_LINENO[2]}] $* -- " +- }' +- else +- eval ' +- _start_test() { +- echo -n "* $* -- " +- }' +- fi ++if eval 'test -n "${BASH_LINENO[0]}" 2>/dev/null'; then ++ eval ' ++ _start_test() { ++ printf "[${BASH_LINENO[2]}] %s -- " "$*" ++ }' + else + eval ' + _start_test() { +- echo "* $*" ++ printf "* %s -- " "$*" + }' + fi + diff --git a/SOURCES/patch-CVE-2018-1000156.patch b/SOURCES/patch-CVE-2018-1000156.patch new file mode 100644 index 0000000..988964f --- /dev/null +++ b/SOURCES/patch-CVE-2018-1000156.patch @@ -0,0 +1,202 @@ +commit 123eaff0d5d1aebe128295959435b9ca5909c26d +Author: Andreas Gruenbacher +Date: Fri Apr 6 12:14:49 2018 +0200 + + Fix arbitrary command execution in ed-style patches (CVE-2018-1000156) + + * src/pch.c (do_ed_script): Write ed script to a temporary file instead + of piping it to ed: this will cause ed to abort on invalid commands + instead of rejecting them and carrying on. + * tests/ed-style: New test case. + * tests/Makefile.am (TESTS): Add test case. + +diff --git a/src/pch.c b/src/pch.c +index 0c5cc26..4fd5a05 100644 +--- a/src/pch.c ++++ b/src/pch.c +@@ -33,6 +33,7 @@ + # include + #endif + #include ++#include + + #define INITHUNKMAX 125 /* initial dynamic allocation size */ + +@@ -2389,24 +2390,28 @@ do_ed_script (char const *inname, char const *outname, + static char const editor_program[] = EDITOR_PROGRAM; + + file_offset beginning_of_this_line; +- FILE *pipefp = 0; + size_t chars_read; ++ FILE *tmpfp = 0; ++ char const *tmpname; ++ int tmpfd; ++ pid_t pid; ++ ++ if (! dry_run && ! skip_rest_of_patch) ++ { ++ /* Write ed script to a temporary file. This causes ed to abort on ++ invalid commands such as when line numbers or ranges exceed the ++ number of available lines. When ed reads from a pipe, it rejects ++ invalid commands and treats the next line as a new command, which ++ can lead to arbitrary command execution. */ ++ ++ tmpfd = make_tempfile (&tmpname, 'e', NULL, O_RDWR | O_BINARY, 0); ++ if (tmpfd == -1) ++ pfatal ("Can't create temporary file %s", quotearg (tmpname)); ++ tmpfp = fdopen (tmpfd, "w+b"); ++ if (! tmpfp) ++ pfatal ("Can't open stream for file %s", quotearg (tmpname)); ++ } + +- if (! dry_run && ! skip_rest_of_patch) { +- int exclusive = *outname_needs_removal ? 0 : O_EXCL; +- if (inerrno != ENOENT) +- { +- *outname_needs_removal = true; +- copy_file (inname, outname, 0, exclusive, instat.st_mode, true); +- } +- sprintf (buf, "%s %s%s", editor_program, +- verbosity == VERBOSE ? "" : "- ", +- outname); +- fflush (stdout); +- pipefp = popen(buf, binary_transput ? "wb" : "w"); +- if (!pipefp) +- pfatal ("Can't open pipe to %s", quotearg (buf)); +- } + for (;;) { + char ed_command_letter; + beginning_of_this_line = file_tell (pfp); +@@ -2417,14 +2422,14 @@ do_ed_script (char const *inname, char const *outname, + } + ed_command_letter = get_ed_command_letter (buf); + if (ed_command_letter) { +- if (pipefp) +- if (! fwrite (buf, sizeof *buf, chars_read, pipefp)) ++ if (tmpfp) ++ if (! fwrite (buf, sizeof *buf, chars_read, tmpfp)) + write_fatal (); + if (ed_command_letter != 'd' && ed_command_letter != 's') { + p_pass_comments_through = true; + while ((chars_read = get_line ()) != 0) { +- if (pipefp) +- if (! fwrite (buf, sizeof *buf, chars_read, pipefp)) ++ if (tmpfp) ++ if (! fwrite (buf, sizeof *buf, chars_read, tmpfp)) + write_fatal (); + if (chars_read == 2 && strEQ (buf, ".\n")) + break; +@@ -2437,13 +2442,49 @@ do_ed_script (char const *inname, char const *outname, + break; + } + } +- if (!pipefp) ++ if (!tmpfp) + return; +- if (fwrite ("w\nq\n", sizeof (char), (size_t) 4, pipefp) == 0 +- || fflush (pipefp) != 0) ++ if (fwrite ("w\nq\n", sizeof (char), (size_t) 4, tmpfp) == 0 ++ || fflush (tmpfp) != 0) + write_fatal (); +- if (pclose (pipefp) != 0) +- fatal ("%s FAILED", editor_program); ++ ++ if (lseek (tmpfd, 0, SEEK_SET) == -1) ++ pfatal ("Can't rewind to the beginning of file %s", quotearg (tmpname)); ++ ++ if (! dry_run && ! skip_rest_of_patch) { ++ int exclusive = *outname_needs_removal ? 0 : O_EXCL; ++ *outname_needs_removal = true; ++ if (inerrno != ENOENT) ++ { ++ *outname_needs_removal = true; ++ copy_file (inname, outname, 0, exclusive, instat.st_mode, true); ++ } ++ sprintf (buf, "%s %s%s", editor_program, ++ verbosity == VERBOSE ? "" : "- ", ++ outname); ++ fflush (stdout); ++ ++ pid = fork(); ++ if (pid == -1) ++ pfatal ("Can't fork"); ++ else if (pid == 0) ++ { ++ dup2 (tmpfd, 0); ++ execl ("/bin/sh", "sh", "-c", buf, (char *) 0); ++ _exit (2); ++ } ++ else ++ { ++ int wstatus; ++ if (waitpid (pid, &wstatus, 0) == -1 ++ || ! WIFEXITED (wstatus) ++ || WEXITSTATUS (wstatus) != 0) ++ fatal ("%s FAILED", editor_program); ++ } ++ } ++ ++ fclose (tmpfp); ++ safe_unlink (tmpname); + + if (ofp) + { +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 6b6df63..16f8693 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -32,6 +32,7 @@ TESTS = \ + crlf-handling \ + dash-o-append \ + deep-directories \ ++ ed-style \ + empty-files \ + false-match \ + fifo \ +diff --git a/tests/ed-style b/tests/ed-style +new file mode 100644 +index 0000000..d8c0689 +--- /dev/null ++++ b/tests/ed-style +@@ -0,0 +1,41 @@ ++# 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 > ed1.diff < ed2.diff < /dev/null || echo "Status: $?"' < + #include + ++#include ++ + #include + + #include +@@ -84,6 +86,7 @@ XTERN char *outfile; + XTERN int inerrno; + XTERN int invc; + XTERN struct stat instat; ++XTERN security_context_t incontext; + XTERN bool dry_run; + XTERN bool posixly_correct; + +diff -up patch-2.7.6/src/inp.c.selinux patch-2.7.6/src/inp.c +--- patch-2.7.6/src/inp.c.selinux 2017-09-04 12:34:16.000000000 +0100 ++++ patch-2.7.6/src/inp.c 2018-02-12 12:29:44.415225377 +0000 +@@ -145,7 +145,7 @@ get_input_file (char const *filename, ch + char *getbuf; + + if (inerrno == -1) +- inerrno = stat_file (filename, &instat); ++ inerrno = stat_file (filename, &instat, &incontext); + + /* Perhaps look for RCS or SCCS versions. */ + if (S_ISREG (file_type) +@@ -190,7 +190,7 @@ get_input_file (char const *filename, ch + } + + if (cs && version_get (filename, cs, ! inerrno, elsewhere, getbuf, +- &instat)) ++ &instat, &incontext)) + inerrno = 0; + + free (getbuf); +@@ -201,6 +201,7 @@ get_input_file (char const *filename, ch + { + instat.st_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; + instat.st_size = 0; ++ incontext = NULL; + } + else if (! ((S_ISREG (file_type) || S_ISLNK (file_type)) + && (file_type & S_IFMT) == (instat.st_mode & S_IFMT))) +diff -up patch-2.7.6/src/Makefile.am.selinux patch-2.7.6/src/Makefile.am +--- patch-2.7.6/src/Makefile.am.selinux 2017-09-04 12:34:16.000000000 +0100 ++++ patch-2.7.6/src/Makefile.am 2018-02-12 12:29:44.415225377 +0000 +@@ -37,7 +37,7 @@ patch_SOURCES = \ + + AM_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib + patch_LDADD = $(LDADD) $(top_builddir)/lib/libpatch.a $(LIB_CLOCK_GETTIME) \ +- $(LIB_XATTR) $(LIB_EACCESS) ++ $(LIB_XATTR) $(LIB_EACCESS) -lselinux + + if ENABLE_MERGE + patch_SOURCES += merge.c +diff -up patch-2.7.6/src/Makefile.in.selinux patch-2.7.6/src/Makefile.in +--- patch-2.7.6/src/Makefile.in.selinux 2018-02-03 13:33:56.000000000 +0000 ++++ patch-2.7.6/src/Makefile.in 2018-02-12 12:29:44.415225377 +0000 +@@ -1147,7 +1147,7 @@ patch_SOURCES = bestmatch.h common.h inp + AM_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib \ + $(am__append_2) + patch_LDADD = $(LDADD) $(top_builddir)/lib/libpatch.a $(LIB_CLOCK_GETTIME) \ +- $(LIB_XATTR) $(LIB_EACCESS) ++ $(LIB_XATTR) $(LIB_EACCESS) -lselinux + + all: all-am + +diff -up patch-2.7.6/src/patch.c.selinux patch-2.7.6/src/patch.c +--- patch-2.7.6/src/patch.c.selinux 2018-02-03 12:41:49.000000000 +0000 ++++ patch-2.7.6/src/patch.c 2018-02-12 12:30:27.315164138 +0000 +@@ -269,19 +269,19 @@ main (int argc, char **argv) + if (! strcmp (inname, outname)) + { + if (inerrno == -1) +- inerrno = stat_file (inname, &instat); ++ inerrno = stat_file (inname, &instat, NULL); + outstat = instat; + outerrno = inerrno; + } + else +- outerrno = stat_file (outname, &outstat); ++ outerrno = stat_file (outname, &outstat, NULL); + + if (! outerrno) + { + if (has_queued_output (&outstat)) + { + output_files (&outstat); +- outerrno = stat_file (outname, &outstat); ++ outerrno = stat_file (outname, &outstat, NULL); + inerrno = -1; + } + if (! outerrno) +@@ -598,7 +598,7 @@ main (int argc, char **argv) + } + else + { +- attr |= FA_IDS | FA_MODE | FA_XATTRS; ++ attr |= FA_IDS | FA_MODE | FA_XATTRS | FA_SECCONTEXT; + set_file_attributes (TMPOUTNAME, attr, inname, &instat, + mode, &new_time); + } +@@ -658,7 +658,7 @@ main (int argc, char **argv) + struct stat oldst; + int olderrno; + +- olderrno = stat_file (rej, &oldst); ++ olderrno = stat_file (rej, &oldst, NULL); + if (olderrno && olderrno != ENOENT) + write_fatal (); + if (! olderrno && lookup_file_id (&oldst) == CREATED) +@@ -1790,7 +1790,7 @@ delete_file_later (const char *name, con + + if (! st) + { +- if (stat_file (name, &st_tmp) != 0) ++ if (stat_file (name, &st_tmp, NULL) != 0) + pfatal ("Can't get file attributes of %s %s", "file", name); + st = &st_tmp; + } +diff -up patch-2.7.6/src/pch.c.selinux patch-2.7.6/src/pch.c +--- patch-2.7.6/src/pch.c.selinux 2018-02-03 12:41:49.000000000 +0000 ++++ patch-2.7.6/src/pch.c 2018-02-12 12:29:44.416225375 +0000 +@@ -1,6 +1,6 @@ + /* reading patches */ + +-/* Copyright (C) 1986, 1987, 1988 Larry Wall ++/* Copyright (C) 1986, 1987, 1988, 2012 Larry Wall + + Copyright (C) 1990-1993, 1997-2003, 2006, 2009-2012 Free Software + Foundation, Inc. +@@ -296,7 +296,7 @@ there_is_another_patch (bool need_header + if (t > buf + 1 && *(t - 1) == '\n') + { + inname = xmemdup0 (buf, t - buf - 1); +- inerrno = stat_file (inname, &instat); ++ inerrno = stat_file (inname, &instat, &incontext); + if (inerrno) + { + perror (inname); +@@ -433,6 +433,7 @@ intuit_diff_type (bool need_header, mode + bool extended_headers = false; + enum nametype i; + struct stat st[3]; ++ security_context_t con[3]; + int stat_errno[3]; + int version_controlled[3]; + enum diff retval; +@@ -473,6 +474,7 @@ intuit_diff_type (bool need_header, mode + version_controlled[OLD] = -1; + version_controlled[NEW] = -1; + version_controlled[INDEX] = -1; ++ con[OLD] = con[NEW] = con[INDEX] = NULL; + p_rfc934_nesting = 0; + p_timestamp[OLD].tv_sec = p_timestamp[NEW].tv_sec = -1; + p_says_nonexistent[OLD] = p_says_nonexistent[NEW] = 0; +@@ -883,7 +885,7 @@ intuit_diff_type (bool need_header, mode + } + else + { +- stat_errno[i] = stat_file (p_name[i], &st[i]); ++ stat_errno[i] = stat_file (p_name[i], &st[i], &con[i]); + if (! stat_errno[i]) + { + if (lookup_file_id (&st[i]) == DELETE_LATER) +@@ -922,7 +924,7 @@ intuit_diff_type (bool need_header, mode + if (cs) + { + if (version_get (p_name[i], cs, false, readonly, +- getbuf, &st[i])) ++ getbuf, &st[i], &con[i])) + stat_errno[i] = 0; + else + version_controlled[i] = 0; +@@ -985,7 +987,7 @@ intuit_diff_type (bool need_header, mode + { + if (inname) + { +- inerrno = stat_file (inname, &instat); ++ inerrno = stat_file (inname, &instat, &incontext); + if (inerrno || (instat.st_mode & S_IFMT) == file_type) + maybe_reverse (inname, inerrno, inerrno || instat.st_size == 0); + } +@@ -998,8 +1000,14 @@ intuit_diff_type (bool need_header, mode + inerrno = stat_errno[i]; + invc = version_controlled[i]; + instat = st[i]; ++ incontext = con[i]; ++ con[i] = NULL; + } + ++ for (i = OLD; i <= INDEX; i++) ++ if (con[i]) ++ freecon (con[i]); ++ + return retval; + } + +diff -up patch-2.7.6/src/util.c.selinux patch-2.7.6/src/util.c +--- patch-2.7.6/src/util.c.selinux 2018-02-03 12:41:49.000000000 +0000 ++++ patch-2.7.6/src/util.c 2018-02-12 12:29:44.417225374 +0000 +@@ -300,6 +300,23 @@ set_file_attributes (char const *to, enu + S_ISLNK (mode) ? "symbolic link" : "file", + quotearg (to)); + } ++ if (attr & FA_SECCONTEXT) ++ { ++ security_context_t outcontext; ++ if (incontext && getfilecon (to, &outcontext) != -1 && outcontext) ++ { ++ if (strcmp (outcontext, incontext) && ++ setfilecon (to, incontext) != 0) ++ { ++ freecon (outcontext); ++ if (errno != ENOTSUP && errno != EPERM) ++ pfatal ("Can't set security context on file %s", ++ quotearg (to)); ++ } ++ else ++ freecon (outcontext); ++ } ++ } + } + + static void +@@ -446,7 +463,7 @@ move_file (char const *from, bool *from_ + struct stat to_st; + int to_errno; + +- to_errno = stat_file (to, &to_st); ++ to_errno = stat_file (to, &to_st, NULL); + if (backup) + create_backup (to, to_errno ? NULL : &to_st, false); + if (! to_errno) +@@ -818,7 +835,8 @@ version_controller (char const *filename + Return true if successful. */ + bool + version_get (char const *filename, char const *cs, bool exists, bool readonly, +- char const *getbuf, struct stat *filestat) ++ char const *getbuf, struct stat *filestat, ++ security_context_t *filecontext) + { + if (patch_get < 0) + { +@@ -843,6 +861,13 @@ version_get (char const *filename, char + fatal ("Can't get file %s from %s", quotearg (filename), cs); + if (safe_stat (filename, filestat) != 0) + pfatal ("%s", quotearg (filename)); ++ if (filecontext && getfilecon (filename, filecontext) == -1) ++ { ++ if (errno == ENODATA || errno == ENOTSUP) ++ *filecontext = NULL; ++ else ++ pfatal ("%s", quotearg (filename)); ++ } + } + + return 1; +@@ -1670,12 +1695,28 @@ make_tempfile (char const **name, char l + return fd; + } + +-int stat_file (char const *filename, struct stat *st) ++int stat_file (char const *filename, struct stat *st, security_context_t *con) + { + int (*xstat)(char const *, struct stat *) = + follow_symlinks ? safe_stat : safe_lstat; ++ int (*xgetfilecon)(char const *, security_context_t *) = ++ follow_symlinks ? getfilecon : lgetfilecon; ++ ++ if (xstat (filename, st) == 0) ++ { ++ if (con) ++ { ++ if (xgetfilecon (filename, con) != -1 || ++ errno == ENODATA || errno == ENOTSUP) ++ return 0; + +- return xstat (filename, st) == 0 ? 0 : errno; ++ *con = NULL; ++ } ++ else ++ return 0; ++ } ++ ++ return errno; + } + + /* Check if a filename is relative and free of ".." components. +diff -up patch-2.7.6/src/util.h.selinux patch-2.7.6/src/util.h +--- patch-2.7.6/src/util.h.selinux 2018-02-03 12:41:49.000000000 +0000 ++++ patch-2.7.6/src/util.h 2018-02-12 12:30:08.533190949 +0000 +@@ -44,7 +44,7 @@ char *parse_name (char const *, int, cha + char *savebuf (char const *, size_t); + char *savestr (char const *); + char const *version_controller (char const *, bool, struct stat const *, char **, char **); +-bool version_get (char const *, char const *, bool, bool, char const *, struct stat *); ++bool version_get (char const *, char const *, bool, bool, char const *, struct stat *, security_context_t *); + int create_file (char const *, int, mode_t, bool); + int systemic (char const *); + char *format_linenum (char[LINENUM_LENGTH_BOUND + 1], lin); +@@ -67,7 +67,7 @@ void insert_file_id (struct stat const * + enum file_id_type lookup_file_id (struct stat const *); + void set_queued_output (struct stat const *, bool); + bool has_queued_output (struct stat const *); +-int stat_file (char const *, struct stat *); ++int stat_file (char const *, struct stat *, security_context_t *); + bool filename_is_safe (char const *) _GL_ATTRIBUTE_PURE; + bool cwd_is_root (char const *); + +@@ -75,7 +75,8 @@ enum file_attributes { + FA_TIMES = 1, + FA_IDS = 2, + FA_MODE = 4, +- FA_XATTRS = 8 ++ FA_XATTRS = 8, ++ FA_SECCONTEXT = 16 + }; + + void set_file_attributes (char const *, enum file_attributes, char const *, diff --git a/SPECS/patch.spec b/SPECS/patch.spec new file mode 100644 index 0000000..58c85a2 --- /dev/null +++ b/SPECS/patch.spec @@ -0,0 +1,470 @@ +%global gnulib_ver 20180203 + +Summary: Utility for modifying/upgrading files +Name: patch +Version: 2.7.6 +Release: 16%{?dist} +License: GPLv3+ +URL: https://savannah.gnu.org/projects/patch/ +Source: https://ftp.gnu.org/gnu/patch/patch-%{version}.tar.xz +Patch0: patch-2.7.6-avoid-set_file_attributes-sign-conversion-warnings.patch +patch1: patch-2.7.6-test-suite-compatibility-fixes.patch +Patch2: patch-2.7.6-fix-korn-shell-incompatibility.patch +Patch3: patch-2.7.6-fix-segfault-with-mangled-rename-patch.patch +Patch4: patch-2.7.6-allow-input-files-to-be-missing-for-ed-style-patches.patch +Patch5: patch-CVE-2018-1000156.patch +Patch6: patch-2.7.6-CVE-2019-13638-invoked-ed-directly-instead-of-using-the-shell.patch +Patch7: patch-2.7.6-switch-from-fork-execlp-to-execute.patch +Patch8: patch-2.7.6-cleanups-in-do_ed_script.patch +Patch9: patch-2.7.6-avoid-warnings-gcc8.patch +Patch10: patch-2.7.6-check-of-return-value-of-fwrite.patch +Patch11: patch-2.7.6-fix-ed-style-test-failure.patch +Patch12: patch-2.7.6-dont-leak-temporary-file-on-failed-ed-style-patch.patch +Patch13: patch-2.7.6-dont-leak-temporary-file-on-failed-multi-file-ed-style-patch.patch +Patch14: patch-2.7.6-make-debug-output-more-useful.patch +Patch15: patch-2.7.6-CVE-2018-6952-fix-swapping-fake-lines-in-pch_swap.patch +Patch16: patch-2.7.6-improve_support_for_memory_leak_detection.patch +patch17: patch-2.7.6-skip-ed-test-when-the-ed-utility-is-not-installed.patch +Patch18: patch-2.7.6-abort_when_cleaning_up_fails.patch +Patch19: patch-2.7.6-crash-RLIMIT_NOFILE.patch +Patch20: patch-2.7.6-CVE-2019-13636-symlinks.patch +Patch21: patch-2.7.6-avoid-invalid-memory-access-in-context-format-diffs.patch +Patch22: patch-2.7.6-CVE-2018-17942.patch +Patch23: patch-2.7.6-failed_assertion.patch +Patch100: patch-selinux.patch + +BuildRequires: make +BuildRequires: gcc +BuildRequires: libselinux-devel +BuildRequires: libattr-devel +BuildRequires: ed +BuildRequires: autoconf automake + +Requires: ed + +Provides: bundled(gnulib) = %{gnulib_ver} + +%description +The patch program applies diff files to originals. The diff command +is used to compare an original to a changed file. Diff lists the +changes made to the file. A person who has the original file can then +use the patch command with the diff file to add the changes to their +original file (patching the file). + +Patch should be installed because it is a common way of upgrading +applications. + +%prep +%setup -q +%patch0 -p1 -b .avoid-set_file_attributes-sign-conversion-warnings +%patch1 -p1 -b .test-suite-compatibility-fixes +%patch2 -p1 -b .fix-korn-shell-incompatibility +%patch3 -p1 -b .fix-segfault-with-mangled-rename-patch +%patch4 -p1 -b .allow-input-files-to-be-missing-for-ed-style-patches +# CVE-2018-1000156, Malicious patch files cause ed to execute arbitrary commands +%patch5 -p1 -b .CVE-2018-1000156 +%patch6 -p1 -b .CVE-2019-13638-invoked-ed-directly-instead-of-using-the-shell +%patch7 -p1 -b .switch-from-fork-execlp-to-execute +%patch8 -p1 -b .cleanups-in-do_ed_script +%patch9 -p1 -b .avoid-warnings-gcc8 +%patch10 -p1 -b .check-of-return-value-of-fwrite +%patch11 -p1 -b .fix-ed-style-test-failure +%patch12 -p1 -b .dont-leak-temporary-file-on-failed-ed-style-patch +%patch13 -p1 -b .dont-leak-temporary-file-on-failed-multi-file-ed-style-patch +%patch14 -p1 -b .make-debug-output-more-useful +%patch15 -p1 -b .CVE-2018-6952-fix-swapping-fake-lines-in-pch_swap +%patch16 -p1 -b .improve_support_for_memory_leak_detection +%patch17 -p1 -b .skip-ed-test-when-the-ed-utility-is-not-installed +%patch18 -p1 -b .abort_when_cleaning_up_fails +%patch19 -p1 -b .crash-RLIMIT_NOFILE +%patch20 -p1 -b .CVE-2019-13636-symlinks +%patch21 -p1 -b .avoid-invalid-memory-access-in-context-format-diffs +# CVE-2018-17942 gnulib: heap-based buffer overflow +%patch22 -p1 -b .CVE-2018-17942-gnulib_buffer_overflow +%patch23 -p1 -b .failed_assertion +# SELinux support. +%patch100 -p1 -b .selinux + +%build +CFLAGS="$RPM_OPT_FLAGS -D_GNU_SOURCE" +%ifarch sparcv9 +CFLAGS=`echo $CFLAGS|sed -e 's|-fstack-protector||g'` +%endif +autoreconf +%configure --disable-silent-rules +%make_build + +%check +make check + +%install +%makeinstall + +%files +%license COPYING +%doc NEWS README +%{_bindir}/* +%{_mandir}/*/* + +%changelog +* Mon Aug 09 2021 Mohan Boddu - 2.7.6-16 +- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags + Related: rhbz#1991688 + +* Fri Apr 16 2021 Mohan Boddu - 2.7.6-15 +- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937 + +* Tue Jan 26 2021 Fedora Release Engineering - 2.7.6-14 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild + +* Tue Jul 28 2020 Fedora Release Engineering - 2.7.6-13 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Wed Jan 29 2020 Fedora Release Engineering - 2.7.6-12 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Mon Jul 29 2019 Than Ngo - 2.7.6-11 +- fixed #1733917, CVE-2019-13638 patch: OS shell command injection when processing crafted patch files + +* 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 + +* Mon Nov 26 2018 Than Ngo - 2.7.6-8 +- Added virtual provides for bundled gnulib library +- Fixed CVE-2018-17942, gnulib: heap-based buffer overflow + +* Thu Oct 11 2018 Than Ngo - 2.7.6-7 +- Fixed #1582675 - Patch can be crashed and coredumped with a trivial wrong command + +* Wed Aug 15 2018 Than Ngo - 2.7.6-6 +- Fixed #1554752 - Double free of memory, CVE-2018-6952 + +* Fri Jul 13 2018 Fedora Release Engineering - 2.7.6-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Thu May 3 2018 Tim Waugh - 2.7.6-4 +- Fixed CVE-2018-1000156 - Malicious patch files cause ed to execute arbitrary + commands. + +* Mon Feb 12 2018 Tim Waugh - 2.7.6-3 +- 2.7.6 (CVE-2016-10713, CVE-2018-6951, CVE-2018-6952). + +* Thu Feb 08 2018 Fedora Release Engineering - 2.7.5-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Thu Aug 03 2017 Fedora Release Engineering - 2.7.5-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Thu Jul 27 2017 Fedora Release Engineering - 2.7.5-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Wed Feb 01 2017 Stephen Gallagher - 2.7.5-4 +- Add missing %%license macro + +* Thu Feb 04 2016 Fedora Release Engineering - 2.7.5-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Thu Jun 18 2015 Fedora Release Engineering - 2.7.5-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Mon Mar 9 2015 Tim Waugh - 2.7.5-1 +- Fixed memory leak in selinux patch. +- 2.7.5, including an even better fix for CVE-2015-1196 that still + allows relative symlinks to be created/used. + +* Sat Feb 21 2015 Till Maas - 2.7.4-2 +- Rebuilt for Fedora 23 Change + https://fedoraproject.org/wiki/Changes/Harden_all_packages_with_position-independent_code + +* Sun Feb 1 2015 Tim Waugh - 2.7.4-1 +- 2.7.4, including a better fix for CVE-2015-1196 that still allows + symlinks referencing ".." to be created. + +* Fri Jan 23 2015 Tim Waugh - 2.7.3-1 +- 2.7.3 (bug #1182157, CVE-2015-1196, bug #1184491, CVE-2014-9637). + +* Tue Jan 20 2015 Tim Waugh - 2.7.1-12 +- Apply upstream patch to fix line numbering integer overflow. + +* Tue Jan 20 2015 Tim Waugh - 2.7.1-11 +- Apply upstream patch to fix directory traversal via symlinks + (bug #1182157, CVE-2015-1196). + +* Sun Aug 17 2014 Fedora Release Engineering - 2.7.1-9 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Fri Jun 06 2014 Fedora Release Engineering - 2.7.1-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Sat Aug 03 2013 Fedora Release Engineering - 2.7.1-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* Wed Jun 12 2013 Tim Waugh 2.7.1-6 +- Don't segfault when given bad arguments (bug #972330). + +* Thu Apr 11 2013 Tim Waugh 2.7.1-5 +- Don't document unsupported -m option; document -x option (bug #948972). + +* Mon Mar 25 2013 Ville Skyttä - 2.7.1-4 +- Build with xattr support. +- Make build output more verbose. +- Fix bogus date in %%changelog. + +* Mon Mar 11 2013 Tim Waugh 2.7.1-3 +- Upstream patch to fix removal of empty directories (bug #919489). + +* Thu Feb 14 2013 Fedora Release Engineering - 2.7.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Thu Oct 18 2012 Tim Waugh 2.7.1-1 +- Fixed license (since 2.6 it has been GPLv3+). +- 2.7.1. + +* Thu Oct 18 2012 Tim Waugh 2.7-1 +- 2.7. No longer need sigsegv, get-arg, CVE-2010-4651, + backup-if-mismatch or coverity-leak patches. + +* Fri Jul 20 2012 Fedora Release Engineering - 2.6.1-13 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Fri Jan 13 2012 Fedora Release Engineering - 2.6.1-12 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Fri Nov 25 2011 Tim Waugh 2.6.1-11 +- Fixed NULL dereference in selinux patch. + +* Mon May 16 2011 Tim Waugh 2.6.1-10 +- Applied Jiri Popelka's fixes from Coverity scan (bug #704554): + - Avoid unchecked return from getfilecon() in patch-selinux.patch. + - Fix memory leak. + +* Wed Feb 16 2011 Tim Waugh 2.6.1-9 +- Let --posix cause --no-backup-if-mismatch (bug #678016). + +* Thu Feb 10 2011 Tim Waugh 2.6.1-8 +- Incorporate upstream fix for CVE-2010-4651 patch so that a target + name given on the command line is not validated (bug #667529). + +* Tue Feb 8 2011 Tim Waugh 2.6.1-7 +- Applied upstream patch to fix CVE-2010-4651 so that malicious + patches cannot create files above the current directory + (bug #667529). + +* Tue Jan 4 2011 Tim Waugh 2.6.1-6 +- Use smp_mflags correctly (bug #665770). + +* Mon Aug 16 2010 Tim Waugh 2.6.1-5 +- Another fix for the selinux patch (bug #618215). + +* Fri Aug 6 2010 Tim Waugh 2.6.1-4 +- Fixed interpretation of return value from getfilecon(). +- Fixed argument type for --get (bug #553624). + +* Fri Aug 6 2010 Dennis Gilmore +- using -fstack-projector causes weirdness on 32 bit sparc so disabling for now + +* Tue Jul 27 2010 Tim Waugh 2.6.1-3 +- Fixed argument type for --get (bug #553624). + +* Wed Mar 3 2010 Tim Waugh 2.6.1-2 +- Added comments for all patches. +- Ship COPYING file. +- Removed sparc ifdefs in spec file. + +* Mon Jan 4 2010 Tim Waugh 2.6.1-1 +- 2.6.1 (bug #551569). No longer need best-name patch. + +* Thu Dec 24 2009 Tim Waugh 2.6-2 +- Applied upstream patch to prevent incorrect filename being chosen + when adding a new file (bug #549122). + +* Mon Nov 16 2009 Tim Waugh 2.6-1 +- 2.6. No longer need stderr, suffix, stripcr, parse, allow-spaces, + ifdef, program_name, or posix-backup patches. + +* Sat Jul 25 2009 Fedora Release Engineering - 2.5.4-40 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Wed Apr 29 2009 Tim Waugh 2.5.4-39 +- Fixed operation when SELinux is disabled (bug #498102). Patch from + Jan Kratochvil. + +* Thu Feb 26 2009 Fedora Release Engineering - 2.5.4-38 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Tue Feb 17 2009 Tim Waugh 2.5.4-37 +- Don't set SELinux file context if it is already correct. + +* Mon Nov 24 2008 Tim Waugh 2.5.4-36 +- Better summary. + +* Mon Jun 30 2008 Tim Waugh 2.5.4-35 +- Don't fail if setfilecon() returns EPERM (bug #453365), although the + setfilecon man page suggests that ENOTSUP will be returned in this + case. + +* Mon Jun 16 2008 Tim Waugh 2.5.4-34 +- Only write simple backups for each file once during a run + (bug #234822). + +* Thu Jun 12 2008 Tim Waugh 2.5.4-33 +- Fix selinux patch and apply it. Build requires libselinux-devel. + +* Fri Feb 8 2008 Tim Waugh 2.5.4-32 +- Applied patch from 2.5.9 to allow spaces in filenames (bug #431887). + +* Mon Dec 3 2007 Tim Waugh 2.5.4-31 +- Convert spec file to UTF-8 (bug #226233). +- Use _bindir macro in %%files (bug #226233). +- Parallel make (bug #226233). +- Better defattr declaration (bug #226233). + +* Thu Oct 4 2007 Tim Waugh +- Beginnings of an SELinux patch (bug #165799); not applied yet. + +* Wed Aug 29 2007 Tim Waugh 2.5.4-30 +- Added dist tag. +- More specific license tag. +- Fixed summary. +- Better buildroot tag. + +* Wed Jul 12 2006 Jesse Keating - 2.5.4-29.2.2 +- rebuild + +* Fri Feb 10 2006 Jesse Keating - 2.5.4-29.2.1 +- bump again for double-long bug on ppc(64) + +* Tue Feb 07 2006 Jesse Keating - 2.5.4-29.2 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Thu Sep 8 2005 Tim Waugh 2.5.4-29 +- Remove SELinux patch for now (bug #167822). + +* Wed Sep 7 2005 Tim Waugh 2.5.4-27 +- Applied patch from Ulrich Drepper to fix string overread (bug #167675). + +* Tue Sep 6 2005 Tim Waugh 2.5.4-26 +- Preserve SELinux file contexts (bug #165799). + +* Thu Aug 11 2005 Tim Waugh 2.5.4-25 +- Fixed CRLF detection (bug #154283). + +* Wed May 4 2005 Tim Waugh 2.5.4-24 +- Reverted last change (bug #154283, bug #156762). + +* Fri Apr 29 2005 Tim Waugh 2.5.4-23 +- Applied patch from Toshio Kuratomi to avoid problems with DOS-format + newlines (bug #154283). + +* Wed Mar 2 2005 Tim Waugh 2.5.4-22 +- Rebuild for new GCC. + +* Wed Feb 9 2005 Tim Waugh 2.5.4-21 +- Rebuilt. + +* Tue Jun 15 2004 Elliot Lee +- rebuilt + +* Fri Feb 13 2004 Elliot Lee +- rebuilt + +* Sat Oct 25 2003 Tim Waugh 2.5.4-18 +- Rebuilt. + +* Wed Jun 04 2003 Elliot Lee +- rebuilt + +* Wed Jan 22 2003 Tim Powers +- rebuilt + +* Wed Nov 20 2002 Tim Powers +- rebuilt in current collinst + +* Fri Jun 21 2002 Tim Powers +- automated rebuild + +* Thu May 23 2002 Tim Powers +- automated rebuild + +* Tue Apr 9 2002 Tim Waugh 2.5.4-12 +- Fix error reporting when given bad options (bug #62981). + +* Tue Mar 5 2002 Tim Waugh 2.5.4-11 +- s/Copyright:/License:/. +- Fix -D behaviour (bug #60688). + +* Tue May 29 2001 Tim Waugh 2.5.4-10 +- Merge Mandrake patch: + - fix possible segfault + +* Fri Dec 1 2000 Tim Waugh +- Rebuild because of fileutils bug. + +* Thu Nov 2 2000 Tim Waugh +- use .orig as default suffix, as per man page and previous behaviour + (bug #20202). +- use better patch for this, from maintainer. + +* Wed Oct 4 2000 Tim Waugh +- actually use the RPM_OPT_FLAGS + +* Wed Jul 12 2000 Prospector +- automatic rebuild + +* Tue Jun 13 2000 Trond Eivind Glomsrød +- Use %%makeinstall, %%{_tmppath} and %%{_mandir} + +* Fri May 12 2000 Trond Eivind Glomsrød +- added URL + +* Wed Feb 16 2000 Bernhard Rosenkraenzer +- 2.5.4 +- Fix up LFS support on Alpha (Bug #5732) + +* Mon Feb 7 2000 Bill Nottingham +- handle compressed manpages + +* Sun Jun 06 1999 Alan Cox +- Fix the case where stderr isnt flushed for ask(). Now the 'no such file' + appears before the skip patch question, not at the very end, Doh! + +* Mon Mar 22 1999 Jeff Johnson +- (ultra?) sparc was getting large file system support. + +* Sun Mar 21 1999 Cristian Gafton +- auto rebuild in the new build environment (release 7) + +* Fri Dec 18 1998 Cristian Gafton +- build against glibc 2.1 + +* Tue Sep 1 1998 Jeff Johnson +- bump release to preserve newer than back-ported 4.2. + +* Tue Jun 09 1998 Prospector System +- translations modified for de, fr + +* Tue Jun 9 1998 Jeff Johnson +- Fix for problem #682 segfault. + +* Fri Apr 24 1998 Prospector System +- translations modified for de, fr, tr + +* Tue Apr 07 1998 Cristian Gafton +- added buildroot + +* Tue Oct 21 1997 Cristian Gafton +- updated to 2.5 + +* Mon Jun 02 1997 Erik Troan +- built against glibc