This is the stall detection part from the earlier patch(1)
report, split out for separate discussion.  The fd leak
fix (patch.c fclose) has ok op@.

Problem: when intuit_diff_type() detects an ed script in
malformed input, do_ed_script() may fail to advance the
file position.  On the next iteration, intuit_diff_type()
finds the same pattern at the same position and the main
loop repeats indefinitely.  After hundreds of iterations,
malloc detects heap corruption and aborts.

Fix: track p_base across calls.  If it hasn't advanced
since the last call, the patch machinery failed to consume
whatever was detected.  Stop and treat the rest as garbage.

The alternative of skipping one line and retrying was
discussed.  It guarantees reaching EOF but risks silent
corruption: intuit_diff_type picks up any line starting
with "@@ -" as a unified diff, and extracts filenames
from "---"/"+++" lines.  Garbled input could match these
patterns, causing patch to write to unintended files or
create files with arbitrary names.  Stopping seems safer.

The same bug is present in NetBSD, FreeBSD, and
DragonFlyBSD (shared Larry Wall codebase).

Index: usr.bin/patch/pch.c
===================================================================
RCS file: /cvs/src/usr.bin/patch/pch.c,v
retrieving revision 1.66
diff -u -p -r1.66 pch.c
--- usr.bin/patch/pch.c 12 Jul 2023 15:45:34 -0000      1.66
+++ usr.bin/patch/pch.c
@@ -180,6 +180,7 @@ static char *posix_name(const struct fil
 bool
 there_is_another_patch(void)
 {
+       static off_t prev_p_base = -1;
        bool exists = false;

        if (p_base != 0 && p_base >= p_filesize) {
@@ -190,6 +191,12 @@ there_is_another_patch(void)
        if (verbose)
                say("Hmm...");
        diff_type = intuit_diff_type();
+       if (diff_type && p_base == prev_p_base) {
+               if (verbose)
+                       say("  Ignoring the trailing garbage.\ndone\n");
+               return false;
+       }
+       prev_p_base = p_base;
        if (!diff_type) {
                if (p_base != 0) {
                        if (verbose)

Reply via email to