aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Somov <public.somov@gmail.com>2022-09-08 21:52:24 +0300
committerAndrey Somov <public.somov@gmail.com>2022-09-08 21:52:24 +0300
commit72dfa9f1074abe2b8a6c8776bee4476b0aed02e3 (patch)
tree698be3a1520e18548a8ca6e6d969117733b3af79
parentebad791333afee13bfd48fd9cf1ff6dab5faa51a (diff)
downloadsnakeyaml-72dfa9f1074abe2b8a6c8776bee4476b0aed02e3.tar.gz
Set the limit for incoming data to prevent a CVE report in NIST
-rw-r--r--src/changes/changes.xml3
-rw-r--r--src/main/java/org/yaml/snakeyaml/LoaderOptions.java14
-rw-r--r--src/main/java/org/yaml/snakeyaml/Yaml.java2
-rw-r--r--src/main/java/org/yaml/snakeyaml/parser/ParserImpl.java6
-rw-r--r--src/main/java/org/yaml/snakeyaml/reader/StreamReader.java5
-rw-r--r--src/main/java/org/yaml/snakeyaml/scanner/ScannerImpl.java18
-rw-r--r--src/test/java/org/yaml/snakeyaml/issues/issue102/BigDataLoadTest.java10
-rw-r--r--src/test/java/org/yaml/snakeyaml/issues/issue547/ByteLimitTest.java37
8 files changed, 82 insertions, 13 deletions
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 73981624..406c4c4f 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -6,6 +6,9 @@
</properties>
<body>
<release version="1.32-SNAPSHOT" date="in GIT" description="Maintenance">
+ <action dev="asomov" type="fix" issue="547">
+ Set the limit for incoming data to prevent a CVE report in NIST
+ </action>
<action dev="asomov" type="update">
Format the source with Google style.
Info: https://stackoverflow.com/questions/49712148/maven-plugin-for-auto-formatting-code-to-match-google-checkstyle
diff --git a/src/main/java/org/yaml/snakeyaml/LoaderOptions.java b/src/main/java/org/yaml/snakeyaml/LoaderOptions.java
index 1f6b81aa..bcb97135 100644
--- a/src/main/java/org/yaml/snakeyaml/LoaderOptions.java
+++ b/src/main/java/org/yaml/snakeyaml/LoaderOptions.java
@@ -23,6 +23,7 @@ public class LoaderOptions {
private boolean processComments = false;
private boolean enumCaseSensitive = true;
private int nestingDepthLimit = 50;
+ private int codePointLimit = 100 * 1024;
public boolean isAllowDuplicateKeys() {
return allowDuplicateKeys;
@@ -130,4 +131,17 @@ public class LoaderOptions {
public void setNestingDepthLimit(int nestingDepthLimit) {
this.nestingDepthLimit = nestingDepthLimit;
}
+
+ public int getCodePointLimit() {
+ return codePointLimit;
+ }
+
+ /**
+ * The max amount of code points in the input YAML document. Please be aware that byte limit
+ * depends on the encoding.
+ * @param codePointLimit - the max allowed size of the YAML data
+ */
+ public void setCodePointLimit(int codePointLimit) {
+ this.codePointLimit = codePointLimit;
+ }
}
diff --git a/src/main/java/org/yaml/snakeyaml/Yaml.java b/src/main/java/org/yaml/snakeyaml/Yaml.java
index 42a4c977..0cfd2bb2 100644
--- a/src/main/java/org/yaml/snakeyaml/Yaml.java
+++ b/src/main/java/org/yaml/snakeyaml/Yaml.java
@@ -471,7 +471,7 @@ public class Yaml {
}
private Object loadFromReader(StreamReader sreader, Class<?> type) {
- Composer composer = new Composer(new ParserImpl(sreader, loadingConfig.isProcessComments()),
+ Composer composer = new Composer(new ParserImpl(sreader, loadingConfig),
resolver, loadingConfig);
constructor.setComposer(composer);
return constructor.getSingleData(type);
diff --git a/src/main/java/org/yaml/snakeyaml/parser/ParserImpl.java b/src/main/java/org/yaml/snakeyaml/parser/ParserImpl.java
index a359aa83..3a8eac28 100644
--- a/src/main/java/org/yaml/snakeyaml/parser/ParserImpl.java
+++ b/src/main/java/org/yaml/snakeyaml/parser/ParserImpl.java
@@ -19,6 +19,7 @@ import java.util.List;
import java.util.Map;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.DumperOptions.Version;
+import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.comments.CommentType;
import org.yaml.snakeyaml.error.Mark;
import org.yaml.snakeyaml.error.YAMLException;
@@ -135,10 +136,15 @@ public class ParserImpl implements Parser {
this(new ScannerImpl(reader));
}
+ @Deprecated
public ParserImpl(StreamReader reader, boolean parseComments) {
this(new ScannerImpl(reader).setParseComments(parseComments));
}
+ public ParserImpl(StreamReader reader, LoaderOptions options) {
+ this(new ScannerImpl(reader, options));
+ }
+
public ParserImpl(Scanner scanner) {
this.scanner = scanner;
currentEvent = null;
diff --git a/src/main/java/org/yaml/snakeyaml/reader/StreamReader.java b/src/main/java/org/yaml/snakeyaml/reader/StreamReader.java
index b026f952..6799e76e 100644
--- a/src/main/java/org/yaml/snakeyaml/reader/StreamReader.java
+++ b/src/main/java/org/yaml/snakeyaml/reader/StreamReader.java
@@ -44,11 +44,6 @@ public class StreamReader {
*/
private int pointer = 0;
private boolean eof;
- /**
- * index is only required to implement 1024 key length restriction
- * http://yaml.org/spec/1.1/#simple key/ It must count code points, but it counts characters (to
- * be fixed)
- */
private int index = 0; // in code points
private int line = 0;
private int column = 0; // in code points
diff --git a/src/main/java/org/yaml/snakeyaml/scanner/ScannerImpl.java b/src/main/java/org/yaml/snakeyaml/scanner/ScannerImpl.java
index 51a723b6..1bd73569 100644
--- a/src/main/java/org/yaml/snakeyaml/scanner/ScannerImpl.java
+++ b/src/main/java/org/yaml/snakeyaml/scanner/ScannerImpl.java
@@ -23,6 +23,7 @@ import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.comments.CommentType;
import org.yaml.snakeyaml.error.Mark;
import org.yaml.snakeyaml.error.YAMLException;
@@ -178,6 +179,7 @@ public final class ScannerImpl implements Scanner {
// A flag that indicates if comments should be parsed
private boolean parseComments;
+ private final LoaderOptions loaderOptions;
// Variables related to simple keys treatment. See PyYAML.
@@ -214,12 +216,17 @@ public final class ScannerImpl implements Scanner {
private final Map<Integer, SimpleKey> possibleSimpleKeys;
public ScannerImpl(StreamReader reader) {
+ this(reader, new LoaderOptions());
+ }
+
+ public ScannerImpl(StreamReader reader, LoaderOptions options) {
this.parseComments = false;
this.reader = reader;
this.tokens = new ArrayList<Token>(100);
this.indents = new ArrayStack<Integer>(10);
// The order in possibleSimpleKeys is kept for nextPossibleSimpleKey()
this.possibleSimpleKeys = new LinkedHashMap<Integer, SimpleKey>();
+ this.loaderOptions = options;
fetchStreamStart();// Add the STREAM-START token.
}
@@ -319,6 +326,9 @@ public final class ScannerImpl implements Scanner {
* Fetch one or more tokens from the StreamReader.
*/
private void fetchMoreTokens() {
+ if (reader.getIndex() > loaderOptions.getCodePointLimit()) {
+ throw new YAMLException("The incoming YAML document exceeds the limit: " + loaderOptions.getCodePointLimit());
+ }
// Eat whitespaces and process comments until we reach the next token.
scanToNextToken();
// Remove obsolete possible simple keys.
@@ -1175,7 +1185,7 @@ public final class ScannerImpl implements Scanner {
// whitespace, then this is the start of a plain scalar.
return Constant.NULL_BL_T_LINEBR.hasNo(c, "-?:,[]{}#&*!|>'\"%@`")
|| (Constant.NULL_BL_T_LINEBR.hasNo(reader.peek(1))
- && (c == '-' || (this.flowLevel == 0 && "?:".indexOf(c) != -1)));
+ && (c == '-' || (this.flowLevel == 0 && "?:".indexOf(c) != -1)));
}
// Scanners.
@@ -1820,7 +1830,7 @@ public final class ScannerImpl implements Scanner {
}
}
// Pass several results back together.
- return new Object[] {chunks.toString(), maxIndent, endMark};
+ return new Object[]{chunks.toString(), maxIndent, endMark};
}
private Object[] scanBlockScalarBreaks(int indent) {
@@ -1850,7 +1860,7 @@ public final class ScannerImpl implements Scanner {
}
}
// Return both the assembled intervening string and the end-mark.
- return new Object[] {chunks.toString(), endMark};
+ return new Object[]{chunks.toString(), endMark};
}
/**
@@ -2039,7 +2049,7 @@ public final class ScannerImpl implements Scanner {
c = reader.peek(length);
if (Constant.NULL_BL_T_LINEBR.has(c)
|| (c == ':' && Constant.NULL_BL_T_LINEBR.has(reader.peek(length + 1),
- flowLevel != 0 ? ",[]{}" : ""))
+ flowLevel != 0 ? ",[]{}" : ""))
|| (this.flowLevel != 0 && ",?[]{}".indexOf(c) != -1)) {
break;
}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue102/BigDataLoadTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue102/BigDataLoadTest.java
index 8572bbe1..65826234 100644
--- a/src/test/java/org/yaml/snakeyaml/issues/issue102/BigDataLoadTest.java
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue102/BigDataLoadTest.java
@@ -19,6 +19,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import junit.framework.TestCase;
+import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
public class BigDataLoadTest extends TestCase {
@@ -26,14 +27,17 @@ public class BigDataLoadTest extends TestCase {
private static final int SIZE = 5000;
public void testBigStringData() {
- Yaml yaml = new Yaml();
+ LoaderOptions options = new LoaderOptions();
+ options.setCodePointLimit(10000000);
+ Yaml yaml = new Yaml(options);
List<?> loaded = yaml.load(getLongYamlDocument(SIZE));
assertEquals(SIZE, loaded.size());
}
public void testBigStreamData() {
- Yaml yaml = new Yaml();
- StringReader buffer = new StringReader(getLongYamlDocument(SIZE));
+ LoaderOptions options = new LoaderOptions();
+ options.setCodePointLimit(10000000);
+ Yaml yaml = new Yaml(options); StringReader buffer = new StringReader(getLongYamlDocument(SIZE));
List<?> loaded = yaml.load(buffer);
assertEquals(SIZE, loaded.size());
}
diff --git a/src/test/java/org/yaml/snakeyaml/issues/issue547/ByteLimitTest.java b/src/test/java/org/yaml/snakeyaml/issues/issue547/ByteLimitTest.java
new file mode 100644
index 00000000..69b3dce2
--- /dev/null
+++ b/src/test/java/org/yaml/snakeyaml/issues/issue547/ByteLimitTest.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2008, SnakeYAML
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.yaml.snakeyaml.issues.issue547;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+import org.yaml.snakeyaml.LoaderOptions;
+import org.yaml.snakeyaml.Yaml;
+
+public class ByteLimitTest {
+
+ @Test
+ public void testUnicode() {
+ LoaderOptions options = new LoaderOptions();
+ options.setCodePointLimit(15);
+ Yaml yaml = new Yaml(options);
+ try {
+ yaml.load("12345678901234567890");
+ fail("Long input should not be accepted");
+ } catch (Exception e) {
+ assertEquals("The incoming YAML document exceeds the limit: 15", e.getMessage());
+ }
+ }
+}