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