• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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