From af92b565250adce354d1af936c0013d0175a5b81 Mon Sep 17 00:00:00 2001
From: Jitka Plesnikova <jplesnik@redhat.com>
Date: Mon, 1 Jun 2020 18:33:56 +0200
Subject: [PATCH 4/4] study_chunk: extract rck_elide_nothing
(CVE-2020-10878)
---
embed.fnc | 1 +
embed.h | 1 +
proto.h | 4 ++++
regcomp.c | 70 ++++++++++++++++++++++++++++++++++---------------------
4 files changed, 49 insertions(+), 27 deletions(-)
diff --git a/embed.fnc b/embed.fnc
index 9546555..aa6c886 100644
--- a/embed.fnc
+++ b/embed.fnc
@@ -1952,6 +1952,7 @@ Es |I32 |study_chunk |NN struct RExC_state_t *pRExC_state \
|I32 stopparen|NULLOK U8* recursed \
|NULLOK struct regnode_charclass_class *and_withp \
|U32 flags|U32 depth|bool was_mutate_ok
+Es |void |rck_elide_nothing|NN regnode *node
EsRn |U32 |add_data |NN struct RExC_state_t *pRExC_state|U32 n \
|NN const char *s
rs |void |re_croak2 |NN const char* pat1|NN const char* pat2|...
diff --git a/embed.h b/embed.h
index f7db1e0..555538d 100644
--- a/embed.h
+++ b/embed.h
@@ -933,6 +933,7 @@
#define make_trie(a,b,c,d,e,f,g,h) S_make_trie(aTHX_ a,b,c,d,e,f,g,h)
#define make_trie_failtable(a,b,c,d) S_make_trie_failtable(aTHX_ a,b,c,d)
#define nextchar(a) S_nextchar(aTHX_ a)
+#define rck_elide_nothing(a) S_rck_elide_nothing(aTHX_ a)
#define reg(a,b,c,d) S_reg(aTHX_ a,b,c,d)
#define reg_namedseq(a,b,c,d) S_reg_namedseq(aTHX_ a,b,c,d)
#define reg_node(a,b) S_reg_node(aTHX_ a,b)
diff --git a/proto.h b/proto.h
index 143eee0..d7cba26 100644
--- a/proto.h
+++ b/proto.h
@@ -6477,6 +6477,10 @@ STATIC char * S_nextchar(pTHX_ struct RExC_state_t *pRExC_state)
#define PERL_ARGS_ASSERT_NEXTCHAR \
assert(pRExC_state)
+STATIC void S_rck_elide_nothing(pTHX_ regnode *node);
+#define PERL_ARGS_ASSERT_RCK_ELIDE_NOTHING \
+ assert(node)
+
STATIC void S_re_croak2(pTHX_ const char* pat1, const char* pat2, ...)
__attribute__noreturn__
__attribute__nonnull__(pTHX_1)
diff --git a/regcomp.c b/regcomp.c
index 9842a83..aa96980 100644
--- a/regcomp.c
+++ b/regcomp.c
@@ -2967,6 +2967,43 @@ case N ## nAmE: \
break
+/* Follow the next-chain of the current node and optimize away
+ all the NOTHINGs from it.
+ */
+STATIC void
+S_rck_elide_nothing(pTHX_ regnode *node)
+{
+ dVAR;
+
+ PERL_ARGS_ASSERT_RCK_ELIDE_NOTHING;
+
+ if (OP(node) != CURLYX) {
+ const int max = (reg_off_by_arg[OP(node)]
+ ? I32_MAX
+ /* I32 may be smaller than U16 on CRAYs! */
+ : (I32_MAX < U16_MAX ? I32_MAX : U16_MAX));
+ int off = (reg_off_by_arg[OP(node)] ? ARG(node) : NEXT_OFF(node));
+ int noff;
+ regnode *n = node;
+
+ /* Skip NOTHING and LONGJMP. */
+ while (
+ (n = regnext(n))
+ && (
+ (PL_regkind[OP(n)] == NOTHING && (noff = NEXT_OFF(n)))
+ || ((OP(n) == LONGJMP) && (noff = ARG(n)))
+ )
+ && off + noff < max
+ ) {
+ off += noff;
+ }
+ if (reg_off_by_arg[OP(node)])
+ ARG(node) = off;
+ else
+ NEXT_OFF(node) = off;
+ }
+ return;
+}
STATIC I32
S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
@@ -3034,27 +3071,9 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
/* Follow the next-chain of the current node and optimize
- away all the NOTHINGs from it. */
- if (OP(scan) != CURLYX) {
- const int max = (reg_off_by_arg[OP(scan)]
- ? I32_MAX
- /* I32 may be smaller than U16 on CRAYs! */
- : (I32_MAX < U16_MAX ? I32_MAX : U16_MAX));
- int off = (reg_off_by_arg[OP(scan)] ? ARG(scan) : NEXT_OFF(scan));
- int noff;
- regnode *n = scan;
-
- /* Skip NOTHING and LONGJMP. */
- while ((n = regnext(n))
- && ((PL_regkind[OP(n)] == NOTHING && (noff = NEXT_OFF(n)))
- || ((OP(n) == LONGJMP) && (noff = ARG(n))))
- && off + noff < max)
- off += noff;
- if (reg_off_by_arg[OP(scan)])
- ARG(scan) = off;
- else
- NEXT_OFF(scan) = off;
- }
+ away all the NOTHINGs from it.
+ */
+ rck_elide_nothing(scan);
@@ -4057,11 +4094,7 @@ S_study_chunk(pTHX_ RExC_state_t *pRExC_state, regnode **scanp,
if (data && (fl & SF_HAS_EVAL))
data->flags |= SF_HAS_EVAL;
optimize_curly_tail:
- if (OP(oscan) != CURLYX) {
- while (PL_regkind[OP(next = regnext(oscan))] == NOTHING
- && NEXT_OFF(next))
- NEXT_OFF(oscan) += NEXT_OFF(next);
- }
+ rck_elide_nothing(oscan);
continue;
default: /* REF, ANYOFV, and CLUMP only? */
if (flags & SCF_DO_SUBSTR) {
--
2.25.4