On Tue, Jul 11, 2023 at 02:32:48PM +0200, Theo Buehler wrote:
> On Tue, Jul 11, 2023 at 11:48:57AM +0100, Stuart Henderson wrote:
> > I ran into a segfault with patch(1) in a port, here's a test case with a
> > minimal reproducer.
> > 
> > $ echo foo > test
> > $ perl -e 'print "--- test.orig\n+++ test\n@@ -1,1 +1,2 @@\n foo\n+" . 'x' 
> > x 32768 . "\n\\ No newline at end of file\n"' > test.patch
> 
> patch maintains the line lengths in an array of shorts p_len[] and
> doesn't check for overflows. This long line overflows the length, so
> you get a bad buffer underrun when doing 's[p_len[filldst - 1]] = 0;'

The below appears to fix this and passes regress. It won't be able to
apply the binary patch, but it should no longer segfault.

Index: pch.c
===================================================================
RCS file: /cvs/src/usr.bin/patch/pch.c,v
retrieving revision 1.63
diff -u -p -r1.63 pch.c
--- pch.c       26 Dec 2022 19:16:02 -0000      1.63
+++ pch.c       11 Jul 2023 18:34:29 -0000
@@ -56,7 +56,7 @@ static LINENUM        p_end = -1;     /* last line 
 static LINENUM p_max;          /* max allowed value of p_end */
 static LINENUM p_context = 3;  /* # of context lines */
 static char    **p_line = NULL;/* the text of the hunk */
-static short   *p_len = NULL;  /* length of each line */
+static ssize_t *p_len = NULL;  /* length of each line */
 static char    *p_char = NULL; /* +, -, and ! */
 static int     hunkmax = INITHUNKMAX;  /* size of above arrays to begin with */
 static int     p_indent;       /* indent to patch */
@@ -127,7 +127,7 @@ set_hunkmax(void)
        if (p_line == NULL)
                p_line = calloc((size_t) hunkmax, sizeof(char *));
        if (p_len == NULL)
-               p_len = calloc((size_t) hunkmax, sizeof(short));
+               p_len = calloc((size_t) hunkmax, sizeof(ssize_t));
        if (p_char == NULL)
                p_char = calloc((size_t) hunkmax, sizeof(char));
 }
@@ -140,7 +140,7 @@ grow_hunkmax(void)
 {
        int             new_hunkmax;
        char            **new_p_line;
-       short           *new_p_len;
+       ssize_t         *new_p_len;
        char            *new_p_char;
 
        new_hunkmax = hunkmax * 2;
@@ -152,7 +152,7 @@ grow_hunkmax(void)
        if (new_p_line == NULL)
                free(p_line);
 
-       new_p_len = reallocarray(p_len, new_hunkmax, sizeof(short));
+       new_p_len = reallocarray(p_len, new_hunkmax, sizeof(ssize_t));
        if (new_p_len == NULL)
                free(p_len);
 
@@ -1192,7 +1192,7 @@ bool
 pch_swap(void)
 {
        char    **tp_line;      /* the text of the hunk */
-       short   *tp_len;        /* length of each line */
+       ssize_t *tp_len;        /* length of each line */
        char    *tp_char;       /* +, -, and ! */
        LINENUM i;
        LINENUM n;

Reply via email to