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);
> 

Reply via email to