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