1 /* 2 * Copyright (C) 2016 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 #define LOG_TAG "VehiclePropertyAccessControl" 18 #include <string> 19 #include <stdint.h> 20 #include <sys/types.h> 21 #include <IVehicleNetwork.h> 22 #include "VehiclePropertyAccessControl.h" 23 #include <hardware/vehicle.h> 24 #include <private/android_filesystem_config.h> 25 #include <vehicle-internal.h> 26 27 //#define DBG_EVENT 28 //#define DBG_VERBOSE 29 #ifdef DBG_EVENT 30 #define EVENT_LOG(x...) ALOGD(x) 31 #else 32 #define EVENT_LOG(x...) 33 #endif 34 #ifdef DBG_VERBOSE 35 #define LOG_VERBOSE(x...) ALOGD(x) 36 #else 37 #define LOG_VERBOSE(x...) 38 #endif 39 40 41 namespace android { 42 43 VehiclePropertyAccessControl::VehiclePropertyAccessControl() { 44 } 45 46 VehiclePropertyAccessControl::~VehiclePropertyAccessControl() { 47 int index; 48 int size; 49 50 for (auto& i: mVehicleAccessControlMap) { 51 delete(&i); 52 } 53 54 mVehicleAccessControlMap.clear(); 55 } 56 57 // Returns true if the given string, s, is a hex number that starts with 0x. 58 // Otherwise false is returned. 59 bool VehiclePropertyAccessControl::isHexNotation(std::string const& s) { 60 return s.compare(0, 2, "0x") == 0 61 && s.size() > 2 62 && s.find_first_not_of("0123456789abcdefABCDEF", 2) 63 == std::string::npos; 64 } 65 66 // Converts the string representation, access, to an integer form and store it 67 // in value. true is returned if the parameter, access, is "r", "w", "rw" or 68 // "wr". Otherwise false is returned. The parameters property and uid are 69 // only used for logging in the event that the string, access, was not 70 // recognized. 71 bool VehiclePropertyAccessControl::accessToInt(int32_t* const value, 72 const xmlChar* property, 73 const xmlChar* uid, 74 const xmlChar* access) { 75 if (!value || !property || !uid || !access) { 76 ALOGE("Internal Error\n"); 77 return false; 78 } 79 80 if (xmlStrcmp(access, (const xmlChar *)"r") == 0) { 81 *value = VEHICLE_PROP_ACCESS_READ; 82 } 83 else if (xmlStrcmp(access, (const xmlChar *)"w") == 0) { 84 *value = VEHICLE_PROP_ACCESS_WRITE; 85 } 86 else if ((xmlStrcmp(access, (const xmlChar *)"rw") == 0) 87 || (xmlStrcmp(access, (const xmlChar *)"wr") == 0)) { 88 *value = VEHICLE_PROP_ACCESS_READ_WRITE; 89 } 90 else { 91 ALOGE("Unknown access tag %s for UID %s in PROPERTY %s\n",access, uid, 92 property); 93 return false; 94 } 95 96 return true; 97 } 98 99 // Adds the property/uid pair to the mVehicleAccessControlMap map if the pair 100 // doesn't already exist. If the pair does exist, the access is updated. 101 bool VehiclePropertyAccessControl::updateOrCreate(int32_t uid, int32_t property, 102 int32_t access) { 103 // check if property exists 104 if (mVehicleAccessControlMap.count(property) == 0) { 105 std::map<int32_t, int32_t>* uid_access = 106 new std::map<int32_t, int32_t>(); 107 mVehicleAccessControlMap[property] = uid_access; 108 } 109 110 // Get the propertyAccessMap 111 std::map<int32_t, int32_t>* uidAccessMap = 112 mVehicleAccessControlMap[property]; 113 114 // Now check if uid exists 115 if (uidAccessMap->count(uid) == 0) { 116 (*uidAccessMap)[uid] = access; 117 // uid was not found 118 return false; 119 } 120 121 // The Property, Uid pair exist. So update the access 122 (*uidAccessMap)[uid] = access; 123 124 return true; 125 } 126 127 // Start parsing the xml file and populating the mVehicleAccessControlMap 128 // map. The parameter, a_node, must point to the first <PROPERTY> tag. 129 // true is returned if the parsing completed else false. 130 bool VehiclePropertyAccessControl::populate(xmlNode * a_node) { 131 xmlNode* cur_node = NULL; 132 xmlNode* child = NULL; 133 xmlChar* property = NULL; 134 xmlChar* property_value_str = NULL; 135 xmlChar* uid = NULL; 136 xmlChar* uid_value_str = NULL; 137 xmlChar* access = NULL; 138 int32_t property_value; 139 int32_t uid_value; 140 int32_t access_value; 141 142 if (!a_node) { 143 ALOGE("Internal Error"); 144 return false; 145 } 146 147 // Loop over all the PROPERTY tags 148 for (cur_node = a_node; cur_node; cur_node = cur_node->next) { 149 if ((xmlStrcmp(cur_node->name, (const xmlChar *)"PROPERTY") == 0) && 150 (cur_node->type == XML_ELEMENT_NODE)) { 151 // Free the old property tag 152 xmlFree(property); 153 // get new property tag name attribute 154 property = xmlGetProp(cur_node, (const xmlChar *)"name"); 155 if (!property) { 156 ALOGE("PROPERTY given without name attribute"); 157 continue; 158 } 159 160 // get new property tag value attribute 161 property_value_str = xmlGetProp(cur_node, (const xmlChar*)"value"); 162 if (!property_value_str) { 163 ALOGE("PROPERTY given without value attribute"); 164 continue; 165 } 166 167 std::string tmp_str((const char*)property_value_str); 168 if (isHexNotation(tmp_str)) { 169 property_value = std::stoul(tmp_str, nullptr, 16); 170 } else { 171 property_value = std::stoul(tmp_str, nullptr, 10); 172 } 173 174 // Loop over all UID tags 175 for (child = cur_node->children; child; child = child->next) { 176 if ((xmlStrcmp(child->name, (const xmlChar*)"UID")==0) && 177 (child->type == XML_ELEMENT_NODE)) { 178 if (property != NULL) { 179 // Free the old uid tag 180 xmlFree(uid); 181 // Free the old access tag 182 xmlFree(access); 183 // get new uid tag 184 uid = xmlGetProp(child, (const xmlChar*)"name"); 185 // get new uid tag 186 uid_value_str = xmlGetProp(child, 187 (const xmlChar*)"value"); 188 // get new access tag 189 access = xmlGetProp(child, (const xmlChar *)"access"); 190 191 if (uid == NULL) { 192 ALOGE( 193 "UID tag for property %s given without name attribute\n", 194 property); 195 } else if (uid_value_str == NULL) { 196 ALOGE( 197 "UID tag for property %s given without value attribute\n", 198 property); 199 } else if (access == NULL) { 200 ALOGE( 201 "UID tag for property %s given without access attribute\n", 202 property); 203 } else { 204 std::string tmp_str((const char *)uid_value_str); 205 if (isHexNotation(tmp_str)) { 206 uid_value = std::stoul(tmp_str, nullptr, 16); 207 } else { 208 uid_value = std::stoul(tmp_str, nullptr, 10); 209 } 210 211 bool re1 = accessToInt(&access_value, property, uid, 212 access); 213 if (re1) { 214 if (!updateOrCreate(uid_value, property_value, 215 access_value)) { 216 LOG_VERBOSE( 217 "Property %08x was added: uid=%d access=%d\n", 218 property_value, uid_value, access_value); 219 } else { 220 LOG_VERBOSE("Property %08x was updated: uid=%d access=%d\n", 221 property_value, uid_value, access_value); 222 } 223 } 224 } 225 } 226 } 227 } 228 } 229 } 230 231 xmlFree(property); 232 xmlFree(uid); 233 xmlFree(access); 234 235 return true; 236 } 237 238 // This method initializes the class by parsing the mandatory 239 // /system/etc/vns/vns_policy.xml file and then the optional 240 // /system/etc/vns/vendor_vns_policy.xml if found. 241 // false is returned if vns_policy.xml was not found or is 242 // invalid else true is returned. 243 bool VehiclePropertyAccessControl::init() { 244 static const char* default_policy = "/system/etc/vns/vns_policy.xml"; 245 static const char* vendor_policy = "/system/etc/vns/vendor_vns_policy.xml"; 246 247 if (!process(default_policy)) { 248 return false; 249 } 250 251 if (process(vendor_policy)) { 252 ALOGE("Vendor VNS Policy was applied\n"); 253 } 254 255 return true; 256 } 257 258 // Processes the vns_policy.xml or vendor_vns_policy.xml files 259 // and returns true on success else false is returned. 260 bool VehiclePropertyAccessControl::process(const char* policy) { 261 xmlDoc* doc = NULL; 262 xmlNode* root_element = NULL; 263 264 doc = xmlReadFile(policy, NULL, 0); 265 if (doc == NULL) { 266 ALOGE("Could not find %s\n", policy); 267 return false; 268 } 269 270 root_element = xmlDocGetRootElement(doc); 271 if (!root_element) { 272 ALOGE("Not a valid config file %s\n", policy); 273 xmlFreeDoc(doc); 274 return false; 275 } 276 277 if (xmlStrcmp(root_element->name, (const xmlChar *)"ALLOW") != 0) { 278 ALOGE("Not a valid config file %s\n", policy); 279 xmlFreeDoc(doc); 280 return false; 281 } 282 283 bool ret = populate(root_element->children); 284 285 xmlFreeDoc(doc); 286 287 return ret; 288 } 289 290 void VehiclePropertyAccessControl::dump(String8& msg) { 291 std::string perm; 292 int32_t property; 293 int32_t uid; 294 int32_t access; 295 std::map<int32_t, int32_t> *uid_access_map; 296 297 for (auto& i: mVehicleAccessControlMap) { 298 property = i.first; 299 uid_access_map = mVehicleAccessControlMap[property]; 300 for (auto& j: *uid_access_map) { 301 uid = j.first; 302 access = (*uid_access_map)[uid]; 303 switch(access) { 304 case VEHICLE_PROP_ACCESS_READ: perm = "read"; break; 305 case VEHICLE_PROP_ACCESS_WRITE: perm = "write"; break; 306 case VEHICLE_PROP_ACCESS_READ_WRITE: perm = "read/write"; break; 307 default: perm="unknown"; 308 } 309 msg.appendFormat("UID %d: property 0x%08x, access %s\n", uid, 310 property, perm.c_str()); 311 } 312 } 313 } 314 315 // Test if the given uid has (read or write) access to the given property. If it 316 // does, true is returned and false is returned if it doesn't have access or the 317 // property or uid is unknown. 318 bool VehiclePropertyAccessControl::testAccess(int32_t property, int32_t uid, 319 bool isWrite) { 320 // Check if the property exists 321 if (mVehicleAccessControlMap.count(property) == 0) { 322 // property was not found 323 return false; 324 } 325 326 // Get the uidAccessMap 327 std::map<int32_t, int32_t>* uidAccessMap = 328 mVehicleAccessControlMap[property]; 329 330 // Now check if uid exists 331 if (uidAccessMap->count(uid) == 0) { 332 // uid was not found 333 return false; 334 } 335 336 // Get Access to this Property 337 int32_t access = (*uidAccessMap)[uid]; 338 339 // Test if the UID has access to the property 340 if (isWrite) { 341 if ((access == VEHICLE_PROP_ACCESS_WRITE) 342 || (access == VEHICLE_PROP_ACCESS_READ_WRITE)) { 343 return true; 344 } else { 345 return false; 346 } 347 } else { 348 if ((access == VEHICLE_PROP_ACCESS_READ) 349 || (access == VEHICLE_PROP_ACCESS_READ_WRITE)) { 350 return true; 351 } else { 352 return false; 353 } 354 } 355 } 356 357 }; 358