aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2021-07-04 01:25:34 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2021-07-04 01:25:34 +0200
commite2e3802987266c98df0efdf40ad5da4b07df0113 (patch)
tree8065733d6843453779fbc7927c95edcee805a9bb
parent08ca313d7edb99687068b93b5d2435b59f3db23a (diff)
downloadbusybox-w32-e2e3802987266c98df0efdf40ad5da4b07df0113.tar.gz
busybox-w32-e2e3802987266c98df0efdf40ad5da4b07df0113.tar.bz2
busybox-w32-e2e3802987266c98df0efdf40ad5da4b07df0113.zip
awk: fix printf buffer overflow
function old new delta awk_printf 468 546 +78 fmt_num 239 247 +8 getvar_s 125 111 -14 evaluate 3343 3329 -14 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/2 up/down: 86/-28) Total: 58 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--editors/awk.c94
1 files changed, 55 insertions, 39 deletions
diff --git a/editors/awk.c b/editors/awk.c
index cd135ef64..a440a6234 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -904,25 +904,23 @@ static double my_strtod(char **pp)
904 904
905/* -------- working with variables (set/get/copy/etc) -------- */ 905/* -------- working with variables (set/get/copy/etc) -------- */
906 906
907static int fmt_num(char *b, int size, const char *format, double n, int int_as_int) 907static void fmt_num(const char *format, double n)
908{ 908{
909 int r = 0; 909 if (n == (long long)n) {
910 char c; 910 snprintf(g_buf, MAXVARFMT, "%lld", (long long)n);
911 const char *s = format;
912
913 if (int_as_int && n == (long long)n) {
914 r = snprintf(b, size, "%lld", (long long)n);
915 } else { 911 } else {
912 const char *s = format;
913 char c;
914
916 do { c = *s; } while (c && *++s); 915 do { c = *s; } while (c && *++s);
917 if (strchr("diouxX", c)) { 916 if (strchr("diouxX", c)) {
918 r = snprintf(b, size, format, (int)n); 917 snprintf(g_buf, MAXVARFMT, format, (int)n);
919 } else if (strchr("eEfFgGaA", c)) { 918 } else if (strchr("eEfFgGaA", c)) {
920 r = snprintf(b, size, format, n); 919 snprintf(g_buf, MAXVARFMT, format, n);
921 } else { 920 } else {
922 syntax_error(EMSG_INV_FMT); 921 syntax_error(EMSG_INV_FMT);
923 } 922 }
924 } 923 }
925 return r;
926} 924}
927 925
928static xhash *iamarray(var *a) 926static xhash *iamarray(var *a)
@@ -999,7 +997,7 @@ static const char *getvar_s(var *v)
999{ 997{
1000 /* if v is numeric and has no cached string, convert it to string */ 998 /* if v is numeric and has no cached string, convert it to string */
1001 if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) { 999 if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
1002 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[CONVFMT]), v->number, TRUE); 1000 fmt_num(getvar_s(intvar[CONVFMT]), v->number);
1003 v->string = xstrdup(g_buf); 1001 v->string = xstrdup(g_buf);
1004 v->type |= VF_CACHED; 1002 v->type |= VF_CACHED;
1005 } 1003 }
@@ -2315,12 +2313,9 @@ static int awk_getline(rstream *rsm, var *v)
2315#endif 2313#endif
2316static char *awk_printf(node *n, int *len) 2314static char *awk_printf(node *n, int *len)
2317{ 2315{
2318 char *b = NULL; 2316 char *b;
2319 char *fmt, *s, *f; 2317 char *fmt, *f;
2320 const char *s1; 2318 int i;
2321 int i, j, incr, bsize;
2322 char c, c1;
2323 var *arg;
2324 2319
2325 //tmpvar = nvalloc(1); 2320 //tmpvar = nvalloc(1);
2326#define TMPVAR (&G.awk_printf__tmpvar) 2321#define TMPVAR (&G.awk_printf__tmpvar)
@@ -2333,8 +2328,14 @@ static char *awk_printf(node *n, int *len)
2333 // to evaluate() potentially recursing into another awk_printf() can't 2328 // to evaluate() potentially recursing into another awk_printf() can't
2334 // mangle the value. 2329 // mangle the value.
2335 2330
2331 b = NULL;
2336 i = 0; 2332 i = 0;
2337 while (*f) { 2333 while (*f) { /* "print one format spec" loop */
2334 char *s;
2335 char c;
2336 char sv;
2337 var *arg;
2338
2338 s = f; 2339 s = f;
2339 while (*f && (*f != '%' || *++f == '%')) 2340 while (*f && (*f != '%' || *++f == '%'))
2340 f++; 2341 f++;
@@ -2343,40 +2344,55 @@ static char *awk_printf(node *n, int *len)
2343 syntax_error("%*x formats are not supported"); 2344 syntax_error("%*x formats are not supported");
2344 f++; 2345 f++;
2345 } 2346 }
2346
2347 incr = (f - s) + MAXVARFMT;
2348 b = qrealloc(b, incr + i, &bsize);
2349 c = *f; 2347 c = *f;
2350 if (c != '\0') 2348 if (!c) {
2351 f++; 2349 /* Tail of fmt with no percent chars,
2352 c1 = *f; 2350 * or "....%" (percent seen, but no format specifier char found)
2351 */
2352 goto tail;
2353 }
2354 sv = *++f;
2353 *f = '\0'; 2355 *f = '\0';
2354 arg = evaluate(nextarg(&n), TMPVAR); 2356 arg = evaluate(nextarg(&n), TMPVAR);
2355 2357
2356 j = i; 2358 /* Result can be arbitrarily long. Example:
2357 if (c == 'c' || !c) { 2359 * printf "%99999s", "BOOM"
2358 i += sprintf(b+i, s, is_numeric(arg) ? 2360 */
2361 if (c == 'c') {
2362 s = xasprintf(s, is_numeric(arg) ?
2359 (char)getvar_i(arg) : *getvar_s(arg)); 2363 (char)getvar_i(arg) : *getvar_s(arg));
2360 } else if (c == 's') { 2364 } else if (c == 's') {
2361 s1 = getvar_s(arg); 2365 s = xasprintf(s, getvar_s(arg));
2362 b = qrealloc(b, incr+i+strlen(s1), &bsize);
2363 i += sprintf(b+i, s, s1);
2364 } else { 2366 } else {
2365 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE); 2367 double d = getvar_i(arg);
2368 if (strchr("diouxX", c)) {
2369//TODO: make it wider here (%x -> %llx etc)?
2370 s = xasprintf(s, (int)d);
2371 } else if (strchr("eEfFgGaA", c)) {
2372 s = xasprintf(s, d);
2373 } else {
2374 syntax_error(EMSG_INV_FMT);
2375 }
2366 } 2376 }
2367 *f = c1; 2377 *f = sv;
2368 2378
2369 /* if there was an error while sprintf, return value is negative */ 2379 if (i == 0) {
2370 if (i < j) 2380 b = s;
2371 i = j; 2381 i = strlen(b);
2382 continue;
2383 }
2384 tail:
2385 b = xrealloc(b, i + strlen(s) + 1);
2386 i = stpcpy(b + i, s) - b;
2387 if (!c) /* tail? */
2388 break;
2389 free(s);
2372 } 2390 }
2373 2391
2374 free(fmt); 2392 free(fmt);
2375 //nvfree(tmpvar, 1); 2393 //nvfree(tmpvar, 1);
2376#undef TMPVAR 2394#undef TMPVAR
2377 2395
2378 b = xrealloc(b, i + 1);
2379 b[i] = '\0';
2380#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS 2396#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS
2381 if (len) 2397 if (len)
2382 *len = i; 2398 *len = i;
@@ -2936,8 +2952,8 @@ static var *evaluate(node *op, var *res)
2936 for (;;) { 2952 for (;;) {
2937 var *v = evaluate(nextarg(&op1), TMPVAR0); 2953 var *v = evaluate(nextarg(&op1), TMPVAR0);
2938 if (v->type & VF_NUMBER) { 2954 if (v->type & VF_NUMBER) {
2939 fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]), 2955 fmt_num(getvar_s(intvar[OFMT]),
2940 getvar_i(v), TRUE); 2956 getvar_i(v));
2941 fputs(g_buf, F); 2957 fputs(g_buf, F);
2942 } else { 2958 } else {
2943 fputs(getvar_s(v), F); 2959 fputs(getvar_s(v), F);