From 3c1f5da406cfcee43383d973ced2271440803c16 Mon Sep 17 00:00:00 2001 From: wangxiao65 <287608437@qq.com> Date: Tue, 16 Mar 2021 09:27:59 +0800 Subject: [PATCH] fix CVE-2020-10693 --- CVE-2020-10693-1.patch | 70 ++++++ CVE-2020-10693-2.patch | 79 ++++++ CVE-2020-10693-3.patch | 516 +++++++++++++++++++++++++++++++++++++++ CVE-2020-10693-4.patch | 84 +++++++ CVE-2020-10693-pre.patch | 441 +++++++++++++++++++++++++++++++++ hibernate-validator.spec | 15 +- 6 files changed, 1204 insertions(+), 1 deletion(-) create mode 100644 CVE-2020-10693-1.patch create mode 100644 CVE-2020-10693-2.patch create mode 100644 CVE-2020-10693-3.patch create mode 100644 CVE-2020-10693-4.patch create mode 100644 CVE-2020-10693-pre.patch diff --git a/CVE-2020-10693-1.patch b/CVE-2020-10693-1.patch new file mode 100644 index 0000000..9c66723 --- /dev/null +++ b/CVE-2020-10693-1.patch @@ -0,0 +1,70 @@ +From 29bd0f42bf63e28d9a71adef02af67b319144576 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= +Date: Mon, 24 Feb 2020 17:58:41 +0100 +Subject: [PATCH] HV-1774 Do not interpret '$\A{1+1}' in message templates + +--- + .../messageinterpolation/parser/ELState.java | 6 +++++- + .../TokenCollectorTest.java | 21 ++++++++++++++++++- + 2 files changed, 25 insertions(+), 2 deletions(-) + +diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/ELState.java b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/ELState.java +index 9460fae05..fda95a153 100644 +--- a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/ELState.java ++++ b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/ELState.java +@@ -51,7 +51,11 @@ public void handleEndTerm(char character, TokenCollector tokenCollector) throws + @Override + public void handleEscapeCharacter(char character, TokenCollector tokenCollector) + throws MessageDescriptorFormatException { +- tokenCollector.transitionState( new EscapedState( this ) ); ++ tokenCollector.appendToToken( TokenCollector.EL_DESIGNATOR ); ++ tokenCollector.appendToToken( character ); ++ // Do not go back to this state after the escape: $\ is not the start of an EL expression ++ ParserState stateAfterEscape = new MessageState(); ++ tokenCollector.transitionState( new EscapedState( stateAfterEscape ) ); + } + + @Override +diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/TokenCollectorTest.java b/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/TokenCollectorTest.java +index 972a9e051..ab9299f17 100644 +--- a/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/TokenCollectorTest.java ++++ b/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/TokenCollectorTest.java +@@ -8,7 +8,11 @@ + + import org.hibernate.validator.internal.engine.messageinterpolation.InterpolationTermType; + import org.hibernate.validator.internal.engine.messageinterpolation.parser.MessageDescriptorFormatException; ++import org.hibernate.validator.internal.engine.messageinterpolation.parser.Token; + import org.hibernate.validator.internal.engine.messageinterpolation.parser.TokenCollector; ++ ++import org.assertj.core.api.Assertions; ++import org.assertj.core.api.ListAssert; + import org.testng.annotations.Test; + + /** +@@ -29,10 +33,25 @@ public void testParameterWithoutOpeningBraceThrowsException() throws Exception { + } + + @Test(expectedExceptions = MessageDescriptorFormatException.class, expectedExceptionsMessageRegExp = "HV000168.*") +- public void testELExpressionWithoutOpeningBraceThrowsException() throws Exception { ++ public void testELExpressionDollarThenClosingBraceThrowsException() throws Exception { + new TokenCollector( "$}", InterpolationTermType.EL ); + } + ++ @Test ++ public void testELExpressionDollarThenEscapeInterpretedAsLiterals() { ++ ListAssert assertion = Assertions.assertThat( ++ new TokenCollector( "$\\A{1+1}", InterpolationTermType.EL ) ++ .getTokenList() ++ ) ++ .hasSize( 2 ); ++ assertion.element( 0 ) ++ .returns( "$\\A", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ assertion.element( 1 ) ++ .returns( "{1+1}", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ } ++ + @Test(expectedExceptions = MessageDescriptorFormatException.class, expectedExceptionsMessageRegExp = "HV000168.*") + public void testTermWithoutClosingBraceThrowsException() throws Exception { + new TokenCollector( "{foo", InterpolationTermType.PARAMETER ); diff --git a/CVE-2020-10693-2.patch b/CVE-2020-10693-2.patch new file mode 100644 index 0000000..e99f04e --- /dev/null +++ b/CVE-2020-10693-2.patch @@ -0,0 +1,79 @@ +From 4b9f2a1a3e1c67fbd29a7fc710c611d7aca6eab9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= +Date: Tue, 25 Feb 2020 13:05:53 +0100 +Subject: [PATCH] HV-1774 Fix an invalid error message for unbalanced '{'/'}' + +--- + .../internal/engine/messageinterpolation/parser/ELState.java | 2 +- + .../messageinterpolation/parser/InterpolationTermState.java | 2 +- + .../engine/messageinterpolation/parser/MessageState.java | 2 +- + .../org/hibernate/validator/internal/util/logging/Log.java | 4 ++-- + 4 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/ELState.java b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/ELState.java +index fda95a153..9f480f848 100644 +--- a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/ELState.java ++++ b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/ELState.java +@@ -42,7 +42,7 @@ public void handleBeginTerm(char character, TokenCollector tokenCollector) throw + + @Override + public void handleEndTerm(char character, TokenCollector tokenCollector) throws MessageDescriptorFormatException { +- throw log.getNonTerminatedParameterException( ++ throw log.getUnbalancedBeginEndParameterException( + tokenCollector.getOriginalMessageDescriptor(), + character + ); +diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/InterpolationTermState.java b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/InterpolationTermState.java +index 9b00c3594..809db34dd 100644 +--- a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/InterpolationTermState.java ++++ b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/InterpolationTermState.java +@@ -17,7 +17,7 @@ + + @Override + public void terminate(TokenCollector tokenCollector) throws MessageDescriptorFormatException { +- throw log.getNonTerminatedParameterException( ++ throw log.getUnbalancedBeginEndParameterException( + tokenCollector.getOriginalMessageDescriptor(), + TokenCollector.BEGIN_TERM + ); +diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/MessageState.java b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/MessageState.java +index a8b1de63f..88171668a 100644 +--- a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/MessageState.java ++++ b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/MessageState.java +@@ -40,7 +40,7 @@ public void handleBeginTerm(char character, TokenCollector tokenCollector) throw + + @Override + public void handleEndTerm(char character, TokenCollector tokenCollector) throws MessageDescriptorFormatException { +- throw log.getNonTerminatedParameterException( ++ throw log.getUnbalancedBeginEndParameterException( + tokenCollector.getOriginalMessageDescriptor(), + character + ); +diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/BeginState.java b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/BeginState.java +index 678f16e..7d544de 100644 +--- a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/BeginState.java ++++ b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/BeginState.java +@@ -48,7 +48,7 @@ public void handleBeginTerm(char character, TokenCollector tokenCollector) throw + + @Override + public void handleEndTerm(char character, TokenCollector tokenCollector) throws MessageDescriptorFormatException { +- throw log.getNonTerminatedParameterException( tokenCollector.getOriginalMessageDescriptor(), character ); ++ throw log.getUnbalancedBeginEndParameterException( tokenCollector.getOriginalMessageDescriptor(), character ); + } + + @Override +diff --git a/engine/src/main/java/org/hibernate/validator/internal/util/logging/Log.java b/engine/src/main/java/org/hibernate/validator/internal/util/logging/Log.java +index 3effce1c9..33034cb0c 100644 +--- a/engine/src/main/java/org/hibernate/validator/internal/util/logging/Log.java ++++ b/engine/src/main/java/org/hibernate/validator/internal/util/logging/Log.java +@@ -552,8 +552,8 @@ ConstraintDefinitionException getValidatorForCrossParameterConstraintMustEitherV + ValidationException getOverridingConstraintDefinitionsInMultipleMappingFilesException(String constraintClass); + + @Message(id = 168, +- value = "The message descriptor '%1$s' contains an unbalanced meta character '%2$c' parameter.") +- MessageDescriptorFormatException getNonTerminatedParameterException(String messageDescriptor, char character); ++ value = "The message descriptor '%1$s' contains an unbalanced meta character '%2$c'.") ++ MessageDescriptorFormatException getUnbalancedBeginEndParameterException(String messageDescriptor, char character); + + @Message(id = 169, + value = "The message descriptor '%1$s' has nested parameters.") diff --git a/CVE-2020-10693-3.patch b/CVE-2020-10693-3.patch new file mode 100644 index 0000000..0fa5aa7 --- /dev/null +++ b/CVE-2020-10693-3.patch @@ -0,0 +1,516 @@ +From c7c904db1b146d24e25927b613155d130bbe40d1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= +Date: Tue, 25 Feb 2020 15:17:03 +0100 +Subject: [PATCH] HV-1774 Add a few tests to demonstrate the behavior of + TokenCollector + +--- + .../AbstractTokenCollectorTest.java | 186 ++++++++++++++++++ + .../TokenCollectorMessageExpressionTest.java | 110 +++++++++++ + .../TokenCollectorMessageParameterTest.java | 115 +++++++++++ + .../TokenCollectorTest.java | 64 ------ + 4 files changed, 411 insertions(+), 64 deletions(-) + create mode 100644 engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/AbstractTokenCollectorTest.java + create mode 100644 engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/TokenCollectorMessageExpressionTest.java + create mode 100644 engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/TokenCollectorMessageParameterTest.java + delete mode 100644 engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/TokenCollectorTest.java + +diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/AbstractTokenCollectorTest.java b/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/AbstractTokenCollectorTest.java +new file mode 100644 +index 000000000..004d5c9bd +--- /dev/null ++++ b/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/AbstractTokenCollectorTest.java +@@ -0,0 +1,186 @@ ++/* ++ * Hibernate Validator, declare and validate application constraints ++ * ++ * License: Apache License, Version 2.0 ++ * See the license.txt file in the root directory or . ++ */ ++package org.hibernate.validator.test.internal.engine.messageinterpolation; ++ ++import org.hibernate.validator.internal.engine.messageinterpolation.InterpolationTermType; ++import org.hibernate.validator.internal.engine.messageinterpolation.parser.MessageDescriptorFormatException; ++import org.hibernate.validator.internal.engine.messageinterpolation.parser.Token; ++import org.hibernate.validator.internal.engine.messageinterpolation.parser.TokenCollector; ++ ++import org.assertj.core.api.Assertions; ++import org.testng.annotations.Test; ++ ++/** ++ * Abstract base for {@code TokenCollector} tests. ++ * ++ * @author Hardy Ferentschik ++ */ ++public abstract class AbstractTokenCollectorTest { ++ ++ protected abstract InterpolationTermType getInterpolationTermType(); ++ ++ @Test ++ public void testLiteral() { ++ Assertions.assertThat( ++ new TokenCollector( "foo bar", getInterpolationTermType() ) ++ .getTokenList() ++ ) ++ .hasSize( 1 ) ++ .element( 0 ) ++ .returns( "foo bar", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ } ++ ++ @Test(expectedExceptions = MessageDescriptorFormatException.class, expectedExceptionsMessageRegExp = "HV000169.*") ++ public void testNestedParametersThrowException() { ++ new TokenCollector( "#{foo {}", getInterpolationTermType() ); ++ } ++ ++ @Test(expectedExceptions = MessageDescriptorFormatException.class, expectedExceptionsMessageRegExp = "HV000168.*") ++ public void testClosingBraceWithoutOpeningBraceThrowsException() { ++ new TokenCollector( "foo}", getInterpolationTermType() ); ++ } ++ ++ @Test(expectedExceptions = MessageDescriptorFormatException.class, expectedExceptionsMessageRegExp = "HV000168.*") ++ public void testOpeningBraceWithoutClosingBraceThrowsException() { ++ new TokenCollector( "{foo", getInterpolationTermType() ); ++ } ++ ++ @Test ++ public void testBackslashEscapesNonMetaCharacter() { ++ Assertions.assertThat( ++ new TokenCollector( "foo \\bar", getInterpolationTermType() ) ++ .getTokenList() ++ ) ++ .hasSize( 1 ) ++ .element( 0 ) ++ // Backslashes are removed later, in AbstractMessageInterpolator.replaceEscapedLiterals ++ .returns( "foo \\bar", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ } ++ ++ @Test ++ public void testBackslashEscapesDollar() { ++ Assertions.assertThat( ++ new TokenCollector( "foo \\$ bar", getInterpolationTermType() ) ++ .getTokenList() ++ ) ++ .hasSize( 1 ) ++ .element( 0 ) ++ // Backslashes are removed later, in AbstractMessageInterpolator.replaceEscapedLiterals ++ .returns( "foo \\$ bar", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ } ++ ++ @Test ++ public void testBackslashEscapesOpeningBrace() { ++ Assertions.assertThat( ++ new TokenCollector( "foo \\{ bar", getInterpolationTermType() ) ++ .getTokenList() ++ ) ++ .hasSize( 1 ) ++ .element( 0 ) ++ // Backslashes are removed later, in AbstractMessageInterpolator.replaceEscapedLiterals ++ .returns( "foo \\{ bar", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ } ++ ++ @Test ++ public void testBackslashEscapesClosingBrace() { ++ Assertions.assertThat( ++ new TokenCollector( "foo \\} bar", getInterpolationTermType() ) ++ .getTokenList() ++ ) ++ .hasSize( 1 ) ++ .element( 0 ) ++ // Backslashes are removed later, in AbstractMessageInterpolator.replaceEscapedLiterals ++ .returns( "foo \\} bar", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ } ++ ++ @Test ++ public void testBackslashEscapesBackslash() { ++ Assertions.assertThat( ++ new TokenCollector( "foo \\\\ bar", getInterpolationTermType() ) ++ .getTokenList() ++ ) ++ .hasSize( 1 ) ++ .element( 0 ) ++ // Backslashes are removed later, in AbstractMessageInterpolator.replaceEscapedLiterals ++ .returns( "foo \\\\ bar", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ } ++ ++ @Test ++ public void testBackslashEscapesEL() { ++ Assertions.assertThat( ++ new TokenCollector( "foo \\$\\{bar\\}", getInterpolationTermType() ) ++ .getTokenList() ++ ) ++ .hasSize( 1 ) ++ .element( 0 ) ++ // Backslashes are removed later, in AbstractMessageInterpolator.replaceEscapedLiterals ++ .returns( "foo \\$\\{bar\\}", Token::getTokenValue ) ++ // What's important is that we did NOT detect the expression ++ .returns( false, Token::isParameter ); ++ } ++ ++ @Test ++ public void testBackslashEscapesParameter() { ++ Assertions.assertThat( ++ new TokenCollector( "foo \\{bar\\}", getInterpolationTermType() ) ++ .getTokenList() ++ ) ++ .hasSize( 1 ) ++ .element( 0 ) ++ // Backslashes are removed later, in AbstractMessageInterpolator.replaceEscapedLiterals ++ .returns( "foo \\{bar\\}", Token::getTokenValue ) ++ // What's important is that we did NOT detect the parameter ++ .returns( false, Token::isParameter ); ++ } ++ ++ @Test(expectedExceptions = MessageDescriptorFormatException.class, expectedExceptionsMessageRegExp = "HV000168.*") ++ public void testTrailingClosingBraceThrowsException() { ++ new TokenCollector( "this message contains a invalid parameter start token {", getInterpolationTermType() ); ++ } ++ ++ @Test ++ public void testDollarThenNonMetaCharacterInterpretedAsLiteral() { ++ Assertions.assertThat( ++ new TokenCollector( "$a", getInterpolationTermType() ) ++ .getTokenList() ++ ) ++ .hasSize( 1 ) ++ .element( 0 ) ++ .returns( "$a", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ } ++ ++ @Test ++ public void testTrailingDollarInterpretedAsLiteral() { ++ Assertions.assertThat( ++ new TokenCollector( "foo $", getInterpolationTermType() ) ++ .getTokenList() ++ ) ++ .hasSize( 1 ) ++ .element( 0 ) ++ .returns( "foo $", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ } ++ ++ @Test ++ public void testTrailingBackslashInterpretedAsLiteral() { ++ Assertions.assertThat( ++ new TokenCollector( "foo \\", getInterpolationTermType() ) ++ .getTokenList() ++ ) ++ .hasSize( 1 ) ++ .element( 0 ) ++ .returns( "foo \\", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ } ++} +diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/TokenCollectorMessageExpressionTest.java b/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/TokenCollectorMessageExpressionTest.java +new file mode 100644 +index 000000000..229e34174 +--- /dev/null ++++ b/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/TokenCollectorMessageExpressionTest.java +@@ -0,0 +1,110 @@ ++/* ++ * Hibernate Validator, declare and validate application constraints ++ * ++ * License: Apache License, Version 2.0 ++ * See the license.txt file in the root directory or . ++ */ ++package org.hibernate.validator.test.internal.engine.messageinterpolation; ++ ++import org.hibernate.validator.internal.engine.messageinterpolation.InterpolationTermType; ++import org.hibernate.validator.internal.engine.messageinterpolation.parser.MessageDescriptorFormatException; ++import org.hibernate.validator.internal.engine.messageinterpolation.parser.Token; ++import org.hibernate.validator.internal.engine.messageinterpolation.parser.TokenCollector; ++ ++import org.assertj.core.api.Assertions; ++import org.assertj.core.api.ListAssert; ++import org.testng.annotations.Test; ++ ++/** ++ * Tests for {@code TokenCollector} in message expression mode. ++ * ++ * @author Hardy Ferentschik ++ */ ++public class TokenCollectorMessageExpressionTest extends AbstractTokenCollectorTest { ++ @Override ++ protected InterpolationTermType getInterpolationTermType() { ++ return InterpolationTermType.EL; ++ } ++ ++ // Several tests inherited from the abstract class ++ ++ @Test ++ public void testMessageParameter() { ++ ListAssert assertion = Assertions.assertThat( ++ new TokenCollector( "foo {bar}", getInterpolationTermType() ) ++ .getTokenList() ++ ) ++ .hasSize( 2 ); ++ assertion.element( 0 ) ++ .returns( "foo ", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ assertion.element( 1 ) ++ .returns( "{bar}", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ } ++ ++ @Test ++ public void testMessageExpression() { ++ ListAssert assertion = Assertions.assertThat( ++ new TokenCollector( "foo ${bar}", getInterpolationTermType() ) ++ .getTokenList() ++ ) ++ .hasSize( 2 ); ++ assertion.element( 0 ) ++ .returns( "foo ", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ assertion.element( 1 ) ++ .returns( "${bar}", Token::getTokenValue ) ++ .returns( true, Token::isParameter ); ++ } ++ ++ @Test ++ public void testDollarThenDollarThenParameterInterpretedAsLiterals() { ++ ListAssert assertion = Assertions.assertThat( ++ new TokenCollector( "$${1+1}", getInterpolationTermType() ) ++ .getTokenList() ++ ) ++ .hasSize( 2 ); ++ assertion.element( 0 ) ++ .returns( "$$", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ assertion.element( 1 ) ++ .returns( "{1+1}", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ } ++ ++ @Test ++ public void testDollarThenDollarThenLiteralsInterpretedAsLiterals() { ++ ListAssert assertion = Assertions.assertThat( ++ new TokenCollector( "$$foo", getInterpolationTermType() ) ++ .getTokenList() ++ ) ++ .hasSize( 2 ); ++ assertion.element( 0 ) ++ .returns( "$$", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ assertion.element( 1 ) ++ .returns( "foo", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ } ++ ++ @Test(expectedExceptions = MessageDescriptorFormatException.class, expectedExceptionsMessageRegExp = "HV000168.*") ++ public void testDollarThenClosingBraceThrowsException() { ++ new TokenCollector( "$}", getInterpolationTermType() ); ++ } ++ ++ @Test ++ public void testDollarThenEscapeInterpretedAsLiterals() { ++ ListAssert assertion = Assertions.assertThat( ++ new TokenCollector( "$\\A{1+1}", getInterpolationTermType() ) ++ .getTokenList() ++ ) ++ .hasSize( 2 ); ++ assertion.element( 0 ) ++ .returns( "$\\A", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ assertion.element( 1 ) ++ .returns( "{1+1}", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ } ++} +diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/TokenCollectorMessageParameterTest.java b/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/TokenCollectorMessageParameterTest.java +new file mode 100644 +index 000000000..9189f496b +--- /dev/null ++++ b/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/TokenCollectorMessageParameterTest.java +@@ -0,0 +1,115 @@ ++/* ++ * Hibernate Validator, declare and validate application constraints ++ * ++ * License: Apache License, Version 2.0 ++ * See the license.txt file in the root directory or . ++ */ ++package org.hibernate.validator.test.internal.engine.messageinterpolation; ++ ++import org.hibernate.validator.internal.engine.messageinterpolation.InterpolationTermType; ++import org.hibernate.validator.internal.engine.messageinterpolation.parser.MessageDescriptorFormatException; ++import org.hibernate.validator.internal.engine.messageinterpolation.parser.Token; ++import org.hibernate.validator.internal.engine.messageinterpolation.parser.TokenCollector; ++ ++import org.assertj.core.api.Assertions; ++import org.assertj.core.api.ListAssert; ++import org.testng.annotations.Test; ++ ++/** ++ * Tests for {@code TokenCollector} in message parameter mode. ++ * ++ * @author Hardy Ferentschik ++ */ ++public class TokenCollectorMessageParameterTest extends AbstractTokenCollectorTest { ++ @Override ++ protected InterpolationTermType getInterpolationTermType() { ++ return InterpolationTermType.PARAMETER; ++ } ++ ++ // Several tests inherited from the abstract class ++ ++ @Test ++ public void testMessageParameter() { ++ ListAssert assertion = Assertions.assertThat( ++ new TokenCollector( "foo {bar}", getInterpolationTermType() ) ++ .getTokenList() ++ ) ++ .hasSize( 2 ); ++ assertion.element( 0 ) ++ .returns( "foo ", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ assertion.element( 1 ) ++ .returns( "{bar}", Token::getTokenValue ) ++ .returns( true, Token::isParameter ); ++ } ++ ++ @Test ++ public void testMessageExpression() { ++ ListAssert assertion = Assertions.assertThat( ++ new TokenCollector( "foo ${bar}", getInterpolationTermType() ) ++ .getTokenList() ++ ) ++ .hasSize( 2 ); ++ /* ++ * 6.3.1.1: ++ * Parameter interpolation has precedence over message expressions. ++ * For example for the message descriptor ${value}, ++ * trying to evaluate {value} as message parameter has precedence ++ * over evaluating ${value} as message expression. ++ */ ++ assertion.element( 0 ) ++ .returns( "foo $", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ assertion.element( 1 ) ++ .returns( "{bar}", Token::getTokenValue ) ++ .returns( true, Token::isParameter ); ++ } ++ ++ @Test ++ public void testDollarThenDollarThenParameterInterpretedAsLiteralAndParameter() { ++ ListAssert assertion = Assertions.assertThat( ++ new TokenCollector( "$${1+1}", getInterpolationTermType() ) ++ .getTokenList() ++ ) ++ .hasSize( 2 ); ++ assertion.element( 0 ) ++ .returns( "$$", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ assertion.element( 1 ) ++ .returns( "{1+1}", Token::getTokenValue ) ++ .returns( true, Token::isParameter ); ++ } ++ ++ @Test ++ public void testDollarThenDollarThenLiteralsInterpretedAsLiterals() { ++ ListAssert assertion = Assertions.assertThat( ++ new TokenCollector( "$$foo", getInterpolationTermType() ) ++ .getTokenList() ++ ) ++ .hasSize( 1 ); ++ assertion.element( 0 ) ++ .returns( "$$foo", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ } ++ ++ @Test(expectedExceptions = MessageDescriptorFormatException.class, expectedExceptionsMessageRegExp = "HV000168.*") ++ public void testDollarThenClosingBraceThrowsException() { ++ // Fails because of the dangling closing brace; the dollar sign is irrelevant ++ new TokenCollector( "$}", getInterpolationTermType() ); ++ } ++ ++ @Test ++ public void testDollarThenEscapeInterpretedAsLiterals() { ++ ListAssert assertion = Assertions.assertThat( ++ new TokenCollector( "$\\A{1+1}", getInterpolationTermType() ) ++ .getTokenList() ++ ) ++ .hasSize( 2 ); ++ assertion.element( 0 ) ++ .returns( "$\\A", Token::getTokenValue ) ++ .returns( false, Token::isParameter ); ++ assertion.element( 1 ) ++ .returns( "{1+1}", Token::getTokenValue ) ++ .returns( true, Token::isParameter ); ++ } ++} +diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/TokenCollectorTest.java b/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/TokenCollectorTest.java +deleted file mode 100644 +index ab9299f17..000000000 +--- a/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/TokenCollectorTest.java ++++ /dev/null +@@ -1,64 +0,0 @@ +-/* +- * Hibernate Validator, declare and validate application constraints +- * +- * License: Apache License, Version 2.0 +- * See the license.txt file in the root directory or . +- */ +-package org.hibernate.validator.test.internal.engine.messageinterpolation; +- +-import org.hibernate.validator.internal.engine.messageinterpolation.InterpolationTermType; +-import org.hibernate.validator.internal.engine.messageinterpolation.parser.MessageDescriptorFormatException; +-import org.hibernate.validator.internal.engine.messageinterpolation.parser.Token; +-import org.hibernate.validator.internal.engine.messageinterpolation.parser.TokenCollector; +- +-import org.assertj.core.api.Assertions; +-import org.assertj.core.api.ListAssert; +-import org.testng.annotations.Test; +- +-/** +- * Tests for {@code TokenCollector}. +- * +- * @author Hardy Ferentschik +- */ +-public class TokenCollectorTest { +- +- @Test(expectedExceptions = MessageDescriptorFormatException.class, expectedExceptionsMessageRegExp = "HV000169.*") +- public void testNestedParametersThrowException() throws Exception { +- new TokenCollector( "#{foo {}", InterpolationTermType.PARAMETER ); +- } +- +- @Test(expectedExceptions = MessageDescriptorFormatException.class, expectedExceptionsMessageRegExp = "HV000168.*") +- public void testParameterWithoutOpeningBraceThrowsException() throws Exception { +- new TokenCollector( "foo}", InterpolationTermType.PARAMETER ); +- } +- +- @Test(expectedExceptions = MessageDescriptorFormatException.class, expectedExceptionsMessageRegExp = "HV000168.*") +- public void testELExpressionDollarThenClosingBraceThrowsException() throws Exception { +- new TokenCollector( "$}", InterpolationTermType.EL ); +- } +- +- @Test +- public void testELExpressionDollarThenEscapeInterpretedAsLiterals() { +- ListAssert assertion = Assertions.assertThat( +- new TokenCollector( "$\\A{1+1}", InterpolationTermType.EL ) +- .getTokenList() +- ) +- .hasSize( 2 ); +- assertion.element( 0 ) +- .returns( "$\\A", Token::getTokenValue ) +- .returns( false, Token::isParameter ); +- assertion.element( 1 ) +- .returns( "{1+1}", Token::getTokenValue ) +- .returns( false, Token::isParameter ); +- } +- +- @Test(expectedExceptions = MessageDescriptorFormatException.class, expectedExceptionsMessageRegExp = "HV000168.*") +- public void testTermWithoutClosingBraceThrowsException() throws Exception { +- new TokenCollector( "{foo", InterpolationTermType.PARAMETER ); +- } +- +- @Test(expectedExceptions = MessageDescriptorFormatException.class, expectedExceptionsMessageRegExp = "HV000168.*") +- public void testSingleClosingBraceThrowsException() throws Exception { +- new TokenCollector( "this message contains a invalid parameter start token {", InterpolationTermType.EL ); +- } +-} diff --git a/CVE-2020-10693-4.patch b/CVE-2020-10693-4.patch new file mode 100644 index 0000000..60c13a5 --- /dev/null +++ b/CVE-2020-10693-4.patch @@ -0,0 +1,84 @@ +From 93c027b954d4ccce1ad82b2f5e27e22357757fa8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= +Date: Mon, 24 Feb 2020 17:23:37 +0100 +Subject: [PATCH] HV-1774 Test arbitrary code injection through + buildConstraintViolationWithTemplate() + +--- + .../ConstraintValidatorContextTest.java | 51 +++++++++++++++++++ + 1 file changed, 51 insertions(+) + +diff --git a/engine/src/test/java/org/hibernate/validator/test/constraints/ConstraintValidatorContextTest.java b/engine/src/test/java/org/hibernate/validator/test/constraints/ConstraintValidatorContextTest.java +index 6094195e3..a89a97016 100644 +--- a/engine/src/test/java/org/hibernate/validator/test/constraints/ConstraintValidatorContextTest.java ++++ b/engine/src/test/java/org/hibernate/validator/test/constraints/ConstraintValidatorContextTest.java +@@ -194,6 +194,20 @@ public void testAddParameterNodeForFieldLevelConstraintCausesException() throws + } + } + ++ @Test ++ public void testInjectionCausedByRecklessConcatenation() { ++ String maliciousPayload = "$\\A{1 + 1}"; ++ ++ // Simulate user entry, through a web form for example ++ MyObjectWithELInjectionRiskCausedByRecklessConcatenation object = new MyObjectWithELInjectionRiskCausedByRecklessConcatenation(); ++ object.field1 = maliciousPayload; ++ Set> constraintViolations = validator.validate( object ); ++ assertThat( constraintViolations ).containsOnlyViolations( ++ violationOf( ValidationWithELInjectionRiskCausedByRecklessConcatenation.class ) ++ .withMessage( "Value '" + maliciousPayload + "' is invalid" ) ++ ); ++ } ++ + @MyClassLevelValidation + private static class MyObject { + @NotNull +@@ -264,6 +278,13 @@ public String getName() { + } + } + ++ @ValidationWithELInjectionRiskCausedByRecklessConcatenation ++ private static class MyObjectWithELInjectionRiskCausedByRecklessConcatenation { ++ ++ String field1; ++ ++ } ++ + @Retention(RUNTIME) + @Constraint(validatedBy = MyClassLevelValidation.Validator.class) + public @interface MyClassLevelValidation { +@@ -496,4 +517,34 @@ public boolean isValid(String value, ConstraintValidatorContext context) { + } + + } ++ ++ @Retention(RUNTIME) ++ @Constraint(validatedBy = ValidationWithELInjectionRiskCausedByRecklessConcatenation.Validator.class) ++ public @interface ValidationWithELInjectionRiskCausedByRecklessConcatenation { ++ String message() default "failed"; ++ ++ Class[] groups() default { }; ++ ++ Class[] payload() default { }; ++ ++ class Validator ++ implements ConstraintValidator { ++ ++ @Override ++ public boolean isValid(MyObjectWithELInjectionRiskCausedByRecklessConcatenation value, ConstraintValidatorContext context) { ++ context.disableDefaultConstraintViolation(); ++ ++ // This is bad practice: message parameters should be used instead. ++ // Regardless, it can happen and should work as well as possible. ++ context.buildConstraintViolationWithTemplate( "Value '" + escape( value.field1 ) + "' is invalid" ) ++ .addConstraintViolation(); ++ ++ return false; ++ } ++ ++ private String escape(String value) { ++ return value.replaceAll( "\\$+\\{", "{" ); ++ } ++ } ++ } + } diff --git a/CVE-2020-10693-pre.patch b/CVE-2020-10693-pre.patch new file mode 100644 index 0000000..fb414fe --- /dev/null +++ b/CVE-2020-10693-pre.patch @@ -0,0 +1,441 @@ +From 72049532fa289d0f5664e9b1a7fd19fd514e595f Mon Sep 17 00:00:00 2001 +From: Gunnar Morling +Date: Wed, 31 Aug 2016 15:28:25 +0200 +Subject: [PATCH] HV-1091 Using iterative instead of recursive approach for + message parsing + +--- + .../parser/BeginState.java | 12 +-- + .../messageinterpolation/parser/ELState.java | 10 --- + .../parser/EscapedState.java | 9 -- + .../parser/InterpolationTermState.java | 12 --- + .../parser/MessageState.java | 11 --- + .../parser/ParserState.java | 2 - + .../parser/TokenCollector.java | 16 ++-- + .../validator/bugs/TooBigMessageTest.java | 90 +++++++++++++++++++ + .../TokenIteratorTest.java | 8 +- + 9 files changed, 103 insertions(+), 67 deletions(-) + create mode 100644 engine/src/test/java/org/hibernate/validator/bugs/TooBigMessageTest.java + +diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/BeginState.java b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/BeginState.java +index 678f16e46..5aee73b9f 100644 +--- a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/BeginState.java ++++ b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/BeginState.java +@@ -18,11 +18,7 @@ + + @Override + public void terminate(TokenCollector tokenCollector) throws MessageDescriptorFormatException { +- } +- +- @Override +- public void start(TokenCollector tokenCollector) throws MessageDescriptorFormatException { +- tokenCollector.next(); ++ tokenCollector.terminateToken(); + } + + @Override +@@ -30,7 +26,6 @@ public void handleNonMetaCharacter(char character, TokenCollector tokenCollector + throws MessageDescriptorFormatException { + tokenCollector.appendToToken( character ); + tokenCollector.transitionState( new MessageState() ); +- tokenCollector.next(); + } + + @Override +@@ -43,7 +38,6 @@ public void handleBeginTerm(char character, TokenCollector tokenCollector) throw + tokenCollector.makeParameterToken(); + } + tokenCollector.transitionState( new InterpolationTermState() ); +- tokenCollector.next(); + } + + @Override +@@ -56,7 +50,6 @@ public void handleEscapeCharacter(char character, TokenCollector tokenCollector) + throws MessageDescriptorFormatException { + tokenCollector.appendToToken( character ); + tokenCollector.transitionState( new EscapedState( this ) ); +- tokenCollector.next(); + } + + @Override +@@ -68,9 +61,6 @@ public void handleELDesignator(char character, TokenCollector tokenCollector) + else { + ParserState state = new ELState(); + tokenCollector.transitionState( state ); +- tokenCollector.next(); + } + } + } +- +- +diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/ELState.java b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/ELState.java +index ce7df402f..569ea1e2e 100644 +--- a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/ELState.java ++++ b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/ELState.java +@@ -15,11 +15,6 @@ + public class ELState implements ParserState { + private static final Log log = LoggerFactory.make(); + +- @Override +- public void start(TokenCollector tokenCollector) { +- throw new IllegalStateException( "Parsing of message descriptor cannot start in this state" ); +- } +- + @Override + public void terminate(TokenCollector tokenCollector) throws MessageDescriptorFormatException { + tokenCollector.appendToToken( TokenCollector.EL_DESIGNATOR ); +@@ -33,7 +28,6 @@ public void handleNonMetaCharacter(char character, TokenCollector tokenCollector + tokenCollector.appendToToken( character ); + tokenCollector.terminateToken(); + tokenCollector.transitionState( new BeginState() ); +- tokenCollector.next(); + } + + @Override +@@ -44,7 +38,6 @@ public void handleBeginTerm(char character, TokenCollector tokenCollector) throw + tokenCollector.appendToToken( character ); + tokenCollector.makeELToken(); + tokenCollector.transitionState( new InterpolationTermState() ); +- tokenCollector.next(); + } + + @Override +@@ -59,7 +52,6 @@ public void handleEndTerm(char character, TokenCollector tokenCollector) throws + public void handleEscapeCharacter(char character, TokenCollector tokenCollector) + throws MessageDescriptorFormatException { + tokenCollector.transitionState( new EscapedState( this ) ); +- tokenCollector.next(); + } + + @Override +@@ -68,5 +60,3 @@ public void handleELDesignator(char character, TokenCollector tokenCollector) + handleNonMetaCharacter( character, tokenCollector ); + } + } +- +- +diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/EscapedState.java b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/EscapedState.java +index 901acff4f..f44242dd1 100644 +--- a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/EscapedState.java ++++ b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/EscapedState.java +@@ -16,11 +16,6 @@ public EscapedState(ParserState previousState) { + this.previousState = previousState; + } + +- @Override +- public void start(TokenCollector tokenCollector) { +- throw new IllegalStateException( "Parsing of message descriptor cannot start in this state" ); +- } +- + @Override + public void terminate(TokenCollector tokenCollector) throws MessageDescriptorFormatException { + tokenCollector.terminateToken(); +@@ -58,9 +53,5 @@ private void handleEscapedCharacter(char character, TokenCollector tokenCollecto + throws MessageDescriptorFormatException { + tokenCollector.appendToToken( character ); + tokenCollector.transitionState( previousState ); +- tokenCollector.next(); + } + } +- +- +- +diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/InterpolationTermState.java b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/InterpolationTermState.java +index f921113f9..11c974373 100644 +--- a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/InterpolationTermState.java ++++ b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/InterpolationTermState.java +@@ -15,11 +15,6 @@ + public class InterpolationTermState implements ParserState { + private static final Log log = LoggerFactory.make(); + +- @Override +- public void start(TokenCollector tokenCollector) { +- throw new IllegalStateException( "Parsing of message descriptor cannot start in this state" ); +- } +- + @Override + public void terminate(TokenCollector tokenCollector) throws MessageDescriptorFormatException { + throw log.getNonTerminatedParameterException( +@@ -32,7 +27,6 @@ public void terminate(TokenCollector tokenCollector) throws MessageDescriptorFor + public void handleNonMetaCharacter(char character, TokenCollector tokenCollector) + throws MessageDescriptorFormatException { + tokenCollector.appendToToken( character ); +- tokenCollector.next(); + } + + @Override +@@ -46,7 +40,6 @@ public void handleEndTerm(char character, TokenCollector tokenCollector) throws + tokenCollector.terminateToken(); + BeginState beginState = new BeginState(); + tokenCollector.transitionState( beginState ); +- tokenCollector.next(); + } + + @Override +@@ -55,16 +48,11 @@ public void handleEscapeCharacter(char character, TokenCollector tokenCollector) + tokenCollector.appendToToken( character ); + ParserState state = new EscapedState( this ); + tokenCollector.transitionState( state ); +- tokenCollector.next(); +- + } + + @Override + public void handleELDesignator(char character, TokenCollector tokenCollector) + throws MessageDescriptorFormatException { + tokenCollector.appendToToken( character ); +- tokenCollector.next(); + } + } +- +- +diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/MessageState.java b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/MessageState.java +index bac9c7e46..37cd23503 100644 +--- a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/MessageState.java ++++ b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/MessageState.java +@@ -16,11 +16,6 @@ + public class MessageState implements ParserState { + private static final Log log = LoggerFactory.make(); + +- @Override +- public void start(TokenCollector tokenCollector) { +- throw new IllegalStateException( "The parsing of the message descriptor cannot start in this state." ); +- } +- + @Override + public void terminate(TokenCollector tokenCollector) throws MessageDescriptorFormatException { + tokenCollector.terminateToken(); +@@ -30,7 +25,6 @@ public void terminate(TokenCollector tokenCollector) throws MessageDescriptorFor + public void handleNonMetaCharacter(char character, TokenCollector tokenCollector) + throws MessageDescriptorFormatException { + tokenCollector.appendToToken( character ); +- tokenCollector.next(); + } + + @Override +@@ -42,7 +36,6 @@ public void handleBeginTerm(char character, TokenCollector tokenCollector) throw + tokenCollector.makeParameterToken(); + } + tokenCollector.transitionState( new InterpolationTermState() ); +- tokenCollector.next(); + } + + @Override +@@ -59,7 +52,6 @@ public void handleEscapeCharacter(char character, TokenCollector tokenCollector) + tokenCollector.appendToToken( character ); + + tokenCollector.transitionState( new EscapedState( this ) ); +- tokenCollector.next(); + } + + @Override +@@ -70,9 +62,6 @@ public void handleELDesignator(char character, TokenCollector tokenCollector) + } + else { + tokenCollector.transitionState( new ELState() ); +- tokenCollector.next(); + } + } + } +- +- +diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/ParserState.java b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/ParserState.java +index a48a48f2b..64317de46 100644 +--- a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/ParserState.java ++++ b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/ParserState.java +@@ -13,7 +13,6 @@ + * @author Hardy Ferentschik + */ + public interface ParserState { +- void start(TokenCollector tokenCollector) throws MessageDescriptorFormatException; + + void terminate(TokenCollector tokenCollector) throws MessageDescriptorFormatException; + +@@ -27,4 +26,3 @@ + + void handleELDesignator(char character, TokenCollector tokenCollector) throws MessageDescriptorFormatException; + } +- +diff --git a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/TokenCollector.java b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/TokenCollector.java +index 1443eee7f..ffce7bb68 100644 +--- a/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/TokenCollector.java ++++ b/engine/src/main/java/org/hibernate/validator/internal/engine/messageinterpolation/parser/TokenCollector.java +@@ -6,13 +6,13 @@ + */ + package org.hibernate.validator.internal.engine.messageinterpolation.parser; + ++import static org.hibernate.validator.internal.util.CollectionHelper.newArrayList; ++ + import java.util.Collections; + import java.util.List; + + import org.hibernate.validator.internal.engine.messageinterpolation.InterpolationTermType; + +-import static org.hibernate.validator.internal.util.CollectionHelper.newArrayList; +- + /** + * Used to creates a list of tokens from a message descriptor. + * +@@ -28,7 +28,7 @@ + private final String originalMessageDescriptor; + private final InterpolationTermType interpolationTermType; + +- private List tokenList; ++ private final List tokenList; + private ParserState currentParserState; + private int currentPosition; + private Token currentToken; +@@ -69,10 +69,11 @@ public void makeELToken() { + currentToken.makeELToken(); + } + +- public void next() throws MessageDescriptorFormatException { ++ private void next() throws MessageDescriptorFormatException { + if ( currentPosition == originalMessageDescriptor.length() ) { + // give the current context the chance to complete + currentParserState.terminate( this ); ++ currentPosition++; + return; + } + char currentCharacter = originalMessageDescriptor.charAt( currentPosition ); +@@ -98,12 +99,12 @@ public void next() throws MessageDescriptorFormatException { + currentParserState.handleNonMetaCharacter( currentCharacter, this ); + } + } +- // make sure the last token is terminated +- terminateToken(); + } + + public void parse() throws MessageDescriptorFormatException { +- currentParserState.start( this ); ++ while ( currentPosition <= originalMessageDescriptor.length() ) { ++ next(); ++ } + } + + public void transitionState(ParserState newState) { +@@ -122,4 +123,3 @@ public String getOriginalMessageDescriptor() { + return originalMessageDescriptor; + } + } +- +diff --git a/engine/src/test/java/org/hibernate/validator/bugs/TooBigMessageTest.java b/engine/src/test/java/org/hibernate/validator/bugs/TooBigMessageTest.java +new file mode 100644 +index 000000000..4eb8ffc18 +--- /dev/null ++++ b/engine/src/test/java/org/hibernate/validator/bugs/TooBigMessageTest.java +@@ -0,0 +1,90 @@ ++/* ++ * Hibernate Validator, declare and validate application constraints ++ * ++ * License: Apache License, Version 2.0 ++ * See the license.txt file in the root directory or . ++ */ ++package org.hibernate.validator.bugs; ++ ++import static org.hibernate.validator.testutil.ConstraintViolationAssert.assertCorrectConstraintViolationMessages; ++import static org.hibernate.validator.testutil.ConstraintViolationAssert.assertNumberOfViolations; ++ ++import java.util.Set; ++ ++import javax.validation.ConstraintViolation; ++import javax.validation.Validator; ++import javax.validation.constraints.NotNull; ++ ++import org.hibernate.validator.testutil.TestForIssue; ++import org.hibernate.validator.testutils.ValidatorUtil; ++import org.junit.Test; ++ ++/** ++ * Ensure large error messages can be interpolated. ++ * ++ * @author Gunnar Morling ++ */ ++public class TooBigMessageTest { ++ ++ /** ++ * Large enough to trigger a stack overflow with the recursive scheme, assuming default settings ++ */ ++ private static final String LARGE_MESSAGE = ++ "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ++ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890"; ++ ++ @Test ++ @TestForIssue(jiraKey = "HV-1091") ++ public void largeMessageCanBeInterpolated() { ++ Validator validator = ValidatorUtil.getValidator(); ++ GoldFish fish = new GoldFish(); ++ ++ Set> constraintViolations = validator.validate( fish ); ++ assertNumberOfViolations( constraintViolations, 1 ); ++ assertCorrectConstraintViolationMessages( constraintViolations, LARGE_MESSAGE ); ++ } ++ ++ private static class GoldFish { ++ ++ @NotNull(message = LARGE_MESSAGE) ++ String name; ++ } ++} +diff --git a/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/TokenIteratorTest.java b/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/TokenIteratorTest.java +index a63e1996a..281f3bccf 100644 +--- a/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/TokenIteratorTest.java ++++ b/engine/src/test/java/org/hibernate/validator/test/internal/engine/messageinterpolation/TokenIteratorTest.java +@@ -6,15 +6,15 @@ + */ + package org.hibernate.validator.test.internal.engine.messageinterpolation; + ++import static org.testng.Assert.assertEquals; ++import static org.testng.Assert.assertFalse; ++import static org.testng.Assert.assertTrue; ++ + import org.hibernate.validator.internal.engine.messageinterpolation.InterpolationTermType; + import org.hibernate.validator.internal.engine.messageinterpolation.parser.TokenCollector; + import org.hibernate.validator.internal.engine.messageinterpolation.parser.TokenIterator; + import org.testng.annotations.Test; + +-import static org.testng.Assert.assertEquals; +-import static org.testng.Assert.assertFalse; +-import static org.testng.Assert.assertTrue; +- + /** + * Tests for {@code TokenIterator}. + * diff --git a/hibernate-validator.spec b/hibernate-validator.spec index d9b6c89..71629b8 100644 --- a/hibernate-validator.spec +++ b/hibernate-validator.spec @@ -4,7 +4,7 @@ Name: hibernate-validator Version: 5.2.4 -Release: 2 +Release: 3 Summary: Bean Validation 1.1 (JSR 349) Reference Implementation License: ASL 2.0 URL: http://www.hibernate.org/subprojects/validator.html @@ -12,6 +12,11 @@ Source0: https://github.com/hibernate/hibernate-validator/archive/%{ # JAXB2 and JDK7+ problems see https://hibernate.atlassian.net/browse/HV-528 Patch0: %{name}-5.2.4.Final-jaxb.patch Patch1: CVE-2017-7536.patch +Patch2: CVE-2020-10693-pre.patch +Patch3: CVE-2020-10693-1.patch +Patch4: CVE-2020-10693-2.patch +Patch5: CVE-2020-10693-3.patch +Patch6: CVE-2020-10693-4.patch BuildRequires: maven-local mvn(com.fasterxml:classmate) mvn(com.sun.xml.bind:jaxb-impl) BuildRequires: mvn(com.thoughtworks.paranamer:paranamer) @@ -76,6 +81,11 @@ This package contains javadoc for %{name}. find . -name "*.jar" -delete %patch0 -p1 %patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 %pom_disable_module distribution %pom_disable_module documentation %pom_disable_module engine-jdk8-tests @@ -132,6 +142,9 @@ rm engine/src/main/java/org/hibernate/validator/internal/engine/valuehandling/Ja %license copyright.txt license.txt %changelog +* Mon Mar 15 2021 wangxiao - 5.2.4-3 +- Fix CVE-2020-10693 + * Sat Sep 19 2020 maminjie - 5.2.4-2 - fix CVE-2017-7536 -- Gitee