aboutsummaryrefslogtreecommitdiff
path: root/editors
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2021-06-16 09:18:08 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2021-06-16 09:21:40 +0200
commita885ce1af05c4eaa5ebcf883cb3da3433ca1c48b (patch)
tree783574a66ea5a5af83d047b2a2c1feba42230159 /editors
parent83a4967e50422867f340328d404994553e56b839 (diff)
downloadbusybox-w32-a885ce1af05c4eaa5ebcf883cb3da3433ca1c48b.tar.gz
busybox-w32-a885ce1af05c4eaa5ebcf883cb3da3433ca1c48b.tar.bz2
busybox-w32-a885ce1af05c4eaa5ebcf883cb3da3433ca1c48b.zip
awk: fix use-after-free in "$BIGNUM1 $BIGGERNUM2" concat op
Second reference to a field reallocs/moves Fields[] array, but first ref still tries to use the element where it was before move. function old new delta fsrealloc 94 106 +12 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'editors')
-rw-r--r--editors/awk.c85
1 files changed, 71 insertions, 14 deletions
diff --git a/editors/awk.c b/editors/awk.c
index b4f6a3741..48836298c 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -1745,12 +1745,22 @@ static char* qrealloc(char *b, int n, int *size)
1745/* resize field storage space */ 1745/* resize field storage space */
1746static void fsrealloc(int size) 1746static void fsrealloc(int size)
1747{ 1747{
1748 int i; 1748 int i, newsize;
1749 1749
1750 if (size >= maxfields) { 1750 if (size >= maxfields) {
1751 /* Sanity cap, easier than catering for overflows */
1752 if (size > 0xffffff)
1753 bb_die_memory_exhausted();
1754
1751 i = maxfields; 1755 i = maxfields;
1752 maxfields = size + 16; 1756 maxfields = size + 16;
1753 Fields = xrealloc(Fields, maxfields * sizeof(Fields[0])); 1757
1758 newsize = maxfields * sizeof(Fields[0]);
1759 debug_printf_eval("fsrealloc: xrealloc(%p, %u)\n", Fields, newsize);
1760 Fields = xrealloc(Fields, newsize);
1761 debug_printf_eval("fsrealloc: Fields=%p..%p\n", Fields, (char*)Fields + newsize - 1);
1762 /* ^^^ did Fields[] move? debug aid for L.v getting "upstaged" by R.v in evaluate() */
1763
1754 for (; i < maxfields; i++) { 1764 for (; i < maxfields; i++) {
1755 Fields[i].type = VF_SPECIAL; 1765 Fields[i].type = VF_SPECIAL;
1756 Fields[i].string = NULL; 1766 Fields[i].string = NULL;
@@ -2614,20 +2624,30 @@ static var *evaluate(node *op, var *res)
2614 /* execute inevitable things */ 2624 /* execute inevitable things */
2615 if (opinfo & OF_RES1) 2625 if (opinfo & OF_RES1)
2616 L.v = evaluate(op1, v1); 2626 L.v = evaluate(op1, v1);
2617 if (opinfo & OF_RES2)
2618 R.v = evaluate(op->r.n, v1+1);
2619 if (opinfo & OF_STR1) { 2627 if (opinfo & OF_STR1) {
2620 L.s = getvar_s(L.v); 2628 L.s = getvar_s(L.v);
2621 debug_printf_eval("L.s:'%s'\n", L.s); 2629 debug_printf_eval("L.s:'%s'\n", L.s);
2622 } 2630 }
2623 if (opinfo & OF_STR2) {
2624 R.s = getvar_s(R.v);
2625 debug_printf_eval("R.s:'%s'\n", R.s);
2626 }
2627 if (opinfo & OF_NUM1) { 2631 if (opinfo & OF_NUM1) {
2628 L_d = getvar_i(L.v); 2632 L_d = getvar_i(L.v);
2629 debug_printf_eval("L_d:%f\n", L_d); 2633 debug_printf_eval("L_d:%f\n", L_d);
2630 } 2634 }
2635 /* NB: Must get string/numeric values of L (done above)
2636 * _before_ evaluate()'ing R.v: if both L and R are $NNNs,
2637 * and right one is large, then L.v points to Fields[NNN1],
2638 * second evaluate() reallocates and moves (!) Fields[],
2639 * R.v points to Fields[NNN2] but L.v now points to freed mem!
2640 * (Seen trying to evaluate "$444 $44444")
2641 */
2642 if (opinfo & OF_RES2) {
2643 R.v = evaluate(op->r.n, v1+1);
2644 //TODO: L.v may be invalid now, set L.v to NULL to catch bugs?
2645 //L.v = NULL;
2646 }
2647 if (opinfo & OF_STR2) {
2648 R.s = getvar_s(R.v);
2649 debug_printf_eval("R.s:'%s'\n", R.s);
2650 }
2631 2651
2632 debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK)); 2652 debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK));
2633 switch (XC(opinfo & OPCLSMASK)) { 2653 switch (XC(opinfo & OPCLSMASK)) {
@@ -2636,6 +2656,7 @@ static var *evaluate(node *op, var *res)
2636 2656
2637 /* test pattern */ 2657 /* test pattern */
2638 case XC( OC_TEST ): 2658 case XC( OC_TEST ):
2659 debug_printf_eval("TEST\n");
2639 if ((op1->info & OPCLSMASK) == OC_COMMA) { 2660 if ((op1->info & OPCLSMASK) == OC_COMMA) {
2640 /* it's range pattern */ 2661 /* it's range pattern */
2641 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) { 2662 if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) {
@@ -2653,25 +2674,32 @@ static var *evaluate(node *op, var *res)
2653 2674
2654 /* just evaluate an expression, also used as unconditional jump */ 2675 /* just evaluate an expression, also used as unconditional jump */
2655 case XC( OC_EXEC ): 2676 case XC( OC_EXEC ):
2677 debug_printf_eval("EXEC\n");
2656 break; 2678 break;
2657 2679
2658 /* branch, used in if-else and various loops */ 2680 /* branch, used in if-else and various loops */
2659 case XC( OC_BR ): 2681 case XC( OC_BR ):
2682 debug_printf_eval("BR\n");
2660 op = istrue(L.v) ? op->a.n : op->r.n; 2683 op = istrue(L.v) ? op->a.n : op->r.n;
2661 break; 2684 break;
2662 2685
2663 /* initialize for-in loop */ 2686 /* initialize for-in loop */
2664 case XC( OC_WALKINIT ): 2687 case XC( OC_WALKINIT ):
2688 debug_printf_eval("WALKINIT\n");
2665 hashwalk_init(L.v, iamarray(R.v)); 2689 hashwalk_init(L.v, iamarray(R.v));
2666 break; 2690 break;
2667 2691
2668 /* get next array item */ 2692 /* get next array item */
2669 case XC( OC_WALKNEXT ): 2693 case XC( OC_WALKNEXT ):
2694 debug_printf_eval("WALKNEXT\n");
2670 op = hashwalk_next(L.v) ? op->a.n : op->r.n; 2695 op = hashwalk_next(L.v) ? op->a.n : op->r.n;
2671 break; 2696 break;
2672 2697
2673 case XC( OC_PRINT ): 2698 case XC( OC_PRINT ):
2674 case XC( OC_PRINTF ): { 2699 debug_printf_eval("PRINT /\n");
2700 case XC( OC_PRINTF ):
2701 debug_printf_eval("PRINTF\n");
2702 {
2675 FILE *F = stdout; 2703 FILE *F = stdout;
2676 IF_FEATURE_AWK_GNU_EXTENSIONS(int len;) 2704 IF_FEATURE_AWK_GNU_EXTENSIONS(int len;)
2677 2705
@@ -2726,22 +2754,28 @@ static var *evaluate(node *op, var *res)
2726 /* case XC( OC_DELETE ): - moved to happen before arg evaluation */ 2754 /* case XC( OC_DELETE ): - moved to happen before arg evaluation */
2727 2755
2728 case XC( OC_NEWSOURCE ): 2756 case XC( OC_NEWSOURCE ):
2757 debug_printf_eval("NEWSOURCE\n");
2729 g_progname = op->l.new_progname; 2758 g_progname = op->l.new_progname;
2730 break; 2759 break;
2731 2760
2732 case XC( OC_RETURN ): 2761 case XC( OC_RETURN ):
2762 debug_printf_eval("RETURN\n");
2733 copyvar(res, L.v); 2763 copyvar(res, L.v);
2734 break; 2764 break;
2735 2765
2736 case XC( OC_NEXTFILE ): 2766 case XC( OC_NEXTFILE ):
2767 debug_printf_eval("NEXTFILE\n");
2737 nextfile = TRUE; 2768 nextfile = TRUE;
2738 case XC( OC_NEXT ): 2769 case XC( OC_NEXT ):
2770 debug_printf_eval("NEXT\n");
2739 nextrec = TRUE; 2771 nextrec = TRUE;
2740 case XC( OC_DONE ): 2772 case XC( OC_DONE ):
2773 debug_printf_eval("DONE\n");
2741 clrvar(res); 2774 clrvar(res);
2742 break; 2775 break;
2743 2776
2744 case XC( OC_EXIT ): 2777 case XC( OC_EXIT ):
2778 debug_printf_eval("EXIT\n");
2745 awk_exit(L_d); 2779 awk_exit(L_d);
2746 2780
2747 /* -- recursive node type -- */ 2781 /* -- recursive node type -- */
@@ -2761,15 +2795,18 @@ static var *evaluate(node *op, var *res)
2761 break; 2795 break;
2762 2796
2763 case XC( OC_IN ): 2797 case XC( OC_IN ):
2798 debug_printf_eval("IN\n");
2764 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0); 2799 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
2765 break; 2800 break;
2766 2801
2767 case XC( OC_REGEXP ): 2802 case XC( OC_REGEXP ):
2803 debug_printf_eval("REGEXP\n");
2768 op1 = op; 2804 op1 = op;
2769 L.s = getvar_s(intvar[F0]); 2805 L.s = getvar_s(intvar[F0]);
2770 goto re_cont; 2806 goto re_cont;
2771 2807
2772 case XC( OC_MATCH ): 2808 case XC( OC_MATCH ):
2809 debug_printf_eval("MATCH\n");
2773 op1 = op->r.n; 2810 op1 = op->r.n;
2774 re_cont: 2811 re_cont:
2775 { 2812 {
@@ -2795,6 +2832,7 @@ static var *evaluate(node *op, var *res)
2795 break; 2832 break;
2796 2833
2797 case XC( OC_TERNARY ): 2834 case XC( OC_TERNARY ):
2835 debug_printf_eval("TERNARY\n");
2798 if ((op->r.n->info & OPCLSMASK) != OC_COLON) 2836 if ((op->r.n->info & OPCLSMASK) != OC_COLON)
2799 syntax_error(EMSG_POSSIBLE_ERROR); 2837 syntax_error(EMSG_POSSIBLE_ERROR);
2800 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res); 2838 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
@@ -2803,6 +2841,7 @@ static var *evaluate(node *op, var *res)
2803 case XC( OC_FUNC ): { 2841 case XC( OC_FUNC ): {
2804 var *vbeg, *v; 2842 var *vbeg, *v;
2805 const char *sv_progname; 2843 const char *sv_progname;
2844 debug_printf_eval("FUNC\n");
2806 2845
2807 /* The body might be empty, still has to eval the args */ 2846 /* The body might be empty, still has to eval the args */
2808 if (!op->r.n->info && !op->r.f->body.first) 2847 if (!op->r.n->info && !op->r.f->body.first)
@@ -2832,7 +2871,10 @@ static var *evaluate(node *op, var *res)
2832 } 2871 }
2833 2872
2834 case XC( OC_GETLINE ): 2873 case XC( OC_GETLINE ):
2835 case XC( OC_PGETLINE ): { 2874 debug_printf_eval("GETLINE /\n");
2875 case XC( OC_PGETLINE ):
2876 debug_printf_eval("PGETLINE\n");
2877 {
2836 rstream *rsm; 2878 rstream *rsm;
2837 int i; 2879 int i;
2838 2880
@@ -2873,6 +2915,7 @@ static var *evaluate(node *op, var *res)
2873 /* simple builtins */ 2915 /* simple builtins */
2874 case XC( OC_FBLTIN ): { 2916 case XC( OC_FBLTIN ): {
2875 double R_d = R_d; /* for compiler */ 2917 double R_d = R_d; /* for compiler */
2918 debug_printf_eval("FBLTIN\n");
2876 2919
2877 switch (opn) { 2920 switch (opn) {
2878 case F_in: 2921 case F_in:
@@ -2986,14 +3029,18 @@ static var *evaluate(node *op, var *res)
2986 } 3029 }
2987 3030
2988 case XC( OC_BUILTIN ): 3031 case XC( OC_BUILTIN ):
3032 debug_printf_eval("BUILTIN\n");
2989 res = exec_builtin(op, res); 3033 res = exec_builtin(op, res);
2990 break; 3034 break;
2991 3035
2992 case XC( OC_SPRINTF ): 3036 case XC( OC_SPRINTF ):
3037 debug_printf_eval("SPRINTF\n");
2993 setvar_p(res, awk_printf(op1, NULL)); 3038 setvar_p(res, awk_printf(op1, NULL));
2994 break; 3039 break;
2995 3040
2996 case XC( OC_UNARY ): { 3041 case XC( OC_UNARY ):
3042 debug_printf_eval("UNARY\n");
3043 {
2997 double Ld, R_d; 3044 double Ld, R_d;
2998 3045
2999 Ld = R_d = getvar_i(R.v); 3046 Ld = R_d = getvar_i(R.v);
@@ -3023,7 +3070,9 @@ static var *evaluate(node *op, var *res)
3023 break; 3070 break;
3024 } 3071 }
3025 3072
3026 case XC( OC_FIELD ): { 3073 case XC( OC_FIELD ):
3074 debug_printf_eval("FIELD\n");
3075 {
3027 int i = (int)getvar_i(R.v); 3076 int i = (int)getvar_i(R.v);
3028 if (i < 0) 3077 if (i < 0)
3029 syntax_error(EMSG_NEGATIVE_FIELD); 3078 syntax_error(EMSG_NEGATIVE_FIELD);
@@ -3040,8 +3089,10 @@ static var *evaluate(node *op, var *res)
3040 3089
3041 /* concatenation (" ") and index joining (",") */ 3090 /* concatenation (" ") and index joining (",") */
3042 case XC( OC_CONCAT ): 3091 case XC( OC_CONCAT ):
3092 debug_printf_eval("CONCAT /\n");
3043 case XC( OC_COMMA ): { 3093 case XC( OC_COMMA ): {
3044 const char *sep = ""; 3094 const char *sep = "";
3095 debug_printf_eval("COMMA\n");
3045 if ((opinfo & OPCLSMASK) == OC_COMMA) 3096 if ((opinfo & OPCLSMASK) == OC_COMMA)
3046 sep = getvar_s(intvar[SUBSEP]); 3097 sep = getvar_s(intvar[SUBSEP]);
3047 setvar_p(res, xasprintf("%s%s%s", L.s, sep, R.s)); 3098 setvar_p(res, xasprintf("%s%s%s", L.s, sep, R.s));
@@ -3049,17 +3100,22 @@ static var *evaluate(node *op, var *res)
3049 } 3100 }
3050 3101
3051 case XC( OC_LAND ): 3102 case XC( OC_LAND ):
3103 debug_printf_eval("LAND\n");
3052 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0); 3104 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
3053 break; 3105 break;
3054 3106
3055 case XC( OC_LOR ): 3107 case XC( OC_LOR ):
3108 debug_printf_eval("LOR\n");
3056 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n)); 3109 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
3057 break; 3110 break;
3058 3111
3059 case XC( OC_BINARY ): 3112 case XC( OC_BINARY ):
3060 case XC( OC_REPLACE ): { 3113 debug_printf_eval("BINARY /\n");
3114 case XC( OC_REPLACE ):
3115 debug_printf_eval("REPLACE\n");
3116 {
3061 double R_d = getvar_i(R.v); 3117 double R_d = getvar_i(R.v);
3062 debug_printf_eval("BINARY/REPLACE: R_d:%f opn:%c\n", R_d, opn); 3118 debug_printf_eval("R_d:%f opn:%c\n", R_d, opn);
3063 switch (opn) { 3119 switch (opn) {
3064 case '+': 3120 case '+':
3065 L_d += R_d; 3121 L_d += R_d;
@@ -3095,6 +3151,7 @@ static var *evaluate(node *op, var *res)
3095 case XC( OC_COMPARE ): { 3151 case XC( OC_COMPARE ): {
3096 int i = i; /* for compiler */ 3152 int i = i; /* for compiler */
3097 double Ld; 3153 double Ld;
3154 debug_printf_eval("COMPARE\n");
3098 3155
3099 if (is_numeric(L.v) && is_numeric(R.v)) { 3156 if (is_numeric(L.v) && is_numeric(R.v)) {
3100 Ld = getvar_i(L.v) - getvar_i(R.v); 3157 Ld = getvar_i(L.v) - getvar_i(R.v);