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
VehiclePropertyAccessControl()43 VehiclePropertyAccessControl::VehiclePropertyAccessControl() {
44 }
45
~VehiclePropertyAccessControl()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.
isHexNotation(std::string const & s)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.
accessToInt(int32_t * const value,const xmlChar * property,const xmlChar * uid,const xmlChar * access)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.
updateOrCreate(int32_t uid,int32_t property,int32_t access)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.
populate(xmlNode * a_node)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.
init()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.
process(const char * policy)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
dump(String8 & msg)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.
testAccess(int32_t property,int32_t uid,bool isWrite)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