Skip to content

Commit

Permalink
Add release notes for #160, minor tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Oct 24, 2022
1 parent 7e93907 commit 8d66153
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 43 deletions.
4 changes: 3 additions & 1 deletion release-notes/VERSION
Expand Up @@ -8,12 +8,14 @@ Project: woodstox

#78: Shade MSV dependency

5.3.1 (not yet released)
5.4.0 (not yet released)

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

5.3.0 (15-Jul-2019)

Expand Down
27 changes: 26 additions & 1 deletion src/main/java/com/ctc/wstx/api/ReaderConfig.java
Expand Up @@ -46,6 +46,9 @@ public final class ReaderConfig
public final static int DEFAULT_MAX_ENTITY_DEPTH = 500;
public final static int DEFAULT_MAX_ENTITY_COUNT = 100 * 1000;

// @since 5.4/6.4
public final static int DEFAULT_MAX_DTD_DEPTH = 500;

/*
///////////////////////////////////////////////////////////////////////
// Constants for reader properties:
Expand Down Expand Up @@ -133,7 +136,9 @@ public final class ReaderConfig
final static int PROP_MAX_TEXT_LENGTH = 66;
final static int PROP_MAX_ENTITY_COUNT = 67;
final static int PROP_MAX_ENTITY_DEPTH = 68;


final static int PROP_MAX_DTD_DEPTH = 69;

/*
////////////////////////////////////////////////
// Limits for numeric properties
Expand Down Expand Up @@ -341,6 +346,10 @@ public final class ReaderConfig
PROP_MAX_ENTITY_DEPTH);
sProperties.put(WstxInputProperties.P_MAX_ENTITY_COUNT,
PROP_MAX_ENTITY_COUNT);
// since 5.4/6.4
sProperties.put(WstxInputProperties.P_MAX_DTD_DEPTH,
PROP_MAX_DTD_DEPTH);

sProperties.put(WstxInputProperties.P_MAX_CHARACTERS, PROP_MAX_CHARACTERS);
sProperties.put(WstxInputProperties.P_CUSTOM_INTERNAL_ENTITIES,
Integer.valueOf(PROP_CUSTOM_INTERNAL_ENTITIES));
Expand Down Expand Up @@ -400,6 +409,9 @@ public final class ReaderConfig

protected int mMaxEntityDepth = DEFAULT_MAX_ENTITY_DEPTH;
protected long mMaxEntityCount = DEFAULT_MAX_ENTITY_COUNT;

// since 5.4/6.4
protected int mMaxDtdDepth = DEFAULT_MAX_DTD_DEPTH;

/**
* Base URL to use as the resolution context for relative entity
Expand Down Expand Up @@ -506,6 +518,7 @@ private ReaderConfig(ReaderConfig base,
mMaxTextLength = base.mMaxTextLength;
mMaxEntityDepth = base.mMaxEntityDepth;
mMaxEntityCount = base.mMaxEntityCount;
mMaxDtdDepth = base.mMaxDtdDepth;
}

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

public int getMaxDtdDepth() { return mMaxDtdDepth; }

public long getMaxCharacters() { return mMaxCharacters; }
public long getMaxTextLength() { return mMaxTextLength; }

Expand Down Expand Up @@ -988,6 +1004,10 @@ public void setMaxEntityDepth(int value) {
public void setMaxEntityCount(long value) {
mMaxEntityCount = value;
}
// @since 5.4/6.4
public void setMaxDtdDepth(int value) {
mMaxDtdDepth = value;
}

public void setCustomInternalEntities(Map<String,?> m)
{
Expand Down Expand Up @@ -1486,6 +1506,8 @@ public Object getProperty(int id)
return getMaxEntityDepth();
case PROP_MAX_ENTITY_COUNT:
return getMaxEntityCount();
case PROP_MAX_DTD_DEPTH:
return getMaxDtdDepth();

case PROP_MIN_TEXT_SEGMENT:
return getShortestReportedTextSegment();
Expand Down Expand Up @@ -1674,6 +1696,9 @@ public boolean setProperty(String propName, int id, Object value)
case PROP_MAX_ENTITY_COUNT:
setMaxEntityCount(ArgUtil.convertToLong(propName, value, 1));
break;
case PROP_MAX_DTD_DEPTH:
setMaxDtdDepth(ArgUtil.convertToInt(propName, value, 1));
break;

case PROP_MIN_TEXT_SEGMENT:
setShortestReportedTextSegment(ArgUtil.convertToInt(propName, value, 1));
Expand Down
10 changes: 9 additions & 1 deletion src/main/java/com/ctc/wstx/api/WstxInputProperties.java
Expand Up @@ -184,7 +184,6 @@ public final class WstxInputProperties

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


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

// and yet more size constraints (4.3+)

/**
* Maximum level of nesting of XML elements, starting with root element.
*
* @since 5.4 / 6.4
*/
public final static String P_MAX_DTD_DEPTH = "com.ctc.wstx.maxDtdDepth";

// // // Entity handling

/**
Expand Down
30 changes: 5 additions & 25 deletions src/main/java/com/ctc/wstx/dtd/FullDTDReader.java
Expand Up @@ -74,9 +74,6 @@ public class FullDTDReader

final static Boolean ENTITY_EXP_PE = Boolean.TRUE;

final static int DEFAULT_DTD_RECURSION_DEPTH_LIMIT = 500;
static int DTD_RECURSION_DEPTH_LIMIT = DEFAULT_DTD_RECURSION_DEPTH_LIMIT;

/*
///////////////////////////////////////////////////////////
// Configuration
Expand Down Expand Up @@ -330,24 +327,6 @@ public class FullDTDReader

transient TextBuffer mTextBuffer = null;

/**
* Sets the limit on how many times the code will recurse through DTD data.
* The default is 500.
* @param limit new limit on how many times the code will recurse through DTD data
*/
public static void setDtdRecursionDepthLimit(final int limit) {
DTD_RECURSION_DEPTH_LIMIT = limit;
}

/**
* Gets the limit on how many times the code will recurse through DTD data.
* The default is 500.
* @return limit on how many times the code will recurse through DTD data
*/
public static int getDtdRecursionDepthLimit() {
return DTD_RECURSION_DEPTH_LIMIT;
}

/*
///////////////////////////////////////////////////////////
// Life-cycle
Expand Down Expand Up @@ -3070,12 +3049,13 @@ private StructValidator readMixedSpec(PrefixedName elemName, boolean construct)
return val;
}

private ContentSpec readContentSpec(final PrefixedName elemName, final boolean construct, final int recursionDepth)
private ContentSpec readContentSpec(final PrefixedName elemName, final boolean construct,
final int recursionDepth)
throws XMLStreamException
{
if (recursionDepth > DTD_RECURSION_DEPTH_LIMIT) {
throw new XMLStreamException("FullDTDReader has reached recursion depth limit of " + DTD_RECURSION_DEPTH_LIMIT);
}
verifyLimit("Maximum DTD nesting depth (WstxInputProperties.P_MAX_DTD_DEPTH)",
mConfig.getMaxDtdDepth(),
recursionDepth);

ArrayList<ContentSpec> subSpecs = new ArrayList<ContentSpec>();
boolean isChoice = false; // default to sequence
Expand Down
34 changes: 19 additions & 15 deletions src/test/java/wstxtest/fuzz/Fuzz_DTDReadTest.java
@@ -1,16 +1,17 @@
package wstxtest.fuzz;

import com.ctc.wstx.dtd.FullDTDReader;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.io.Reader;

import javax.xml.stream.XMLStreamReader;

import com.ctc.wstx.api.WstxInputProperties;
import com.ctc.wstx.exc.WstxLazyException;
import com.ctc.wstx.stax.WstxInputFactory;
import org.codehaus.stax2.io.Stax2ByteArraySource;
import wstxtest.stream.BaseStreamTest;

import javax.xml.stream.XMLStreamReader;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.io.Reader;

public class Fuzz_DTDReadTest extends BaseStreamTest
{
private final byte[] DOC = readResource("/fuzz/clusterfuzz-testcase-modified-XmlFuzzer-5219006592450560.txt");
Expand All @@ -24,23 +25,24 @@ public void testIssueInputStream() throws Exception
streamThrough(sr);
fail("Should not pass");
} catch (WstxLazyException e) {
verifyException(e, "FullDTDReader has reached recursion depth limit of 500");
verifyException(e, "Maximum DTD nesting depth");
verifyException(e, "500");
}
sr.close();
}

public void testIssueInputStreamHigherRecursionLimit() throws Exception
{
final int defaultLimit = FullDTDReader.getDtdRecursionDepthLimit();
XMLStreamReader sr = STAX_F.createXMLStreamReader(new ByteArrayInputStream(DOC));
final WstxInputFactory staxF = getWstxInputFactory();
staxF.setProperty(WstxInputProperties.P_MAX_DTD_DEPTH, 1100);

XMLStreamReader sr = staxF.createXMLStreamReader(new ByteArrayInputStream(DOC));
try {
FullDTDReader.setDtdRecursionDepthLimit(1000);
streamThrough(sr);
fail("Should not pass");
} catch (WstxLazyException e) {
verifyException(e, "FullDTDReader has reached recursion depth limit of 1000");
} finally {
FullDTDReader.setDtdRecursionDepthLimit(defaultLimit);
verifyException(e, "Maximum DTD nesting depth");
verifyException(e, "1100");
}
sr.close();
}
Expand All @@ -54,7 +56,8 @@ public void testIssueReader() throws Exception
streamThrough(sr);
fail("Should not pass");
} catch (WstxLazyException e) {
verifyException(e, "FullDTDReader has reached recursion depth limit of 500");
verifyException(e, "Maximum DTD nesting depth");
verifyException(e, "500");
}
sr.close();
}
Expand All @@ -68,7 +71,8 @@ public void testIssueStax2ByteArray() throws Exception
streamThrough(sr);
fail("Should not pass");
} catch (WstxLazyException e) {
verifyException(e, "FullDTDReader has reached recursion depth limit of 500");
verifyException(e, "Maximum DTD nesting depth");
verifyException(e, "500");
}
sr.close();
}
Expand Down

0 comments on commit 8d66153

Please sign in to comment.