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