Fri, 24 Sep 2010 22:42:14 -0700
6891766: Vulnerabilities in use of reflection in CORBA
Reviewed-by: hawtin
1 /*
2 * Copyright (c) 2002, 2010, 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 com.sun.corba.se.spi.orb ;
27 import java.util.StringTokenizer ;
28 import java.util.Arrays ;
30 import java.lang.reflect.Array ;
32 import java.net.URL ;
33 import java.net.MalformedURLException ;
35 import com.sun.corba.se.spi.logging.CORBALogDomains ;
37 import com.sun.corba.se.impl.logging.ORBUtilSystemException ;
38 import com.sun.corba.se.impl.orbutil.ORBClassLoader ;
39 import com.sun.corba.se.impl.orbutil.ObjectUtility ;
41 /** This is a static factory class for commonly used operations
42 * for property parsing. The following operations are supported:
43 * <ul>
44 * <li>maskErrorAction( Operation op ) executes op and returns the result. If op throws an
45 * exception, the result is null.
46 * <li>indexAction( int arg ) returns the [arg] element of value, which must be an Object[]</li>
47 * <li>identityAction() return the value</li>
48 * <li>booleanAction() return a Boolean representing true or false values of the String value</li>
49 * <li>integerAction() returns an Integer for the String value, which must be a decimal integer</li>
50 * <li>stringAction() returns the String value</li>
51 * <li>classAction() returns a class for the String value, as loaded by the ORB classloader</li>
52 * <li>setFlagAction() always return Boolean.TRUE</li>
53 * <li>URLAction() returns a java.net.URL for the String value, which must be a valid URL</li>
54 * <li>integerRangeAction( int min, int max ) returns an Integer for the String value, which must be a
55 * decimal integer in the range min to max inclusive</li>
56 * <li>listAction( String sep, Operation ) tokenizes the String value with sep as separator, then
57 * applies the Operation to each token, and returns an array of the result</li>
58 * <li>sequenceAction( String, Operation[] ) tokenizes the String value with sep as separator, then
59 * applies each Operation in the Operation array to successive tokens, and returns an array of the results</li>
60 * <li>compose( Operation op1, Operation op2 ) is the operation that applies op2 to the result of applying
61 * op1 to the value</li>
62 * <li>mapAction( Operation ) applies the Operation to each element of an array of objects, and returns
63 * an array of the results</li>
64 * <li>mapSequenceAction( Operation[] ) applies the corresponding element of the Operation array to an
65 * element of the Object[] value, and returns an array of the results</li>
66 * <li>convertIntegerToShort coerces an Integer into a Short.</li>
67 * </ul>
68 * Other operations can be directly defined, and combined using these basic operations.
69 */
70 public abstract class OperationFactory {
71 private OperationFactory() {}
73 private static String getString( Object obj )
74 {
75 if (obj instanceof String)
76 return (String)obj ;
77 else
78 throw new Error( "String expected" ) ;
79 }
81 private static Object[] getObjectArray( Object obj )
82 {
83 if (obj instanceof Object[])
84 return (Object[])obj ;
85 else
86 throw new Error( "Object[] expected" ) ;
87 }
89 private static StringPair getStringPair( Object obj )
90 {
91 if (obj instanceof StringPair)
92 return (StringPair)obj ;
93 else
94 throw new Error( "StringPair expected" ) ;
95 }
97 private static abstract class OperationBase implements Operation{
98 public boolean equals( Object obj )
99 {
100 if (this==obj)
101 return true ;
103 if (!(obj instanceof OperationBase))
104 return false ;
106 OperationBase other = (OperationBase)obj ;
108 return toString().equals( other.toString() ) ;
109 }
111 public int hashCode()
112 {
113 return toString().hashCode() ;
114 }
115 }
117 private static class MaskErrorAction extends OperationBase
118 {
119 private Operation op ;
121 public MaskErrorAction( Operation op )
122 {
123 this.op = op ;
124 }
126 public Object operate( Object arg )
127 {
128 try {
129 return op.operate( arg ) ;
130 } catch (java.lang.Exception exc) {
131 return null ;
132 }
133 }
135 public String toString()
136 {
137 return "maskErrorAction(" + op + ")" ;
138 }
139 }
141 public static Operation maskErrorAction( Operation op )
142 {
143 return new MaskErrorAction( op ) ;
144 }
146 private static class IndexAction extends OperationBase
147 {
148 private int index ;
150 public IndexAction( int index )
151 {
152 this.index = index ;
153 }
155 public Object operate( Object value )
156 {
157 return getObjectArray( value )[ index ] ;
158 }
160 public String toString()
161 {
162 return "indexAction(" + index + ")" ;
163 }
164 }
166 public static Operation indexAction( int index )
167 {
168 return new IndexAction( index ) ;
169 }
171 private static class SuffixAction extends OperationBase
172 {
173 public Object operate( Object value )
174 {
175 return getStringPair( value ).getFirst() ;
176 }
178 public String toString() { return "suffixAction" ; }
179 }
181 private static Operation suffixActionImpl = new SuffixAction() ;
183 private static class ValueAction extends OperationBase
184 {
185 public Object operate( Object value )
186 {
187 return getStringPair( value ).getSecond() ;
188 }
190 public String toString() { return "valueAction" ; }
191 }
193 private static Operation valueActionImpl = new ValueAction() ;
195 private static class IdentityAction extends OperationBase
196 {
197 public Object operate( Object value )
198 {
199 return value ;
200 }
202 public String toString() { return "identityAction" ; }
203 }
205 private static Operation identityActionImpl = new IdentityAction() ;
207 private static class BooleanAction extends OperationBase
208 {
209 public Object operate( Object value )
210 {
211 return new Boolean( getString( value ) ) ;
212 }
214 public String toString() { return "booleanAction" ; }
215 }
217 private static Operation booleanActionImpl = new BooleanAction() ;
219 private static class IntegerAction extends OperationBase
220 {
221 public Object operate( Object value )
222 {
223 return new Integer( getString( value ) ) ;
224 }
226 public String toString() { return "integerAction" ; }
227 }
229 private static Operation integerActionImpl = new IntegerAction() ;
231 private static class StringAction extends OperationBase
232 {
233 public Object operate( Object value )
234 {
235 return value ;
236 }
238 public String toString() { return "stringAction" ; }
239 }
241 private static Operation stringActionImpl = new StringAction() ;
243 private static class ClassAction extends OperationBase
244 {
245 public Object operate( Object value )
246 {
247 String className = getString( value ) ;
249 try {
250 Class result = ORBClassLoader.loadClass( className ) ;
251 return result ;
252 } catch (Exception exc) {
253 ORBUtilSystemException wrapper = ORBUtilSystemException.get(
254 CORBALogDomains.ORB_LIFECYCLE ) ;
255 throw wrapper.couldNotLoadClass( exc, className ) ;
256 }
257 }
259 public String toString() { return "classAction" ; }
260 }
262 private static Operation classActionImpl = new ClassAction() ;
264 private static class SetFlagAction extends OperationBase
265 {
266 public Object operate( Object value )
267 {
268 return Boolean.TRUE ;
269 }
271 public String toString() { return "setFlagAction" ; }
272 }
274 private static Operation setFlagActionImpl = new SetFlagAction() ;
276 private static class URLAction extends OperationBase
277 {
278 public Object operate( Object value )
279 {
280 String val = (String)value ;
281 try {
282 return new URL( val ) ;
283 } catch (MalformedURLException exc) {
284 ORBUtilSystemException wrapper = ORBUtilSystemException.get(
285 CORBALogDomains.ORB_LIFECYCLE ) ;
286 throw wrapper.badUrl( exc, val ) ;
287 }
288 }
290 public String toString() { return "URLAction" ; }
291 }
293 private static Operation URLActionImpl = new URLAction() ;
295 public static Operation identityAction()
296 {
297 return identityActionImpl ;
298 }
300 public static Operation suffixAction()
301 {
302 return suffixActionImpl ;
303 }
305 public static Operation valueAction()
306 {
307 return valueActionImpl ;
308 }
310 public static Operation booleanAction()
311 {
312 return booleanActionImpl ;
313 }
315 public static Operation integerAction()
316 {
317 return integerActionImpl ;
318 }
320 public static Operation stringAction()
321 {
322 return stringActionImpl ;
323 }
325 public static Operation classAction()
326 {
327 return classActionImpl ;
328 }
330 public static Operation setFlagAction()
331 {
332 return setFlagActionImpl ;
333 }
335 public static Operation URLAction()
336 {
337 return URLActionImpl ;
338 }
340 private static class IntegerRangeAction extends OperationBase
341 {
342 private int min ;
343 private int max ;
345 IntegerRangeAction( int min, int max )
346 {
347 this.min = min ;
348 this.max = max ;
349 }
351 public Object operate( Object value )
352 {
353 int result = Integer.parseInt( getString( value ) ) ;
354 if ((result >= min) && (result <= max))
355 return new Integer( result ) ;
356 else
357 throw new IllegalArgumentException(
358 "Property value " + result + " is not in the range " +
359 min + " to " + max ) ;
360 }
362 public String toString() {
363 return "integerRangeAction(" + min + "," + max + ")" ;
364 }
365 }
367 public static Operation integerRangeAction( int min, int max )
368 {
369 return new IntegerRangeAction( min, max ) ;
370 }
372 private static class ListAction extends OperationBase {
373 private String sep ;
374 private Operation act ;
376 ListAction( String sep, Operation act )
377 {
378 this.sep = sep ;
379 this.act = act ;
380 }
382 // Note that this method carefully constructs an array of the type
383 // of the first result, rather than just using Object[], which is
384 // not convertible into the correct type. Also note that no tokens
385 // results in a null result.
386 public Object operate( Object value )
387 {
388 StringTokenizer st = new StringTokenizer( getString( value ),
389 sep ) ;
390 int length = st.countTokens() ;
391 Object result = null ;
392 int ctr = 0 ;
393 while (st.hasMoreTokens()) {
394 String next = st.nextToken() ;
395 Object val = act.operate( next ) ;
396 if (result == null)
397 result = Array.newInstance( val.getClass(), length ) ;
398 Array.set( result, ctr++, val ) ;
399 }
401 return result ;
402 }
404 public String toString() {
405 return "listAction(separator=\"" + sep +
406 "\",action=" + act + ")" ;
407 }
408 }
410 public static Operation listAction( String sep, Operation act )
411 {
412 return new ListAction( sep, act ) ;
413 }
415 private static class SequenceAction extends OperationBase
416 {
417 private String sep ;
418 private Operation[] actions ;
420 SequenceAction( String sep, Operation[] actions )
421 {
422 this.sep = sep ;
423 this.actions = actions ;
424 }
426 public Object operate( Object value )
427 {
428 StringTokenizer st = new StringTokenizer( getString( value ),
429 sep ) ;
431 int numTokens = st.countTokens() ;
432 if (numTokens != actions.length)
433 throw new Error(
434 "Number of tokens and number of actions do not match" ) ;
436 int ctr = 0 ;
437 Object[] result = new Object[ numTokens ] ;
438 while (st.hasMoreTokens()) {
439 Operation act = actions[ctr] ;
440 String next = st.nextToken() ;
441 result[ctr++] = act.operate( next ) ;
442 }
444 return result ;
445 }
447 public String toString() {
448 return "sequenceAction(separator=\"" + sep +
449 "\",actions=" +
450 Arrays.toString(actions) + ")" ;
451 }
452 }
454 public static Operation sequenceAction( String sep,
455 Operation[] actions )
456 {
457 return new SequenceAction( sep, actions ) ;
458 }
460 private static class ComposeAction extends OperationBase
461 {
462 private Operation op1 ;
463 private Operation op2 ;
465 ComposeAction( Operation op1, Operation op2 )
466 {
467 this.op1 = op1 ;
468 this.op2 = op2 ;
469 }
471 public Object operate( Object value )
472 {
473 return op2.operate( op1.operate( value ) ) ;
474 }
476 public String toString() {
477 return "composition(" + op1 + "," + op2 + ")" ;
478 }
479 }
481 public static Operation compose( Operation op1, Operation op2 )
482 {
483 return new ComposeAction( op1, op2 ) ;
484 }
486 private static class MapAction extends OperationBase
487 {
488 Operation op ;
490 MapAction( Operation op )
491 {
492 this.op = op ;
493 }
495 public Object operate( Object value )
496 {
497 Object[] values = (Object[])value ;
498 Object[] result = new Object[ values.length ] ;
499 for (int ctr=0; ctr<values.length; ctr++ )
500 result[ctr] = op.operate( values[ctr] ) ;
501 return result ;
502 }
504 public String toString() {
505 return "mapAction(" + op + ")" ;
506 }
507 }
509 public static Operation mapAction( Operation op )
510 {
511 return new MapAction( op ) ;
512 }
514 private static class MapSequenceAction extends OperationBase
515 {
516 private Operation[] op ;
518 public MapSequenceAction( Operation[] op )
519 {
520 this.op = op ;
521 }
523 // XXX Does this correctly handle array types? It seems
524 // that hetereogeneous arrays work this way, while
525 // homogeneous arrays need to use Array.newInstance tricks.
526 public Object operate( Object value )
527 {
528 Object[] values = (Object[])value ;
529 Object[] result = new Object[ values.length ] ;
530 for (int ctr=0; ctr<values.length; ctr++ )
531 result[ctr] = op[ctr].operate( values[ctr] ) ;
532 return result ;
533 }
535 public String toString() {
536 return "mapSequenceAction(" +
537 Arrays.toString(op) + ")" ;
538 }
539 }
541 public static Operation mapSequenceAction( Operation[] op )
542 {
543 return new MapSequenceAction( op ) ;
544 }
546 private static class ConvertIntegerToShort extends OperationBase
547 {
548 public Object operate( Object value )
549 {
550 Integer val = (Integer)value ;
551 return new Short( val.shortValue() ) ;
552 }
554 public String toString() {
555 return "ConvertIntegerToShort" ;
556 }
557 }
559 private static Operation convertIntegerToShortImpl = new ConvertIntegerToShort() ;
561 public static Operation convertIntegerToShort()
562 {
563 return convertIntegerToShortImpl ;
564 }
565 }