United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-6739302 : Check that deserialization preserves EnumSet integrity

Details
Type:
Bug
Submit Date:
2008-08-20
Status:
Resolved
Updated Date:
2010-04-02
Project Name:
JDK
Resolved Date:
2008-08-30
Component:
core-libs
OS:
generic
Sub-Component:
java.util
CPU:
generic
Priority:
P4
Resolution:
Fixed
Affected Versions:
6
Fixed Versions:

Related Reports
Backport:
Backport:

Sub Tasks

Description
The java.util.EnumSet class uses the "Serialization Proxy" pattern, as described in Effective Java, Second Ed., Item 78.  Unfortunately EnumSet, is missing the requisite readObject method (p. 313):

    // readObject method for the serialization proxy pattern
    private void readObject(ObjectInputStream stream)
            throws InvalidObjectException {
        throw new InvalidObjectException("Proxy required");
    }

Because this method is missing, it is possible to deserialize a carefully crafted byte stream that represents a serialized RegularEnumSet or JumboEnumSet (rather than an EnumSet.SerializationProxy). The default deserialization is performed (with no invariant checking) so it is easy to produce a corrupt EnumSet instance. For example, it is possible to set bits that do not represent valid enum constants. Such EnumSet instances behave erratically, as demonstrated by this program:

import java.util.*;
import java.io.*;

public class BogusEnumSet {
    public static void main(String[] args) {
        byte[] serializedForm  = {
            (byte)0xac, (byte)0xed, 0x0, 0x5, 0x73, 0x72, 0x0, 0x18,
            0x6a,  0x61,  0x76,  0x61, 0x2e,  0x75,  0x74,  0x69,
            0x6c,  0x2e, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x45,
            0x6e, 0x75, 0x6d, 0x53, 0x65, 0x74, 0x2f, 0x58, 0x6f, (byte)0xc7,
            0x7e, (byte)0xb0, (byte)0xd0, 0x7e, 0x2, 0x0, 0x1, 0x4a, 0x0, 0x8,
            0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x78, 0x72, 0x0,
            0x11, 0x6a,  0x61,  0x76,  0x61, 0x2e,  0x75,  0x74,  0x69,
            0x6c,  0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x53, 0x65, 0x74, 0xe,
            0x3, 0x21, 0x6a, (byte)0xcd, (byte)0x8c, 0x29, (byte)0xdd, 0x2,
            0x0, 0x2, 0x4c, 0x0, 0xb, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74,
            0x54, 0x79, 0x70, 0x65, 0x74, 0x0, 0x11, 0x4c, 0x6a, 0x61, 0x76,
            0x61, 0x2f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x43, 0x6c, 0x61, 0x73,
            0x73, 0x3b, 0x5b, 0x0, 0x8, 0x75, 0x6e, 0x69, 0x76, 0x65, 0x72,
            0x73, 0x65, 0x74, 0x0, 0x11, 0x5b, 0x4c, 0x6a, 0x61, 0x76, 0x61,
            0x2f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x45, 0x6e, 0x75, 0x6d, 0x3b,
            0x78, 0x70, 0x76, 0x72, 0x0, 0x16, 0x6a, 0x61, 0x76, 0x61, 0x2e,
            0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x54, 0x68, 0x72, 0x65, 0x61,
            0x64, 0x24, 0x53, 0x74, 0x61, 0x74, 0x65, 0x0, 0x0, 0x0, 0x0, 0x0,
            0x0, 0x0, 0x0, 0x12, 0x0, 0x0, 0x78, 0x72, 0x0, 0xe, 0x6a, 0x61,
            0x76, 0x61, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x45, 0x6e, 0x75,
            0x6d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12, 0x0, 0x0, 0x78,
            0x70, 0x75, 0x72, 0x0, 0x19, 0x5b, 0x4c, 0x6a, 0x61, 0x76, 0x61,
            0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x54, 0x68, 0x72, 0x65, 0x61,
            0x64, 0x24, 0x53, 0x74, 0x61, 0x74, 0x65, 0x3b, 0x68, (byte)0xa3,
            (byte)0xb5, (byte)0xd5, 0x11, 0x7d, 0x1b, (byte)0xb3, 0x2, 0x0,
            0x0, 0x78, 0x70, 0x0, 0x0, 0x0, 0x6, 0x7e, 0x71, 0x0, 0x7e, 0x0,
            0x5, 0x74, 0x0, 0x3, 0x4e, 0x45, 0x57, 0x7e, 0x71, 0x0, 0x7e, 0x0,
            0x5, 0x74, 0x0, 0x8, 0x52, 0x55, 0x4e, 0x4e, 0x41, 0x42, 0x4c, 0x45,
            0x7e, 0x71, 0x0, 0x7e, 0x0, 0x5, 0x74, 0x0, 0x7, 0x42, 0x4c, 0x4f,
            0x43, 0x4b, 0x45, 0x44, 0x7e, 0x71, 0x0, 0x7e, 0x0, 0x5, 0x74, 0x0,
            0x7, 0x57, 0x41, 0x49, 0x54, 0x49, 0x4e, 0x47, 0x7e, 0x71, 0x0,
            0x7e, 0x0, 0x5, 0x74, 0x0, 0xd, 0x54, 0x49, 0x4d, 0x45, 0x44,
            0x5f, 0x57, 0x41, 0x49, 0x54, 0x49, 0x4e, 0x47, 0x7e, 0x71, 0x0,
            0x7e, 0x0, 0x5, 0x74, 0x0, 0xa, 0x54, 0x45, 0x52, 0x4d, 0x49,
            0x4e, 0x41, 0x54, 0x45, 0x44, (byte)0xff, (byte)0xff, (byte)0xff,
            (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff
        };

        // Should fail, but instead creates corrupt EnumSet
        EnumSet<Thread.State> es = (EnumSet<Thread.State>)
            deserialize(serializedForm);

        // Demonstrates corruption
        System.out.println("Enum size: " + Thread.State.values().length); // 6
        System.out.println("Set size: " + es.size()); // 64
        System.out.println("Set: " + es); // Throws IndexOutOfBoundsException
    }

    private static Object deserialize(byte[] sf) {
        try {
            InputStream is = new ByteArrayInputStream(sf);
            ObjectInputStream ois = new ObjectInputStream(is);
            return ois.readObject();
        } catch (Exception e) {
            throw new IllegalArgumentException(e);
        }
    }
}

                                    

Comments
EVALUATION

see description
                                     
2008-08-20



Hardware and Software, Engineered to Work Together