From 820db14f26ad8d203f6c3de6b51ff7bc2ec3476f Mon Sep 17 00:00:00 2001 From: "Andrew J. Schorr" Date: Thu, 26 Jan 2017 15:37:12 -0500 Subject: Fix bug in strftime when format argument is an unterminated field string. --- builtin.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'builtin.c') diff --git a/builtin.c b/builtin.c index f71d71dd..0c6cbc01 100644 --- a/builtin.c +++ b/builtin.c @@ -1907,6 +1907,7 @@ do_strftime(int nargs) int do_gmt; NODE *val = NULL; NODE *sub = NULL; + char save; static const time_t time_t_min = TYPE_MINIMUM(time_t); static const time_t time_t_max = TYPE_MAXIMUM(time_t); @@ -1980,6 +1981,8 @@ do_strftime(int nargs) DEREF(t1); return make_string("", 0); } + save = format[formatlen]; + t1->stptr[formatlen] = '\0'; } if (do_gmt) @@ -1987,8 +1990,10 @@ do_strftime(int nargs) else tm = localtime(& fclock); - if (tm == NULL) - return make_string("", 0); + if (tm == NULL) { + ret = make_string("", 0); + goto done; + } bufp = buf; bufsize = sizeof(buf); @@ -2014,8 +2019,11 @@ do_strftime(int nargs) ret = make_string(bufp, buflen); if (bufp != buf) efree(bufp); - if (t1) +done: + if (t1) { + t1->stptr[formatlen] = save; DEREF(t1); + } return ret; } -- cgit v1.2.3 From e1bfc3a49d45024f84f489ac6a7ebcd505ec203a Mon Sep 17 00:00:00 2001 From: "Andrew J. Schorr" Date: Thu, 26 Jan 2017 20:17:22 -0500 Subject: Fix possible string overrun in strtonum function. --- builtin.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'builtin.c') diff --git a/builtin.c b/builtin.c index 0c6cbc01..32062d08 100644 --- a/builtin.c +++ b/builtin.c @@ -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) -- cgit v1.2.3 From e8c6871e80524e928954b01ff50030a11b2a94eb Mon Sep 17 00:00:00 2001 From: "Andrew J. Schorr" Date: Thu, 26 Jan 2017 21:36:00 -0500 Subject: Terminate strings in dcgettext, dcngettext, and bindtextdomain functions. --- builtin.c | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) (limited to 'builtin.c') diff --git a/builtin.c b/builtin.c index 32062d08..faee54ee 100644 --- a/builtin.c +++ b/builtin.c @@ -3751,7 +3751,7 @@ do_dcgettext(int nargs) #if ENABLE_NLS && defined(LC_MESSAGES) && HAVE_DCGETTEXT int lc_cat; char *domain; - char save; + char save, save1; bool saved_end = false; if (nargs == 3) { /* third argument */ @@ -3782,9 +3782,12 @@ do_dcgettext(int nargs) t1 = POP_STRING(); /* first argument */ string = t1->stptr; + save1 = string[t1->stlen]; + string[t1->stlen] = '\0'; #if ENABLE_NLS && defined(LC_MESSAGES) && HAVE_DCGETTEXT the_result = dcgettext(domain, string, lc_cat); + string[t1->stlen] = save1; if (saved_end) domain[t2->stlen] = save; if (t2 != NULL) @@ -3805,11 +3808,12 @@ do_dcngettext(int nargs) unsigned long number; AWKNUM d; char *the_result; + size_t reslen; #if ENABLE_NLS && defined(LC_MESSAGES) && HAVE_DCGETTEXT int lc_cat; char *domain; - char save; + char save, save1, save2; bool saved_end = false; if (nargs == 5) { /* fifth argument */ @@ -3851,17 +3855,31 @@ do_dcngettext(int nargs) #if ENABLE_NLS && defined(LC_MESSAGES) && HAVE_DCGETTEXT + save1 = string1[t1->stlen]; + string1[t1->stlen] = '\0'; + save2 = string2[t2->stlen]; + string2[t2->stlen] = '\0'; the_result = dcngettext(domain, string1, string2, number, lc_cat); + reslen = strlen(the_result); + string1[t1->stlen] = save1; + string2[t2->stlen] = save2; if (saved_end) domain[t3->stlen] = save; if (t3 != NULL) DEREF(t3); #else - the_result = (number == 1 ? string1 : string2); + if (number == 1) { + the_result = string1; + reslen = t1->stlen; + } + else { + the_result = string2; + reslen = t2->stlen; + } #endif DEREF(t1); DEREF(t2); - return make_string(the_result, strlen(the_result)); + return make_string(the_result, reslen); } /* do_bindtextdomain --- set the directory for a text domain */ @@ -3886,29 +3904,32 @@ do_bindtextdomain(int nargs) /* set defaults */ directory = NULL; domain = TEXTDOMAIN; - char save; - bool saved_end = false; + char save, save1; if (nargs == 2) { /* second argument */ t2 = POP_STRING(); domain = (const char *) t2->stptr; save = t2->stptr[t2->stlen]; t2->stptr[t2->stlen] = '\0'; - saved_end = true; } /* first argument */ t1 = POP_STRING(); - if (t1->stlen > 0) + if (t1->stlen > 0) { directory = (const char *) t1->stptr; + save1 = t1->stptr[t1->stlen]; + t1->stptr[t1->stlen] = '\0'; + } the_result = bindtextdomain(domain, directory); + if (directory) + t1->stptr[t1->stlen] = save1; DEREF(t1); - if (saved_end) + if (t2 != NULL) { t2->stptr[t2->stlen] = save; - if (t2 != NULL) DEREF(t2); + } return make_string(the_result, strlen(the_result)); } -- cgit v1.2.3 From a7addf98875555f48f30e7a9260f39a36a7b3e75 Mon Sep 17 00:00:00 2001 From: "Andrew J. Schorr" Date: Fri, 27 Jan 2017 13:25:02 -0500 Subject: Introduce some helpful macros for terminating strings, and fix overrun in dcgettext. --- builtin.c | 43 +++++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 24 deletions(-) (limited to 'builtin.c') diff --git a/builtin.c b/builtin.c index faee54ee..14f5c730 100644 --- a/builtin.c +++ b/builtin.c @@ -1981,8 +1981,7 @@ do_strftime(int nargs) DEREF(t1); return make_string("", 0); } - save = format[formatlen]; - t1->stptr[formatlen] = '\0'; + str_terminate(t1, save); } if (do_gmt) @@ -2021,7 +2020,7 @@ do_strftime(int nargs) efree(bufp); done: if (t1) { - t1->stptr[formatlen] = save; + str_restore(t1, save); DEREF(t1); } return ret; @@ -3751,8 +3750,8 @@ do_dcgettext(int nargs) #if ENABLE_NLS && defined(LC_MESSAGES) && HAVE_DCGETTEXT int lc_cat; char *domain; - char save, save1; - bool saved_end = false; + char save1, save2; + size_t reslen; if (nargs == 3) { /* third argument */ tmp = POP_STRING(); @@ -3764,9 +3763,7 @@ do_dcgettext(int nargs) if (nargs >= 2) { /* second argument */ t2 = POP_STRING(); domain = t2->stptr; - save = domain[t2->stlen]; - domain[t2->stlen] = '\0'; - saved_end = true; + str_terminate(t2, save2); } else domain = TEXTDOMAIN; #else @@ -3782,21 +3779,22 @@ do_dcgettext(int nargs) t1 = POP_STRING(); /* first argument */ string = t1->stptr; - save1 = string[t1->stlen]; - string[t1->stlen] = '\0'; #if ENABLE_NLS && defined(LC_MESSAGES) && HAVE_DCGETTEXT + str_terminate(t1, save1); the_result = dcgettext(domain, string, lc_cat); - string[t1->stlen] = save1; - if (saved_end) - domain[t2->stlen] = save; - if (t2 != NULL) + str_restore(t1, save1); + if (t2 != NULL) { + str_restore(t2, save2); DEREF(t2); + } + reslen = strlen(the_result); #else the_result = string; + reslen = t1->stlen; #endif DEREF(t1); - return make_string(the_result, strlen(the_result)); + return make_string(the_result, reslen); } @@ -3855,14 +3853,12 @@ do_dcngettext(int nargs) #if ENABLE_NLS && defined(LC_MESSAGES) && HAVE_DCGETTEXT - save1 = string1[t1->stlen]; - string1[t1->stlen] = '\0'; - save2 = string2[t2->stlen]; - string2[t2->stlen] = '\0'; + str_terminate(t1, save1); + str_terminate(t2, save2); the_result = dcngettext(domain, string1, string2, number, lc_cat); reslen = strlen(the_result); - string1[t1->stlen] = save1; - string2[t2->stlen] = save2; + str_restore(t1, save1); + str_restore(t2, save2); if (saved_end) domain[t3->stlen] = save; if (t3 != NULL) @@ -3917,13 +3913,12 @@ do_bindtextdomain(int nargs) t1 = POP_STRING(); if (t1->stlen > 0) { directory = (const char *) t1->stptr; - save1 = t1->stptr[t1->stlen]; - t1->stptr[t1->stlen] = '\0'; + str_terminate(t1, save1); } the_result = bindtextdomain(domain, directory); if (directory) - t1->stptr[t1->stlen] = save1; + str_restore(t1, save1); DEREF(t1); if (t2 != NULL) { -- cgit v1.2.3