--- b/usr.bin/patch/common.h +++ b/usr.bin/patch/common.h @@ -23,7 +23,7 @@ * -C option added in 1998, original code by Marc Espie, based on FreeBSD * behaviour * - * $OpenBSD: common.h,v 1.26 2006/03/11 19:41:30 otto Exp $ + * $OpenBSD: common.h,v 1.28 2014/11/25 10:26:07 tobias Exp $ * $FreeBSD$ */ @@ -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 @@ -24,7 +24,7 @@ * -C option added in 1998, original code by Marc Espie, based on FreeBSD * behaviour * - * $OpenBSD: pch.c,v 1.39 2012/04/11 08:07:13 ajacoutot Exp $ + * $OpenBSD: pch.c,v 1.46 2014/11/26 10:11:21 tobias Exp $ * $FreeBSD$ */ @@ -38,6 +38,7 @@ #include #include #include +#include #include "common.h" #include "util.h" @@ -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) strtol(s, 0, 0); + if (errno == ERANGE) + 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) strtol(s, 0, + 0)) - p_first + 1; + if (errno == ERANGE) + 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) strtol(s, 0, 0); + if (errno == ERANGE) + 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) strtol(s, 0, + 0)) - p_newfirst + 1; + if (errno == ERANGE) + 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,17 @@ hunk_done: s = buf + 4; if (!*s) malformed(); - p_first = (LINENUM) atol(s); + p_first = (LINENUM) strtol(s, 0, 0); + if (errno == ERANGE) + 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) strtol(++s, 0, 0); + if (errno == ERANGE) + fatal("at line %ld: bad line number %s", + p_input_line, s); while (isdigit((unsigned char)*s)) s++; } else @@ -877,11 +904,17 @@ hunk_done: s++; if (*s != '+' || !*++s) malformed(); - p_newfirst = (LINENUM) atol(s); + p_newfirst = (LINENUM) strtol(s, 0, 0); + if (errno == ERANGE) + 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) strtol(++s, 0, 0); + if (errno == ERANGE) + fatal("at line %ld: bad line number %s", + p_input_line, s); while (isdigit((unsigned char)*s)) s++; } else @@ -890,6 +923,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 +1066,52 @@ hunk_done: next_intuit_at(line_beginning, p_input_line); return false; } - p_first = (LINENUM) atol(buf); + p_first = (LINENUM) strtol(buf, 0, 0); + if (errno == ERANGE) + 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) strtol(++s, 0, + 0) - p_first + 1; + if (errno == ERANGE) + 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) strtol(++s, 0, 0); + if (errno == ERANGE) + malformed(); for (; isdigit((unsigned char)*s); s++) ; - if (*s == ',') - max = (LINENUM) atol(++s); - else + if (*s == ',') { + max = (LINENUM) strtol(++s, 0, 0); + if (errno == ERANGE) + 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);