1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 /*
17 * Check access to fields and methods.
18 */
19 #include "Dalvik.h"
20
21 /*
22 * Return the #of initial characters that match.
23 */
strcmpCount(const char * str1,const char * str2)24 static int strcmpCount(const char* str1, const char* str2)
25 {
26 int count = 0;
27
28 while (true) {
29 char ch = str1[count];
30 if (ch == '\0' || ch != str2[count])
31 return count;
32 count++;
33 }
34 }
35
36 /*
37 * Returns "true" if the two classes are in the same runtime package.
38 */
dvmInSamePackage(const ClassObject * class1,const ClassObject * class2)39 bool dvmInSamePackage(const ClassObject* class1, const ClassObject* class2)
40 {
41 /* quick test for intra-class access */
42 if (class1 == class2)
43 return true;
44
45 /* class loaders must match */
46 if (class1->classLoader != class2->classLoader)
47 return false;
48
49 /*
50 * Switch array classes to their element types. Arrays receive the
51 * class loader of the underlying element type. The point of doing
52 * this is to get the un-decorated class name, without all the
53 * "[[L...;" stuff.
54 */
55 if (dvmIsArrayClass(class1))
56 class1 = class1->elementClass;
57 if (dvmIsArrayClass(class2))
58 class2 = class2->elementClass;
59
60 /* check again */
61 if (class1 == class2)
62 return true;
63
64 /*
65 * We have two classes with different names. Compare them and see
66 * if they match up through the final '/'.
67 *
68 * Ljava/lang/Object; + Ljava/lang/Class; --> true
69 * LFoo; + LBar; --> true
70 * Ljava/lang/Object; + Ljava/io/File; --> false
71 * Ljava/lang/Object; + Ljava/lang/reflect/Method; --> false
72 */
73 int commonLen;
74
75 commonLen = strcmpCount(class1->descriptor, class2->descriptor);
76 if (strchr(class1->descriptor + commonLen, '/') != NULL ||
77 strchr(class2->descriptor + commonLen, '/') != NULL)
78 {
79 return false;
80 }
81
82 return true;
83 }
84
85 /*
86 * Validate method/field access.
87 */
checkAccess(const ClassObject * accessFrom,const ClassObject * accessTo,u4 accessFlags)88 static bool checkAccess(const ClassObject* accessFrom,
89 const ClassObject* accessTo, u4 accessFlags)
90 {
91 /* quick accept for public access */
92 if (accessFlags & ACC_PUBLIC)
93 return true;
94
95 /* quick accept for access from same class */
96 if (accessFrom == accessTo)
97 return true;
98
99 /* quick reject for private access from another class */
100 if (accessFlags & ACC_PRIVATE)
101 return false;
102
103 /*
104 * Semi-quick test for protected access from a sub-class, which may or
105 * may not be in the same package.
106 */
107 if (accessFlags & ACC_PROTECTED)
108 if (dvmIsSubClass(accessFrom, accessTo))
109 return true;
110
111 /*
112 * Allow protected and private access from other classes in the same
113 * package.
114 */
115 return dvmInSamePackage(accessFrom, accessTo);
116 }
117
118 /*
119 * Determine whether the "accessFrom" class is allowed to get at "clazz".
120 *
121 * It's allowed if "clazz" is public or is in the same package. (Only
122 * inner classes can be marked "private" or "protected", so we don't need
123 * to check for it here.)
124 */
dvmCheckClassAccess(const ClassObject * accessFrom,const ClassObject * clazz)125 bool dvmCheckClassAccess(const ClassObject* accessFrom,
126 const ClassObject* clazz)
127 {
128 if (dvmIsPublicClass(clazz))
129 return true;
130 return dvmInSamePackage(accessFrom, clazz);
131 }
132
133 /*
134 * Determine whether the "accessFrom" class is allowed to get at "method".
135 */
dvmCheckMethodAccess(const ClassObject * accessFrom,const Method * method)136 bool dvmCheckMethodAccess(const ClassObject* accessFrom, const Method* method)
137 {
138 return checkAccess(accessFrom, method->clazz, method->accessFlags);
139 }
140
141 /*
142 * Determine whether the "accessFrom" class is allowed to get at "field".
143 */
dvmCheckFieldAccess(const ClassObject * accessFrom,const Field * field)144 bool dvmCheckFieldAccess(const ClassObject* accessFrom, const Field* field)
145 {
146 //LOGI("CHECK ACCESS from '%s' to field '%s' (in %s) flags=%#x",
147 // accessFrom->descriptor, field->name,
148 // field->clazz->descriptor, field->accessFlags);
149 return checkAccess(accessFrom, field->clazz, field->accessFlags);
150 }
151