/*
 * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.org.apache.xerces.internal.utils;

import com.sun.org.apache.xerces.internal.impl.Constants;
import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager.Limit;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;

A helper for analyzing entity expansion limits
Author:Joe Wang Oracle Corp.
/** * A helper for analyzing entity expansion limits * * @author Joe Wang Oracle Corp. * */
public final class XMLLimitAnalyzer {
Map old property names with the new ones
/** * Map old property names with the new ones */
public static enum NameMap { ENTITY_EXPANSION_LIMIT(Constants.SP_ENTITY_EXPANSION_LIMIT, Constants.ENTITY_EXPANSION_LIMIT), MAX_OCCUR_NODE_LIMIT(Constants.SP_MAX_OCCUR_LIMIT, Constants.MAX_OCCUR_LIMIT), ELEMENT_ATTRIBUTE_LIMIT(Constants.SP_ELEMENT_ATTRIBUTE_LIMIT, Constants.ELEMENT_ATTRIBUTE_LIMIT); final String newName; final String oldName; NameMap(String newName, String oldName) { this.newName = newName; this.oldName = oldName; } String getOldName(String newName) { if (newName.equals(this.newName)) { return oldName; } return null; } }
Max value accumulated for each property
/** * Max value accumulated for each property */
private final int[] values;
Names of the entities corresponding to their max values
/** * Names of the entities corresponding to their max values */
private final String[] names;
Total value of accumulated entities
/** * Total value of accumulated entities */
private final int[] totalValue;
Maintain values of the top 10 elements in the process of parsing
/** * Maintain values of the top 10 elements in the process of parsing */
private final Map<String, Integer>[] caches; private String entityStart, entityEnd;
Default constructor. Establishes default values for known security vulnerabilities.
/** * Default constructor. Establishes default values for known security * vulnerabilities. */
@SuppressWarnings({"rawtypes", "unchecked"}) public XMLLimitAnalyzer() { values = new int[Limit.values().length]; totalValue = new int[Limit.values().length]; names = new String[Limit.values().length]; caches = new Map[Limit.values().length]; }
Add the value to the current max count for the specified property To find the max value of all entities, set no limit
Params:
  • limit – the type of the property
  • entityName – the name of the entity
  • value – the value of the entity
/** * Add the value to the current max count for the specified property * To find the max value of all entities, set no limit * * @param limit the type of the property * @param entityName the name of the entity * @param value the value of the entity */
public void addValue(Limit limit, String entityName, int value) { addValue(limit.ordinal(), entityName, value); }
Add the value to the current count by the index of the property
Params:
  • index – the index of the property
  • entityName – the name of the entity
  • value – the value of the entity
/** * Add the value to the current count by the index of the property * @param index the index of the property * @param entityName the name of the entity * @param value the value of the entity */
public void addValue(int index, String entityName, int value) { if (index == Limit.ENTITY_EXPANSION_LIMIT.ordinal() || index == Limit.MAX_OCCUR_NODE_LIMIT.ordinal() || index == Limit.ELEMENT_ATTRIBUTE_LIMIT.ordinal() || index == Limit.TOTAL_ENTITY_SIZE_LIMIT.ordinal() || index == Limit.ENTITY_REPLACEMENT_LIMIT.ordinal() ) { totalValue[index] += value; return; } if (index == Limit.MAX_ELEMENT_DEPTH_LIMIT.ordinal() || index == Limit.MAX_NAME_LIMIT.ordinal()) { values[index] = value; totalValue[index] = value; return; } Map<String, Integer> cache; if (caches[index] == null) { cache = new HashMap<>(10); caches[index] = cache; } else { cache = caches[index]; } int accumulatedValue = value; if (cache.containsKey(entityName)) { accumulatedValue += cache.get(entityName); cache.put(entityName, accumulatedValue); } else { cache.put(entityName, value); } if (accumulatedValue > values[index]) { values[index] = accumulatedValue; names[index] = entityName; } if (index == Limit.GENERAL_ENTITY_SIZE_LIMIT.ordinal() || index == Limit.PARAMETER_ENTITY_SIZE_LIMIT.ordinal()) { totalValue[Limit.TOTAL_ENTITY_SIZE_LIMIT.ordinal()] += value; } }
Return the value of the current max count for the specified property
Params:
  • limit – the property
Returns:the value of the property
/** * Return the value of the current max count for the specified property * * @param limit the property * @return the value of the property */
public int getValue(Limit limit) { return getValue(limit.ordinal()); } public int getValue(int index) { if (index == Limit.ENTITY_REPLACEMENT_LIMIT.ordinal()) { return totalValue[index]; } return values[index]; }
Return the total value accumulated so far
Params:
  • limit – the property
Returns:the accumulated value of the property
/** * Return the total value accumulated so far * * @param limit the property * @return the accumulated value of the property */
public int getTotalValue(Limit limit) { return totalValue[limit.ordinal()]; } public int getTotalValue(int index) { return totalValue[index]; }
Return the current max value (count or length) by the index of a property
Params:
  • index – the index of a property
Returns:count of a property
/** * Return the current max value (count or length) by the index of a property * @param index the index of a property * @return count of a property */
public int getValueByIndex(int index) { return values[index]; } public void startEntity(String name) { entityStart = name; } public boolean isTracking(String name) { if (entityStart == null) { return false; } return entityStart.equals(name); }
Stop tracking the entity
Params:
  • limit – the limit property
  • name – the name of an entity
/** * Stop tracking the entity * @param limit the limit property * @param name the name of an entity */
public void endEntity(Limit limit, String name) { entityStart = ""; Map<String, Integer> cache = caches[limit.ordinal()]; if (cache != null) { cache.remove(name); } }
Resets the current value of the specified limit.
Params:
  • limit – The limit to be reset.
/** * Resets the current value of the specified limit. * @param limit The limit to be reset. */
public void reset(Limit limit) { if (limit.ordinal() == Limit.TOTAL_ENTITY_SIZE_LIMIT.ordinal()) { totalValue[limit.ordinal()] = 0; } else if (limit.ordinal() == Limit.GENERAL_ENTITY_SIZE_LIMIT.ordinal()) { names[limit.ordinal()] = null; values[limit.ordinal()] = 0; caches[limit.ordinal()] = null; totalValue[limit.ordinal()] = 0; } } public void debugPrint(XMLSecurityManager securityManager) { Formatter formatter = new Formatter(); System.out.println(formatter.format("%30s %15s %15s %15s %30s", "Property","Limit","Total size","Size","Entity Name")); for (Limit limit : Limit.values()) { formatter = new Formatter(); System.out.println(formatter.format("%30s %15d %15d %15d %30s", limit.name(), securityManager.getLimit(limit), totalValue[limit.ordinal()], values[limit.ordinal()], names[limit.ordinal()])); } } }