diff options
author | Andrey Somov <public.somov@gmail.com> | 2022-09-08 21:52:24 +0300 |
---|---|---|
committer | Andrey Somov <public.somov@gmail.com> | 2022-09-08 21:52:24 +0300 |
commit | 72dfa9f1074abe2b8a6c8776bee4476b0aed02e3 (patch) | |
tree | 698be3a1520e18548a8ca6e6d969117733b3af79 | |
parent | ebad791333afee13bfd48fd9cf1ff6dab5faa51a (diff) | |
download | snakeyaml-72dfa9f1074abe2b8a6c8776bee4476b0aed02e3.tar.gz |
Set the limit for incoming data to prevent a CVE report in NIST
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()); + } + } +} |