diff options
| -rw-r--r-- | meta/recipes-devtools/perl/files/CVE-2020-12723.patch | 302 | ||||
| -rw-r--r-- | meta/recipes-devtools/perl/perl_5.30.1.bb | 1 |
2 files changed, 303 insertions, 0 deletions
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 @@ | |||
| 1 | From da9ec461e22915ccabb06785bf39ec34577ada12 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Hugo van der Sanden <hv@crypt.org> | ||
| 3 | Date: Sat, 11 Apr 2020 14:10:24 +0100 | ||
| 4 | Subject: [PATCH] study_chunk: avoid mutating regexp program within GOSUB | ||
| 5 | |||
| 6 | gh16947 and gh17743: studying GOSUB may restudy in an inner call | ||
| 7 | (via a mix of recursion and enframing) something that an outer call | ||
| 8 | is in the middle of looking at. Let the outer frame deal with it. | ||
| 9 | |||
| 10 | (CVE-2020-12723) | ||
| 11 | |||
| 12 | (cherry picked from commit c4033e740bd18d9fbe3456a9db2ec2053cdc5271) | ||
| 13 | |||
| 14 | Upstream-Status: Backport [https://github.com/perl/perl5/commit/66bbb51b93253a3f87d11c2695cfb7bdb782184a] | ||
| 15 | CVE: CVE-2020-12723 | ||
| 16 | Signed-off-by: Chee Yang Lee <chee.yang.lee@intel.com> | ||
| 17 | |||
| 18 | --- | ||
| 19 | embed.fnc | 2 +- | ||
| 20 | embed.h | 2 +- | ||
| 21 | proto.h | 2 +- | ||
| 22 | regcomp.c | 54 +++++++++++++++++++++++++++++++++++------------------- | ||
| 23 | t/re/pat.t | 26 +++++++++++++++++++++++++- | ||
| 24 | 5 files changed, 63 insertions(+), 23 deletions(-) | ||
| 25 | |||
| 26 | diff --git a/embed.fnc b/embed.fnc | ||
| 27 | index f45c127..eff4a50 100644 | ||
| 28 | --- a/embed.fnc | ||
| 29 | +++ b/embed.fnc | ||
| 30 | @@ -2480,7 +2480,7 @@ Es |SSize_t|study_chunk |NN RExC_state_t *pRExC_state \ | ||
| 31 | |NULLOK struct scan_data_t *data \ | ||
| 32 | |I32 stopparen|U32 recursed_depth \ | ||
| 33 | |NULLOK regnode_ssc *and_withp \ | ||
| 34 | - |U32 flags|U32 depth | ||
| 35 | + |U32 flags|U32 depth|bool was_mutate_ok | ||
| 36 | Es |void |rck_elide_nothing|NN regnode *node | ||
| 37 | EsR |SV * |get_ANYOFM_contents|NN const regnode * n | ||
| 38 | EsRn |U32 |add_data |NN RExC_state_t* const pRExC_state \ | ||
| 39 | diff --git a/embed.h b/embed.h | ||
| 40 | index 356a8b9..5346ec5 100644 | ||
| 41 | --- a/embed.h | ||
| 42 | +++ b/embed.h | ||
| 43 | @@ -1239,7 +1239,7 @@ | ||
| 44 | #define ssc_is_cp_posixl_init S_ssc_is_cp_posixl_init | ||
| 45 | #define ssc_or(a,b,c) S_ssc_or(aTHX_ a,b,c) | ||
| 46 | #define ssc_union(a,b,c) S_ssc_union(aTHX_ a,b,c) | ||
| 47 | -#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) | ||
| 48 | +#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) | ||
| 49 | # endif | ||
| 50 | # if defined(PERL_IN_REGCOMP_C) || defined (PERL_IN_DUMP_C) | ||
| 51 | #define _invlist_dump(a,b,c,d) Perl__invlist_dump(aTHX_ a,b,c,d) | ||
| 52 | diff --git a/proto.h b/proto.h | ||
| 53 | index 91530b1..1bda01f 100644 | ||
| 54 | --- a/proto.h | ||
| 55 | +++ b/proto.h | ||
| 56 | @@ -5655,7 +5655,7 @@ PERL_STATIC_INLINE void S_ssc_union(pTHX_ regnode_ssc *ssc, SV* const invlist, c | ||
| 57 | #define PERL_ARGS_ASSERT_SSC_UNION \ | ||
| 58 | assert(ssc); assert(invlist) | ||
| 59 | #endif | ||
| 60 | -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); | ||
| 61 | +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); | ||
| 62 | #define PERL_ARGS_ASSERT_STUDY_CHUNK \ | ||
| 63 | assert(pRExC_state); assert(scanp); assert(minlenp); assert(deltap); assert(last) | ||
| 64 | #endif | ||
| 65 | diff --git a/regcomp.c b/regcomp.c | ||
| 66 | index 5a9adee..8d7df1f 100644 | ||
| 67 | --- a/regcomp.c | ||
| 68 | +++ b/regcomp.c | ||
| 69 | @@ -106,6 +106,7 @@ typedef struct scan_frame { | ||
| 70 | regnode *next_regnode; /* next node to process when last is reached */ | ||
| 71 | U32 prev_recursed_depth; | ||
| 72 | I32 stopparen; /* what stopparen do we use */ | ||
| 73 | + bool in_gosub; /* this or an outer frame is for GOSUB */ | ||
| 74 | |||
| 75 | struct scan_frame *this_prev_frame; /* this previous frame */ | ||
| 76 | struct scan_frame *prev_frame; /* previous frame */ | ||
| 77 | @@ -4466,7 +4467,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, | ||
| 78 | I32 stopparen, | ||
| 79 | U32 recursed_depth, | ||
| 80 | regnode_ssc *and_withp, | ||
| 81 | - U32 flags, U32 depth) | ||
| 82 | + U32 flags, U32 depth, bool was_mutate_ok) | ||
| 83 | /* scanp: Start here (read-write). */ | ||
| 84 | /* deltap: Write maxlen-minlen here. */ | ||
| 85 | /* last: Stop before this one. */ | ||
| 86 | @@ -4545,6 +4546,10 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, | ||
| 87 | node length to get a real minimum (because | ||
| 88 | the folded version may be shorter) */ | ||
| 89 | bool unfolded_multi_char = FALSE; | ||
| 90 | + /* avoid mutating ops if we are anywhere within the recursed or | ||
| 91 | + * enframed handling for a GOSUB: the outermost level will handle it. | ||
| 92 | + */ | ||
| 93 | + bool mutate_ok = was_mutate_ok && !(frame && frame->in_gosub); | ||
| 94 | /* Peephole optimizer: */ | ||
| 95 | DEBUG_STUDYDATA("Peep", data, depth, is_inf); | ||
| 96 | DEBUG_PEEP("Peep", scan, depth, flags); | ||
| 97 | @@ -4555,7 +4560,8 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, | ||
| 98 | * parsing code, as each (?:..) is handled by a different invocation of | ||
| 99 | * reg() -- Yves | ||
| 100 | */ | ||
| 101 | - JOIN_EXACT(scan,&min_subtract, &unfolded_multi_char, 0); | ||
| 102 | + if (mutate_ok) | ||
| 103 | + JOIN_EXACT(scan,&min_subtract, &unfolded_multi_char, 0); | ||
| 104 | |||
| 105 | /* Follow the next-chain of the current node and optimize | ||
| 106 | away all the NOTHINGs from it. | ||
| 107 | @@ -4587,7 +4593,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, | ||
| 108 | /* DEFINEP study_chunk() recursion */ | ||
| 109 | (void)study_chunk(pRExC_state, &scan, &minlen, | ||
| 110 | &deltanext, next, &data_fake, stopparen, | ||
| 111 | - recursed_depth, NULL, f, depth+1); | ||
| 112 | + recursed_depth, NULL, f, depth+1, mutate_ok); | ||
| 113 | |||
| 114 | scan = next; | ||
| 115 | } else | ||
| 116 | @@ -4655,7 +4661,8 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, | ||
| 117 | /* recurse study_chunk() for each BRANCH in an alternation */ | ||
| 118 | minnext = study_chunk(pRExC_state, &scan, minlenp, | ||
| 119 | &deltanext, next, &data_fake, stopparen, | ||
| 120 | - recursed_depth, NULL, f, depth+1); | ||
| 121 | + recursed_depth, NULL, f, depth+1, | ||
| 122 | + mutate_ok); | ||
| 123 | |||
| 124 | if (min1 > minnext) | ||
| 125 | min1 = minnext; | ||
| 126 | @@ -4722,9 +4729,10 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | - if (PERL_ENABLE_TRIE_OPTIMISATION && | ||
| 131 | - OP( startbranch ) == BRANCH ) | ||
| 132 | - { | ||
| 133 | + if (PERL_ENABLE_TRIE_OPTIMISATION | ||
| 134 | + && OP(startbranch) == BRANCH | ||
| 135 | + && mutate_ok | ||
| 136 | + ) { | ||
| 137 | /* demq. | ||
| 138 | |||
| 139 | Assuming this was/is a branch we are dealing with: 'scan' | ||
| 140 | @@ -5179,6 +5187,9 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, | ||
| 141 | newframe->stopparen = stopparen; | ||
| 142 | newframe->prev_recursed_depth = recursed_depth; | ||
| 143 | newframe->this_prev_frame= frame; | ||
| 144 | + newframe->in_gosub = ( | ||
| 145 | + (frame && frame->in_gosub) || OP(scan) == GOSUB | ||
| 146 | + ); | ||
| 147 | |||
| 148 | DEBUG_STUDYDATA("frame-new", data, depth, is_inf); | ||
| 149 | DEBUG_PEEP("fnew", scan, depth, flags); | ||
| 150 | @@ -5336,7 +5347,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, | ||
| 151 | |||
| 152 | /* This temporary node can now be turned into EXACTFU, and | ||
| 153 | * must, as regexec.c doesn't handle it */ | ||
| 154 | - if (OP(next) == EXACTFU_S_EDGE) { | ||
| 155 | + if (OP(next) == EXACTFU_S_EDGE && mutate_ok) { | ||
| 156 | OP(next) = EXACTFU; | ||
| 157 | } | ||
| 158 | |||
| 159 | @@ -5344,8 +5355,9 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, | ||
| 160 | && isALPHA_A(* STRING(next)) | ||
| 161 | && ( OP(next) == EXACTFAA | ||
| 162 | || ( OP(next) == EXACTFU | ||
| 163 | - && ! HAS_NONLATIN1_SIMPLE_FOLD_CLOSURE(* STRING(next))))) | ||
| 164 | - { | ||
| 165 | + && ! HAS_NONLATIN1_SIMPLE_FOLD_CLOSURE(* STRING(next)))) | ||
| 166 | + && mutate_ok | ||
| 167 | + ) { | ||
| 168 | /* These differ in just one bit */ | ||
| 169 | U8 mask = ~ ('A' ^ 'a'); | ||
| 170 | |||
| 171 | @@ -5432,7 +5444,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, | ||
| 172 | (mincount == 0 | ||
| 173 | ? (f & ~SCF_DO_SUBSTR) | ||
| 174 | : f) | ||
| 175 | - ,depth+1); | ||
| 176 | + , depth+1, mutate_ok); | ||
| 177 | |||
| 178 | if (flags & SCF_DO_STCLASS) | ||
| 179 | data->start_class = oclass; | ||
| 180 | @@ -5498,7 +5510,9 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, | ||
| 181 | if ( OP(oscan) == CURLYX && data | ||
| 182 | && data->flags & SF_IN_PAR | ||
| 183 | && !(data->flags & SF_HAS_EVAL) | ||
| 184 | - && !deltanext && minnext == 1 ) { | ||
| 185 | + && !deltanext && minnext == 1 | ||
| 186 | + && mutate_ok | ||
| 187 | + ) { | ||
| 188 | /* Try to optimize to CURLYN. */ | ||
| 189 | regnode *nxt = NEXTOPER(oscan) + EXTRA_STEP_2ARGS; | ||
| 190 | regnode * const nxt1 = nxt; | ||
| 191 | @@ -5548,10 +5562,10 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, | ||
| 192 | && !(data->flags & SF_HAS_EVAL) | ||
| 193 | && !deltanext /* atom is fixed width */ | ||
| 194 | && minnext != 0 /* CURLYM can't handle zero width */ | ||
| 195 | - | ||
| 196 | /* Nor characters whose fold at run-time may be | ||
| 197 | * multi-character */ | ||
| 198 | && ! (RExC_seen & REG_UNFOLDED_MULTI_SEEN) | ||
| 199 | + && mutate_ok | ||
| 200 | ) { | ||
| 201 | /* XXXX How to optimize if data == 0? */ | ||
| 202 | /* Optimize to a simpler form. */ | ||
| 203 | @@ -5604,7 +5618,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp, | ||
| 204 | /* recurse study_chunk() on optimised CURLYX => CURLYM */ | ||
| 205 | study_chunk(pRExC_state, &nxt1, minlenp, &deltanext, nxt, | ||
| 206 | NULL, stopparen, recursed_depth, NULL, 0, | ||
| 207 | - depth+1); | ||
| 208 | + depth+1, mutate_ok); | ||
| 209 | } | ||
| 210 | else | ||
| 211 | oscan->flags = 0; | ||
| 212 | @@ -6009,7 +6023,8 @@ Perl_re_printf( aTHX_ "LHS=%" UVuf " RHS=%" UVuf "\n", | ||
| 213 | /* recurse study_chunk() for lookahead body */ | ||
| 214 | minnext = study_chunk(pRExC_state, &nscan, minlenp, &deltanext, | ||
| 215 | last, &data_fake, stopparen, | ||
| 216 | - recursed_depth, NULL, f, depth+1); | ||
| 217 | + recursed_depth, NULL, f, depth+1, | ||
| 218 | + mutate_ok); | ||
| 219 | if (scan->flags) { | ||
| 220 | if ( deltanext < 0 | ||
| 221 | || deltanext > (I32) U8_MAX | ||
| 222 | @@ -6114,7 +6129,7 @@ Perl_re_printf( aTHX_ "LHS=%" UVuf " RHS=%" UVuf "\n", | ||
| 223 | *minnextp = study_chunk(pRExC_state, &nscan, minnextp, | ||
| 224 | &deltanext, last, &data_fake, | ||
| 225 | stopparen, recursed_depth, NULL, | ||
| 226 | - f, depth+1); | ||
| 227 | + f, depth+1, mutate_ok); | ||
| 228 | if (scan->flags) { | ||
| 229 | assert(0); /* This code has never been tested since this | ||
| 230 | is normally not compiled */ | ||
| 231 | @@ -6282,7 +6297,8 @@ Perl_re_printf( aTHX_ "LHS=%" UVuf " RHS=%" UVuf "\n", | ||
| 232 | /* optimise study_chunk() for TRIE */ | ||
| 233 | minnext = study_chunk(pRExC_state, &scan, minlenp, | ||
| 234 | &deltanext, (regnode *)nextbranch, &data_fake, | ||
| 235 | - stopparen, recursed_depth, NULL, f, depth+1); | ||
| 236 | + stopparen, recursed_depth, NULL, f, depth+1, | ||
| 237 | + mutate_ok); | ||
| 238 | } | ||
| 239 | if (nextbranch && PL_regkind[OP(nextbranch)]==BRANCH) | ||
| 240 | nextbranch= regnext((regnode*)nextbranch); | ||
| 241 | @@ -8075,7 +8091,7 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count, | ||
| 242 | &data, -1, 0, NULL, | ||
| 243 | SCF_DO_SUBSTR | SCF_WHILEM_VISITED_POS | stclass_flag | ||
| 244 | | (restudied ? SCF_TRIE_DOING_RESTUDY : 0), | ||
| 245 | - 0); | ||
| 246 | + 0, TRUE); | ||
| 247 | |||
| 248 | |||
| 249 | CHECK_RESTUDY_GOTO_butfirst(LEAVE_with_name("study_chunk")); | ||
| 250 | @@ -8204,7 +8220,7 @@ Perl_re_op_compile(pTHX_ SV ** const patternp, int pat_count, | ||
| 251 | SCF_DO_STCLASS_AND|SCF_WHILEM_VISITED_POS|(restudied | ||
| 252 | ? SCF_TRIE_DOING_RESTUDY | ||
| 253 | : 0), | ||
| 254 | - 0); | ||
| 255 | + 0, TRUE); | ||
| 256 | |||
| 257 | CHECK_RESTUDY_GOTO_butfirst(NOOP); | ||
| 258 | |||
| 259 | diff --git a/t/re/pat.t b/t/re/pat.t | ||
| 260 | index 6a868f4..2869b58 100644 | ||
| 261 | --- a/t/re/pat.t | ||
| 262 | +++ b/t/re/pat.t | ||
| 263 | @@ -25,7 +25,7 @@ BEGIN { | ||
| 264 | skip_all('no re module') unless defined &DynaLoader::boot_DynaLoader; | ||
| 265 | skip_all_without_unicode_tables(); | ||
| 266 | |||
| 267 | -plan tests => 864; # Update this when adding/deleting tests. | ||
| 268 | +plan tests => 873; # Update this when adding/deleting tests. | ||
| 269 | |||
| 270 | run_tests() unless caller; | ||
| 271 | |||
| 272 | @@ -2115,6 +2115,30 @@ x{0c!}\;\;îçÿ | ||
| 273 | like(runperl(prog => "$s", stderr => 1), qr/Unmatched \(/); | ||
| 274 | } | ||
| 275 | |||
| 276 | + # gh16947: test regexp corruption (GOSUB) | ||
| 277 | + { | ||
| 278 | + fresh_perl_is(q{ | ||
| 279 | + 'xy' =~ /x(?0)|x(?|y|y)/ && print 'ok' | ||
| 280 | + }, 'ok', {}, 'gh16947: test regexp corruption (GOSUB)'); | ||
| 281 | + } | ||
| 282 | + # gh16947: test fix doesn't break SUSPEND | ||
| 283 | + { | ||
| 284 | + fresh_perl_is(q{ 'sx' =~ m{ss++}i; print 'ok' }, | ||
| 285 | + 'ok', {}, "gh16947: test fix doesn't break SUSPEND"); | ||
| 286 | + } | ||
| 287 | + | ||
| 288 | + # gh17743: more regexp corruption via GOSUB | ||
| 289 | + { | ||
| 290 | + fresh_perl_is(q{ | ||
| 291 | + "0" =~ /((0(?0)|000(?|0000|0000)(?0))|)/; print "ok" | ||
| 292 | + }, 'ok', {}, 'gh17743: test regexp corruption (1)'); | ||
| 293 | + | ||
| 294 | + fresh_perl_is(q{ | ||
| 295 | + "000000000000" =~ /(0(())(0((?0)())|000(?|\x{ef}\x{bf}\x{bd}|\x{ef}\x{bf}\x{bd}))|)/; | ||
| 296 | + print "ok" | ||
| 297 | + }, 'ok', {}, 'gh17743: test regexp corruption (2)'); | ||
| 298 | + } | ||
| 299 | + | ||
| 300 | } # End of sub run_tests | ||
| 301 | |||
| 302 | 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 \ | |||
| 27 | file://CVE-2020-10543.patch \ | 27 | file://CVE-2020-10543.patch \ |
| 28 | file://CVE-2020-10878_1.patch \ | 28 | file://CVE-2020-10878_1.patch \ |
| 29 | file://CVE-2020-10878_2.patch \ | 29 | file://CVE-2020-10878_2.patch \ |
| 30 | file://CVE-2020-12723.patch \ | ||
| 30 | " | 31 | " |
| 31 | SRC_URI_append_class-native = " \ | 32 | SRC_URI_append_class-native = " \ |
| 32 | file://perl-configpm-switch.patch \ | 33 | file://perl-configpm-switch.patch \ |
