Home | History | Annotate | Download | only in vehicle_network_service
      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