--- b/usr.bin/patch/common.h +++ b/usr.bin/patch/common.h @@ -40,6 +40,7 @@ #define INITHUNKMAX 125 /* initial dynamic allocation size */ #define INITLINELEN 4096 #define BUFFERSIZE 4096 +#define LINENUM_MAX LONG_MAX #define SCCSPREFIX "s." #define GET "get -e %s" --- b/usr.bin/patch/pch.c +++ b/usr.bin/patch/pch.c @@ -501,6 +501,7 @@ another_hunk(void) long repl_backtrack_position; /* file pos of first repl line */ LINENUM repl_patch_line; /* input line number for same */ LINENUM ptrn_copiable; /* # of copiable lines in ptrn */ + const char *p_err; char *s; size_t len; int context = 0; @@ -589,7 +590,10 @@ another_hunk(void) malformed(); if (strnEQ(s, "0,0", 3)) memmove(s, s + 2, strlen(s + 2) + 1); - p_first = (LINENUM) atol(s); + p_first = (LINENUM) strtonum(s, 0, LINENUM_MAX, &p_err); + if (p_err != NULL) + fatal("at line %ld: bad line number %s", + p_input_line, s); while (isdigit((unsigned char)*s)) s++; if (*s == ',') { @@ -597,7 +601,11 @@ another_hunk(void) ; if (!*s) malformed(); - p_ptrn_lines = ((LINENUM) atol(s)) - p_first + 1; + p_ptrn_lines = ((LINENUM) strtonum(s, 0, + LINENUM_MAX, &p_err)) - p_first + 1; + if (p_err != NULL) + fatal("at line %ld: bad line number %s", + p_input_line, s); } else if (p_first) p_ptrn_lines = 1; else { @@ -605,6 +613,9 @@ another_hunk(void) p_first = 1; } + if (p_first >= LINENUM_MAX - p_ptrn_lines || + p_ptrn_lines >= LINENUM_MAX - 6) + malformed(); /* we need this much at least */ p_max = p_ptrn_lines + 6; while (p_max >= hunkmax) @@ -656,7 +667,10 @@ another_hunk(void) ; if (!*s) malformed(); - p_newfirst = (LINENUM) atol(s); + p_newfirst = (LINENUM) strtonum(s, 0, LINENUM_MAX, &p_err); + if (p_err != NULL) + fatal("at line %ld: bad line number %s", + p_input_line, s); while (isdigit((unsigned char)*s)) s++; if (*s == ',') { @@ -664,14 +678,21 @@ another_hunk(void) ; if (!*s) malformed(); - p_repl_lines = ((LINENUM) atol(s)) - - p_newfirst + 1; + p_repl_lines = ((LINENUM) strtonum(s, 0, + LINENUM_MAX, &p_err)) - p_newfirst + 1; + if (p_err != NULL) + fatal("at line %ld: bad line number %s", + p_input_line, s); } else if (p_newfirst) p_repl_lines = 1; else { p_repl_lines = 0; p_newfirst = 1; } + + if (p_newfirst >= LINENUM_MAX - p_repl_lines || + p_repl_lines >= LINENUM_MAX - p_end) + malformed(); p_max = p_repl_lines + p_end; if (p_max > MAXHUNKSIZE) fatal("hunk too large (%ld lines) at line %ld: %s", @@ -864,11 +885,18 @@ hunk_done: s = buf + 4; if (!*s) malformed(); - p_first = (LINENUM) atol(s); + p_first = (LINENUM) strtonum(s, 0, LINENUM_MAX, &p_err); + if (p_err != NULL) + fatal("at line %ld: bad line number %s", + p_input_line, s); while (isdigit((unsigned char)*s)) s++; if (*s == ',') { - p_ptrn_lines = (LINENUM) atol(++s); + p_ptrn_lines = (LINENUM) strtonum(++s, 0, LINENUM_MAX, + &p_err); + if (p_err != NULL) + fatal("at line %ld: bad line number %s", + p_input_line, s); while (isdigit((unsigned char)*s)) s++; } else @@ -877,11 +905,17 @@ hunk_done: s++; if (*s != '+' || !*++s) malformed(); - p_newfirst = (LINENUM) atol(s); + p_newfirst = (LINENUM) strtonum(s, 0, LINENUM_MAX, &p_err); + if (p_err != NULL) + fatal("at line %ld: bad line number %s", + p_input_line, s); while (isdigit((unsigned char)*s)) s++; if (*s == ',') { - p_repl_lines = (LINENUM) atol(++s); + p_repl_lines = (LINENUM) strtonum(++s, 0, LINENUM_MAX, &p_err); + if (p_err != NULL) + fatal("at line %ld: bad line number %s", + p_input_line, s); while (isdigit((unsigned char)*s)) s++; } else @@ -890,6 +924,10 @@ hunk_done: s++; if (*s != '@') malformed(); + if (p_first >= LINENUM_MAX - p_ptrn_lines || + p_newfirst > LINENUM_MAX - p_repl_lines || + p_ptrn_lines >= LINENUM_MAX - p_repl_lines - 1) + malformed(); if (!p_ptrn_lines) p_first++; /* do append rather than insert */ p_max = p_ptrn_lines + p_repl_lines + 1; @@ -1029,35 +1067,52 @@ hunk_done: next_intuit_at(line_beginning, p_input_line); return false; } - p_first = (LINENUM) atol(buf); + p_first = (LINENUM) strtonum(buf, 0, LINENUM_MAX, &p_err); + if (p_err != NULL) + fatal("at line %ld: bad line number %s", + p_input_line, buf); for (s = buf; isdigit((unsigned char)*s); s++) ; if (*s == ',') { - p_ptrn_lines = (LINENUM) atol(++s) - p_first + 1; + p_ptrn_lines = (LINENUM) strtonum(++s, 0, + LINENUM_MAX, &p_err) - p_first + 1; + if (p_err != NULL) + malformed(); while (isdigit((unsigned char)*s)) s++; } else p_ptrn_lines = (*s != 'a'); + if (p_first >= LINENUM_MAX - p_ptrn_lines) + malformed(); hunk_type = *s; if (hunk_type == 'a') p_first++; /* do append rather than insert */ - min = (LINENUM) atol(++s); + min = (LINENUM) strtonum(++s, 0, LINENUM_MAX, &p_err); + if (p_err != NULL) + malformed(); for (; isdigit((unsigned char)*s); s++) ; - if (*s == ',') - max = (LINENUM) atol(++s); - else + if (*s == ',') { + max = (LINENUM) strtonum(++s, 0, LINENUM_MAX, &p_err); + if (p_err != NULL) + malformed(); + } else max = min; + if (min < 0 || min > max || max - min == LINENUM_MAX) + malformed(); if (hunk_type == 'd') min++; - p_end = p_ptrn_lines + 1 + max - min + 1; + p_newfirst = min; + p_repl_lines = max - min + 1; + if (p_newfirst > LINENUM_MAX - p_repl_lines || + p_ptrn_lines >= LINENUM_MAX - p_repl_lines - 1) + malformed(); + p_end = p_ptrn_lines + p_repl_lines + 1; if (p_end > MAXHUNKSIZE) fatal("hunk too large (%ld lines) at line %ld: %s", p_end, p_input_line, buf); while (p_end >= hunkmax) grow_hunkmax(); - p_newfirst = min; - p_repl_lines = max - min + 1; snprintf(buf, buf_size, "*** %ld,%ld\n", p_first, p_first + p_ptrn_lines - 1); p_line[0] = savestr(buf);