On Tue, Jul 11, 2023 at 09:13:38PM +0200, Theo Buehler wrote:
> On Tue, Jul 11, 2023 at 08:35:31PM +0200, Theo Buehler wrote:
> > 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.
>
> More complete diff, thanks otto
The test case sthen posted applies now. I did not check in detail if the
result is right though,
OK,
-Otto
>
> Index: patch.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/patch/patch.c,v
> retrieving revision 1.71
> diff -u -p -r1.71 patch.c
> --- patch.c 3 Aug 2022 07:30:37 -0000 1.71
> +++ patch.c 11 Jul 2023 19:10:55 -0000
> @@ -99,7 +99,7 @@ static void copy_till(LINENUM, bool);
> static void spew_output(void);
> static void dump_line(LINENUM, bool);
> static bool patch_match(LINENUM, LINENUM, LINENUM);
> -static bool similar(const char *, const char *, int);
> +static bool similar(const char *, const char *, ssize_t);
> static __dead void usage(void);
>
> /* true if -E was specified on command line. */
> @@ -1012,7 +1012,7 @@ patch_match(LINENUM base, LINENUM offset
> LINENUM pat_lines = pch_ptrn_lines() - fuzz;
> const char *ilineptr;
> const char *plineptr;
> - short plinelen;
> + ssize_t plinelen;
>
> for (iline = base + offset + fuzz; pline <= pat_lines; pline++,
> iline++) {
> ilineptr = ifetch(iline, offset >= 0);
> @@ -1048,7 +1048,7 @@ patch_match(LINENUM base, LINENUM offset
> * Do two lines match with canonicalized white space?
> */
> static bool
> -similar(const char *a, const char *b, int len)
> +similar(const char *a, const char *b, ssize_t len)
> {
> while (len) {
> if (isspace((unsigned char)*b)) { /* whitespace (or \n) to
> match? */
> 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 19:08:06 -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;
> @@ -1349,7 +1349,7 @@ pch_context(void)
> /*
> * Return the length of a particular patch line.
> */
> -short
> +ssize_t
> pch_line_len(LINENUM line)
> {
> return p_len[line];
> Index: pch.h
> ===================================================================
> RCS file: /cvs/src/usr.bin/patch/pch.h,v
> retrieving revision 1.13
> diff -u -p -r1.13 pch.h
> --- pch.h 11 Dec 2019 20:10:17 -0000 1.13
> +++ pch.h 11 Jul 2023 19:07:57 -0000
> @@ -53,7 +53,7 @@ LINENUM pch_newfirst(void);
> LINENUM pch_repl_lines(void);
> LINENUM pch_end(void);
> LINENUM pch_context(void);
> -short pch_line_len(LINENUM);
> +ssize_t pch_line_len(LINENUM);
> char pch_char(LINENUM);
> char *pfetch(LINENUM);
> LINENUM pch_hunk_beg(void);
>