• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 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 #include <algorithm>
18 #include <string>
19 
20 #include "dumpsys/internal/filter_internal.h"
21 #include "flatbuffers/flatbuffers.h"
22 #include "flatbuffers/idl.h"
23 #include "os/log.h"
24 
25 #define DBG 0
26 
27 using namespace bluetooth;
28 using namespace dumpsys;
29 
30 constexpr flatbuffers::voffset_t kErasedFromTable = 0;
31 constexpr bool kFieldIsNotPopulated = true;
32 constexpr bool kFieldHasBeenFiltered = true;
33 constexpr bool kFieldContinueFiltering = false;
34 
ScrubFromTable(flatbuffers::Table * table,flatbuffers::voffset_t field_offset)35 void internal::ScrubFromTable(flatbuffers::Table* table, flatbuffers::voffset_t field_offset) {
36   ASSERT(table != nullptr);
37   uint8_t* vtable = const_cast<uint8_t*>(table->GetVTable());
38   vtable[field_offset] = kErasedFromTable;
39 }
40 
ReplaceInString(flatbuffers::String * string,int c)41 void internal::ReplaceInString(flatbuffers::String* string, int c) {
42   uint8_t* p = const_cast<uint8_t*>(string->Data());
43   memset(p, c, string->size());
44 }
45 
RandomizeInString(flatbuffers::String * string)46 void internal::RandomizeInString(flatbuffers::String* string) {
47   std::size_t hash = std::hash<std::string>{}(string->str());
48   std::string hashed_string = std::to_string(hash);
49   ReplaceInString(string, ' ');
50   size_t len = std::min(static_cast<size_t>(string->size()), hashed_string.size());
51   uint8_t* p = const_cast<uint8_t*>(string->Data());
52   memcpy(p, hashed_string.c_str(), len);
53 }
54 
PrivacyLevelName(PrivacyLevel privacy_level)55 const char* internal::PrivacyLevelName(PrivacyLevel privacy_level) {
56   switch (privacy_level) {
57     case kPrivate:
58       return "Private";
59       break;
60     case kOpaque:
61       return "Opaque";
62       break;
63     case kAnonymized:
64       return "Anonymized";
65       break;
66     case kAny:
67       return "Any";
68       break;
69   }
70 };
GetPrivacyLevelAttribute(const std::string & string)71 internal::PrivacyLevel internal::GetPrivacyLevelAttribute(const std::string& string) {
72   if (string == "Any") {
73     return kAny;
74   } else if (string == "Anonymized") {
75     return kAnonymized;
76   } else if (string == "Opaque") {
77     return kOpaque;
78   } else if (string == "Private") {
79     return kPrivate;
80   }
81   return kDefaultPrivacyLevel;
82 }
83 
FindFieldPrivacyLevel(const reflection::Field & field)84 internal::PrivacyLevel internal::FindFieldPrivacyLevel(const reflection::Field& field) {
85   PrivacyLevel privacy_level = kDefaultPrivacyLevel;
86 
87   if (field.attributes() != nullptr) {
88     auto key = field.attributes()->LookupByKey(kPrivacyAttributeKeyword);
89     if (key != nullptr) {
90       privacy_level = internal::GetPrivacyLevelAttribute(key->value()->str());
91     }
92   }
93   return privacy_level;
94 }
95 
FindReflectionObject(const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>> * objects,const flatbuffers::String * name)96 const reflection::Object* internal::FindReflectionObject(
97     const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>>* objects, const flatbuffers::String* name) {
98   ASSERT(objects != nullptr);
99   ASSERT(name != nullptr);
100   for (auto it = objects->cbegin(); it != objects->cend(); ++it) {
101     if (it->name()->str() == name->str()) {
102       return *it;
103     }
104   }
105   return nullptr;
106 }
107 
FilterTypeBool(const reflection::Field & field,flatbuffers::Table * table,PrivacyLevel privacy_level)108 bool internal::FilterTypeBool(const reflection::Field& field, flatbuffers::Table* table, PrivacyLevel privacy_level) {
109   ASSERT(table != nullptr);
110 
111   const bool default_val = flatbuffers::GetFieldDefaultI<int8_t>(field);
112   flatbuffers::voffset_t field_offset = field.offset();
113 
114   // boolean privacy levels are simpler.
115   switch (privacy_level) {
116     case kPrivate:
117     case kOpaque:
118     case kAnonymized:
119       flatbuffers::SetField<int8_t>(table, field, default_val);
120       internal::ScrubFromTable(table, field_offset);
121       break;
122     default:
123     case kAny:
124       break;
125   }
126   return kFieldHasBeenFiltered;
127 }
128 
FilterTypeInteger(const reflection::Field & field,flatbuffers::Table * table,PrivacyLevel privacy_level)129 bool internal::FilterTypeInteger(
130     const reflection::Field& field, flatbuffers::Table* table, PrivacyLevel privacy_level) {
131   ASSERT(table != nullptr);
132   ASSERT(flatbuffers::IsInteger(field.type()->base_type()));
133 
134   int32_t default_val = flatbuffers::GetFieldDefaultI<int32_t>(field);
135   flatbuffers::voffset_t field_offset = field.offset();
136   [[maybe_unused]] int32_t val = table->GetField<int32_t>(field_offset, default_val);
137 
138   switch (privacy_level) {
139     case kPrivate:
140       flatbuffers::SetField<int32_t>(table, field, default_val);
141       internal::ScrubFromTable(table, field_offset);
142       break;
143     case kOpaque:
144       flatbuffers::SetField<int32_t>(table, field, default_val);
145       break;
146     case kAnonymized: {
147       auto target_field = flatbuffers::GetFieldI<int32_t>(*table, field);
148       int32_t new_val = static_cast<int32_t>(std::hash<std::string>{}(std::to_string(target_field)));
149       flatbuffers::SetField<int32_t>(table, field, new_val);
150     } break;
151     default:
152     case kAny:
153       break;
154   }
155 
156   if (DBG) {
157     LOG_INFO(
158         "Integer Field_name:%s privacy_level:%s old_value:%d / 0x%x ==> new_value:%d\n",
159         field.name()->c_str(),
160         PrivacyLevelName(privacy_level),
161         val,
162         val,
163         table->GetField<int32_t>(field_offset, default_val));
164   }
165   return kFieldHasBeenFiltered;
166 }
167 
FilterTypeFloat(const reflection::Field & field,flatbuffers::Table * table,PrivacyLevel privacy_level)168 bool internal::FilterTypeFloat(const reflection::Field& field, flatbuffers::Table* table, PrivacyLevel privacy_level) {
169   ASSERT(table != nullptr);
170   ASSERT(flatbuffers::IsFloat(field.type()->base_type()));
171 
172   float default_val = flatbuffers::GetFieldDefaultI<float>(field);
173   flatbuffers::voffset_t field_offset = field.offset();
174   [[maybe_unused]] float val = table->GetField<float>(field_offset, default_val);
175   switch (privacy_level) {
176     case kPrivate:
177       flatbuffers::SetField<float>(table, field, default_val);
178       internal::ScrubFromTable(table, field_offset);
179       break;
180     case kOpaque:
181       flatbuffers::SetField<float>(table, field, default_val);
182       break;
183     case kAnonymized: {
184       auto target_field = flatbuffers::GetFieldF<float>(*table, field);
185       int32_t new_val = static_cast<float>(std::hash<std::string>{}(std::to_string(target_field)));
186       flatbuffers::SetField<float>(table, field, new_val);
187     } break;
188     default:
189     case kAny:
190       break;
191   }
192   if (DBG) {
193     LOG_INFO(
194         "Float Field_name:%s privacy_level:%s old_value:%f ==> new_value:%f",
195         field.name()->c_str(),
196         PrivacyLevelName(privacy_level),
197         val,
198         table->GetField<float>(field_offset, default_val));
199   }
200   return kFieldHasBeenFiltered;
201 }
202 
FilterTypeLong(const reflection::Field & field,flatbuffers::Table * table,PrivacyLevel privacy_level)203 bool internal::FilterTypeLong(const reflection::Field& field, flatbuffers::Table* table, PrivacyLevel privacy_level) {
204   ASSERT(table != nullptr);
205 
206   const int64_t default_val = flatbuffers::GetFieldDefaultI<int64_t>(field);
207   flatbuffers::voffset_t field_offset = field.offset();
208 
209   switch (privacy_level) {
210     case kPrivate:
211       flatbuffers::SetField<int64_t>(table, field, default_val);
212       internal::ScrubFromTable(table, field_offset);
213       break;
214     case kOpaque:
215       flatbuffers::SetField<int64_t>(table, field, default_val);
216       break;
217     case kAnonymized: {
218       auto target_field = flatbuffers::GetFieldI<int64_t>(*table, field);
219       int64_t new_val = static_cast<int64_t>(std::hash<std::string>{}(std::to_string(target_field)));
220       flatbuffers::SetField<int64_t>(table, field, new_val);
221     } break;
222     default:
223     case kAny:
224       break;
225   }
226   return kFieldHasBeenFiltered;
227 }
228 
FilterTypeString(const reflection::Field & field,flatbuffers::Table * table,PrivacyLevel privacy_level)229 bool internal::FilterTypeString(const reflection::Field& field, flatbuffers::Table* table, PrivacyLevel privacy_level) {
230   ASSERT(table != nullptr);
231   ASSERT(field.type()->base_type() == reflection::BaseType::String);
232 
233   flatbuffers::voffset_t field_offset = field.offset();
234 
235   const flatbuffers::String* string = flatbuffers::GetFieldS(*table, field);
236   if (string == nullptr) {
237     return kFieldIsNotPopulated;
238     // Field is not populated
239   }
240   ASSERT(string != nullptr);
241   flatbuffers::String* mutable_string = const_cast<flatbuffers::String*>(string);
242 
243   [[maybe_unused]] std::string old_string(string->str());
244   switch (privacy_level) {
245     case kPrivate:
246       internal::ReplaceInString(mutable_string, '*');
247       internal::ScrubFromTable(table, field_offset);
248       break;
249     case kOpaque:
250       internal::ReplaceInString(mutable_string, '*');
251       break;
252     case kAnonymized:
253       internal::RandomizeInString(mutable_string);
254       break;
255     default:
256     case kAny:
257       break;
258   }
259   if (DBG) {
260     LOG_INFO(
261         "%s Field_name:%s size:%u privacy_level:%s old_string:%s ==> new_string:%s",
262         __func__,
263         field.name()->c_str(),
264         string->size(),
265         PrivacyLevelName(privacy_level),
266         old_string.c_str(),
267         string->c_str());
268   }
269   return kFieldHasBeenFiltered;
270 }
271 
FilterTypeStruct(const reflection::Field & field,flatbuffers::Table * table,PrivacyLevel privacy_level)272 bool internal::FilterTypeStruct(const reflection::Field& field, flatbuffers::Table* table, PrivacyLevel privacy_level) {
273   ASSERT(table != nullptr);
274   ASSERT(!flatbuffers::IsScalar(field.type()->base_type()));
275 
276   flatbuffers::voffset_t field_offset = field.offset();
277 
278   if (privacy_level != kAny) {
279     flatbuffers::SetFieldT(table, field, nullptr);
280     internal::ScrubFromTable(table, field_offset);
281     if (DBG) {
282       LOG_INFO(
283           " Table Removing field name:%s privacy_level:%s", field.name()->c_str(), PrivacyLevelName(privacy_level));
284     }
285   }
286   return kFieldContinueFiltering;
287 }
288