8344011: Remove usage of security manager from Class and reflective APIs

Reviewed-by: liach, yzheng, rriggs
This commit is contained in:
Alan Bateman 2024-11-14 07:39:28 +00:00
parent c977ef7b45
commit abacece826
26 changed files with 163 additions and 1251 deletions

View file

@ -311,8 +311,6 @@ public class VerifyAccess {
// will use the result cached in the JVM system dictionary. Note that the JVM system dictionary
// will record the first successful result. Unsuccessful results are not stored.
//
// We use doPrivileged in order to allow an unprivileged caller to ask an arbitrary
// class loader about the binding of the proposed name (type.getName()).
// The looked up type ("res") is compared for equality against the proposed
// type ("type") and then is discarded. Thus, the worst that can happen to
// the "child" class loader is that it is bothered to load and report a class
@ -320,17 +318,12 @@ public class VerifyAccess {
// memoization. And the caller never gets to look at the alternate type binding
// ("res"), whether it exists or not.
final String name = type.getName();
@SuppressWarnings("removal")
Class<?> res = java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<>() {
public Class<?> run() {
try {
return Class.forName(name, false, refcLoader);
} catch (ClassNotFoundException | LinkageError e) {
return null; // Assume the class is not found
}
}
});
Class<?> res = null;
try {
res = Class.forName(name, false, refcLoader);
} catch (ClassNotFoundException | LinkageError e) {
// Assume the class is not found
}
return (type == res);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 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
@ -23,7 +23,6 @@
* questions.
*/
package sun.reflect.misc;
import java.lang.reflect.Member;
@ -31,16 +30,13 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import jdk.internal.reflect.Reflection;
import sun.security.util.SecurityConstants;
public final class ReflectUtil {
private ReflectUtil() {
}
public static Class<?> forName(String name)
throws ClassNotFoundException {
checkPackageAccess(name);
public static Class<?> forName(String name) throws ClassNotFoundException {
return Class.forName(name);
}
@ -73,182 +69,48 @@ public final class ReflectUtil {
}
/**
* Does a conservative approximation of member access check. Use this if
* you don't have an actual 'userland' caller Class/ClassLoader available.
* This might be more restrictive than a precise member access check where
* you have a caller, but should never allow a member access that is
* forbidden.
*
* @param m the {@code Member} about to be accessed
* Does nothing.
*/
public static void conservativeCheckMemberAccess(Member m) throws SecurityException{
@SuppressWarnings("removal")
final SecurityManager sm = System.getSecurityManager();
if (sm == null)
return;
// Check for package access on the declaring class.
//
// In addition, unless the member and the declaring class are both
// public check for access declared member permissions.
//
// This is done regardless of ClassLoader relations between the {@code
// Member m} and any potential caller.
final Class<?> declaringClass = m.getDeclaringClass();
privateCheckPackageAccess(sm, declaringClass);
if (Modifier.isPublic(m.getModifiers()) &&
Modifier.isPublic(declaringClass.getModifiers()))
return;
// Check for declared member access.
sm.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
public static void conservativeCheckMemberAccess(Member m) {
}
/**
* Checks package access on the given class.
*
* If it is a {@link Proxy#isProxyClass(java.lang.Class)} that implements
* a non-public interface (i.e. may be in a non-restricted package),
* also check the package access on the proxy interfaces.
* Does nothing.
*/
public static void checkPackageAccess(Class<?> clazz) {
@SuppressWarnings("removal")
SecurityManager s = System.getSecurityManager();
if (s != null) {
privateCheckPackageAccess(s, clazz);
}
}
/**
* NOTE: should only be called if a SecurityManager is installed
*/
private static void privateCheckPackageAccess(@SuppressWarnings("removal") SecurityManager s, Class<?> clazz) {
String pkg = clazz.getPackageName();
if (!pkg.isEmpty()) {
s.checkPackageAccess(pkg);
}
if (isNonPublicProxyClass(clazz)) {
privateCheckProxyPackageAccess(s, clazz);
}
}
/**
* Checks package access on the given classname.
* This method is typically called when the Class instance is not
* available and the caller attempts to load a class on behalf
* the true caller (application).
* Does nothing
*/
public static void checkPackageAccess(String name) {
@SuppressWarnings("removal")
SecurityManager s = System.getSecurityManager();
if (s != null) {
String cname = name.replace('/', '.');
if (cname.startsWith("[")) {
int b = cname.lastIndexOf('[') + 2;
if (b > 1 && b < cname.length()) {
cname = cname.substring(b);
}
}
int i = cname.lastIndexOf('.');
if (i != -1) {
s.checkPackageAccess(cname.substring(0, i));
}
}
}
/**
* Returns true.
*/
public static boolean isPackageAccessible(Class<?> clazz) {
try {
checkPackageAccess(clazz);
} catch (SecurityException e) {
return false;
}
return true;
}
// Returns true if p is an ancestor of cl i.e. class loader 'p' can
// be found in the cl's delegation chain
private static boolean isAncestor(ClassLoader p, ClassLoader cl) {
ClassLoader acl = cl;
do {
acl = acl.getParent();
if (p == acl) {
return true;
}
} while (acl != null);
/**
* Returns false.
*/
public static boolean needsPackageAccessCheck(ClassLoader from, ClassLoader to) {
return false;
}
/**
* Returns true if package access check is needed for reflective
* access from a class loader 'from' to classes or members in
* a class defined by class loader 'to'. This method returns true
* if 'from' is not the same as or an ancestor of 'to'. All code
* in a system domain are granted with all permission and so this
* method returns false if 'from' class loader is a class loader
* loading system classes. On the other hand, if a class loader
* attempts to access system domain classes, it requires package
* access check and this method will return true.
*/
public static boolean needsPackageAccessCheck(ClassLoader from, ClassLoader to) {
if (from == null || from == to)
return false;
if (to == null)
return true;
return !isAncestor(from, to);
}
/**
* Check package access on the proxy interfaces that the given proxy class
* implements.
*
* @param clazz Proxy class object
* Does nothing
*/
public static void checkProxyPackageAccess(Class<?> clazz) {
@SuppressWarnings("removal")
SecurityManager s = System.getSecurityManager();
if (s != null) {
privateCheckProxyPackageAccess(s, clazz);
}
}
/**
* NOTE: should only be called if a SecurityManager is installed
*/
private static void privateCheckProxyPackageAccess(@SuppressWarnings("removal") SecurityManager s, Class<?> clazz) {
// check proxy interfaces if the given class is a proxy class
if (Proxy.isProxyClass(clazz)) {
for (Class<?> intf : clazz.getInterfaces()) {
privateCheckPackageAccess(s, intf);
}
}
}
/**
* Access check on the interfaces that a proxy class implements and throw
* {@code SecurityException} if it accesses a restricted package from
* the caller's class loader.
*
* @param ccl the caller's class loader
* @param interfaces the list of interfaces that a proxy class implements
* Does nothing.
*/
public static void checkProxyPackageAccess(ClassLoader ccl,
Class<?>... interfaces)
{
@SuppressWarnings("removal")
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
for (Class<?> intf : interfaces) {
ClassLoader cl = intf.getClassLoader();
if (needsPackageAccessCheck(ccl, cl)) {
privateCheckPackageAccess(sm, intf);
}
}
}
Class<?>... interfaces) {
}
// Note that bytecode instrumentation tools may exclude 'sun.*'