8344034: Remove security manager dependency in Serialization
Reviewed-by: mullan, alanb
This commit is contained in:
parent
d52d136486
commit
9b0ab92b16
@ -29,8 +29,6 @@ import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.util.StaticProperty;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.Security;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -630,17 +628,13 @@ public interface ObjectInputFilter {
|
||||
configLog = System.getLogger("java.io.serialization");
|
||||
|
||||
// Get the values of the system properties, if they are defined
|
||||
@SuppressWarnings("removal")
|
||||
String factoryClassName = StaticProperty.jdkSerialFilterFactory() != null
|
||||
? StaticProperty.jdkSerialFilterFactory()
|
||||
: AccessController.doPrivileged((PrivilegedAction<String>) () ->
|
||||
Security.getProperty(SERIAL_FILTER_FACTORY_PROPNAME));
|
||||
: Security.getProperty(SERIAL_FILTER_FACTORY_PROPNAME);
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
String filterString = StaticProperty.jdkSerialFilter() != null
|
||||
? StaticProperty.jdkSerialFilter()
|
||||
: AccessController.doPrivileged((PrivilegedAction<String>) () ->
|
||||
Security.getProperty(SERIAL_FILTER_PROPNAME));
|
||||
: Security.getProperty(SERIAL_FILTER_PROPNAME);
|
||||
|
||||
// Initialize the static filter if the jdk.serialFilter is present
|
||||
String filterMessage = null;
|
||||
@ -734,11 +728,6 @@ public interface ObjectInputFilter {
|
||||
*/
|
||||
public static void setSerialFilter(ObjectInputFilter filter) {
|
||||
Objects.requireNonNull(filter, "filter");
|
||||
@SuppressWarnings("removal")
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(ObjectStreamConstants.SERIAL_FILTER_PERMISSION);
|
||||
}
|
||||
if (invalidFilterMessage != null) {
|
||||
throw new IllegalStateException(invalidFilterMessage);
|
||||
}
|
||||
@ -831,11 +820,6 @@ public interface ObjectInputFilter {
|
||||
*/
|
||||
public static void setSerialFilterFactory(BinaryOperator<ObjectInputFilter> filterFactory) {
|
||||
Objects.requireNonNull(filterFactory, "filterFactory");
|
||||
@SuppressWarnings("removal")
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(ObjectStreamConstants.SERIAL_FILTER_PERMISSION);
|
||||
}
|
||||
if (filterFactoryNoReplace.getAndSet(true)) {
|
||||
final String msg = serialFilterFactory != null
|
||||
? "Cannot replace filter factory: " + serialFilterFactory.getClass().getName()
|
||||
|
@ -34,13 +34,7 @@ import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.internal.access.JavaLangAccess;
|
||||
@ -49,8 +43,6 @@ import jdk.internal.event.DeserializationEvent;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.internal.util.ByteArray;
|
||||
import sun.reflect.misc.ReflectUtil;
|
||||
import sun.security.action.GetBooleanAction;
|
||||
import sun.security.action.GetIntegerAction;
|
||||
|
||||
/**
|
||||
* An ObjectInputStream deserializes primitive data and objects previously
|
||||
@ -278,8 +270,8 @@ public class ObjectInputStream
|
||||
* have been read.
|
||||
* See {@link #setObjectInputFilter(ObjectInputFilter)}
|
||||
*/
|
||||
static final boolean SET_FILTER_AFTER_READ = GetBooleanAction
|
||||
.privilegedGetProperty("jdk.serialSetFilterAfterRead");
|
||||
static final boolean SET_FILTER_AFTER_READ =
|
||||
Boolean.getBoolean("jdk.serialSetFilterAfterRead");
|
||||
|
||||
/**
|
||||
* Property to control {@link GetField#get(String, Object)} conversion of
|
||||
@ -287,8 +279,8 @@ public class ObjectInputStream
|
||||
* {@link GetField#get(String, Object)} returns null otherwise
|
||||
* throwing {@link ClassNotFoundException}.
|
||||
*/
|
||||
private static final boolean GETFIELD_CNFE_RETURNS_NULL = GetBooleanAction
|
||||
.privilegedGetProperty("jdk.serialGetFieldCnfeReturnsNull");
|
||||
private static final boolean GETFIELD_CNFE_RETURNS_NULL =
|
||||
Boolean.getBoolean("jdk.serialGetFieldCnfeReturnsNull");
|
||||
|
||||
/**
|
||||
* Property to override the implementation limit on the number
|
||||
@ -296,8 +288,8 @@ public class ObjectInputStream
|
||||
* The maximum number of interfaces allowed for a proxy is limited to 65535 by
|
||||
* {@link java.lang.reflect.Proxy#newProxyInstance(ClassLoader, Class[], InvocationHandler)}.
|
||||
*/
|
||||
static final int PROXY_INTERFACE_LIMIT = Math.clamp(GetIntegerAction
|
||||
.privilegedGetProperty("jdk.serialProxyInterfaceLimit", 65535), 0, 65535);
|
||||
static final int PROXY_INTERFACE_LIMIT =
|
||||
Math.clamp(Integer.getInteger("jdk.serialProxyInterfaceLimit", 65535), 0, 65535);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -386,7 +378,6 @@ public class ObjectInputStream
|
||||
*/
|
||||
@SuppressWarnings("this-escape")
|
||||
public ObjectInputStream(InputStream in) throws IOException {
|
||||
verifySubclass();
|
||||
bin = new BlockDataInputStream(in);
|
||||
handles = new HandleTable(10);
|
||||
vlist = new ValidationList();
|
||||
@ -416,11 +407,6 @@ public class ObjectInputStream
|
||||
* fails due to invalid serial filter or serial filter factory properties.
|
||||
*/
|
||||
protected ObjectInputStream() throws IOException {
|
||||
@SuppressWarnings("removal")
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
|
||||
}
|
||||
bin = null;
|
||||
handles = null;
|
||||
vlist = null;
|
||||
@ -907,13 +893,6 @@ public class ObjectInputStream
|
||||
if (enable == enableResolve) {
|
||||
return enable;
|
||||
}
|
||||
if (enable) {
|
||||
@SuppressWarnings("removal")
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(SUBSTITUTION_PERMISSION);
|
||||
}
|
||||
}
|
||||
enableResolve = enable;
|
||||
return !enableResolve;
|
||||
}
|
||||
@ -1309,11 +1288,6 @@ public class ObjectInputStream
|
||||
* @since 9
|
||||
*/
|
||||
public final void setObjectInputFilter(ObjectInputFilter filter) {
|
||||
@SuppressWarnings("removal")
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(ObjectStreamConstants.SERIAL_FILTER_PERMISSION);
|
||||
}
|
||||
if (totalObjectRefs > 0 && !Caches.SET_FILTER_AFTER_READ) {
|
||||
throw new IllegalStateException(
|
||||
"filter can not be set after an object has been read");
|
||||
@ -1571,58 +1545,29 @@ public class ObjectInputStream
|
||||
public abstract Object get(String name, Object val) throws IOException, ClassNotFoundException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that this (possibly subclass) instance can be constructed
|
||||
* without violating security constraints: the subclass must not override
|
||||
* security-sensitive non-final methods, or else the
|
||||
* "enableSubclassImplementation" SerializablePermission is checked.
|
||||
*/
|
||||
private void verifySubclass() {
|
||||
Class<?> cl = getClass();
|
||||
if (cl == ObjectInputStream.class) {
|
||||
return;
|
||||
}
|
||||
@SuppressWarnings("removal")
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm == null) {
|
||||
return;
|
||||
}
|
||||
boolean result = Caches.subclassAudits.get(cl);
|
||||
if (!result) {
|
||||
sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs reflective checks on given subclass to verify that it doesn't
|
||||
* override security-sensitive non-final methods. Returns TRUE if subclass
|
||||
* is "safe", FALSE otherwise.
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
private static Boolean auditSubclass(Class<?> subcl) {
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedAction<Boolean>() {
|
||||
public Boolean run() {
|
||||
for (Class<?> cl = subcl;
|
||||
cl != ObjectInputStream.class;
|
||||
cl = cl.getSuperclass())
|
||||
{
|
||||
try {
|
||||
cl.getDeclaredMethod(
|
||||
"readUnshared", (Class[]) null);
|
||||
return Boolean.FALSE;
|
||||
} catch (NoSuchMethodException ex) {
|
||||
}
|
||||
try {
|
||||
cl.getDeclaredMethod("readFields", (Class[]) null);
|
||||
return Boolean.FALSE;
|
||||
} catch (NoSuchMethodException ex) {
|
||||
}
|
||||
}
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
for (Class<?> cl = subcl;
|
||||
cl != ObjectInputStream.class;
|
||||
cl = cl.getSuperclass())
|
||||
{
|
||||
try {
|
||||
cl.getDeclaredMethod(
|
||||
"readUnshared", (Class[]) null);
|
||||
return Boolean.FALSE;
|
||||
} catch (NoSuchMethodException ex) {
|
||||
}
|
||||
);
|
||||
try {
|
||||
cl.getDeclaredMethod("readFields", (Class[]) null);
|
||||
return Boolean.FALSE;
|
||||
} catch (NoSuchMethodException ex) {
|
||||
}
|
||||
}
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2702,16 +2647,11 @@ public class ObjectInputStream
|
||||
final ObjectInputValidation obj;
|
||||
final int priority;
|
||||
Callback next;
|
||||
@SuppressWarnings("removal")
|
||||
final AccessControlContext acc;
|
||||
|
||||
Callback(ObjectInputValidation obj, int priority, Callback next,
|
||||
@SuppressWarnings("removal") AccessControlContext acc)
|
||||
{
|
||||
Callback(ObjectInputValidation obj, int priority, Callback next) {
|
||||
this.obj = obj;
|
||||
this.priority = priority;
|
||||
this.next = next;
|
||||
this.acc = acc;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2740,12 +2680,10 @@ public class ObjectInputStream
|
||||
prev = cur;
|
||||
cur = cur.next;
|
||||
}
|
||||
@SuppressWarnings("removal")
|
||||
AccessControlContext acc = AccessController.getContext();
|
||||
if (prev != null) {
|
||||
prev.next = new Callback(obj, priority, cur, acc);
|
||||
prev.next = new Callback(obj, priority, cur);
|
||||
} else {
|
||||
list = new Callback(obj, priority, list, acc);
|
||||
list = new Callback(obj, priority, list);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2756,23 +2694,15 @@ public class ObjectInputStream
|
||||
* throws an InvalidObjectException, the callback process is terminated
|
||||
* and the exception propagated upwards.
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
void doCallbacks() throws InvalidObjectException {
|
||||
try {
|
||||
while (list != null) {
|
||||
AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<Void>()
|
||||
{
|
||||
public Void run() throws InvalidObjectException {
|
||||
list.obj.validateObject();
|
||||
return null;
|
||||
}
|
||||
}, list.acc);
|
||||
list.obj.validateObject();
|
||||
list = list.next;
|
||||
}
|
||||
} catch (PrivilegedActionException ex) {
|
||||
} catch (InvalidObjectException ex) {
|
||||
list = null;
|
||||
throw (InvalidObjectException) ex.getException();
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,8 +26,6 @@
|
||||
|
||||
package java.io;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@ -224,11 +222,8 @@ public class ObjectOutputStream
|
||||
* value of "sun.io.serialization.extendedDebugInfo" property,
|
||||
* as true or false for extended information about exception's place
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
private static final boolean extendedDebugInfo =
|
||||
java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetBooleanAction(
|
||||
"sun.io.serialization.extendedDebugInfo")).booleanValue();
|
||||
Boolean.getBoolean("sun.io.serialization.extendedDebugInfo");
|
||||
|
||||
/**
|
||||
* Creates an ObjectOutputStream that writes to the specified OutputStream.
|
||||
@ -247,7 +242,6 @@ public class ObjectOutputStream
|
||||
*/
|
||||
@SuppressWarnings("this-escape")
|
||||
public ObjectOutputStream(OutputStream out) throws IOException {
|
||||
verifySubclass();
|
||||
bout = new BlockDataOutputStream(out);
|
||||
handles = new HandleTable(10, (float) 3.00);
|
||||
subs = new ReplaceTable(10, (float) 3.00);
|
||||
@ -269,11 +263,6 @@ public class ObjectOutputStream
|
||||
* @throws IOException if an I/O error occurs while creating this stream
|
||||
*/
|
||||
protected ObjectOutputStream() throws IOException {
|
||||
@SuppressWarnings("removal")
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
|
||||
}
|
||||
bout = null;
|
||||
handles = null;
|
||||
subs = null;
|
||||
@ -595,13 +584,6 @@ public class ObjectOutputStream
|
||||
if (enable == enableReplace) {
|
||||
return enable;
|
||||
}
|
||||
if (enable) {
|
||||
@SuppressWarnings("removal")
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(SUBSTITUTION_PERMISSION);
|
||||
}
|
||||
}
|
||||
enableReplace = enable;
|
||||
return !enableReplace;
|
||||
}
|
||||
@ -625,8 +607,8 @@ public class ObjectOutputStream
|
||||
* stream. Subclasses of ObjectOutputStream may override this method to
|
||||
* customize the way in which class descriptors are written to the
|
||||
* serialization stream. The corresponding method in ObjectInputStream,
|
||||
* {@link ObjectInputStream#readClassDescriptor readClassDescriptor}, should then be overridden to
|
||||
* reconstitute the class descriptor from its custom stream representation.
|
||||
* {@link ObjectInputStream#readClassDescriptor readClassDescriptor}, should then be
|
||||
* overridden to reconstitute the class descriptor from its custom stream representation.
|
||||
* By default, this method writes class descriptors according to the format
|
||||
* defined in the <a href="{@docRoot}/../specs/serialization/index.html">
|
||||
* <cite>Java Object Serialization Specification</cite></a>.
|
||||
@ -1022,58 +1004,29 @@ public class ObjectOutputStream
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that this (possibly subclass) instance can be constructed
|
||||
* without violating security constraints: the subclass must not override
|
||||
* security-sensitive non-final methods, or else the
|
||||
* "enableSubclassImplementation" SerializablePermission is checked.
|
||||
*/
|
||||
private void verifySubclass() {
|
||||
Class<?> cl = getClass();
|
||||
if (cl == ObjectOutputStream.class) {
|
||||
return;
|
||||
}
|
||||
@SuppressWarnings("removal")
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm == null) {
|
||||
return;
|
||||
}
|
||||
boolean result = Caches.subclassAudits.get(cl);
|
||||
if (!result) {
|
||||
sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs reflective checks on given subclass to verify that it doesn't
|
||||
* override security-sensitive non-final methods. Returns TRUE if subclass
|
||||
* is "safe", FALSE otherwise.
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
private static Boolean auditSubclass(Class<?> subcl) {
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedAction<>() {
|
||||
public Boolean run() {
|
||||
for (Class<?> cl = subcl;
|
||||
cl != ObjectOutputStream.class;
|
||||
cl = cl.getSuperclass())
|
||||
{
|
||||
try {
|
||||
cl.getDeclaredMethod(
|
||||
"writeUnshared", new Class<?>[] { Object.class });
|
||||
return Boolean.FALSE;
|
||||
} catch (NoSuchMethodException ex) {
|
||||
}
|
||||
try {
|
||||
cl.getDeclaredMethod("putFields", (Class<?>[]) null);
|
||||
return Boolean.FALSE;
|
||||
} catch (NoSuchMethodException ex) {
|
||||
}
|
||||
}
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
for (Class<?> cl = subcl;
|
||||
cl != ObjectOutputStream.class;
|
||||
cl = cl.getSuperclass())
|
||||
{
|
||||
try {
|
||||
cl.getDeclaredMethod(
|
||||
"writeUnshared", new Class<?>[] { Object.class });
|
||||
return Boolean.FALSE;
|
||||
} catch (NoSuchMethodException ex) {
|
||||
}
|
||||
);
|
||||
try {
|
||||
cl.getDeclaredMethod("putFields", (Class<?>[]) null);
|
||||
return Boolean.FALSE;
|
||||
} catch (NoSuchMethodException ex) {
|
||||
}
|
||||
}
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2024, 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
|
||||
@ -32,21 +32,12 @@ import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.RecordComponent;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PermissionCollection;
|
||||
import java.security.Permissions;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@ -58,13 +49,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import jdk.internal.event.SerializationMisdeclarationEvent;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.internal.reflect.CallerSensitive;
|
||||
import jdk.internal.reflect.Reflection;
|
||||
import jdk.internal.reflect.ReflectionFactory;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.access.JavaSecurityAccess;
|
||||
import jdk.internal.util.ByteArray;
|
||||
import sun.reflect.misc.ReflectUtil;
|
||||
|
||||
/**
|
||||
* Serialization's descriptor for classes. It contains the name and
|
||||
@ -98,12 +84,6 @@ public final class ObjectStreamClass implements Serializable {
|
||||
private static final ObjectStreamField[] serialPersistentFields =
|
||||
NO_FIELDS;
|
||||
|
||||
/** reflection factory for obtaining serialization constructors */
|
||||
@SuppressWarnings("removal")
|
||||
private static final ReflectionFactory reflFactory =
|
||||
AccessController.doPrivileged(
|
||||
new ReflectionFactory.GetReflectionFactoryAction());
|
||||
|
||||
private static class Caches {
|
||||
/** cache mapping local classes -> descriptors */
|
||||
static final ClassCache<ObjectStreamClass> localDescs =
|
||||
@ -206,8 +186,6 @@ public final class ObjectStreamClass implements Serializable {
|
||||
/** session-cache of record deserialization constructor
|
||||
* (in de-serialized OSC only), or null */
|
||||
private MethodHandle deserializationCtr;
|
||||
/** protection domains that need to be checked when calling the constructor */
|
||||
private ProtectionDomain[] domains;
|
||||
|
||||
/** class-defined writeObject method, or null if none */
|
||||
private Method writeObjectMethod;
|
||||
@ -280,20 +258,13 @@ public final class ObjectStreamClass implements Serializable {
|
||||
*
|
||||
* @return the SUID of the class described by this descriptor
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
public long getSerialVersionUID() {
|
||||
// REMIND: synchronize instead of relying on volatile?
|
||||
if (suid == null) {
|
||||
if (isRecord)
|
||||
return 0L;
|
||||
|
||||
suid = AccessController.doPrivileged(
|
||||
new PrivilegedAction<Long>() {
|
||||
public Long run() {
|
||||
return computeDefaultSUID(cl);
|
||||
}
|
||||
}
|
||||
);
|
||||
suid = computeDefaultSUID(cl);
|
||||
}
|
||||
return suid.longValue();
|
||||
}
|
||||
@ -304,19 +275,11 @@ public final class ObjectStreamClass implements Serializable {
|
||||
*
|
||||
* @return the {@code Class} instance that this descriptor represents
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
@CallerSensitive
|
||||
public Class<?> forClass() {
|
||||
if (cl == null) {
|
||||
return null;
|
||||
}
|
||||
requireInitialized();
|
||||
if (System.getSecurityManager() != null) {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), cl.getClassLoader())) {
|
||||
ReflectUtil.checkPackageAccess(cl);
|
||||
}
|
||||
}
|
||||
return cl;
|
||||
}
|
||||
|
||||
@ -369,7 +332,6 @@ public final class ObjectStreamClass implements Serializable {
|
||||
/**
|
||||
* Creates local class descriptor representing given class.
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
private ObjectStreamClass(final Class<?> cl) {
|
||||
this.cl = cl;
|
||||
name = cl.getName();
|
||||
@ -384,53 +346,44 @@ public final class ObjectStreamClass implements Serializable {
|
||||
localDesc = this;
|
||||
|
||||
if (serializable) {
|
||||
AccessController.doPrivileged(new PrivilegedAction<>() {
|
||||
public Void run() {
|
||||
if (isEnum) {
|
||||
suid = 0L;
|
||||
fields = NO_FIELDS;
|
||||
return null;
|
||||
}
|
||||
if (cl.isArray()) {
|
||||
fields = NO_FIELDS;
|
||||
return null;
|
||||
}
|
||||
|
||||
suid = getDeclaredSUID(cl);
|
||||
try {
|
||||
fields = getSerialFields(cl);
|
||||
computeFieldOffsets();
|
||||
} catch (InvalidClassException e) {
|
||||
serializeEx = deserializeEx =
|
||||
if (isEnum) {
|
||||
suid = 0L;
|
||||
fields = NO_FIELDS;
|
||||
} else if (cl.isArray()) {
|
||||
fields = NO_FIELDS;
|
||||
} else {
|
||||
suid = getDeclaredSUID(cl);
|
||||
try {
|
||||
fields = getSerialFields(cl);
|
||||
computeFieldOffsets();
|
||||
} catch (InvalidClassException e) {
|
||||
serializeEx = deserializeEx =
|
||||
new ExceptionInfo(e.classname, e.getMessage());
|
||||
fields = NO_FIELDS;
|
||||
}
|
||||
|
||||
if (isRecord) {
|
||||
canonicalCtr = canonicalRecordCtr(cl);
|
||||
deserializationCtrs = new DeserializationConstructorsCache();
|
||||
} else if (externalizable) {
|
||||
cons = getExternalizableConstructor(cl);
|
||||
} else {
|
||||
cons = getSerializableConstructor(cl);
|
||||
writeObjectMethod = getPrivateMethod(cl, "writeObject",
|
||||
new Class<?>[] { ObjectOutputStream.class },
|
||||
Void.TYPE);
|
||||
readObjectMethod = getPrivateMethod(cl, "readObject",
|
||||
new Class<?>[] { ObjectInputStream.class },
|
||||
Void.TYPE);
|
||||
readObjectNoDataMethod = getPrivateMethod(
|
||||
cl, "readObjectNoData", null, Void.TYPE);
|
||||
hasWriteObjectData = (writeObjectMethod != null);
|
||||
}
|
||||
domains = getProtectionDomains(cons, cl);
|
||||
writeReplaceMethod = getInheritableMethod(
|
||||
cl, "writeReplace", null, Object.class);
|
||||
readResolveMethod = getInheritableMethod(
|
||||
cl, "readResolve", null, Object.class);
|
||||
return null;
|
||||
fields = NO_FIELDS;
|
||||
}
|
||||
});
|
||||
|
||||
if (isRecord) {
|
||||
canonicalCtr = canonicalRecordCtr(cl);
|
||||
deserializationCtrs = new DeserializationConstructorsCache();
|
||||
} else if (externalizable) {
|
||||
cons = getExternalizableConstructor(cl);
|
||||
} else {
|
||||
cons = getSerializableConstructor(cl);
|
||||
writeObjectMethod = getPrivateMethod(cl, "writeObject",
|
||||
new Class<?>[]{ObjectOutputStream.class},
|
||||
Void.TYPE);
|
||||
readObjectMethod = getPrivateMethod(cl, "readObject",
|
||||
new Class<?>[]{ObjectInputStream.class},
|
||||
Void.TYPE);
|
||||
readObjectNoDataMethod = getPrivateMethod(
|
||||
cl, "readObjectNoData", null, Void.TYPE);
|
||||
hasWriteObjectData = (writeObjectMethod != null);
|
||||
}
|
||||
writeReplaceMethod = getInheritableMethod(
|
||||
cl, "writeReplace", null, Object.class);
|
||||
readResolveMethod = getInheritableMethod(
|
||||
cl, "readResolve", null, Object.class);
|
||||
}
|
||||
} else {
|
||||
suid = 0L;
|
||||
fields = NO_FIELDS;
|
||||
@ -474,66 +427,6 @@ public final class ObjectStreamClass implements Serializable {
|
||||
ObjectStreamClass() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PermissionDomain that grants no permission.
|
||||
*/
|
||||
private ProtectionDomain noPermissionsDomain() {
|
||||
PermissionCollection perms = new Permissions();
|
||||
perms.setReadOnly();
|
||||
return new ProtectionDomain(null, perms);
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggregate the ProtectionDomains of all the classes that separate
|
||||
* a concrete class {@code cl} from its ancestor's class declaring
|
||||
* a constructor {@code cons}.
|
||||
*
|
||||
* If {@code cl} is defined by the boot loader, or the constructor
|
||||
* {@code cons} is declared by {@code cl}, or if there is no security
|
||||
* manager, then this method does nothing and {@code null} is returned.
|
||||
*
|
||||
* @param cons A constructor declared by {@code cl} or one of its
|
||||
* ancestors.
|
||||
* @param cl A concrete class, which is either the class declaring
|
||||
* the constructor {@code cons}, or a serializable subclass
|
||||
* of that class.
|
||||
* @return An array of ProtectionDomain representing the set of
|
||||
* ProtectionDomain that separate the concrete class {@code cl}
|
||||
* from its ancestor's declaring {@code cons}, or {@code null}.
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
private ProtectionDomain[] getProtectionDomains(Constructor<?> cons,
|
||||
Class<?> cl) {
|
||||
ProtectionDomain[] domains = null;
|
||||
if (cons != null && cl.getClassLoader() != null
|
||||
&& System.getSecurityManager() != null) {
|
||||
Class<?> cls = cl;
|
||||
Class<?> fnscl = cons.getDeclaringClass();
|
||||
Set<ProtectionDomain> pds = null;
|
||||
while (cls != fnscl) {
|
||||
ProtectionDomain pd = cls.getProtectionDomain();
|
||||
if (pd != null) {
|
||||
if (pds == null) pds = new HashSet<>();
|
||||
pds.add(pd);
|
||||
}
|
||||
cls = cls.getSuperclass();
|
||||
if (cls == null) {
|
||||
// that's not supposed to happen
|
||||
// make a ProtectionDomain with no permission.
|
||||
// should we throw instead?
|
||||
if (pds == null) pds = new HashSet<>();
|
||||
else pds.clear();
|
||||
pds.add(noPermissionsDomain());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pds != null) {
|
||||
domains = pds.toArray(new ProtectionDomain[0]);
|
||||
}
|
||||
}
|
||||
return domains;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes class descriptor representing a proxy class.
|
||||
*/
|
||||
@ -564,7 +457,6 @@ public final class ObjectStreamClass implements Serializable {
|
||||
writeReplaceMethod = localDesc.writeReplaceMethod;
|
||||
readResolveMethod = localDesc.readResolveMethod;
|
||||
deserializeEx = localDesc.deserializeEx;
|
||||
domains = localDesc.domains;
|
||||
cons = localDesc.cons;
|
||||
}
|
||||
fieldRefl = getReflector(fields, localDesc);
|
||||
@ -656,7 +548,6 @@ public final class ObjectStreamClass implements Serializable {
|
||||
if (deserializeEx == null) {
|
||||
deserializeEx = localDesc.deserializeEx;
|
||||
}
|
||||
domains = localDesc.domains;
|
||||
assert cl.isRecord() ? localDesc.cons == null : true;
|
||||
cons = localDesc.cons;
|
||||
}
|
||||
@ -1013,7 +904,6 @@ public final class ObjectStreamClass implements Serializable {
|
||||
* class is non-serializable or if the appropriate no-arg constructor is
|
||||
* inaccessible/unavailable.
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
Object newInstance()
|
||||
throws InstantiationException, InvocationTargetException,
|
||||
UnsupportedOperationException
|
||||
@ -1021,35 +911,7 @@ public final class ObjectStreamClass implements Serializable {
|
||||
requireInitialized();
|
||||
if (cons != null) {
|
||||
try {
|
||||
if (domains == null || domains.length == 0) {
|
||||
return cons.newInstance();
|
||||
} else {
|
||||
JavaSecurityAccess jsa = SharedSecrets.getJavaSecurityAccess();
|
||||
PrivilegedAction<?> pea = () -> {
|
||||
try {
|
||||
return cons.newInstance();
|
||||
} catch (InstantiationException
|
||||
| InvocationTargetException
|
||||
| IllegalAccessException x) {
|
||||
throw new UndeclaredThrowableException(x);
|
||||
}
|
||||
}; // Can't use PrivilegedExceptionAction with jsa
|
||||
try {
|
||||
return jsa.doIntersectionPrivilege(pea,
|
||||
AccessController.getContext(),
|
||||
new AccessControlContext(domains));
|
||||
} catch (UndeclaredThrowableException x) {
|
||||
Throwable cause = x.getCause();
|
||||
if (cause instanceof InstantiationException ie)
|
||||
throw ie;
|
||||
if (cause instanceof InvocationTargetException ite)
|
||||
throw ite;
|
||||
if (cause instanceof IllegalAccessException iae)
|
||||
throw iae;
|
||||
// not supposed to happen
|
||||
throw x;
|
||||
}
|
||||
}
|
||||
return cons.newInstance();
|
||||
} catch (IllegalAccessException ex) {
|
||||
// should not occur, as access checks have been suppressed
|
||||
throw new InternalError(ex);
|
||||
@ -1454,7 +1316,7 @@ public final class ObjectStreamClass implements Serializable {
|
||||
* returned constructor (if any).
|
||||
*/
|
||||
private static Constructor<?> getSerializableConstructor(Class<?> cl) {
|
||||
return reflFactory.newConstructorForSerialization(cl);
|
||||
return ReflectionFactory.getReflectionFactory().newConstructorForSerialization(cl);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1462,22 +1324,18 @@ public final class ObjectStreamClass implements Serializable {
|
||||
* the not found ( which should never happen for correctly generated record
|
||||
* classes ).
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
private static MethodHandle canonicalRecordCtr(Class<?> cls) {
|
||||
assert cls.isRecord() : "Expected record, got: " + cls;
|
||||
PrivilegedAction<MethodHandle> pa = () -> {
|
||||
Class<?>[] paramTypes = Arrays.stream(cls.getRecordComponents())
|
||||
.map(RecordComponent::getType)
|
||||
.toArray(Class<?>[]::new);
|
||||
try {
|
||||
Constructor<?> ctr = cls.getDeclaredConstructor(paramTypes);
|
||||
ctr.setAccessible(true);
|
||||
return MethodHandles.lookup().unreflectConstructor(ctr);
|
||||
} catch (IllegalAccessException | NoSuchMethodException e) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
return AccessController.doPrivileged(pa);
|
||||
Class<?>[] paramTypes = Arrays.stream(cls.getRecordComponents())
|
||||
.map(RecordComponent::getType)
|
||||
.toArray(Class<?>[]::new);
|
||||
try {
|
||||
Constructor<?> ctr = cls.getDeclaredConstructor(paramTypes);
|
||||
ctr.setAccessible(true);
|
||||
return MethodHandles.lookup().unreflectConstructor(ctr);
|
||||
} catch (IllegalAccessException | NoSuchMethodException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2358,7 +2216,6 @@ public final class ObjectStreamClass implements Serializable {
|
||||
* and return
|
||||
* {@code Object}
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
static MethodHandle deserializationCtr(ObjectStreamClass desc) {
|
||||
// check the cached value 1st
|
||||
MethodHandle mh = desc.deserializationCtr;
|
||||
@ -2367,14 +2224,7 @@ public final class ObjectStreamClass implements Serializable {
|
||||
if (mh != null) return desc.deserializationCtr = mh;
|
||||
|
||||
// retrieve record components
|
||||
RecordComponent[] recordComponents;
|
||||
try {
|
||||
Class<?> cls = desc.forClass();
|
||||
PrivilegedExceptionAction<RecordComponent[]> pa = cls::getRecordComponents;
|
||||
recordComponents = AccessController.doPrivileged(pa);
|
||||
} catch (PrivilegedActionException e) {
|
||||
throw new InternalError(e.getCause());
|
||||
}
|
||||
RecordComponent[] recordComponents = desc.forClass().getRecordComponents();
|
||||
|
||||
// retrieve the canonical constructor
|
||||
// (T1, T2, ..., Tn):TR
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2024, 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
|
||||
@ -26,9 +26,6 @@
|
||||
package java.io;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import jdk.internal.reflect.CallerSensitive;
|
||||
import jdk.internal.reflect.Reflection;
|
||||
import sun.reflect.misc.ReflectUtil;
|
||||
|
||||
/**
|
||||
* A description of a Serializable field from a Serializable class. An array
|
||||
@ -161,15 +158,7 @@ public class ObjectStreamField
|
||||
* @return a {@code Class} object representing the type of the
|
||||
* serializable field
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
@CallerSensitive
|
||||
public Class<?> getType() {
|
||||
if (System.getSecurityManager() != null) {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), type.getClassLoader())) {
|
||||
ReflectUtil.checkPackageAccess(type);
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
|
@ -29,8 +29,6 @@ import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static jdk.internal.event.SerializationMisdeclarationEvent.*;
|
||||
@ -75,7 +73,7 @@ final class SerializationMisdeclarationChecker {
|
||||
}
|
||||
|
||||
private static void checkSerialVersionUID(Class<?> cl) {
|
||||
Field f = privilegedDeclaredField(cl, SUID_NAME);
|
||||
Field f = declaredField(cl, SUID_NAME);
|
||||
if (f == null) {
|
||||
if (isOrdinaryClass(cl)) {
|
||||
commitEvent(cl, SUID_NAME + " should be declared explicitly" +
|
||||
@ -101,7 +99,7 @@ final class SerializationMisdeclarationChecker {
|
||||
}
|
||||
|
||||
private static void checkSerialPersistentFields(Class<?> cl) {
|
||||
Field f = privilegedDeclaredField(cl, SERIAL_PERSISTENT_FIELDS_NAME);
|
||||
Field f = declaredField(cl, SERIAL_PERSISTENT_FIELDS_NAME);
|
||||
if (f == null) {
|
||||
return;
|
||||
}
|
||||
@ -142,7 +140,7 @@ final class SerializationMisdeclarationChecker {
|
||||
|
||||
private static void checkPrivateMethod(Class<?> cl,
|
||||
String name, Class<?>[] paramTypes, Class<?> retType) {
|
||||
for (Method m : privilegedDeclaredMethods(cl)) {
|
||||
for (Method m : cl.getDeclaredMethods()) {
|
||||
if (m.getName().equals(name)) {
|
||||
checkPrivateMethod(cl, m, paramTypes, retType);
|
||||
}
|
||||
@ -173,7 +171,7 @@ final class SerializationMisdeclarationChecker {
|
||||
private static void checkAccessibleMethod(Class<?> cl,
|
||||
String name, Class<?>[] paramTypes, Class<?> retType) {
|
||||
for (Class<?> superCl = cl; superCl != null; superCl = superCl.getSuperclass()) {
|
||||
for (Method m : privilegedDeclaredMethods(superCl)) {
|
||||
for (Method m : superCl.getDeclaredMethods()) {
|
||||
if (m.getName().equals(name)) {
|
||||
checkAccessibleMethod(cl, superCl, m, paramTypes, retType);
|
||||
}
|
||||
@ -236,14 +234,6 @@ final class SerializationMisdeclarationChecker {
|
||||
return (m.getModifiers() & STATIC) != 0;
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private static Field privilegedDeclaredField(Class<?> cl, String name) {
|
||||
if (System.getSecurityManager() == null) {
|
||||
return declaredField(cl, name);
|
||||
}
|
||||
return AccessController.doPrivileged((PrivilegedAction<Field>) () ->
|
||||
declaredField(cl, name));
|
||||
}
|
||||
|
||||
private static Field declaredField(Class<?> cl, String name) {
|
||||
try {
|
||||
@ -253,14 +243,6 @@ final class SerializationMisdeclarationChecker {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private static Method[] privilegedDeclaredMethods(Class<?> cl) {
|
||||
if (System.getSecurityManager() == null) {
|
||||
return cl.getDeclaredMethods();
|
||||
}
|
||||
return AccessController.doPrivileged(
|
||||
(PrivilegedAction<Method[]>) cl::getDeclaredMethods);
|
||||
}
|
||||
|
||||
private static Object objectFromStatic(Field f) {
|
||||
try {
|
||||
|
@ -70,8 +70,7 @@ public class CheckCSMs {
|
||||
// The goal is to remove this list of Non-final instance @CS methods
|
||||
// over time. Do not add any new one to this list.
|
||||
private static final Set<String> KNOWN_NON_FINAL_CSMS =
|
||||
Set.of("java/io/ObjectStreamField#getType ()Ljava/lang/Class;",
|
||||
"java/lang/Runtime#load (Ljava/lang/String;)V",
|
||||
Set.of("java/lang/Runtime#load (Ljava/lang/String;)V",
|
||||
"java/lang/Runtime#loadLibrary (Ljava/lang/String;)V",
|
||||
"javax/sql/rowset/serial/SerialJavaObject#getFields ()[Ljava/lang/reflect/Field;"
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user