diff options
author | Andrew J. Schorr <aschorr@telemetry-investments.com> | 2017-01-26 20:17:22 -0500 |
---|---|---|
committer | Andrew J. Schorr <aschorr@telemetry-investments.com> | 2017-01-26 20:17:22 -0500 |
commit | e1bfc3a49d45024f84f489ac6a7ebcd505ec203a (patch) | |
tree | d867f14cbca1f6771e4ab7b203ea7f5e60a83080 | |
parent | 820db14f26ad8d203f6c3de6b51ff7bc2ec3476f (diff) | |
download | egawk-e1bfc3a49d45024f84f489ac6a7ebcd505ec203a.tar.gz egawk-e1bfc3a49d45024f84f489ac6a7ebcd505ec203a.tar.bz2 egawk-e1bfc3a49d45024f84f489ac6a7ebcd505ec203a.zip |
Fix possible string overrun in strtonum function.
-rw-r--r-- | ChangeLog | 13 | ||||
-rw-r--r-- | awk.h | 2 | ||||
-rw-r--r-- | awkgram.c | 4 | ||||
-rw-r--r-- | awkgram.y | 4 | ||||
-rw-r--r-- | builtin.c | 6 | ||||
-rw-r--r-- | mpfr.c | 2 | ||||
-rw-r--r-- | node.c | 8 |
7 files changed, 26 insertions, 13 deletions
@@ -1,5 +1,18 @@ 2017-01-26 Andrew J. Schorr <aschorr@telemetry-investments.com> + * awk.h (get_numbase): Add string length argument so we can operate + on unterminated strings. + * awkgram.y: Call get_numbase with string length, and fix off-by-one + error in length passed to nondec2awknum: should be strlen(tokstart)-1 + based on surrounding code. + * builtin.c (do_strtonum): Pass string length to get_numbase. + (nondec2awknum): Check string length before accessing characters. + * mpfr.c (force_mpnum): Pass string length to get_numbase. + * node.c (r_force_number): Pass string length to get_numbase. + (get_numbase): Add string length argument and honor it. + +2017-01-26 Andrew J. Schorr <aschorr@telemetry-investments.com> + * builtin.c (do_strftime): If format argument is passed, we need to terminate it in case it's a field variable. @@ -1679,7 +1679,7 @@ extern Regexp *re_update(NODE *t); extern void resyntax(int syntax); extern void resetup(void); extern int reisstring(const char *text, size_t len, Regexp *re, const char *buf); -extern int get_numbase(const char *str, bool use_locale); +extern int get_numbase(const char *str, size_t len, bool use_locale); extern bool using_utf8(void); /* symbol.c */ @@ -6414,7 +6414,7 @@ retry: base = 10; if (! do_traditional) { - base = get_numbase(tokstart, false); + base = get_numbase(tokstart, strlen(tokstart)-1, false); if (do_lint) { if (base == 8) lintwarn("numeric constant `%.*s' treated as octal", @@ -6450,7 +6450,7 @@ retry: } #endif if (base != 10) - d = nondec2awknum(tokstart, strlen(tokstart), NULL); + d = nondec2awknum(tokstart, strlen(tokstart)-1, NULL); else d = atof(tokstart); yylval->memory = make_profile_number(d, tokstart, strlen(tokstart) - 1); @@ -3994,7 +3994,7 @@ retry: base = 10; if (! do_traditional) { - base = get_numbase(tokstart, false); + base = get_numbase(tokstart, strlen(tokstart)-1, false); if (do_lint) { if (base == 8) lintwarn("numeric constant `%.*s' treated as octal", @@ -4030,7 +4030,7 @@ retry: } #endif if (base != 10) - d = nondec2awknum(tokstart, strlen(tokstart), NULL); + d = nondec2awknum(tokstart, strlen(tokstart)-1, NULL); else d = atof(tokstart); yylval->memory = make_profile_number(d, tokstart, strlen(tokstart) - 1); @@ -3558,7 +3558,7 @@ do_strtonum(int nargs) tmp = fixtype(POP_SCALAR()); if ((tmp->flags & NUMBER) != 0) d = (AWKNUM) tmp->numbr; - else if (get_numbase(tmp->stptr, use_lc_numeric) != 10) + else if (get_numbase(tmp->stptr, tmp->stlen, use_lc_numeric) != 10) d = nondec2awknum(tmp->stptr, tmp->stlen, NULL); else d = (AWKNUM) force_number(tmp)->numbr; @@ -3583,7 +3583,7 @@ nondec2awknum(char *str, size_t len, char **endptr) short val; char *start = str; - if (*str == '0' && (str[1] == 'x' || str[1] == 'X')) { + if (len >= 2 && *str == '0' && (str[1] == 'x' || str[1] == 'X')) { /* * User called strtonum("0x") or some such, * so just quit early. @@ -3633,7 +3633,7 @@ nondec2awknum(char *str, size_t len, char **endptr) } if (endptr) *endptr = str; - } else if (*str == '0') { + } else if (len >= 1 && *str == '0') { for (; len > 0; len--) { if (! isdigit((unsigned char) *str)) { if (endptr) @@ -303,7 +303,7 @@ force_mpnum(NODE *n, int do_nondec, int use_locale) cp1 = cp; if (do_nondec) - base = get_numbase(cp1, use_locale); + base = get_numbase(cp1, cpend - cp1, use_locale); if (! mpg_maybe_float(cp1, use_locale)) { mpg_zero(n); @@ -129,7 +129,7 @@ r_force_number(NODE *n) errno = 0; if (do_non_decimal_data /* main.c assures false if do_posix */ - && ! do_traditional && get_numbase(cp, true) != 10) { + && ! do_traditional && get_numbase(cp, cpend - cp, true) != 10) { /* nondec2awknum() saves and restores the byte after the string itself */ n->numbr = nondec2awknum(cp, cpend - cp, &ptr); } else { @@ -631,7 +631,7 @@ parse_escape(const char **string_ptr) /* get_numbase --- return the base to use for the number in 's' */ int -get_numbase(const char *s, bool use_locale) +get_numbase(const char *s, size_t len, bool use_locale) { int dec_point = '.'; const char *str = s; @@ -645,7 +645,7 @@ get_numbase(const char *s, bool use_locale) dec_point = loc.decimal_point[0]; /* XXX --- assumes one char */ #endif - if (str[0] != '0') + if (len < 2 || str[0] != '0') return 10; /* leading 0x or 0X */ @@ -658,7 +658,7 @@ get_numbase(const char *s, bool use_locale) * * These beasts can have trailing whitespace. Deal with that too. */ - for (; *str != '\0'; str++) { + for (; len > 0; len--, str++) { if (*str == 'e' || *str == 'E' || *str == dec_point) return 10; else if (! isdigit((unsigned char) *str)) |