Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use StreamConstraintsException in name canonicalizers #948

Merged
merged 3 commits into from
Mar 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.base.ParserBase;
import com.fasterxml.jackson.core.exc.StreamConstraintsException;
import com.fasterxml.jackson.core.io.CharTypes;
import com.fasterxml.jackson.core.io.IOContext;
import com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer;
Expand Down Expand Up @@ -38,8 +39,6 @@
public class UTF8DataInputJsonParser
extends ParserBase
{
final static byte BYTE_LF = (byte) '\n';

@SuppressWarnings("deprecation")
private final static int FEAT_MASK_TRAILING_COMMA = Feature.ALLOW_TRAILING_COMMA.getMask();
@SuppressWarnings("deprecation")
Expand Down Expand Up @@ -1768,7 +1767,8 @@ protected String _parseAposName() throws IOException
/**********************************************************
*/

private final String findName(int q1, int lastQuadBytes) throws JsonParseException
private final String findName(int q1, int lastQuadBytes)
throws JsonParseException, StreamConstraintsException
{
q1 = pad(q1, lastQuadBytes);
// Usually we'll find it from the canonical symbol table already
Expand All @@ -1781,7 +1781,8 @@ private final String findName(int q1, int lastQuadBytes) throws JsonParseExcepti
return addName(_quadBuffer, 1, lastQuadBytes);
}

private final String findName(int q1, int q2, int lastQuadBytes) throws JsonParseException
private final String findName(int q1, int q2, int lastQuadBytes)
throws JsonParseException, StreamConstraintsException
{
q2 = pad(q2, lastQuadBytes);
// Usually we'll find it from the canonical symbol table already
Expand All @@ -1795,7 +1796,8 @@ private final String findName(int q1, int q2, int lastQuadBytes) throws JsonPars
return addName(_quadBuffer, 2, lastQuadBytes);
}

private final String findName(int q1, int q2, int q3, int lastQuadBytes) throws JsonParseException
private final String findName(int q1, int q2, int q3, int lastQuadBytes)
throws JsonParseException, StreamConstraintsException
{
q3 = pad(q3, lastQuadBytes);
String name = _symbols.findName(q1, q2, q3);
Expand All @@ -1809,7 +1811,8 @@ private final String findName(int q1, int q2, int q3, int lastQuadBytes) throws
return addName(quads, 3, lastQuadBytes);
}

private final String findName(int[] quads, int qlen, int lastQuad, int lastQuadBytes) throws JsonParseException
private final String findName(int[] quads, int qlen, int lastQuad, int lastQuadBytes)
throws JsonParseException, StreamConstraintsException
{
if (qlen >= quads.length) {
_quadBuffer = quads = _growArrayBy(quads, quads.length);
Expand All @@ -1828,7 +1831,8 @@ private final String findName(int[] quads, int qlen, int lastQuad, int lastQuadB
* multi-byte chars (if any), and then construct Name instance
* and add it to the symbol table.
*/
private final String addName(int[] quads, int qlen, int lastQuadBytes) throws JsonParseException
private final String addName(int[] quads, int qlen, int lastQuadBytes)
throws JsonParseException, StreamConstraintsException
{
/* Ok: must decode UTF-8 chars. No other validation is
* needed, since unescaping has been done earlier as necessary
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.base.ParserBase;
import com.fasterxml.jackson.core.exc.StreamConstraintsException;
import com.fasterxml.jackson.core.io.CharTypes;
import com.fasterxml.jackson.core.io.IOContext;
import com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer;
Expand Down Expand Up @@ -2309,7 +2310,8 @@ protected String _parseAposName() throws IOException
/**********************************************************
*/

private final String findName(int q1, int lastQuadBytes) throws JsonParseException
private final String findName(int q1, int lastQuadBytes)
throws JsonParseException, StreamConstraintsException
{
q1 = _padLastQuad(q1, lastQuadBytes);
// Usually we'll find it from the canonical symbol table already
Expand All @@ -2322,7 +2324,8 @@ private final String findName(int q1, int lastQuadBytes) throws JsonParseExcepti
return addName(_quadBuffer, 1, lastQuadBytes);
}

private final String findName(int q1, int q2, int lastQuadBytes) throws JsonParseException
private final String findName(int q1, int q2, int lastQuadBytes)
throws JsonParseException, StreamConstraintsException
{
q2 = _padLastQuad(q2, lastQuadBytes);
// Usually we'll find it from the canonical symbol table already
Expand All @@ -2336,7 +2339,8 @@ private final String findName(int q1, int q2, int lastQuadBytes) throws JsonPars
return addName(_quadBuffer, 2, lastQuadBytes);
}

private final String findName(int q1, int q2, int q3, int lastQuadBytes) throws JsonParseException
private final String findName(int q1, int q2, int q3, int lastQuadBytes)
throws JsonParseException, StreamConstraintsException
{
q3 = _padLastQuad(q3, lastQuadBytes);
String name = _symbols.findName(q1, q2, q3);
Expand All @@ -2350,7 +2354,8 @@ private final String findName(int q1, int q2, int q3, int lastQuadBytes) throws
return addName(quads, 3, lastQuadBytes);
}

private final String findName(int[] quads, int qlen, int lastQuad, int lastQuadBytes) throws JsonParseException
private final String findName(int[] quads, int qlen, int lastQuad, int lastQuadBytes)
throws JsonParseException, StreamConstraintsException
{
if (qlen >= quads.length) {
_quadBuffer = quads = growArrayBy(quads, quads.length);
Expand All @@ -2368,7 +2373,8 @@ private final String findName(int[] quads, int qlen, int lastQuad, int lastQuadB
* multi-byte chars (if any), and then construct Name instance
* and add it to the symbol table.
*/
private final String addName(int[] quads, int qlen, int lastQuadBytes) throws JsonParseException
private final String addName(int[] quads, int qlen, int lastQuadBytes)
throws JsonParseException, StreamConstraintsException
{
/* Ok: must decode UTF-8 chars. No other validation is
* needed, since unescaping has been done earlier as necessary
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.base.ParserBase;
import com.fasterxml.jackson.core.exc.StreamConstraintsException;
import com.fasterxml.jackson.core.io.IOContext;
import com.fasterxml.jackson.core.json.JsonReadContext;
import com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer;
Expand Down Expand Up @@ -639,7 +640,8 @@ protected final JsonToken _closeObjectScope() throws IOException
/**********************************************************
*/

protected final String _findName(int q1, int lastQuadBytes) throws JsonParseException
protected final String _findName(int q1, int lastQuadBytes)
throws JsonParseException, StreamConstraintsException
{
q1 = _padLastQuad(q1, lastQuadBytes);
// Usually we'll find it from the canonical symbol table already
Expand All @@ -652,7 +654,8 @@ protected final String _findName(int q1, int lastQuadBytes) throws JsonParseExce
return _addName(_quadBuffer, 1, lastQuadBytes);
}

protected final String _findName(int q1, int q2, int lastQuadBytes) throws JsonParseException
protected final String _findName(int q1, int q2, int lastQuadBytes)
throws JsonParseException, StreamConstraintsException
{
q2 = _padLastQuad(q2, lastQuadBytes);
// Usually we'll find it from the canonical symbol table already
Expand All @@ -666,7 +669,8 @@ protected final String _findName(int q1, int q2, int lastQuadBytes) throws JsonP
return _addName(_quadBuffer, 2, lastQuadBytes);
}

protected final String _findName(int q1, int q2, int q3, int lastQuadBytes) throws JsonParseException
protected final String _findName(int q1, int q2, int q3, int lastQuadBytes)
throws JsonParseException, StreamConstraintsException
{
q3 = _padLastQuad(q3, lastQuadBytes);
String name = _symbols.findName(q1, q2, q3);
Expand All @@ -684,10 +688,11 @@ protected final String _findName(int q1, int q2, int q3, int lastQuadBytes) thro
// table miss. It needs to demultiplex individual bytes, decode
// multi-byte chars (if any), and then construct Name instance
// and add it to the symbol table.
protected final String _addName(int[] quads, int qlen, int lastQuadBytes) throws JsonParseException
protected final String _addName(int[] quads, int qlen, int lastQuadBytes)
throws JsonParseException, StreamConstraintsException
{
/* Ok: must decode UTF-8 chars. No other validation is
* needed, since unescaping has been done earlier as necessary
* needed, since unescaping has been done earlier, as necessary
* (as well as error reporting for unescaped control chars)
*/
// 4 bytes per quad, except last one maybe less
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.concurrent.atomic.AtomicReference;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.exc.StreamConstraintsException;
import com.fasterxml.jackson.core.util.InternCache;

/**
Expand Down Expand Up @@ -863,7 +864,13 @@ private boolean _verifyLongName2(int[] q, int qlen, int spillOffset)
/**********************************************************
*/

public String addName(String name, int q1) {
/**
* @param name
* @param q1
* @return name (possibly interned)
* @throws StreamConstraintsException if the constraint exceptions
*/
public String addName(String name, int q1) throws StreamConstraintsException {
_verifySharing();
if (_intern) {
name = InternCache.instance.intern(name);
Expand All @@ -876,7 +883,14 @@ public String addName(String name, int q1) {
return name;
}

public String addName(String name, int q1, int q2) {
/**
* @param name
* @param q1
* @param q2
* @return name (possibly interned)
* @throws StreamConstraintsException if the constraint exceptions
*/
public String addName(String name, int q1, int q2) throws StreamConstraintsException {
_verifySharing();
if (_intern) {
name = InternCache.instance.intern(name);
Expand All @@ -896,7 +910,15 @@ public String addName(String name, int q1, int q2) {
return name;
}

public String addName(String name, int q1, int q2, int q3) {
/**
* @param name
* @param q1
* @param q2
* @param q3
* @return name (possibly interned)
* @throws StreamConstraintsException if the constraint exceptions
*/
public String addName(String name, int q1, int q2, int q3) throws StreamConstraintsException {
_verifySharing();
if (_intern) {
name = InternCache.instance.intern(name);
Expand All @@ -911,7 +933,14 @@ public String addName(String name, int q1, int q2, int q3) {
return name;
}

public String addName(String name, int[] q, int qlen)
/**
* @param name
* @param q
* @param qlen
* @return name (possibly interned)
* @throws StreamConstraintsException if the constraint exceptions
*/
public String addName(String name, int[] q, int qlen) throws StreamConstraintsException
{
_verifySharing();
if (_intern) {
Expand All @@ -921,7 +950,7 @@ public String addName(String name, int[] q, int qlen)

switch (qlen) {
case 1:
{
{
offset = _findOffsetForAdd(calcHash(q[0]));
_hashArea[offset] = q[0];
_hashArea[offset+3] = 1;
Expand Down Expand Up @@ -961,16 +990,16 @@ public String addName(String name, int[] q, int qlen)
return name;
}

private void _verifySharing()
private void _verifySharing() throws StreamConstraintsException
{
if (_hashShared) {
// 12-Mar-2021, tatu: prevent modifying of "placeholder" and
// parent tables
if (_parent == null) {
if (_count == 0) { // root
throw new IllegalStateException("Cannot add names to Root symbol table");
throw new StreamConstraintsException("Cannot add names to Root symbol table");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'll change this back, actually, since it's internal sanity check (not something users can trigger). Same for next one.

}
throw new IllegalStateException("Cannot add names to Placeholder symbol table");
throw new StreamConstraintsException("Cannot add names to Placeholder symbol table");
}

_hashArea = Arrays.copyOf(_hashArea, _hashArea.length);
Expand All @@ -982,7 +1011,7 @@ private void _verifySharing()
/**
* Method called to find the location within hash table to add a new symbol in.
*/
private int _findOffsetForAdd(int hash)
private int _findOffsetForAdd(int hash) throws StreamConstraintsException
{
// first, check the primary: if slot found, no need for resize
int offset = _calcOffset(hash);
Expand Down Expand Up @@ -1037,7 +1066,7 @@ private int _findOffsetForAdd(int hash)
}

// @since 2.10
private int _resizeAndFindOffsetForAdd(int hash)
private int _resizeAndFindOffsetForAdd(int hash) throws StreamConstraintsException
{
// First things first: we need to resize+rehash (or, if too big, nuke contents)
rehash();
Expand Down Expand Up @@ -1165,10 +1194,16 @@ public int calcHash(int q1, int q2, int q3)
return hash;
}

/**
* @param q int array
* @param qlen length
* @return hash
* @throws IllegalArgumentException if <code>qlen</code> is less than 4
*/
public int calcHash(int[] q, int qlen)
{
if (qlen < 4) {
throw new IllegalArgumentException();
throw new IllegalArgumentException("qlen is too short, needs to be at least 4");
}
/* And then change handling again for "multi-quad" case; mostly
* to make calculation of collisions less fun. For example,
Expand Down Expand Up @@ -1202,7 +1237,7 @@ public int calcHash(int[] q, int qlen)
/**********************************************************
*/

private void rehash()
private void rehash() throws StreamConstraintsException
{
// Note: since we'll make copies, no need to unshare, can just mark as such:
_hashShared = false;
Expand Down Expand Up @@ -1279,7 +1314,7 @@ private void rehash()
// Sanity checks: since corruption difficult to detect, assert explicitly
// with production code
if (copyCount != oldCount) {
throw new IllegalStateException("Failed rehash(): old count="+oldCount+", copyCount="+copyCount);
throw new StreamConstraintsException("Failed rehash(): old count="+oldCount+", copyCount="+copyCount);
}
}

Expand Down Expand Up @@ -1315,13 +1350,13 @@ private final int _spilloverStart() {
return (offset << 3) - offset;
}

protected void _reportTooManyCollisions()
protected void _reportTooManyCollisions() throws StreamConstraintsException
{
// First: do not fuzz about small symbol tables; may get balanced by doubling up
if (_hashSize <= 1024) { // would have spill-over area of 128 entries
return;
}
throw new IllegalStateException("Spill-over slots in symbol table with "+_count
throw new StreamConstraintsException("Spill-over slots in symbol table with "+_count
+" entries, hash area of "+_hashSize+" slots is now full (all "
+(_hashSize >> 3)+" slots -- suspect a DoS attack based on hash collisions."
+" You can disable the check via `JsonFactory.Feature.FAIL_ON_SYMBOL_HASH_OVERFLOW`");
Expand Down