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;