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