Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/invoke/util/VerifyAccess.java
38918 views
1
/*
2
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.invoke.util;
27
28
import java.lang.reflect.Modifier;
29
import static java.lang.reflect.Modifier.*;
30
import sun.reflect.Reflection;
31
32
/**
33
* This class centralizes information about the JVM's linkage access control.
34
* @author jrose
35
*/
36
public class VerifyAccess {
37
38
private VerifyAccess() { } // cannot instantiate
39
40
private static final int PACKAGE_ONLY = 0;
41
private static final int PACKAGE_ALLOWED = java.lang.invoke.MethodHandles.Lookup.PACKAGE;
42
private static final int PROTECTED_OR_PACKAGE_ALLOWED = (PACKAGE_ALLOWED|PROTECTED);
43
private static final int ALL_ACCESS_MODES = (PUBLIC|PRIVATE|PROTECTED|PACKAGE_ONLY);
44
private static final boolean ALLOW_NESTMATE_ACCESS = false;
45
46
/**
47
* Evaluate the JVM linkage rules for access to the given method
48
* on behalf of a caller class which proposes to perform the access.
49
* Return true if the caller class has privileges to invoke a method
50
* or access a field with the given properties.
51
* This requires an accessibility check of the referencing class,
52
* plus an accessibility check of the member within the class,
53
* which depends on the member's modifier flags.
54
* <p>
55
* The relevant properties include the defining class ({@code defc})
56
* of the member, and its modifier flags ({@code mods}).
57
* Also relevant is the class used to make the initial symbolic reference
58
* to the member ({@code refc}). If this latter class is not distinguished,
59
* the defining class should be passed for both arguments ({@code defc == refc}).
60
* <h3>JVM Specification, 5.4.4 "Access Control"</h3>
61
* A field or method R is accessible to a class or interface D if
62
* and only if any of the following conditions is true:<ul>
63
* <li>R is public.
64
* <li>R is protected and is declared in a class C, and D is either
65
* a subclass of C or C itself. Furthermore, if R is not
66
* static, then the symbolic reference to R must contain a
67
* symbolic reference to a class T, such that T is either a
68
* subclass of D, a superclass of D or D itself.
69
* <li>R is either protected or has default access (that is,
70
* neither public nor protected nor private), and is declared
71
* by a class in the same runtime package as D.
72
* <li>R is private and is declared in D.
73
* </ul>
74
* This discussion of access control omits a related restriction
75
* on the target of a protected field access or method invocation
76
* (the target must be of class D or a subtype of D). That
77
* requirement is checked as part of the verification process
78
* (5.4.1); it is not part of link-time access control.
79
* @param refc the class used in the symbolic reference to the proposed member
80
* @param defc the class in which the proposed member is actually defined
81
* @param mods modifier flags for the proposed member
82
* @param lookupClass the class for which the access check is being made
83
* @return true iff the the accessing class can access such a member
84
*/
85
public static boolean isMemberAccessible(Class<?> refc, // symbolic ref class
86
Class<?> defc, // actual def class
87
int mods, // actual member mods
88
Class<?> lookupClass,
89
int allowedModes) {
90
if (allowedModes == 0) return false;
91
assert((allowedModes & PUBLIC) != 0 &&
92
(allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED)) == 0);
93
// The symbolic reference class (refc) must always be fully verified.
94
if (!isClassAccessible(refc, lookupClass, allowedModes)) {
95
return false;
96
}
97
// Usually refc and defc are the same, but verify defc also in case they differ.
98
if (defc == lookupClass &&
99
(allowedModes & PRIVATE) != 0)
100
return true; // easy check; all self-access is OK
101
switch (mods & ALL_ACCESS_MODES) {
102
case PUBLIC:
103
return true; // already checked above
104
case PROTECTED:
105
assert !defc.isInterface(); // protected members aren't allowed in interfaces
106
if ((allowedModes & PROTECTED_OR_PACKAGE_ALLOWED) != 0 &&
107
isSamePackage(defc, lookupClass))
108
return true;
109
if ((allowedModes & PROTECTED) == 0)
110
return false;
111
// Protected members are accessible by subclasses, which does not include interfaces.
112
// Interfaces are types, not classes. They should not have access to
113
// protected members in j.l.Object, even though it is their superclass.
114
if ((mods & STATIC) != 0 &&
115
!isRelatedClass(refc, lookupClass))
116
return false;
117
if ((allowedModes & PROTECTED) != 0 &&
118
isSubClass(lookupClass, defc))
119
return true;
120
return false;
121
case PACKAGE_ONLY: // That is, zero. Unmarked member is package-only access.
122
assert !defc.isInterface(); // package-private members aren't allowed in interfaces
123
return ((allowedModes & PACKAGE_ALLOWED) != 0 &&
124
isSamePackage(defc, lookupClass));
125
case PRIVATE:
126
// Loosened rules for privates follows access rules for inner classes.
127
return (ALLOW_NESTMATE_ACCESS &&
128
(allowedModes & PRIVATE) != 0 &&
129
isSamePackageMember(defc, lookupClass));
130
default:
131
throw new IllegalArgumentException("bad modifiers: "+Modifier.toString(mods));
132
}
133
}
134
135
static boolean isRelatedClass(Class<?> refc, Class<?> lookupClass) {
136
return (refc == lookupClass ||
137
isSubClass(refc, lookupClass) ||
138
isSubClass(lookupClass, refc));
139
}
140
141
static boolean isSubClass(Class<?> lookupClass, Class<?> defc) {
142
return defc.isAssignableFrom(lookupClass) &&
143
!lookupClass.isInterface(); // interfaces are types, not classes.
144
}
145
146
static int getClassModifiers(Class<?> c) {
147
// This would return the mask stored by javac for the source-level modifiers.
148
// return c.getModifiers();
149
// But what we need for JVM access checks are the actual bits from the class header.
150
// ...But arrays and primitives are synthesized with their own odd flags:
151
if (c.isArray() || c.isPrimitive())
152
return c.getModifiers();
153
return Reflection.getClassAccessFlags(c);
154
}
155
156
/**
157
* Evaluate the JVM linkage rules for access to the given class on behalf of caller.
158
* <h3>JVM Specification, 5.4.4 "Access Control"</h3>
159
* A class or interface C is accessible to a class or interface D
160
* if and only if either of the following conditions are true:<ul>
161
* <li>C is public.
162
* <li>C and D are members of the same runtime package.
163
* </ul>
164
* @param refc the symbolic reference class to which access is being checked (C)
165
* @param lookupClass the class performing the lookup (D)
166
*/
167
public static boolean isClassAccessible(Class<?> refc, Class<?> lookupClass,
168
int allowedModes) {
169
if (allowedModes == 0) return false;
170
assert((allowedModes & PUBLIC) != 0 &&
171
(allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED)) == 0);
172
int mods = getClassModifiers(refc);
173
if (isPublic(mods))
174
return true;
175
if ((allowedModes & PACKAGE_ALLOWED) != 0 &&
176
isSamePackage(lookupClass, refc))
177
return true;
178
return false;
179
}
180
181
/**
182
* Decide if the given method type, attributed to a member or symbolic
183
* reference of a given reference class, is really visible to that class.
184
* @param type the supposed type of a member or symbolic reference of refc
185
* @param refc the class attempting to make the reference
186
*/
187
public static boolean isTypeVisible(Class<?> type, Class<?> refc) {
188
if (type == refc) {
189
return true; // easy check
190
}
191
while (type.isArray()) type = type.getComponentType();
192
if (type.isPrimitive() || type == Object.class) {
193
return true;
194
}
195
ClassLoader typeLoader = type.getClassLoader();
196
ClassLoader refcLoader = refc.getClassLoader();
197
if (typeLoader == refcLoader) {
198
return true;
199
}
200
if (refcLoader == null && typeLoader != null) {
201
return false;
202
}
203
if (typeLoader == null && type.getName().startsWith("java.")) {
204
// Note: The API for actually loading classes, ClassLoader.defineClass,
205
// guarantees that classes with names beginning "java." cannot be aliased,
206
// because class loaders cannot load them directly.
207
return true;
208
}
209
210
// Do it the hard way: Look up the type name from the refc loader.
211
//
212
// Force the refc loader to report and commit to a particular binding for this type name (type.getName()).
213
//
214
// In principle, this query might force the loader to load some unrelated class,
215
// which would cause this query to fail (and the original caller to give up).
216
// This would be wasted effort, but it is expected to be very rare, occurring
217
// only when an attacker is attempting to create a type alias.
218
// In the normal case, one class loader will simply delegate to the other,
219
// and the same type will be visible through both, with no extra loading.
220
//
221
// It is important to go through Class.forName instead of ClassLoader.loadClass
222
// because Class.forName goes through the JVM system dictionary, which records
223
// the class lookup once for all. This means that even if a not-well-behaved class loader
224
// would "change its mind" about the meaning of the name, the Class.forName request
225
// will use the result cached in the JVM system dictionary. Note that the JVM system dictionary
226
// will record the first successful result. Unsuccessful results are not stored.
227
//
228
// We use doPrivileged in order to allow an unprivileged caller to ask an arbitrary
229
// class loader about the binding of the proposed name (type.getName()).
230
// The looked up type ("res") is compared for equality against the proposed
231
// type ("type") and then is discarded. Thus, the worst that can happen to
232
// the "child" class loader is that it is bothered to load and report a class
233
// that differs from "type"; this happens once due to JVM system dictionary
234
// memoization. And the caller never gets to look at the alternate type binding
235
// ("res"), whether it exists or not.
236
final String name = type.getName();
237
Class<?> res = java.security.AccessController.doPrivileged(
238
new java.security.PrivilegedAction<Class>() {
239
public Class<?> run() {
240
try {
241
return Class.forName(name, false, refcLoader);
242
} catch (ClassNotFoundException | LinkageError e) {
243
return null; // Assume the class is not found
244
}
245
}
246
});
247
return (type == res);
248
}
249
250
/**
251
* Decide if the given method type, attributed to a member or symbolic
252
* reference of a given reference class, is really visible to that class.
253
* @param type the supposed type of a member or symbolic reference of refc
254
* @param refc the class attempting to make the reference
255
*/
256
public static boolean isTypeVisible(java.lang.invoke.MethodType type, Class<?> refc) {
257
for (int n = -1, max = type.parameterCount(); n < max; n++) {
258
Class<?> ptype = (n < 0 ? type.returnType() : type.parameterType(n));
259
if (!isTypeVisible(ptype, refc))
260
return false;
261
}
262
return true;
263
}
264
265
/**
266
* Test if two classes have the same class loader and package qualifier.
267
* @param class1 a class
268
* @param class2 another class
269
* @return whether they are in the same package
270
*/
271
public static boolean isSamePackage(Class<?> class1, Class<?> class2) {
272
assert(!class1.isArray() && !class2.isArray());
273
if (class1 == class2)
274
return true;
275
if (class1.getClassLoader() != class2.getClassLoader())
276
return false;
277
String name1 = class1.getName(), name2 = class2.getName();
278
int dot = name1.lastIndexOf('.');
279
if (dot != name2.lastIndexOf('.'))
280
return false;
281
for (int i = 0; i < dot; i++) {
282
if (name1.charAt(i) != name2.charAt(i))
283
return false;
284
}
285
return true;
286
}
287
288
/** Return the package name for this class.
289
*/
290
public static String getPackageName(Class<?> cls) {
291
assert(!cls.isArray());
292
String name = cls.getName();
293
int dot = name.lastIndexOf('.');
294
if (dot < 0) return "";
295
return name.substring(0, dot);
296
}
297
298
/**
299
* Test if two classes are defined as part of the same package member (top-level class).
300
* If this is true, they can share private access with each other.
301
* @param class1 a class
302
* @param class2 another class
303
* @return whether they are identical or nested together
304
*/
305
public static boolean isSamePackageMember(Class<?> class1, Class<?> class2) {
306
if (class1 == class2)
307
return true;
308
if (!isSamePackage(class1, class2))
309
return false;
310
if (getOutermostEnclosingClass(class1) != getOutermostEnclosingClass(class2))
311
return false;
312
return true;
313
}
314
315
private static Class<?> getOutermostEnclosingClass(Class<?> c) {
316
Class<?> pkgmem = c;
317
for (Class<?> enc = c; (enc = enc.getEnclosingClass()) != null; )
318
pkgmem = enc;
319
return pkgmem;
320
}
321
322
private static boolean loadersAreRelated(ClassLoader loader1, ClassLoader loader2,
323
boolean loader1MustBeParent) {
324
if (loader1 == loader2 || loader1 == null
325
|| (loader2 == null && !loader1MustBeParent)) {
326
return true;
327
}
328
for (ClassLoader scan2 = loader2;
329
scan2 != null; scan2 = scan2.getParent()) {
330
if (scan2 == loader1) return true;
331
}
332
if (loader1MustBeParent) return false;
333
// see if loader2 is a parent of loader1:
334
for (ClassLoader scan1 = loader1;
335
scan1 != null; scan1 = scan1.getParent()) {
336
if (scan1 == loader2) return true;
337
}
338
return false;
339
}
340
341
/**
342
* Is the class loader of parentClass identical to, or an ancestor of,
343
* the class loader of childClass?
344
* @param parentClass a class
345
* @param childClass another class, which may be a descendent of the first class
346
* @return whether parentClass precedes or equals childClass in class loader order
347
*/
348
public static boolean classLoaderIsAncestor(Class<?> parentClass, Class<?> childClass) {
349
return loadersAreRelated(parentClass.getClassLoader(), childClass.getClassLoader(), true);
350
}
351
}
352
353