• 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 #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