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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 144 bool dvmCheckFieldAccess(const ClassObject* accessFrom, const Field* field) 145 { 146 //ALOGI("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