• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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