From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by mx.groups.io with SMTP id smtpd.web12.66447.1597759602408912117 for ; Tue, 18 Aug 2020 07:06:42 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: intel.com, ip: 192.55.52.93, mailfrom: chee.yang.lee@intel.com) IronPort-SDR: Yh8Gm8F/GsKy83thofB4CIvGQ2CoqJ3e/Gugv4SZopIDgKX0jC/sLVHyqH8EKc7xDCucWUBRve ijhSnHvjjFzQ== X-IronPort-AV: E=McAfee;i="6000,8403,9716"; a="152534348" X-IronPort-AV: E=Sophos;i="5.76,327,1592895600"; d="scan'208";a="152534348" X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Aug 2020 07:06:41 -0700 IronPort-SDR: oLjrwwaSC/I+IV5LzcPHm8WRVkYJi4v3rlgIWyMF7h3VvULdCXUjFA6by4PzBs9zNLV8qqJLul /7P92Mn9S29Q== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.76,327,1592895600"; d="scan'208";a="496860012" Received: from andromeda01.png.intel.com (HELO guest1-ubuntu1804.png.intel.com) ([10.221.183.10]) by fmsmga006.fm.intel.com with ESMTP; 18 Aug 2020 07:06:39 -0700 From: "Lee Chee Yang" To: openembedded-core@lists.openembedded.org Subject: [PATCH][dunfell 2/2] perl: fix CVE-2020-12723 Date: Tue, 18 Aug 2020 22:06:37 +0800 Message-Id: <20200818140637.64777-2-chee.yang.lee@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200818140637.64777-1-chee.yang.lee@intel.com> References: <20200818140637.64777-1-chee.yang.lee@intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit From: Lee Chee Yang Minor changes to the test cases count in the .patch file to make it align with current version, so the fixes can be apply. Changes apply to line: https://github.com/perl/perl5/commit/66bbb51b93253a3f87d11c2695cfb7bdb782184a#diff-e31ddd69cf47acf02911647c691a0283L28 Signed-off-by: Lee Chee Yang --- .../perl/files/CVE-2020-12723.patch | 302 ++++++++++++++++++ meta/recipes-devtools/perl/perl_5.30.1.bb | 1 + 2 files changed, 303 insertions(+) create mode 100644 meta/recipes-devtools/perl/files/CVE-2020-12723.patch diff --git a/meta/recipes-devtools/perl/files/CVE-2020-12723.patch b/meta/recipes-devtools/perl/files/CVE-2020-12723.patch new file mode 100644 index 0000000000..ad195cffab --- /dev/null +++ b/meta/recipes-devtools/perl/files/CVE-2020-12723.patch @@ -0,0 +1,302 @@ +From da9ec461e22915ccabb06785bf39ec34577ada12 Mon Sep 17 00:00:00 2001 +From: Hugo van der Sanden +Date: Sat, 11 Apr 2020 14:10:24 +0100 +Subject: [PATCH] study_chunk: avoid mutating regexp program within GOSUB + +gh16947 and gh17743: studying GOSUB may restudy in an inner call +(via a mix of recursion and enframing) something that an outer call +is in the middle of looking at. Let the outer frame deal with it. + +(CVE-2020-12723) + +(cherry picked from commit c4033e740bd18d9fbe3456a9db2ec2053cdc5271) + +Upstream-Status: Backport [https://github.com/perl/perl5/commit/66bbb51b93253a3f87d11c2695cfb7bdb782184a] +CVE: CVE-2020-12723 +Signed-off-by: Chee Yang Lee + +--- + embed.fnc | 2 +- + embed.h | 2 +- + proto.h | 2 +- + regcomp.c | 54 +++++++++++++++++++++++++++++++++++------------------- + t/re/pat.t | 26 +++++++++++++++++++++++++- + 5 files changed, 63 insertions(+), 23 deletions(-) + +diff --git a/embed.fnc b/embed.fnc +index f45c127..eff4a50 100644 +--- a/embed.fnc ++++ b/embed.fnc +@@ -2480,7 +2480,7 @@ Es |SSize_t|study_chunk |NN RExC_state_t *pRExC_state \ + |NULLOK struct scan_data_t *data \ + |I32 stopparen|U32 recursed_depth \ + |NULLOK regnode_ssc *and_withp \ +- |U32 flags|U32 depth ++ |U32 flags|U32 depth|bool was_mutate_ok + Es |void |rck_elide_nothing|NN regnode *node + EsR |SV * |get_ANYOFM_contents|NN const regnode * n + EsRn |U32 |add_data |NN RExC_state_t* const pRExC_state \ +diff --git a/embed.h b/embed.h +index 356a8b9..5346ec5 100644 +--- a/embed.h ++++ b/embed.h +@@ -1239,7 +1239,7 @@ + #define ssc_is_cp_posixl_init S_ssc_is_cp_posixl_init + #define ssc_or(a,b,c) S_ssc_or(aTHX_ a,b,c) + #define ssc_union(a,b,c) S_ssc_union(aTHX_ a,b,c) +-#define study_chunk(a,b,c,d,e,f,g,h,i,j,k) S_study_chunk(aTHX_ a,b,c,d,e,f,g,h,i,j,k) ++#define study_chunk(a,b,c,d,e,f,g,h,i,j,k,l) S_study_chunk(aTHX_ a,b,c,d,e,f,g,h,i,j,k,l) + # endif + # if defined(PERL_IN_REGCOMP_C) || defined (PERL_IN_DUMP_C) + #define _invlist_dump(a,b,c,d) Perl__invlist_dump(aTHX_ a,b,c,d) +diff --git a/proto.h b/proto.h +index 91530b1..1bda01f 100644 +--- a/proto.h ++++ b/proto.h +@@ -5655,7 +5655,7 @@ PERL_STATIC_INLINE void S_ssc_union(pTHX_ regnode_ssc *ssc, SV* const invlist, c + #define PERL_ARGS_ASSERT_SSC_UNION \ + assert(ssc); assert(invlist) + #endif +-STATIC SSize_t S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, SSize_t *minlenp, SSize_t *deltap, regnode *last, struct scan_data_t *data, I32 stopparen, U32 recursed_depth, regnode_ssc *and_withp, U32 flags, U32 depth); ++STATIC SSize_t S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, SSize_t *minlenp, SSize_t *deltap, regnode *last, struct scan_data_t *data, I32 stopparen, U32 recursed_depth, regnode_ssc *and_withp, U32 flags, U32 depth, bool was_mutate_ok); + #define PERL_ARGS_ASSERT_STUDY_CHUNK \ + assert(pRExC_state); assert(scanp); assert(minlenp); assert(deltap); assert(last) + #endif +diff --git a/regcomp.c b/regcomp.c +index 5a9adee..8d7df1f 100644 +--- a/regcomp.c ++++ b/regcomp.c +@@ -106,6 +106,7 @@ typedef struct scan_frame { + regnode *next_regnode; /* next node to process when last is reached */ + U32 prev_recursed_depth; + I32 stopparen; /* what stopparen do we use */ ++ bool in_gosub; /* this or an outer frame is for GOSUB */ + + struct scan_frame *this_prev_frame; /* this previous frame */ + struct scan_frame *prev_frame; /* previous frame */ +@@ -4466,7 +4467,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, + I32 stopparen, + U32 recursed_depth, + regnode_ssc *and_withp, +- U32 flags, U32 depth) ++ U32 flags, U32 depth, bool was_mutate_ok) + /* scanp: Start here (read-write). */ + /* deltap: Write maxlen-minlen here. */ + /* last: Stop before this one. */ +@@ -4545,6 +4546,10 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, + node length to get a real minimum (because + the folded version may be shorter) */ + bool unfolded_multi_char = FALSE; ++ /* avoid mutating ops if we are anywhere within the recursed or ++ * enframed handling for a GOSUB: the outermost level will handle it. ++ */ ++ bool mutate_ok = was_mutate_ok && !(frame && frame->in_gosub); + /* Peephole optimizer: */ + DEBUG_STUDYDATA("Peep", data, depth, is_inf); + DEBUG_PEEP("Peep", scan, depth, flags); +@@ -4555,7 +4560,8 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, + * parsing code, as each (?:..) is handled by a different invocation of + * reg() -- Yves + */ +- JOIN_EXACT(scan,&min_subtract, &unfolded_multi_char, 0); ++ if (mutate_ok) ++ JOIN_EXACT(scan,&min_subtract, &unfolded_multi_char, 0); + + /* Follow the next-chain of the current node and optimize + away all the NOTHINGs from it. +@@ -4587,7 +4593,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, + /* DEFINEP study_chunk() recursion */ + (void)study_chunk(pRExC_state, &scan, &minlen, + &deltanext, next, &data_fake, stopparen, +- recursed_depth, NULL, f, depth+1); ++ recursed_depth, NULL, f, depth+1, mutate_ok); + + scan = next; + } else +@@ -4655,7 +4661,8 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, + /* recurse study_chunk() for each BRANCH in an alternation */ + minnext = study_chunk(pRExC_state, &scan, minlenp, + &deltanext, next, &data_fake, stopparen, +- recursed_depth, NULL, f, depth+1); ++ recursed_depth, NULL, f, depth+1, ++ mutate_ok); + + if (min1 > minnext) + min1 = minnext; +@@ -4722,9 +4729,10 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, + } + } + +- if (PERL_ENABLE_TRIE_OPTIMISATION && +- OP( startbranch ) == BRANCH ) +- { ++ if (PERL_ENABLE_TRIE_OPTIMISATION ++ && OP(startbranch) == BRANCH ++ && mutate_ok ++ ) { + /* demq. + + Assuming this was/is a branch we are dealing with: 'scan' +@@ -5179,6 +5187,9 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, + newframe->stopparen = stopparen; + newframe->prev_recursed_depth = recursed_depth; + newframe->this_prev_frame= frame; ++ newframe->in_gosub = ( ++ (frame && frame->in_gosub) || OP(scan) == GOSUB ++ ); + + DEBUG_STUDYDATA("frame-new", data, depth, is_inf); + DEBUG_PEEP("fnew", scan, depth, flags); +@@ -5336,7 +5347,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, + + /* This temporary node can now be turned into EXACTFU, and + * must, as regexec.c doesn't handle it */ +- if (OP(next) == EXACTFU_S_EDGE) { ++ if (OP(next) == EXACTFU_S_EDGE && mutate_ok) { + OP(next) = EXACTFU; + } + +@@ -5344,8 +5355,9 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, + && isALPHA_A(* STRING(next)) + && ( OP(next) == EXACTFAA + || ( OP(next) == EXACTFU +- && ! HAS_NONLATIN1_SIMPLE_FOLD_CLOSURE(* STRING(next))))) +- { ++ && ! HAS_NONLATIN1_SIMPLE_FOLD_CLOSURE(* STRING(next)))) ++ && mutate_ok ++ ) { + /* These differ in just one bit */ + U8 mask = ~ ('A' ^ 'a'); + +@@ -5432,7 +5444,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, + (mincount == 0 + ? (f & ~SCF_DO_SUBSTR) + : f) +- ,depth+1); ++ , depth+1, mutate_ok); + + if (flags & SCF_DO_STCLASS) + data->start_class = oclass; +@@ -5498,7 +5510,9 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, + if ( OP(oscan) == CURLYX && data + && data->flags & SF_IN_PAR + && !(data->flags & SF_HAS_EVAL) +- && !deltanext && minnext == 1 ) { ++ && !deltanext && minnext == 1 ++ && mutate_ok ++ ) { + /* Try to optimize to CURLYN. */ + regnode *nxt = NEXTOPER(oscan) + EXTRA_STEP_2ARGS; + regnode * const nxt1 = nxt; +@@ -5548,10 +5562,10 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, + && !(data->flags & SF_HAS_EVAL) + && !deltanext /* atom is fixed width */ + && minnext != 0 /* CURLYM can't handle zero width */ +- + /* Nor characters whose fold at run-time may be + * multi-character */ + && ! (RExC_seen & REG_UNFOLDED_MULTI_SEEN) ++ && mutate_ok + ) { + /* XXXX How to optimize if data == 0? */ + /* Optimize to a simpler form. */ +@@ -5604,7 +5618,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, + /* recurse study_chunk() on optimised CURLYX => CURLYM */ + study_chunk(pRExC_state, &nxt1, minlenp, &deltanext, nxt, + NULL, stopparen, recursed_depth, NULL, 0, +- depth+1); ++ depth+1, mutate_ok); + } + else + oscan->flags = 0; +@@ -6009,7 +6023,8 @@ Perl_re_printf( aTHX_ "LHS=%" UVuf " RHS=%" UVuf "\n", + /* recurse study_chunk() for lookahead body */ + minnext = study_chunk(pRExC_state, &nscan, minlenp, &deltanext, + last, &data_fake, stopparen, +- recursed_depth, NULL, f, depth+1); ++ recursed_depth, NULL, f, depth+1, ++ mutate_ok); + if (scan->flags) { + if ( deltanext < 0 + || deltanext > (I32) U8_MAX +@@ -6114,7 +6129,7 @@ Perl_re_printf( aTHX_ "LHS=%" UVuf " RHS=%" UVuf "\n", + *minnextp = study_chunk(pRExC_state, &nscan, minnextp, + &deltanext, last, &data_fake, + stopparen, recursed_depth, NULL, +- f, depth+1); ++ f, depth+1, mutate_ok); + if (scan->flags) { + assert(0); /* This code has never been tested since this + is normally not compiled */ +@@ -6282,7 +6297,8 @@ Perl_re_printf( aTHX_ "LHS=%" UVuf " RHS=%" UVuf "\n", + /* optimise study_chunk() for TRIE */ + minnext = study_chunk(pRExC_state, &scan, minlenp, + &deltanext, (regnode *)nextbranch, &data_fake, +- stopparen, recursed_depth, NULL, f, depth+1); ++ stopparen, recursed_depth, NULL, f, depth+1, ++ mutate_ok); + } + if (nextbranch && PL_regkind[OP(nextbranch)]==BRANCH) + nextbranch= regnext((regnode*)nextbranch); +@@ -8075,7 +8091,7 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count, + &data, -1, 0, NULL, + SCF_DO_SUBSTR | SCF_WHILEM_VISITED_POS | stclass_flag + | (restudied ? SCF_TRIE_DOING_RESTUDY : 0), +- 0); ++ 0, TRUE); + + + CHECK_RESTUDY_GOTO_butfirst(LEAVE_with_name("study_chunk")); +@@ -8204,7 +8220,7 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count, + SCF_DO_STCLASS_AND|SCF_WHILEM_VISITED_POS|(restudied + ? SCF_TRIE_DOING_RESTUDY + : 0), +- 0); ++ 0, TRUE); + + CHECK_RESTUDY_GOTO_butfirst(NOOP); + +diff --git a/t/re/pat.t b/t/re/pat.t +index 6a868f4..2869b58 100644 +--- a/t/re/pat.t ++++ b/t/re/pat.t +@@ -25,7 +25,7 @@ BEGIN { + skip_all('no re module') unless defined &DynaLoader::boot_DynaLoader; + skip_all_without_unicode_tables(); + +-plan tests => 864; # Update this when adding/deleting tests. ++plan tests => 873; # Update this when adding/deleting tests. + + run_tests() unless caller; + +@@ -2115,6 +2115,30 @@ x{0c!}\;\;îçÿ /0f/!F/;îçÿù\Qxÿÿÿÿù`x{0c!};ù\Q + like(runperl(prog => "$s", stderr => 1), qr/Unmatched \(/); + } + ++ # gh16947: test regexp corruption (GOSUB) ++ { ++ fresh_perl_is(q{ ++ 'xy' =~ /x(?0)|x(?|y|y)/ && print 'ok' ++ }, 'ok', {}, 'gh16947: test regexp corruption (GOSUB)'); ++ } ++ # gh16947: test fix doesn't break SUSPEND ++ { ++ fresh_perl_is(q{ 'sx' =~ m{ss++}i; print 'ok' }, ++ 'ok', {}, "gh16947: test fix doesn't break SUSPEND"); ++ } ++ ++ # gh17743: more regexp corruption via GOSUB ++ { ++ fresh_perl_is(q{ ++ "0" =~ /((0(?0)|000(?|0000|0000)(?0))|)/; print "ok" ++ }, 'ok', {}, 'gh17743: test regexp corruption (1)'); ++ ++ fresh_perl_is(q{ ++ "000000000000" =~ /(0(())(0((?0)())|000(?|\x{ef}\x{bf}\x{bd}|\x{ef}\x{bf}\x{bd}))|)/; ++ print "ok" ++ }, 'ok', {}, 'gh17743: test regexp corruption (2)'); ++ } ++ + } # End of sub run_tests + + 1; diff --git a/meta/recipes-devtools/perl/perl_5.30.1.bb b/meta/recipes-devtools/perl/perl_5.30.1.bb index 47b2f9ca65..b53aff1216 100644 --- a/meta/recipes-devtools/perl/perl_5.30.1.bb +++ b/meta/recipes-devtools/perl/perl_5.30.1.bb @@ -27,6 +27,7 @@ SRC_URI = "https://www.cpan.org/src/5.0/perl-${PV}.tar.gz;name=perl \ file://CVE-2020-10543.patch \ file://CVE-2020-10878_1.patch \ file://CVE-2020-10878_2.patch \ + file://CVE-2020-12723.patch \ " SRC_URI_append_class-native = " \ file://perl-configpm-switch.patch \ -- 2.17.1