1 /*
2 * Copyright (C) 2017 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 #define DEBUG false
17 #include "Log.h"
18
19 #include "incidentd_util.h"
20 #include "PrivacyFilter.h"
21 #include "proto_util.h"
22
23 #include "incidentd_util.h"
24 #include "proto_util.h"
25 #include "Section.h"
26
27 #include <android-base/file.h>
28 #include <android/util/protobuf.h>
29 #include <android/util/ProtoFileReader.h>
30 #include <log/log.h>
31
32 namespace android {
33 namespace os {
34 namespace incidentd {
35
36 // ================================================================================
37 /**
38 * Write the field to buf based on the wire type, iterator will point to next field.
39 * If skip is set to true, no data will be written to buf. Return number of bytes written.
40 */
write_field_or_skip(ProtoOutputStream * out,const sp<ProtoReader> & in,uint32_t fieldTag,bool skip)41 void write_field_or_skip(ProtoOutputStream* out, const sp<ProtoReader>& in,
42 uint32_t fieldTag, bool skip) {
43 uint8_t wireType = read_wire_type(fieldTag);
44 size_t bytesToWrite = 0;
45 uint64_t varint = 0;
46
47 switch (wireType) {
48 case WIRE_TYPE_VARINT:
49 varint = in->readRawVarint();
50 if (!skip) {
51 out->writeRawVarint(fieldTag);
52 out->writeRawVarint(varint);
53 }
54 return;
55 case WIRE_TYPE_FIXED64:
56 if (!skip) {
57 out->writeRawVarint(fieldTag);
58 }
59 bytesToWrite = 8;
60 break;
61 case WIRE_TYPE_LENGTH_DELIMITED:
62 bytesToWrite = in->readRawVarint();
63 if (!skip) {
64 out->writeLengthDelimitedHeader(read_field_id(fieldTag), bytesToWrite);
65 }
66 break;
67 case WIRE_TYPE_FIXED32:
68 if (!skip) {
69 out->writeRawVarint(fieldTag);
70 }
71 bytesToWrite = 4;
72 break;
73 }
74 if (skip) {
75 in->move(bytesToWrite);
76 } else {
77 for (size_t i = 0; i < bytesToWrite; i++) {
78 out->writeRawByte(in->next());
79 }
80 }
81 }
82
83 /**
84 * Strip next field based on its private policy and request spec, then stores data in buf.
85 * Return NO_ERROR if succeeds, otherwise BAD_VALUE is returned to indicate bad data in
86 * FdBuffer.
87 *
88 * The iterator must point to the head of a protobuf formatted field for successful operation.
89 * After exit with NO_ERROR, iterator points to the next protobuf field's head.
90 *
91 * depth is the depth of recursion, for debugging.
92 */
strip_field(ProtoOutputStream * out,const sp<ProtoReader> & in,const Privacy * parentPolicy,const PrivacySpec & spec,int depth)93 status_t strip_field(ProtoOutputStream* out, const sp<ProtoReader>& in,
94 const Privacy* parentPolicy, const PrivacySpec& spec, int depth) {
95 if (!in->hasNext() || parentPolicy == NULL) {
96 return BAD_VALUE;
97 }
98 uint32_t fieldTag = in->readRawVarint();
99 uint32_t fieldId = read_field_id(fieldTag);
100 const Privacy* policy = lookup(parentPolicy, fieldId);
101
102 if (policy == NULL || policy->children == NULL) {
103 bool skip = !spec.CheckPremission(policy, parentPolicy->policy);
104 // iterator will point to head of next field
105 size_t currentAt = in->bytesRead();
106 write_field_or_skip(out, in, fieldTag, skip);
107 return NO_ERROR;
108 }
109 // current field is message type and its sub-fields have extra privacy policies
110 uint32_t msgSize = in->readRawVarint();
111 size_t start = in->bytesRead();
112 uint64_t token = out->start(encode_field_id(policy));
113 while (in->bytesRead() - start != msgSize) {
114 status_t err = strip_field(out, in, policy, spec, depth + 1);
115 if (err != NO_ERROR) {
116 ALOGW("Bad value when stripping id %d, wiretype %d, tag %#x, depth %d, size %d, "
117 "relative pos %zu, ", fieldId, read_wire_type(fieldTag), fieldTag, depth,
118 msgSize, in->bytesRead() - start);
119 return err;
120 }
121 }
122 out->end(token);
123 return NO_ERROR;
124 }
125
126 // ================================================================================
127 class FieldStripper {
128 public:
129 FieldStripper(const Privacy* restrictions, const sp<ProtoReader>& data,
130 uint8_t bufferLevel);
131
132 /**
133 * Take the data that we have, and filter it down so that no fields
134 * are more sensitive than the given privacy policy.
135 */
136 status_t strip(uint8_t privacyPolicy);
137
138 /**
139 * At the current filter level, how many bytes of data there is.
140 */
dataSize() const141 ssize_t dataSize() const { return mSize; }
142
143 /**
144 * Write the data from the current filter level to the file descriptor.
145 */
146 status_t writeData(int fd);
147
148 private:
149 /**
150 * The global set of field --> required privacy level mapping.
151 */
152 const Privacy* mRestrictions;
153
154 /**
155 * The current buffer.
156 */
157 sp<ProtoReader> mData;
158
159 /**
160 * The current size of the buffer inside mData.
161 */
162 ssize_t mSize;
163
164 /**
165 * The current privacy policy that the data is filtered to, as an optimization
166 * so we don't always re-filter data that has already been filtered.
167 */
168 uint8_t mCurrentLevel;
169
170 };
171
FieldStripper(const Privacy * restrictions,const sp<ProtoReader> & data,uint8_t bufferLevel)172 FieldStripper::FieldStripper(const Privacy* restrictions, const sp<ProtoReader>& data,
173 uint8_t bufferLevel)
174 :mRestrictions(restrictions),
175 mData(data),
176 mSize(data->size()),
177 mCurrentLevel(bufferLevel) {
178 if (mSize < 0) {
179 ALOGW("FieldStripper constructed with a ProtoReader that doesn't support size."
180 " Data will be missing.");
181 }
182 }
183
strip(const uint8_t privacyPolicy)184 status_t FieldStripper::strip(const uint8_t privacyPolicy) {
185 // If the current strip level is less (fewer fields retained) than what's already in the
186 // buffer, then we can skip it.
187 if (mCurrentLevel < privacyPolicy) {
188 PrivacySpec spec(privacyPolicy);
189 ProtoOutputStream proto;
190
191 // Optimization when no strip happens.
192 if (mRestrictions == NULL || spec.RequireAll()) {
193 if (spec.CheckPremission(mRestrictions)) {
194 mSize = mData->size();
195 }
196 return NO_ERROR;
197 }
198
199 while (mData->hasNext()) {
200 status_t err = strip_field(&proto, mData, mRestrictions, spec, 0);
201 if (err != NO_ERROR) {
202 return err; // Error logged in strip_field.
203 }
204 }
205
206 if (mData->bytesRead() != mData->size()) {
207 ALOGW("Buffer corrupted: expect %zu bytes, read %zu bytes", mData->size(),
208 mData->bytesRead());
209 return BAD_VALUE;
210 }
211
212 mData = proto.data();
213 mSize = proto.size();
214 mCurrentLevel = privacyPolicy;
215 }
216 return NO_ERROR;
217 }
218
writeData(int fd)219 status_t FieldStripper::writeData(int fd) {
220 status_t err = NO_ERROR;
221 sp<ProtoReader> reader = mData;
222 if (mData == nullptr) {
223 // There had been an error processing the data. We won't write anything,
224 // but we also won't return an error, because errors are fatal.
225 return NO_ERROR;
226 }
227 while (reader->readBuffer() != NULL) {
228 err = WriteFully(fd, reader->readBuffer(), reader->currentToRead()) ? NO_ERROR : -errno;
229 reader->move(reader->currentToRead());
230 if (err != NO_ERROR) return err;
231 }
232 return NO_ERROR;
233 }
234
235
236 // ================================================================================
FilterFd(uint8_t privacyPolicy,int fd)237 FilterFd::FilterFd(uint8_t privacyPolicy, int fd)
238 :mPrivacyPolicy(privacyPolicy),
239 mFd(fd) {
240 }
241
~FilterFd()242 FilterFd::~FilterFd() {
243 }
244
245 // ================================================================================
PrivacyFilter(int sectionId,const Privacy * restrictions)246 PrivacyFilter::PrivacyFilter(int sectionId, const Privacy* restrictions)
247 :mSectionId(sectionId),
248 mRestrictions(restrictions),
249 mOutputs() {
250 }
251
~PrivacyFilter()252 PrivacyFilter::~PrivacyFilter() {
253 }
254
addFd(const sp<FilterFd> & output)255 void PrivacyFilter::addFd(const sp<FilterFd>& output) {
256 mOutputs.push_back(output);
257 }
258
writeData(const FdBuffer & buffer,uint8_t bufferLevel,size_t * maxSize)259 status_t PrivacyFilter::writeData(const FdBuffer& buffer, uint8_t bufferLevel,
260 size_t* maxSize) {
261 status_t err;
262
263 if (maxSize != NULL) {
264 *maxSize = 0;
265 }
266
267 // Order the writes by privacy filter, with increasing levels of filtration,k
268 // so we can do the filter once, and then write many times.
269 sort(mOutputs.begin(), mOutputs.end(),
270 [](const sp<FilterFd>& a, const sp<FilterFd>& b) -> bool {
271 return a->getPrivacyPolicy() < b->getPrivacyPolicy();
272 });
273
274 uint8_t privacyPolicy = PRIVACY_POLICY_LOCAL; // a.k.a. no filtering
275 FieldStripper fieldStripper(mRestrictions, buffer.data()->read(), bufferLevel);
276 for (const sp<FilterFd>& output: mOutputs) {
277 // Do another level of filtering if necessary
278 if (privacyPolicy != output->getPrivacyPolicy()) {
279 privacyPolicy = output->getPrivacyPolicy();
280 err = fieldStripper.strip(privacyPolicy);
281 if (err != NO_ERROR) {
282 // We can't successfully strip this data. We will skip
283 // the rest of this section.
284 return NO_ERROR;
285 }
286 }
287
288 // Write the resultant buffer to the fd, along with the header.
289 ssize_t dataSize = fieldStripper.dataSize();
290 if (dataSize > 0) {
291 err = write_section_header(output->getFd(), mSectionId, dataSize);
292 if (err != NO_ERROR) {
293 output->onWriteError(err);
294 continue;
295 }
296
297 err = fieldStripper.writeData(output->getFd());
298 if (err != NO_ERROR) {
299 output->onWriteError(err);
300 continue;
301 }
302 }
303
304 if (maxSize != NULL) {
305 if (dataSize > *maxSize) {
306 *maxSize = dataSize;
307 }
308 }
309 }
310
311 return NO_ERROR;
312 }
313
314 // ================================================================================
315 class ReadbackFilterFd : public FilterFd {
316 public:
317 ReadbackFilterFd(uint8_t privacyPolicy, int fd);
318
319 virtual void onWriteError(status_t err);
getError()320 status_t getError() { return mError; }
321
322 private:
323 status_t mError;
324 };
325
ReadbackFilterFd(uint8_t privacyPolicy,int fd)326 ReadbackFilterFd::ReadbackFilterFd(uint8_t privacyPolicy, int fd)
327 :FilterFd(privacyPolicy, fd),
328 mError(NO_ERROR) {
329 }
330
onWriteError(status_t err)331 void ReadbackFilterFd::onWriteError(status_t err) {
332 mError = err;
333 }
334
335 // ================================================================================
filter_and_write_report(int to,int from,uint8_t bufferLevel,const IncidentReportArgs & args)336 status_t filter_and_write_report(int to, int from, uint8_t bufferLevel,
337 const IncidentReportArgs& args) {
338 status_t err;
339 sp<ProtoFileReader> reader = new ProtoFileReader(from);
340
341 while (reader->hasNext()) {
342 uint64_t fieldTag = reader->readRawVarint();
343 uint32_t fieldId = read_field_id(fieldTag);
344 uint8_t wireType = read_wire_type(fieldTag);
345 if (wireType == WIRE_TYPE_LENGTH_DELIMITED
346 && args.containsSection(fieldId, section_requires_specific_mention(fieldId))) {
347 // We need this field, but we need to strip it to the level provided in args.
348 PrivacyFilter filter(fieldId, get_privacy_of_section(fieldId));
349 filter.addFd(new ReadbackFilterFd(args.getPrivacyPolicy(), to));
350
351 // Read this section from the reader into an FdBuffer
352 size_t sectionSize = reader->readRawVarint();
353 FdBuffer sectionData;
354 err = sectionData.write(reader, sectionSize);
355 if (err != NO_ERROR) {
356 ALOGW("filter_and_write_report FdBuffer.write failed (this shouldn't happen): %s",
357 strerror(-err));
358 return err;
359 }
360
361 // Do the filter and write.
362 err = filter.writeData(sectionData, bufferLevel, nullptr);
363 if (err != NO_ERROR) {
364 ALOGW("filter_and_write_report filter.writeData had an error: %s", strerror(-err));
365 return err;
366 }
367 } else {
368 // We don't need this field. Incident does not have any direct children
369 // other than sections. So just skip them.
370 write_field_or_skip(NULL, reader, fieldTag, true);
371 }
372 }
373
374 err = reader->getError();
375 if (err != NO_ERROR) {
376 ALOGW("filter_and_write_report reader had an error: %s", strerror(-err));
377 return err;
378 }
379
380 return NO_ERROR;
381 }
382
383 } // namespace incidentd
384 } // namespace os
385 } // namespace android
386