From c3bfdac8e0e9a21d524ad72036953f68d2193e52 Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Tue, 21 May 2024 14:46:08 +0200 Subject: [PATCH 2/2] awk: fix ternary operator and precedence of = Adjust the = precedence test to match behavior of gawk, mawk and FreeBSD. awk 'BEGIN {print v=3==3; print v}' should print two '1'. To fix this, and to unbreak the ternary conditional operator, we restore the precedence of = in the token list, but override this with a lower priority when the assignment is on the right side of a compare. This fixes commit 0256e00a9d07 (awk: fix precedence of = relative to ==) [1] CVE: CVE-2023-42364 CVE-2023-42365 Upstream-Status: Submitted [http://lists.busybox.net/pipermail/busybox/2024-May/090766.html] [1] https://bugs.busybox.net/show_bug.cgi?id=15871#c6 Signed-off-by: Natanael Copa (cherry picked from commit 1714301c405ef03b39605c85c23f22a190cddd95) Signed-off-by: Khem Raj --- editors/awk.c | 18 ++++++++++++++---- testsuite/awk.tests | 9 +++++++-- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/editors/awk.c b/editors/awk.c index aff86fe..f320d8c 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -442,9 +442,10 @@ static const uint32_t tokeninfo[] ALIGN4 = { #define TI_PREINC (OC_UNARY|xV|P(9)|'P') #define TI_PREDEC (OC_UNARY|xV|P(9)|'M') TI_PREINC, TI_PREDEC, OC_FIELD|xV|P(5), - OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(38), OC_REPLACE|NV|P(38)|'+', OC_REPLACE|NV|P(38)|'-', - OC_REPLACE|NV|P(38)|'*', OC_REPLACE|NV|P(38)|'/', OC_REPLACE|NV|P(38)|'%', OC_REPLACE|NV|P(38)|'&', - OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', OC_REPLACE|NV|P(38)|'&', OC_BINARY|NV|P(15)|'&', +#define TI_ASSIGN (OC_MOVE|VV|P(74)) + OC_COMPARE|VV|P(39)|5, TI_ASSIGN, OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-', + OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&', + OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*', OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1, #define TI_LESS (OC_COMPARE|VV|P(39)|2) @@ -1376,11 +1377,19 @@ static node *parse_expr(uint32_t term_tc) continue; } if (tc & (TS_BINOP | TC_UOPPOST)) { + int prio; debug_printf_parse("%s: TS_BINOP | TC_UOPPOST tc:%x\n", __func__, tc); /* for binary and postfix-unary operators, jump back over * previous operators with higher priority */ vn = cn; - while (((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2)) + /* Let assignment get higher priority when used on right + * side in compare. i.e: 2==v=3 */ + if (t_info == TI_ASSIGN && (vn->a.n->info & OPCLSMASK) == OC_COMPARE) { + prio = PRECEDENCE(38); + } else { + prio = (t_info & PRIMASK); + } + while ((prio > (vn->a.n->info & PRIMASK2)) || (t_info == vn->info && t_info == TI_COLON) ) { vn = vn->a.n; @@ -1412,6 +1421,7 @@ static node *parse_expr(uint32_t term_tc) if ((vn->info & OPCLSMASK) != OC_VAR && (vn->info & OPCLSMASK) != OC_FNARG && (vn->info & OPCLSMASK) != OC_FIELD + && (vn->info & OPCLSMASK) != OC_COMPARE ) { syntax_error(EMSG_UNEXP_TOKEN); /* no. bad */ } diff --git a/testsuite/awk.tests b/testsuite/awk.tests index a78fdcd..d2706de 100755 --- a/testsuite/awk.tests +++ b/testsuite/awk.tests @@ -540,9 +540,14 @@ testing 'awk assign while assign' \ │ trim/eff : 57.02%/26, 0.00% │ [cpu000:100%] └────────────────────────────────────────────────────┘^C" -testing "awk = has higher precedence than == (despite what gawk manpage claims)" \ +testing "awk = has higher precedence than == on right side" \ "awk 'BEGIN { v=1; print 2==v; print 2==v=2; print v; print v=3==3; print v}'" \ - '0\n1\n2\n1\n3\n' \ + '0\n1\n2\n1\n1\n' \ + '' '' + +testing 'awk ternary precedence' \ + "awk 'BEGIN { a = 0 ? \"yes\": \"no\"; print a }'" \ + 'no\n' \ '' '' exit $FAILCOUNT