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                 // Do not iterate through fields if primitive data
200                 || !mRestrictions->children /* != FieldDescriptor::TYPE_MESSAGE */) {
201             if (spec.CheckPremission(mRestrictions)) {
202                 mSize = mData->size();
203             }
204             return NO_ERROR;
205         }
206 
207         while (mData->hasNext()) {
208             status_t err = strip_field(&proto, mData, mRestrictions, spec, 0);
209             if (err != NO_ERROR) {
210                 return err; // Error logged in strip_field.
211             }
212         }
213 
214         if (mData->bytesRead() != mData->size()) {
215             ALOGW("Buffer corrupted: expect %zu bytes, read %zu bytes", mData->size(),
216                     mData->bytesRead());
217             return BAD_VALUE;
218         }
219 
220         mData = proto.data();
221         mSize = proto.size();
222         mCurrentLevel = privacyPolicy;
223     }
224     return NO_ERROR;
225 }
226 
writeData(int fd)227 status_t FieldStripper::writeData(int fd) {
228     status_t err = NO_ERROR;
229     sp<ProtoReader> reader = mData;
230     if (mData == nullptr) {
231         // There had been an error processing the data. We won't write anything,
232         // but we also won't return an error, because errors are fatal.
233         return NO_ERROR;
234     }
235     while (reader->readBuffer() != NULL) {
236         err = WriteFully(fd, reader->readBuffer(), reader->currentToRead()) ? NO_ERROR : -errno;
237         reader->move(reader->currentToRead());
238         if (err != NO_ERROR) return err;
239     }
240     return NO_ERROR;
241 }
242 
243 
244 // ================================================================================
FilterFd(uint8_t privacyPolicy,int fd)245 FilterFd::FilterFd(uint8_t privacyPolicy, int fd)
246         :mPrivacyPolicy(privacyPolicy),
247          mFd(fd) {
248 }
249 
~FilterFd()250 FilterFd::~FilterFd() {
251 }
252 
253 // ================================================================================
PrivacyFilter(int sectionId,const Privacy * restrictions)254 PrivacyFilter::PrivacyFilter(int sectionId, const Privacy* restrictions)
255         :mSectionId(sectionId),
256          mRestrictions(restrictions),
257          mOutputs() {
258 }
259 
~PrivacyFilter()260 PrivacyFilter::~PrivacyFilter() {
261 }
262 
addFd(const sp<FilterFd> & output)263 void PrivacyFilter::addFd(const sp<FilterFd>& output) {
264     mOutputs.push_back(output);
265 }
266 
writeData(const FdBuffer & buffer,uint8_t bufferLevel,size_t * maxSize)267 status_t PrivacyFilter::writeData(const FdBuffer& buffer, uint8_t bufferLevel,
268         size_t* maxSize) {
269     status_t err;
270 
271     if (maxSize != NULL) {
272         *maxSize = 0;
273     }
274 
275     // Order the writes by privacy filter, with increasing levels of filtration,k
276     // so we can do the filter once, and then write many times.
277     sort(mOutputs.begin(), mOutputs.end(),
278         [](const sp<FilterFd>& a, const sp<FilterFd>& b) -> bool {
279             return a->getPrivacyPolicy() < b->getPrivacyPolicy();
280         });
281 
282     uint8_t privacyPolicy = PRIVACY_POLICY_LOCAL; // a.k.a. no filtering
283     FieldStripper fieldStripper(mRestrictions, buffer.data()->read(), bufferLevel);
284     for (const sp<FilterFd>& output: mOutputs) {
285         // Do another level of filtering if necessary
286         if (privacyPolicy != output->getPrivacyPolicy()) {
287             privacyPolicy = output->getPrivacyPolicy();
288             err = fieldStripper.strip(privacyPolicy);
289             if (err != NO_ERROR) {
290                 // We can't successfully strip this data.  We will skip
291                 // the rest of this section.
292                 return NO_ERROR;
293             }
294         }
295 
296         // Write the resultant buffer to the fd, along with the header.
297         ssize_t dataSize = fieldStripper.dataSize();
298         if (dataSize > 0) {
299             err = write_section_header(output->getFd(), mSectionId, dataSize);
300             if (err != NO_ERROR) {
301                 output->onWriteError(err);
302                 continue;
303             }
304 
305             err = fieldStripper.writeData(output->getFd());
306             if (err != NO_ERROR) {
307                 output->onWriteError(err);
308                 continue;
309             }
310         }
311 
312         if (maxSize != NULL) {
313             if (dataSize > *maxSize) {
314                 *maxSize = dataSize;
315             }
316         }
317     }
318 
319     return NO_ERROR;
320 }
321 
322 // ================================================================================
323 class ReadbackFilterFd : public FilterFd {
324 public:
325     ReadbackFilterFd(uint8_t privacyPolicy, int fd);
326 
327     virtual void onWriteError(status_t err);
getError()328     status_t getError() { return mError; }
329 
330 private:
331     status_t mError;
332 };
333 
ReadbackFilterFd(uint8_t privacyPolicy,int fd)334 ReadbackFilterFd::ReadbackFilterFd(uint8_t privacyPolicy, int fd)
335         :FilterFd(privacyPolicy, fd),
336          mError(NO_ERROR) {
337 }
338 
onWriteError(status_t err)339 void ReadbackFilterFd::onWriteError(status_t err) {
340     mError = err;
341 }
342 
343 // ================================================================================
filter_and_write_report(int to,int from,uint8_t bufferLevel,const IncidentReportArgs & args)344 status_t filter_and_write_report(int to, int from, uint8_t bufferLevel,
345         const IncidentReportArgs& args) {
346     status_t err;
347     sp<ProtoFileReader> reader = new ProtoFileReader(from);
348 
349     while (reader->hasNext()) {
350         uint64_t fieldTag = reader->readRawVarint();
351         uint32_t fieldId = read_field_id(fieldTag);
352         uint8_t wireType = read_wire_type(fieldTag);
353         if (wireType == WIRE_TYPE_LENGTH_DELIMITED
354                 && args.containsSection(fieldId, section_requires_specific_mention(fieldId))) {
355             // We need this field, but we need to strip it to the level provided in args.
356             PrivacyFilter filter(fieldId, get_privacy_of_section(fieldId));
357             filter.addFd(new ReadbackFilterFd(args.getPrivacyPolicy(), to));
358 
359             // Read this section from the reader into an FdBuffer
360             size_t sectionSize = reader->readRawVarint();
361             FdBuffer sectionData;
362             err = sectionData.write(reader, sectionSize);
363             if (err != NO_ERROR) {
364                 ALOGW("filter_and_write_report FdBuffer.write failed (this shouldn't happen): %s",
365                         strerror(-err));
366                 return err;
367             }
368 
369             // Do the filter and write.
370             err = filter.writeData(sectionData, bufferLevel, nullptr);
371             if (err != NO_ERROR) {
372                 ALOGW("filter_and_write_report filter.writeData had an error: %s", strerror(-err));
373                 return err;
374             }
375         } else {
376             // We don't need this field.  Incident does not have any direct children
377             // other than sections.  So just skip them.
378             write_field_or_skip(NULL, reader, fieldTag, true);
379         }
380     }
381     clear_buffer_pool();
382     err = reader->getError();
383     if (err != NO_ERROR) {
384         ALOGW("filter_and_write_report reader had an error: %s", strerror(-err));
385         return err;
386     }
387 
388     return NO_ERROR;
389 }
390 
391 }  // namespace incidentd
392 }  // namespace os
393 }  // namespace android
394