Fri, 24 Sep 2010 22:42:14 -0700
6891766: Vulnerabilities in use of reflection in CORBA
Reviewed-by: hawtin
1 /*
2 * Copyright (c) 1999, 2003, 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 /*
26 * Licensed Materials - Property of IBM
27 * RMI-IIOP v1.0
28 * Copyright IBM Corp. 1998 1999 All Rights Reserved
29 *
30 */
32 package com.sun.corba.se.impl.io;
34 import java.io.IOException;
35 import java.io.OutputStream;
36 import java.io.ObjectOutputStream;
37 import java.io.ObjectOutput;
38 import java.util.Hashtable;
40 import org.omg.CORBA.INTERNAL;
42 public abstract class OutputStreamHook extends ObjectOutputStream
43 {
44 private HookPutFields putFields = null;
46 /**
47 * Since ObjectOutputStream.PutField methods specify no exceptions,
48 * we are not checking for null parameters on put methods.
49 */
50 private class HookPutFields extends ObjectOutputStream.PutField
51 {
52 private Hashtable fields = new Hashtable();
54 /**
55 * Put the value of the named boolean field into the persistent field.
56 */
57 public void put(String name, boolean value){
58 fields.put(name, new Boolean(value));
59 }
61 /**
62 * Put the value of the named char field into the persistent fields.
63 */
64 public void put(String name, char value){
65 fields.put(name, new Character(value));
66 }
68 /**
69 * Put the value of the named byte field into the persistent fields.
70 */
71 public void put(String name, byte value){
72 fields.put(name, new Byte(value));
73 }
75 /**
76 * Put the value of the named short field into the persistent fields.
77 */
78 public void put(String name, short value){
79 fields.put(name, new Short(value));
80 }
82 /**
83 * Put the value of the named int field into the persistent fields.
84 */
85 public void put(String name, int value){
86 fields.put(name, new Integer(value));
87 }
89 /**
90 * Put the value of the named long field into the persistent fields.
91 */
92 public void put(String name, long value){
93 fields.put(name, new Long(value));
94 }
96 /**
97 * Put the value of the named float field into the persistent fields.
98 *
99 */
100 public void put(String name, float value){
101 fields.put(name, new Float(value));
102 }
104 /**
105 * Put the value of the named double field into the persistent field.
106 */
107 public void put(String name, double value){
108 fields.put(name, new Double(value));
109 }
111 /**
112 * Put the value of the named Object field into the persistent field.
113 */
114 public void put(String name, Object value){
115 fields.put(name, value);
116 }
118 /**
119 * Write the data and fields to the specified ObjectOutput stream.
120 */
121 public void write(ObjectOutput out) throws IOException {
122 OutputStreamHook hook = (OutputStreamHook)out;
124 ObjectStreamField[] osfields = hook.getFieldsNoCopy();
126 // Write the fields to the stream in the order
127 // provided by the ObjectStreamClass. (They should
128 // be sorted appropriately already.)
129 for (int i = 0; i < osfields.length; i++) {
131 Object value = fields.get(osfields[i].getName());
133 hook.writeField(osfields[i], value);
134 }
135 }
136 }
138 abstract void writeField(ObjectStreamField field, Object value) throws IOException;
140 public OutputStreamHook()
141 throws java.io.IOException {
142 super();
144 }
146 public void defaultWriteObject() throws IOException {
148 writeObjectState.defaultWriteObject(this);
150 defaultWriteObjectDelegate();
151 }
153 public abstract void defaultWriteObjectDelegate();
155 public ObjectOutputStream.PutField putFields()
156 throws IOException {
157 putFields = new HookPutFields();
158 return putFields;
159 }
161 // Stream format version, saved/restored during recursive calls
162 protected byte streamFormatVersion = 1;
164 // Return the stream format version currently being used
165 // to serialize an object
166 public byte getStreamFormatVersion() {
167 return streamFormatVersion;
168 }
170 abstract ObjectStreamField[] getFieldsNoCopy();
172 // User uses PutFields to simulate default data.
173 // See java.io.ObjectOutputStream.PutFields
174 public void writeFields()
175 throws IOException {
177 writeObjectState.defaultWriteObject(this);
179 putFields.write(this);
180 }
182 public abstract org.omg.CORBA_2_3.portable.OutputStream getOrbStream();
184 protected abstract void beginOptionalCustomData();
187 // The following is a State pattern implementation of what
188 // should be done when a Serializable has a
189 // writeObject method. This was especially necessary for
190 // RMI-IIOP stream format version 2. Please see the
191 // state diagrams in the docs directory of the workspace.
193 protected WriteObjectState writeObjectState = NOT_IN_WRITE_OBJECT;
195 protected void setState(WriteObjectState newState) {
196 writeObjectState = newState;
197 }
199 // Description of possible actions
200 protected static class WriteObjectState {
201 public void enterWriteObject(OutputStreamHook stream) throws IOException {}
202 public void exitWriteObject(OutputStreamHook stream) throws IOException {}
203 public void defaultWriteObject(OutputStreamHook stream) throws IOException {}
204 public void writeData(OutputStreamHook stream) throws IOException {}
205 }
207 protected static class DefaultState extends WriteObjectState {
208 public void enterWriteObject(OutputStreamHook stream) throws IOException {
209 stream.setState(IN_WRITE_OBJECT);
210 }
211 }
213 protected static final WriteObjectState NOT_IN_WRITE_OBJECT = new DefaultState();
214 protected static final WriteObjectState IN_WRITE_OBJECT = new InWriteObjectState();
215 protected static final WriteObjectState WROTE_DEFAULT_DATA = new WroteDefaultDataState();
216 protected static final WriteObjectState WROTE_CUSTOM_DATA = new WroteCustomDataState();
218 protected static class InWriteObjectState extends WriteObjectState {
220 public void enterWriteObject(OutputStreamHook stream) throws IOException {
221 // XXX I18N, logging needed.
222 throw new IOException("Internal state failure: Entered writeObject twice");
223 }
225 public void exitWriteObject(OutputStreamHook stream) throws IOException {
227 // We didn't write any data, so write the
228 // called defaultWriteObject indicator as false
229 stream.getOrbStream().write_boolean(false);
231 // If we're in stream format verison 2, we must
232 // put the "null" marker to say that there isn't
233 // any optional data
234 if (stream.getStreamFormatVersion() == 2)
235 stream.getOrbStream().write_long(0);
237 stream.setState(NOT_IN_WRITE_OBJECT);
238 }
240 public void defaultWriteObject(OutputStreamHook stream) throws IOException {
242 // The writeObject method called defaultWriteObject
243 // or writeFields, so put the called defaultWriteObject
244 // indicator as true
245 stream.getOrbStream().write_boolean(true);
247 stream.setState(WROTE_DEFAULT_DATA);
248 }
250 public void writeData(OutputStreamHook stream) throws IOException {
252 // The writeObject method first called a direct
253 // write operation. Write the called defaultWriteObject
254 // indicator as false, put the special stream format
255 // version 2 header (if stream format version 2, of course),
256 // and write the data
257 stream.getOrbStream().write_boolean(false);
258 stream.beginOptionalCustomData();
259 stream.setState(WROTE_CUSTOM_DATA);
260 }
261 }
263 protected static class WroteDefaultDataState extends InWriteObjectState {
265 public void exitWriteObject(OutputStreamHook stream) throws IOException {
267 // We only wrote default data, so if in stream format
268 // version 2, put the null indicator to say that there
269 // is no optional data
270 if (stream.getStreamFormatVersion() == 2)
271 stream.getOrbStream().write_long(0);
273 stream.setState(NOT_IN_WRITE_OBJECT);
274 }
276 public void defaultWriteObject(OutputStreamHook stream) throws IOException {
277 // XXX I18N, logging needed.
278 throw new IOException("Called defaultWriteObject/writeFields twice");
279 }
281 public void writeData(OutputStreamHook stream) throws IOException {
283 // The writeObject method called a direct write operation.
284 // If in stream format version 2, put the fake valuetype
285 // header.
286 stream.beginOptionalCustomData();
288 stream.setState(WROTE_CUSTOM_DATA);
289 }
290 }
292 protected static class WroteCustomDataState extends InWriteObjectState {
294 public void exitWriteObject(OutputStreamHook stream) throws IOException {
295 // In stream format version 2, we must tell the ORB
296 // stream to close the fake custom valuetype.
297 if (stream.getStreamFormatVersion() == 2)
298 ((org.omg.CORBA.portable.ValueOutputStream)stream.getOrbStream()).end_value();
300 stream.setState(NOT_IN_WRITE_OBJECT);
301 }
303 public void defaultWriteObject(OutputStreamHook stream) throws IOException {
304 // XXX I18N, logging needed.
305 throw new IOException("Cannot call defaultWriteObject/writeFields after writing custom data in RMI-IIOP");
306 }
308 // We don't have to do anything special here, just let
309 // the stream write the data.
310 public void writeData(OutputStreamHook stream) throws IOException {}
311 }
312 }