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