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