Skip to content

Commit 8d66153

Browse files
committed
Add release notes for #160, minor tweaks
1 parent 7e93907 commit 8d66153

File tree

5 files changed

+62
-43
lines changed

5 files changed

+62
-43
lines changed

release-notes/VERSION

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ Project: woodstox
88

99
#78: Shade MSV dependency
1010

11-
5.3.1 (not yet released)
11+
5.4.0 (not yet released)
1212

1313
#104: `NullPointerException` in `DTDValidator.validateElementEnd()`
1414
for element undefined in DTD
1515
(reported by ChrisTrenkamp@github)
1616
#105: W3CSchemaFactory constructor incorrectly references relaxng
17+
#160: Add limit and configuration setting for maximum nesting for DTD subsets
18+
(contributed by @pjfanning)
1719

1820
5.3.0 (15-Jul-2019)
1921

src/main/java/com/ctc/wstx/api/ReaderConfig.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ public final class ReaderConfig
4646
public final static int DEFAULT_MAX_ENTITY_DEPTH = 500;
4747
public final static int DEFAULT_MAX_ENTITY_COUNT = 100 * 1000;
4848

49+
// @since 5.4/6.4
50+
public final static int DEFAULT_MAX_DTD_DEPTH = 500;
51+
4952
/*
5053
///////////////////////////////////////////////////////////////////////
5154
// Constants for reader properties:
@@ -133,7 +136,9 @@ public final class ReaderConfig
133136
final static int PROP_MAX_TEXT_LENGTH = 66;
134137
final static int PROP_MAX_ENTITY_COUNT = 67;
135138
final static int PROP_MAX_ENTITY_DEPTH = 68;
136-
139+
140+
final static int PROP_MAX_DTD_DEPTH = 69;
141+
137142
/*
138143
////////////////////////////////////////////////
139144
// Limits for numeric properties
@@ -341,6 +346,10 @@ public final class ReaderConfig
341346
PROP_MAX_ENTITY_DEPTH);
342347
sProperties.put(WstxInputProperties.P_MAX_ENTITY_COUNT,
343348
PROP_MAX_ENTITY_COUNT);
349+
// since 5.4/6.4
350+
sProperties.put(WstxInputProperties.P_MAX_DTD_DEPTH,
351+
PROP_MAX_DTD_DEPTH);
352+
344353
sProperties.put(WstxInputProperties.P_MAX_CHARACTERS, PROP_MAX_CHARACTERS);
345354
sProperties.put(WstxInputProperties.P_CUSTOM_INTERNAL_ENTITIES,
346355
Integer.valueOf(PROP_CUSTOM_INTERNAL_ENTITIES));
@@ -400,6 +409,9 @@ public final class ReaderConfig
400409

401410
protected int mMaxEntityDepth = DEFAULT_MAX_ENTITY_DEPTH;
402411
protected long mMaxEntityCount = DEFAULT_MAX_ENTITY_COUNT;
412+
413+
// since 5.4/6.4
414+
protected int mMaxDtdDepth = DEFAULT_MAX_DTD_DEPTH;
403415

404416
/**
405417
* Base URL to use as the resolution context for relative entity
@@ -506,6 +518,7 @@ private ReaderConfig(ReaderConfig base,
506518
mMaxTextLength = base.mMaxTextLength;
507519
mMaxEntityDepth = base.mMaxEntityDepth;
508520
mMaxEntityCount = base.mMaxEntityCount;
521+
mMaxDtdDepth = base.mMaxDtdDepth;
509522
}
510523

511524
/* Ok, let's then see if we can find a buffer recycler. Since they
@@ -569,6 +582,7 @@ public ReaderConfig createNonShared(SymbolTable sym)
569582
rc.mMaxElementDepth = mMaxElementDepth;
570583
rc.mMaxEntityDepth = mMaxEntityDepth;
571584
rc.mMaxEntityCount = mMaxEntityCount;
585+
rc.mMaxDtdDepth = mMaxDtdDepth;
572586
if (mSpecialProperties != null) {
573587
int len = mSpecialProperties.length;
574588
Object[] specProps = new Object[len];
@@ -735,6 +749,8 @@ public boolean willAllowXml11EscapedCharsInXml10() {
735749
public int getMaxEntityDepth() { return mMaxEntityDepth; }
736750
public long getMaxEntityCount() { return mMaxEntityCount; }
737751

752+
public int getMaxDtdDepth() { return mMaxDtdDepth; }
753+
738754
public long getMaxCharacters() { return mMaxCharacters; }
739755
public long getMaxTextLength() { return mMaxTextLength; }
740756

@@ -988,6 +1004,10 @@ public void setMaxEntityDepth(int value) {
9881004
public void setMaxEntityCount(long value) {
9891005
mMaxEntityCount = value;
9901006
}
1007+
// @since 5.4/6.4
1008+
public void setMaxDtdDepth(int value) {
1009+
mMaxDtdDepth = value;
1010+
}
9911011

9921012
public void setCustomInternalEntities(Map<String,?> m)
9931013
{
@@ -1486,6 +1506,8 @@ public Object getProperty(int id)
14861506
return getMaxEntityDepth();
14871507
case PROP_MAX_ENTITY_COUNT:
14881508
return getMaxEntityCount();
1509+
case PROP_MAX_DTD_DEPTH:
1510+
return getMaxDtdDepth();
14891511

14901512
case PROP_MIN_TEXT_SEGMENT:
14911513
return getShortestReportedTextSegment();
@@ -1674,6 +1696,9 @@ public boolean setProperty(String propName, int id, Object value)
16741696
case PROP_MAX_ENTITY_COUNT:
16751697
setMaxEntityCount(ArgUtil.convertToLong(propName, value, 1));
16761698
break;
1699+
case PROP_MAX_DTD_DEPTH:
1700+
setMaxDtdDepth(ArgUtil.convertToInt(propName, value, 1));
1701+
break;
16771702

16781703
case PROP_MIN_TEXT_SEGMENT:
16791704
setShortestReportedTextSegment(ArgUtil.convertToInt(propName, value, 1));

src/main/java/com/ctc/wstx/api/WstxInputProperties.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,6 @@ public final class WstxInputProperties
184184

185185
// // // Constraints on sizes of text segments parsed:
186186

187-
188187
/**
189188
* Property to specify shortest non-complete text segment (part of
190189
* CDATA section or text content) that parser is allowed to return,
@@ -252,6 +251,15 @@ public final class WstxInputProperties
252251
*/
253252
public final static String P_MAX_ENTITY_DEPTH = "com.ctc.wstx.maxEntityDepth";
254253

254+
// and yet more size constraints (4.3+)
255+
256+
/**
257+
* Maximum level of nesting of XML elements, starting with root element.
258+
*
259+
* @since 5.4 / 6.4
260+
*/
261+
public final static String P_MAX_DTD_DEPTH = "com.ctc.wstx.maxDtdDepth";
262+
255263
// // // Entity handling
256264

257265
/**

src/main/java/com/ctc/wstx/dtd/FullDTDReader.java

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,6 @@ public class FullDTDReader
7474

7575
final static Boolean ENTITY_EXP_PE = Boolean.TRUE;
7676

77-
final static int DEFAULT_DTD_RECURSION_DEPTH_LIMIT = 500;
78-
static int DTD_RECURSION_DEPTH_LIMIT = DEFAULT_DTD_RECURSION_DEPTH_LIMIT;
79-
8077
/*
8178
///////////////////////////////////////////////////////////
8279
// Configuration
@@ -330,24 +327,6 @@ public class FullDTDReader
330327

331328
transient TextBuffer mTextBuffer = null;
332329

333-
/**
334-
* Sets the limit on how many times the code will recurse through DTD data.
335-
* The default is 500.
336-
* @param limit new limit on how many times the code will recurse through DTD data
337-
*/
338-
public static void setDtdRecursionDepthLimit(final int limit) {
339-
DTD_RECURSION_DEPTH_LIMIT = limit;
340-
}
341-
342-
/**
343-
* Gets the limit on how many times the code will recurse through DTD data.
344-
* The default is 500.
345-
* @return limit on how many times the code will recurse through DTD data
346-
*/
347-
public static int getDtdRecursionDepthLimit() {
348-
return DTD_RECURSION_DEPTH_LIMIT;
349-
}
350-
351330
/*
352331
///////////////////////////////////////////////////////////
353332
// Life-cycle
@@ -3070,12 +3049,13 @@ private StructValidator readMixedSpec(PrefixedName elemName, boolean construct)
30703049
return val;
30713050
}
30723051

3073-
private ContentSpec readContentSpec(final PrefixedName elemName, final boolean construct, final int recursionDepth)
3052+
private ContentSpec readContentSpec(final PrefixedName elemName, final boolean construct,
3053+
final int recursionDepth)
30743054
throws XMLStreamException
30753055
{
3076-
if (recursionDepth > DTD_RECURSION_DEPTH_LIMIT) {
3077-
throw new XMLStreamException("FullDTDReader has reached recursion depth limit of " + DTD_RECURSION_DEPTH_LIMIT);
3078-
}
3056+
verifyLimit("Maximum DTD nesting depth (WstxInputProperties.P_MAX_DTD_DEPTH)",
3057+
mConfig.getMaxDtdDepth(),
3058+
recursionDepth);
30793059

30803060
ArrayList<ContentSpec> subSpecs = new ArrayList<ContentSpec>();
30813061
boolean isChoice = false; // default to sequence

src/test/java/wstxtest/fuzz/Fuzz_DTDReadTest.java

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
package wstxtest.fuzz;
22

3-
import com.ctc.wstx.dtd.FullDTDReader;
3+
import java.io.ByteArrayInputStream;
4+
import java.io.InputStreamReader;
5+
import java.io.Reader;
6+
7+
import javax.xml.stream.XMLStreamReader;
8+
9+
import com.ctc.wstx.api.WstxInputProperties;
410
import com.ctc.wstx.exc.WstxLazyException;
511
import com.ctc.wstx.stax.WstxInputFactory;
612
import org.codehaus.stax2.io.Stax2ByteArraySource;
713
import wstxtest.stream.BaseStreamTest;
814

9-
import javax.xml.stream.XMLStreamReader;
10-
import java.io.ByteArrayInputStream;
11-
import java.io.InputStreamReader;
12-
import java.io.Reader;
13-
1415
public class Fuzz_DTDReadTest extends BaseStreamTest
1516
{
1617
private final byte[] DOC = readResource("/fuzz/clusterfuzz-testcase-modified-XmlFuzzer-5219006592450560.txt");
@@ -24,23 +25,24 @@ public void testIssueInputStream() throws Exception
2425
streamThrough(sr);
2526
fail("Should not pass");
2627
} catch (WstxLazyException e) {
27-
verifyException(e, "FullDTDReader has reached recursion depth limit of 500");
28+
verifyException(e, "Maximum DTD nesting depth");
29+
verifyException(e, "500");
2830
}
2931
sr.close();
3032
}
3133

3234
public void testIssueInputStreamHigherRecursionLimit() throws Exception
3335
{
34-
final int defaultLimit = FullDTDReader.getDtdRecursionDepthLimit();
35-
XMLStreamReader sr = STAX_F.createXMLStreamReader(new ByteArrayInputStream(DOC));
36+
final WstxInputFactory staxF = getWstxInputFactory();
37+
staxF.setProperty(WstxInputProperties.P_MAX_DTD_DEPTH, 1100);
38+
39+
XMLStreamReader sr = staxF.createXMLStreamReader(new ByteArrayInputStream(DOC));
3640
try {
37-
FullDTDReader.setDtdRecursionDepthLimit(1000);
3841
streamThrough(sr);
3942
fail("Should not pass");
4043
} catch (WstxLazyException e) {
41-
verifyException(e, "FullDTDReader has reached recursion depth limit of 1000");
42-
} finally {
43-
FullDTDReader.setDtdRecursionDepthLimit(defaultLimit);
44+
verifyException(e, "Maximum DTD nesting depth");
45+
verifyException(e, "1100");
4446
}
4547
sr.close();
4648
}
@@ -54,7 +56,8 @@ public void testIssueReader() throws Exception
5456
streamThrough(sr);
5557
fail("Should not pass");
5658
} catch (WstxLazyException e) {
57-
verifyException(e, "FullDTDReader has reached recursion depth limit of 500");
59+
verifyException(e, "Maximum DTD nesting depth");
60+
verifyException(e, "500");
5861
}
5962
sr.close();
6063
}
@@ -68,7 +71,8 @@ public void testIssueStax2ByteArray() throws Exception
6871
streamThrough(sr);
6972
fail("Should not pass");
7073
} catch (WstxLazyException e) {
71-
verifyException(e, "FullDTDReader has reached recursion depth limit of 500");
74+
verifyException(e, "Maximum DTD nesting depth");
75+
verifyException(e, "500");
7276
}
7377
sr.close();
7478
}

0 commit comments

Comments
 (0)