24 */ |
24 */ |
25 |
25 |
26 package sun.dyn.util; |
26 package sun.dyn.util; |
27 |
27 |
28 import java.dyn.LinkagePermission; |
28 import java.dyn.LinkagePermission; |
29 import java.dyn.MethodHandles.Lookup; |
|
30 import java.dyn.NoAccessException; |
29 import java.dyn.NoAccessException; |
31 import java.lang.reflect.Modifier; |
30 import java.lang.reflect.Modifier; |
32 import sun.dyn.MemberName; |
31 import sun.dyn.MemberName; |
33 import sun.dyn.MethodHandleImpl; |
32 import sun.dyn.MethodHandleImpl; |
34 import sun.dyn.empty.Empty; |
33 import sun.dyn.empty.Empty; |
|
34 import static java.lang.reflect.Modifier.*; |
35 |
35 |
36 /** |
36 /** |
37 * This class centralizes information about the JVM's linkage access control. |
37 * This class centralizes information about the JVM's linkage access control. |
38 * @author jrose |
38 * @author jrose |
39 */ |
39 */ |
40 public class VerifyAccess { |
40 public class VerifyAccess { |
41 |
41 |
42 private VerifyAccess() { } // cannot instantiate |
42 private VerifyAccess() { } // cannot instantiate |
43 |
43 |
44 /** |
44 private static final int PACKAGE_ONLY = 0; |
45 * Evaluate the JVM linkage rules for access to the given method on behalf of caller. |
45 private static final int ALL_ACCESS_MODES = (PUBLIC|PRIVATE|PROTECTED|PACKAGE_ONLY); |
46 * Return non-null if and only if the given accessing class has at least partial |
46 |
47 * privileges to invoke the given method. The return value {@code Object.class} |
47 /** |
48 * denotes unlimited privileges. |
48 * Evaluate the JVM linkage rules for access to the given method |
|
49 * on behalf of a caller class which proposes to perform the access. |
|
50 * Return true if the caller class has privileges to invoke a method |
|
51 * or access a field with the given properties. |
|
52 * This requires an accessibility check of the referencing class, |
|
53 * plus an accessibility check of the member within the class, |
|
54 * which depends on the member's modifier flags. |
49 * <p> |
55 * <p> |
50 * Some circumstances require an additional check on the |
56 * The relevant properties include the defining class ({@code defc}) |
51 * leading parameter (the receiver) of the method, if it is non-static. |
57 * of the member, and its modifier flags ({@code mods}). |
52 * In the case of {@code invokespecial} ({@code isSpecialInvoke} is true), |
58 * Also relevant is the class used to make the initial symbolic reference |
53 * the leading parameter must be the accessing class or a subclass. |
59 * to the member ({@code refc}). If this latter class is not distinguished, |
54 * In the case of a call to a {@code protected} method outside the same |
60 * the defining class should be passed for both arguments ({@code defc == refc}). |
55 * package, the same constraint applies. |
61 * <h3>JVM Specification, 5.4.4 "Access Control"</h3> |
56 * @param m the proposed callee |
62 * A field or method R is accessible to a class or interface D if |
57 * @param isSpecialInvoke if true, a non-static method m is checked as if for {@code invokespecial} |
63 * and only if any of the following conditions is true:<ul> |
|
64 * <li>R is public. |
|
65 * <li>R is protected and is declared in a class C, and D is either |
|
66 * a subclass of C or C itself. Furthermore, if R is not |
|
67 * static, then the symbolic reference to R must contain a |
|
68 * symbolic reference to a class T, such that T is either a |
|
69 * subclass of D, a superclass of D or D itself. |
|
70 * <li>R is either protected or has default access (that is, |
|
71 * neither public nor protected nor private), and is declared |
|
72 * by a class in the same runtime package as D. |
|
73 * <li>R is private and is declared in D. |
|
74 * </ul> |
|
75 * This discussion of access control omits a related restriction |
|
76 * on the target of a protected field access or method invocation |
|
77 * (the target must be of class D or a subtype of D). That |
|
78 * requirement is checked as part of the verification process |
|
79 * (5.4.1); it is not part of link-time access control. |
|
80 * @param refc the class used in the symbolic reference to the proposed member |
|
81 * @param defc the class in which the proposed member is actually defined |
|
82 * @param mods modifier flags for the proposed member |
58 * @param lookupClass the class for which the access check is being made |
83 * @param lookupClass the class for which the access check is being made |
59 * @return null if the method is not accessible, else a receiver type constraint, else {@code Object.class} |
84 * @return true iff the the accessing class can access such a member |
60 */ |
85 */ |
61 public static Class<?> isAccessible(Class<?> defc, int mods, |
86 public static boolean isMemberAccessible(Class<?> refc, // symbolic ref class |
62 Class<?> lookupClass, boolean isSpecialInvoke) { |
87 Class<?> defc, // actual def class |
63 if (!isAccessible(defc, lookupClass)) |
88 int mods, // actual member mods |
64 return null; |
89 Class<?> lookupClass) { |
65 Class<?> constraint = Object.class; |
90 // Usually refc and defc are the same, but if they differ, verify them both. |
66 if (isSpecialInvoke && !Modifier.isStatic(mods)) { |
91 if (refc != defc) { |
67 constraint = lookupClass; |
92 if (!isClassAccessible(refc, lookupClass)) { |
68 } |
93 // Note that defc is verified in the switch below. |
69 if (Modifier.isPublic(mods)) |
94 return false; |
70 return constraint; |
95 } |
71 if (Modifier.isPrivate(mods)) |
96 if ((mods & (ALL_ACCESS_MODES|STATIC)) == (PROTECTED|STATIC)) { |
72 return isSamePackageMember(defc, lookupClass) ? constraint : null; |
97 // Apply the special rules for refc here. |
73 if (isSamePackage(defc, lookupClass)) |
98 if (!isRelatedClass(refc, lookupClass)) |
74 return constraint; |
99 return isSamePackage(defc, lookupClass); |
75 if (Modifier.isProtected(mods) && defc.isAssignableFrom(lookupClass)) |
100 // If refc == defc, the call to isPublicSuperClass will do |
76 return constraint; |
101 // the whole job, since in that case refc (as defc) will be |
77 // else it is private or package scoped, and not close enough |
102 // a superclass of the lookup class. |
78 return null; |
103 } |
|
104 } |
|
105 switch (mods & ALL_ACCESS_MODES) { |
|
106 case PUBLIC: |
|
107 if (refc != defc) return true; // already checked above |
|
108 return isClassAccessible(refc, lookupClass); |
|
109 case PROTECTED: |
|
110 return isSamePackage(defc, lookupClass) || isPublicSuperClass(defc, lookupClass); |
|
111 case PACKAGE_ONLY: |
|
112 return isSamePackage(defc, lookupClass); |
|
113 case PRIVATE: |
|
114 // Loosened rules for privates follows access rules for inner classes. |
|
115 return isSamePackageMember(defc, lookupClass); |
|
116 default: |
|
117 throw new IllegalArgumentException("bad modifiers: "+Modifier.toString(mods)); |
|
118 } |
|
119 } |
|
120 |
|
121 static boolean isRelatedClass(Class<?> refc, Class<?> lookupClass) { |
|
122 return (refc == lookupClass || |
|
123 refc.isAssignableFrom(lookupClass) || |
|
124 lookupClass.isAssignableFrom(refc)); |
|
125 } |
|
126 |
|
127 static boolean isPublicSuperClass(Class<?> defc, Class<?> lookupClass) { |
|
128 return isPublic(defc.getModifiers()) && defc.isAssignableFrom(lookupClass); |
79 } |
129 } |
80 |
130 |
81 /** |
131 /** |
82 * Evaluate the JVM linkage rules for access to the given class on behalf of caller. |
132 * Evaluate the JVM linkage rules for access to the given class on behalf of caller. |
83 */ |
133 * <h3>JVM Specification, 5.4.4 "Access Control"</h3> |
84 public static boolean isAccessible(Class<?> refc, Class<?> lookupClass) { |
134 * A class or interface C is accessible to a class or interface D |
|
135 * if and only if either of the following conditions are true:<ul> |
|
136 * <li>C is public. |
|
137 * <li>C and D are members of the same runtime package. |
|
138 * </ul> |
|
139 */ |
|
140 public static boolean isClassAccessible(Class<?> refc, Class<?> lookupClass) { |
85 int mods = refc.getModifiers(); |
141 int mods = refc.getModifiers(); |
86 if (Modifier.isPublic(mods)) |
142 if (isPublic(mods)) |
87 return true; |
143 return true; |
88 if (isSamePackage(lookupClass, refc)) |
144 if (isSamePackage(lookupClass, refc)) |
89 return true; |
145 return true; |
90 return false; |
146 return false; |
91 } |
147 } |
168 SecurityManager security = System.getSecurityManager(); |
224 SecurityManager security = System.getSecurityManager(); |
169 if (security == null) return; // open season |
225 if (security == null) return; // open season |
170 if (isSamePackage(requestingClass, subjectClass)) return; |
226 if (isSamePackage(requestingClass, subjectClass)) return; |
171 security.checkPermission(new LinkagePermission(permissionName, requestingClass)); |
227 security.checkPermission(new LinkagePermission(permissionName, requestingClass)); |
172 } |
228 } |
173 |
|
174 private static RuntimeException checkNameFailed(MemberName self, Lookup lookup, String comment) { |
|
175 return new NoAccessException("cannot access from "+lookup+": "+self.toString()+": "+comment); |
|
176 } |
|
177 public static void checkName(MemberName self, Lookup lookup) { |
|
178 Class<?> lc = lookup.lookupClass(); |
|
179 if (lc == null) return; // lookup is privileged |
|
180 Class<?> dc = self.getDeclaringClass(); |
|
181 int samepkg = 0; |
|
182 // First check the containing class. Must be public or local. |
|
183 if (!Modifier.isPublic(dc.getModifiers())) { |
|
184 if (lc != Empty.class) |
|
185 samepkg = (isSamePackage(dc, lc) ? 1 : -1); |
|
186 if (samepkg <= 0) |
|
187 throw checkNameFailed(self, lookup, "class is not public"); |
|
188 } |
|
189 // At this point dc is known to be accessible. |
|
190 if (self.isPublic()) { |
|
191 return; |
|
192 } else if (lc == Empty.class) { |
|
193 throw checkNameFailed(self, lookup, "member is not public"); |
|
194 } else if (self.isProtected()) { |
|
195 if (dc.isAssignableFrom(lc)) return; |
|
196 } else if (self.isPrivate()) { |
|
197 if (isSamePackageMember(dc, lc)) return; |
|
198 throw checkNameFailed(self, lookup, "member is private"); |
|
199 } |
|
200 // Fall-through handles the package-private and protected cases. |
|
201 if (samepkg == 0) |
|
202 samepkg = (isSamePackage(dc, lc) ? 1 : -1); |
|
203 if (samepkg > 0) return; |
|
204 throw checkNameFailed(self, lookup, |
|
205 self.isProtected() ? "member is protected" : "member is private to package"); |
|
206 } |
|
207 } |
229 } |