Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/src/java.xml/share/classes/jdk/xml/internal/XMLSecurityManager.java
67862 views
1
/*
2
* Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
package jdk.xml.internal;
26
27
28
import com.sun.org.apache.xerces.internal.util.SecurityManager;
29
import java.util.concurrent.CopyOnWriteArrayList;
30
import jdk.xml.internal.JdkProperty.State;
31
import jdk.xml.internal.JdkProperty.ImplPropMap;
32
import org.xml.sax.SAXException;
33
34
/**
35
* This class manages standard and implementation-specific limitations.
36
*
37
*/
38
public final class XMLSecurityManager {
39
40
/**
41
* Limits managed by the security manager
42
*/
43
@SuppressWarnings("deprecation")
44
public static enum Limit {
45
ENTITY_EXPANSION_LIMIT("EntityExpansionLimit", JdkConstants.JDK_ENTITY_EXPANSION_LIMIT,
46
JdkConstants.SP_ENTITY_EXPANSION_LIMIT, 0, 64000, Processor.PARSER),
47
MAX_OCCUR_NODE_LIMIT("MaxOccurLimit", JdkConstants.JDK_MAX_OCCUR_LIMIT,
48
JdkConstants.SP_MAX_OCCUR_LIMIT, 0, 5000, Processor.PARSER),
49
ELEMENT_ATTRIBUTE_LIMIT("ElementAttributeLimit", JdkConstants.JDK_ELEMENT_ATTRIBUTE_LIMIT,
50
JdkConstants.SP_ELEMENT_ATTRIBUTE_LIMIT, 0, 10000, Processor.PARSER),
51
TOTAL_ENTITY_SIZE_LIMIT("TotalEntitySizeLimit", JdkConstants.JDK_TOTAL_ENTITY_SIZE_LIMIT,
52
JdkConstants.SP_TOTAL_ENTITY_SIZE_LIMIT, 0, 50000000, Processor.PARSER),
53
GENERAL_ENTITY_SIZE_LIMIT("MaxEntitySizeLimit", JdkConstants.JDK_GENERAL_ENTITY_SIZE_LIMIT,
54
JdkConstants.SP_GENERAL_ENTITY_SIZE_LIMIT, 0, 0, Processor.PARSER),
55
PARAMETER_ENTITY_SIZE_LIMIT("MaxEntitySizeLimit", JdkConstants.JDK_PARAMETER_ENTITY_SIZE_LIMIT,
56
JdkConstants.SP_PARAMETER_ENTITY_SIZE_LIMIT, 0, 1000000, Processor.PARSER),
57
MAX_ELEMENT_DEPTH_LIMIT("MaxElementDepthLimit", JdkConstants.JDK_MAX_ELEMENT_DEPTH,
58
JdkConstants.SP_MAX_ELEMENT_DEPTH, 0, 0, Processor.PARSER),
59
MAX_NAME_LIMIT("MaxXMLNameLimit", JdkConstants.JDK_XML_NAME_LIMIT,
60
JdkConstants.SP_XML_NAME_LIMIT, 1000, 1000, Processor.PARSER),
61
ENTITY_REPLACEMENT_LIMIT("EntityReplacementLimit", JdkConstants.JDK_ENTITY_REPLACEMENT_LIMIT,
62
JdkConstants.SP_ENTITY_REPLACEMENT_LIMIT, 0, 3000000, Processor.PARSER),
63
XPATH_GROUP_LIMIT("XPathGroupLimit", JdkConstants.XPATH_GROUP_LIMIT,
64
JdkConstants.XPATH_GROUP_LIMIT, 10, 10, Processor.XPATH),
65
XPATH_OP_LIMIT("XPathExprOpLimit", JdkConstants.XPATH_OP_LIMIT,
66
JdkConstants.XPATH_OP_LIMIT, 100, 100, Processor.XPATH),
67
XPATH_TOTALOP_LIMIT("XPathTotalOpLimit", JdkConstants.XPATH_TOTALOP_LIMIT,
68
JdkConstants.XPATH_TOTALOP_LIMIT, 10000, 10000, Processor.XPATH)
69
;
70
71
final String key;
72
final String apiProperty;
73
final String systemProperty;
74
final int defaultValue;
75
final int secureValue;
76
final Processor processor;
77
78
Limit(String key, String apiProperty, String systemProperty, int value,
79
int secureValue, Processor processor) {
80
this.key = key;
81
this.apiProperty = apiProperty;
82
this.systemProperty = systemProperty;
83
this.defaultValue = value;
84
this.secureValue = secureValue;
85
this.processor = processor;
86
}
87
88
/**
89
* Checks whether the specified name is a limit. Checks both the
90
* property and System Property which is now the new property name.
91
*
92
* @param name the specified name
93
* @return true if there is a match, false otherwise
94
*/
95
public boolean is(String name) {
96
// current spec: new property name == systemProperty
97
return (systemProperty != null && systemProperty.equals(name)) ||
98
// current spec: apiProperty is legacy
99
(apiProperty.equals(name));
100
}
101
102
/**
103
* Returns the state of a property name. By the specification as of JDK 17,
104
* the "jdk.xml." prefixed System property name is also the current API
105
* name. The URI-based qName is legacy.
106
*
107
* @param name the property name
108
* @return the state of the property name, null if no match
109
*/
110
public State getState(String name) {
111
if (systemProperty != null && systemProperty.equals(name)) {
112
return State.APIPROPERTY;
113
} else if (apiProperty.equals(name)) {
114
//the URI-style qName is legacy
115
return State.LEGACY_APIPROPERTY;
116
}
117
return null;
118
}
119
120
public String key() {
121
return key;
122
}
123
124
public String apiProperty() {
125
return apiProperty;
126
}
127
128
public String systemProperty() {
129
return systemProperty;
130
}
131
132
public int defaultValue() {
133
return defaultValue;
134
}
135
136
public boolean isSupported(Processor p) {
137
return processor == p;
138
}
139
140
int secureValue() {
141
return secureValue;
142
}
143
}
144
145
/**
146
* Map old property names with the new ones
147
*/
148
public static enum NameMap {
149
150
ENTITY_EXPANSION_LIMIT(JdkConstants.SP_ENTITY_EXPANSION_LIMIT, JdkConstants.ENTITY_EXPANSION_LIMIT),
151
MAX_OCCUR_NODE_LIMIT(JdkConstants.SP_MAX_OCCUR_LIMIT, JdkConstants.MAX_OCCUR_LIMIT),
152
ELEMENT_ATTRIBUTE_LIMIT(JdkConstants.SP_ELEMENT_ATTRIBUTE_LIMIT, JdkConstants.ELEMENT_ATTRIBUTE_LIMIT);
153
final String newName;
154
final String oldName;
155
156
NameMap(String newName, String oldName) {
157
this.newName = newName;
158
this.oldName = oldName;
159
}
160
161
String getOldName(String newName) {
162
if (newName.equals(this.newName)) {
163
return oldName;
164
}
165
return null;
166
}
167
}
168
169
/**
170
* Supported processors
171
*/
172
public static enum Processor {
173
PARSER,
174
XPATH,
175
}
176
177
private static final int NO_LIMIT = 0;
178
179
/**
180
* Values of the properties
181
*/
182
private final int[] values;
183
184
/**
185
* States of the settings for each property
186
*/
187
private State[] states;
188
189
/**
190
* Flag indicating if secure processing is set
191
*/
192
boolean secureProcessing;
193
194
/**
195
* States that determine if properties are set explicitly
196
*/
197
private boolean[] isSet;
198
199
200
/**
201
* Index of the special entityCountInfo property
202
*/
203
private final int indexEntityCountInfo = 10000;
204
private String printEntityCountInfo = "";
205
206
/**
207
* Default constructor. Establishes default values for known security
208
* vulnerabilities.
209
*/
210
public XMLSecurityManager() {
211
this(false);
212
}
213
214
/**
215
* Instantiate Security Manager in accordance with the status of
216
* secure processing
217
* @param secureProcessing
218
*/
219
public XMLSecurityManager(boolean secureProcessing) {
220
values = new int[Limit.values().length];
221
states = new State[Limit.values().length];
222
isSet = new boolean[Limit.values().length];
223
this.secureProcessing = secureProcessing;
224
for (Limit limit : Limit.values()) {
225
if (secureProcessing) {
226
values[limit.ordinal()] = limit.secureValue;
227
states[limit.ordinal()] = State.FSP;
228
} else {
229
values[limit.ordinal()] = limit.defaultValue();
230
states[limit.ordinal()] = State.DEFAULT;
231
}
232
}
233
//read system properties or jaxp.properties
234
readSystemProperties();
235
}
236
237
/**
238
* Setting FEATURE_SECURE_PROCESSING explicitly
239
*/
240
public void setSecureProcessing(boolean secure) {
241
secureProcessing = secure;
242
for (Limit limit : Limit.values()) {
243
if (secure) {
244
setLimit(limit.ordinal(), State.FSP, limit.secureValue());
245
} else {
246
setLimit(limit.ordinal(), State.FSP, limit.defaultValue());
247
}
248
}
249
}
250
251
/**
252
* Return the state of secure processing
253
* @return the state of secure processing
254
*/
255
public boolean isSecureProcessing() {
256
return secureProcessing;
257
}
258
259
/**
260
* Finds a limit's new name with the given property name.
261
* @param propertyName the property name specified
262
* @return the limit's new name if found, null otherwise
263
*/
264
public String find(String propertyName) {
265
for (Limit limit : Limit.values()) {
266
if (limit.is(propertyName)) {
267
// current spec: new property name == systemProperty
268
return limit.systemProperty();
269
}
270
}
271
//ENTITYCOUNT's new name is qName
272
if (ImplPropMap.ENTITYCOUNT.is(propertyName)) {
273
return ImplPropMap.ENTITYCOUNT.qName();
274
}
275
return null;
276
}
277
278
/**
279
* Set limit by property name and state
280
* @param propertyName property name
281
* @param state the state of the property
282
* @param value the value of the property
283
* @return true if the property is managed by the security manager; false
284
* if otherwise.
285
*/
286
public boolean setLimit(String propertyName, State state, Object value) {
287
int index = getIndex(propertyName);
288
if (index > -1) {
289
State pState = state;
290
if (index != indexEntityCountInfo && state == State.APIPROPERTY) {
291
pState = (Limit.values()[index]).getState(propertyName);
292
}
293
setLimit(index, pState, value);
294
return true;
295
}
296
return false;
297
}
298
299
/**
300
* Set the value for a specific limit.
301
*
302
* @param limit the limit
303
* @param state the state of the property
304
* @param value the value of the property
305
*/
306
public void setLimit(Limit limit, State state, int value) {
307
setLimit(limit.ordinal(), state, value);
308
}
309
310
/**
311
* Set the value of a property by its index
312
*
313
* @param index the index of the property
314
* @param state the state of the property
315
* @param value the value of the property
316
*/
317
public void setLimit(int index, State state, Object value) {
318
if (index == indexEntityCountInfo) {
319
printEntityCountInfo = (String)value;
320
} else {
321
int temp;
322
if (value instanceof Integer) {
323
temp = (Integer)value;
324
} else {
325
temp = Integer.parseInt((String) value);
326
if (temp < 0) {
327
temp = 0;
328
}
329
}
330
setLimit(index, state, temp);
331
}
332
}
333
334
/**
335
* Set the value of a property by its index
336
*
337
* @param index the index of the property
338
* @param state the state of the property
339
* @param value the value of the property
340
*/
341
public void setLimit(int index, State state, int value) {
342
if (index == indexEntityCountInfo) {
343
//if it's explicitly set, it's treated as yes no matter the value
344
printEntityCountInfo = JdkConstants.JDK_YES;
345
} else {
346
//only update if it shall override
347
if (state.compareTo(states[index]) >= 0) {
348
values[index] = value;
349
states[index] = state;
350
isSet[index] = true;
351
}
352
}
353
}
354
355
/**
356
* Return the value of the specified property
357
*
358
* @param propertyName the property name
359
* @return the value of the property as a string. If a property is managed
360
* by this manager, its value shall not be null.
361
*/
362
public String getLimitAsString(String propertyName) {
363
int index = getIndex(propertyName);
364
if (index > -1) {
365
return getLimitValueByIndex(index);
366
}
367
368
return null;
369
}
370
/**
371
* Return the value of the specified property
372
*
373
* @param limit the property
374
* @return the value of the property
375
*/
376
public int getLimit(Limit limit) {
377
return values[limit.ordinal()];
378
}
379
380
/**
381
* Return the value of a property by its ordinal
382
*
383
* @param limit the property
384
* @return value of a property
385
*/
386
public String getLimitValueAsString(Limit limit) {
387
return Integer.toString(values[limit.ordinal()]);
388
}
389
390
/**
391
* Return the value of a property by its ordinal
392
*
393
* @param index the index of a property
394
* @return limit of a property as a string
395
*/
396
public String getLimitValueByIndex(int index) {
397
if (index == indexEntityCountInfo) {
398
return printEntityCountInfo;
399
}
400
401
return Integer.toString(values[index]);
402
}
403
404
/**
405
* Return the state of the limit property
406
*
407
* @param limit the limit
408
* @return the state of the limit property
409
*/
410
public State getState(Limit limit) {
411
return states[limit.ordinal()];
412
}
413
414
/**
415
* Return the state of the limit property
416
*
417
* @param limit the limit
418
* @return the state of the limit property
419
*/
420
public String getStateLiteral(Limit limit) {
421
return states[limit.ordinal()].literal();
422
}
423
424
/**
425
* Get the index by property name
426
*
427
* @param propertyName property name
428
* @return the index of the property if found; return -1 if not
429
*/
430
public int getIndex(String propertyName) {
431
for (Limit limit : Limit.values()) {
432
// see JDK-8265248, accept both the URL and jdk.xml as prefix
433
if (limit.is(propertyName)) {
434
//internally, ordinal is used as index
435
return limit.ordinal();
436
}
437
}
438
//special property to return entity count info
439
if (ImplPropMap.ENTITYCOUNT.is(propertyName)) {
440
return indexEntityCountInfo;
441
}
442
return -1;
443
}
444
445
/**
446
* Check if there's no limit defined by the Security Manager
447
* @param limit
448
* @return
449
*/
450
public boolean isNoLimit(int limit) {
451
return limit == NO_LIMIT;
452
}
453
/**
454
* Check if the size (length or count) of the specified limit property is
455
* over the limit
456
*
457
* @param limit the type of the limit property
458
* @param entityName the name of the entity
459
* @param size the size (count or length) of the entity
460
* @return true if the size is over the limit, false otherwise
461
*/
462
public boolean isOverLimit(Limit limit, String entityName, int size,
463
XMLLimitAnalyzer limitAnalyzer) {
464
return isOverLimit(limit.ordinal(), entityName, size, limitAnalyzer);
465
}
466
467
/**
468
* Check if the value (length or count) of the specified limit property is
469
* over the limit
470
*
471
* @param index the index of the limit property
472
* @param entityName the name of the entity
473
* @param size the size (count or length) of the entity
474
* @return true if the size is over the limit, false otherwise
475
*/
476
public boolean isOverLimit(int index, String entityName, int size,
477
XMLLimitAnalyzer limitAnalyzer) {
478
if (values[index] == NO_LIMIT) {
479
return false;
480
}
481
if (size > values[index]) {
482
limitAnalyzer.addValue(index, entityName, size);
483
return true;
484
}
485
return false;
486
}
487
488
/**
489
* Check against cumulated value
490
*
491
* @param limit the type of the limit property
492
* @param size the size (count or length) of the entity
493
* @return true if the size is over the limit, false otherwise
494
*/
495
public boolean isOverLimit(Limit limit, XMLLimitAnalyzer limitAnalyzer) {
496
return isOverLimit(limit.ordinal(), limitAnalyzer);
497
}
498
499
public boolean isOverLimit(int index, XMLLimitAnalyzer limitAnalyzer) {
500
if (values[index] == NO_LIMIT) {
501
return false;
502
}
503
504
if (index == Limit.ELEMENT_ATTRIBUTE_LIMIT.ordinal() ||
505
index == Limit.ENTITY_EXPANSION_LIMIT.ordinal() ||
506
index == Limit.TOTAL_ENTITY_SIZE_LIMIT.ordinal() ||
507
index == Limit.ENTITY_REPLACEMENT_LIMIT.ordinal() ||
508
index == Limit.MAX_ELEMENT_DEPTH_LIMIT.ordinal() ||
509
index == Limit.MAX_NAME_LIMIT.ordinal()
510
) {
511
return (limitAnalyzer.getTotalValue(index) > values[index]);
512
} else {
513
return (limitAnalyzer.getValue(index) > values[index]);
514
}
515
}
516
517
public void debugPrint(XMLLimitAnalyzer limitAnalyzer) {
518
if (printEntityCountInfo.equals(JdkConstants.JDK_YES)) {
519
limitAnalyzer.debugPrint(this);
520
}
521
}
522
523
524
/**
525
* Indicate if a property is set explicitly
526
* @param index
527
* @return
528
*/
529
public boolean isSet(int index) {
530
return isSet[index];
531
}
532
533
public boolean printEntityCountInfo() {
534
return printEntityCountInfo.equals(JdkConstants.JDK_YES);
535
}
536
537
/**
538
* Read from system properties, or those in jaxp.properties
539
*/
540
private void readSystemProperties() {
541
542
for (Limit limit : Limit.values()) {
543
if (!getSystemProperty(limit, limit.systemProperty())) {
544
//if system property is not found, try the older form if any
545
for (NameMap nameMap : NameMap.values()) {
546
String oldName = nameMap.getOldName(limit.systemProperty());
547
if (oldName != null) {
548
getSystemProperty(limit, oldName);
549
}
550
}
551
}
552
}
553
554
}
555
556
// Array list to store printed warnings for each SAX parser used
557
private static final CopyOnWriteArrayList<String> printedWarnings = new CopyOnWriteArrayList<>();
558
559
/**
560
* Prints out warnings if a parser does not support the specified feature/property.
561
*
562
* @param parserClassName the name of the parser class
563
* @param propertyName the property name
564
* @param exception the exception thrown by the parser
565
*/
566
public static void printWarning(String parserClassName, String propertyName, SAXException exception) {
567
String key = parserClassName+":"+propertyName;
568
if (printedWarnings.addIfAbsent(key)) {
569
System.err.println( "Warning: "+parserClassName+": "+exception.getMessage());
570
}
571
}
572
573
/**
574
* Read from system properties, or those in jaxp.properties
575
*
576
* @param property the type of the property
577
* @param sysPropertyName the name of system property
578
*/
579
private boolean getSystemProperty(Limit limit, String sysPropertyName) {
580
try {
581
String value = SecuritySupport.getSystemProperty(sysPropertyName);
582
if (value != null && !value.equals("")) {
583
values[limit.ordinal()] = Integer.parseInt(value);
584
states[limit.ordinal()] = State.SYSTEMPROPERTY;
585
return true;
586
}
587
588
value = SecuritySupport.readJAXPProperty(sysPropertyName);
589
if (value != null && !value.equals("")) {
590
values[limit.ordinal()] = Integer.parseInt(value);
591
states[limit.ordinal()] = State.JAXPDOTPROPERTIES;
592
return true;
593
}
594
} catch (NumberFormatException e) {
595
//invalid setting
596
throw new NumberFormatException("Invalid setting for system property: " + limit.systemProperty());
597
}
598
return false;
599
}
600
601
602
/**
603
* Convert a value set through setProperty to XMLSecurityManager.
604
* If the value is an instance of XMLSecurityManager, use it to override the default;
605
* If the value is an old SecurityManager, convert to the new XMLSecurityManager.
606
*
607
* @param value user specified security manager
608
* @param securityManager an instance of XMLSecurityManager
609
* @return an instance of the new security manager XMLSecurityManager
610
*/
611
public static XMLSecurityManager convert(Object value, XMLSecurityManager securityManager) {
612
if (value == null) {
613
if (securityManager == null) {
614
securityManager = new XMLSecurityManager(true);
615
}
616
return securityManager;
617
}
618
if (value instanceof XMLSecurityManager) {
619
return (XMLSecurityManager)value;
620
} else {
621
if (securityManager == null) {
622
securityManager = new XMLSecurityManager(true);
623
}
624
if (value instanceof SecurityManager) {
625
SecurityManager origSM = (SecurityManager)value;
626
securityManager.setLimit(Limit.MAX_OCCUR_NODE_LIMIT, State.APIPROPERTY, origSM.getMaxOccurNodeLimit());
627
securityManager.setLimit(Limit.ENTITY_EXPANSION_LIMIT, State.APIPROPERTY, origSM.getEntityExpansionLimit());
628
securityManager.setLimit(Limit.ELEMENT_ATTRIBUTE_LIMIT, State.APIPROPERTY, origSM.getElementAttrLimit());
629
}
630
return securityManager;
631
}
632
}
633
}
634
635