Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 68ac35cd authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "1. Implement Privacy Policy Tag Inheritance 2. Expose Dest values in IIncidentReportArgs.h"

parents ace40144 bdf58942
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ cc_library {
                "core/proto/android/os/procrank.proto",
                "core/proto/android/os/system_properties.proto",
                "core/proto/android/service/graphicsstats.proto",
                "libs/incident/proto/android/privacy.proto",
                "tools/streaming_proto/stream.proto",
            ],
            shared: {
+22 −37
Original line number Diff line number Diff line
@@ -16,37 +16,18 @@

#include "Privacy.h"

#include <android/os/IncidentReportArgs.h>
#include <stdlib.h>

// DESTINATION enum value
const uint8_t DEST_LOCAL = 0;
const uint8_t DEST_EXPLICIT = 1;
const uint8_t DEST_AUTOMATIC = 2;
uint64_t encode_field_id(const Privacy* p) { return (uint64_t)p->type << 32 | p->field_id; }

// type of the field, identitical to protobuf definition
const uint8_t TYPE_STRING = 9;
const uint8_t TYPE_MESSAGE = 11;

bool
Privacy::IsMessageType() const { return type == TYPE_MESSAGE; }

uint64_t
Privacy::EncodedFieldId() const { return (uint64_t)type << 32 | field_id; }

bool
Privacy::IsStringType() const { return type == TYPE_STRING; }

bool
Privacy::HasChildren() const { return children != NULL && children[0] != NULL; }

const Privacy*
Privacy::lookup(uint32_t fieldId) const
const Privacy* lookup(const Privacy* p, uint32_t fieldId)
{
    if (children == NULL) return NULL;
    for (int i=0; children[i] != NULL; i++) {
        if (children[i]->field_id == fieldId) return children[i];
        // This assumes the list's field id is in ascending order and must be true.
        if (children[i]->field_id > fieldId) return NULL;
    if (p->children == NULL) return NULL;
    for (int i=0; p->children[i] != NULL; i++) { // NULL-terminated.
        if (p->children[i]->field_id == fieldId) return p->children[i];
        // Incident section gen tool guarantees field ids in ascending order.
        if (p->children[i]->field_id > fieldId) return NULL;
    }
    return NULL;
}
@@ -54,11 +35,14 @@ Privacy::lookup(uint32_t fieldId) const
static bool allowDest(const uint8_t dest, const uint8_t policy)
{
    switch (policy) {
    case DEST_LOCAL:
        return dest == DEST_LOCAL;
    case DEST_EXPLICIT:
        return dest == DEST_LOCAL || dest == DEST_EXPLICIT;
    case DEST_AUTOMATIC:
    case android::os::DEST_LOCAL:
        return dest == android::os::DEST_LOCAL;
    case android::os::DEST_EXPLICIT:
    case DEST_UNSET:
        return dest == android::os::DEST_LOCAL ||
            dest == android::os::DEST_EXPLICIT ||
            dest == DEST_UNSET;
    case android::os::DEST_AUTOMATIC:
        return true;
    default:
        return false;
@@ -72,18 +56,19 @@ PrivacySpec::operator<(const PrivacySpec& other) const
}

bool
PrivacySpec::CheckPremission(const Privacy* privacy) const
PrivacySpec::CheckPremission(const Privacy* privacy, const uint8_t defaultDest) const
{
    uint8_t policy = privacy == NULL ? DEST_DEFAULT_VALUE : privacy->dest;
    uint8_t policy = privacy != NULL ? privacy->dest : defaultDest;
    return allowDest(dest, policy);
}

bool
PrivacySpec::RequireAll() const { return dest == DEST_LOCAL; }
PrivacySpec::RequireAll() const { return dest == android::os::DEST_LOCAL; }

PrivacySpec new_spec_from_args(int dest) {
PrivacySpec new_spec_from_args(int dest)
{
  if (dest < 0) return PrivacySpec();
  return PrivacySpec(dest);
}

PrivacySpec get_default_dropbox_spec() { return PrivacySpec(DEST_AUTOMATIC); }
 No newline at end of file
PrivacySpec get_default_dropbox_spec() { return PrivacySpec(android::os::DEST_AUTOMATIC); }
 No newline at end of file
+29 −15
Original line number Diff line number Diff line
@@ -19,35 +19,46 @@

#include <stdint.h>

// This is the default value of DEST enum
const uint8_t DEST_DEFAULT_VALUE = 1;
// This is the default value of DEST enum, sync with privacy.proto
const uint8_t DEST_UNSET = 255; // DEST_UNSET is not exposed to libincident
const uint8_t DEST_DEFAULT_VALUE = DEST_UNSET;

/*
 * In order not to depend on libprotobuf-cpp-full nor libplatformprotos in incidentd,
 * privacy options's data structure are explicitly redefined in this file.
 * In order to NOT auto-generate large chuck of code by proto compiler in incidentd,
 * privacy options's data structure are explicitly redefined here and
 * the values are populated by incident_section_gen tool.
 *
 * Each proto field will have a Privacy when it is different from its parent, otherwise
 * it uses its parent's tag. A message type will have an array of Privacy.
 */
struct Privacy {
    // The field number
    uint32_t field_id;

    // The field type, see external/protobuf/src/google/protobuf/descriptor.h
    uint8_t type;
    // ignore parent's privacy flags if children are set, NULL-terminated

    // If children is null, it is a primitive field,
    // otherwise it is a message field which could have overridden privacy tags here.
    // This array is NULL-terminated.
    Privacy** children;

    // the following fields are identitical to
    // frameworks/base/libs/incident/proto/android/privacy.proto
    // DESTINATION Enum in frameworks/base/libs/incident/proto/android/privacy.proto.
    uint8_t dest;
    const char** patterns; // only set when type is string
    // A list of regexp rules for stripping string fields in proto.
    const char** patterns;
};

    bool IsMessageType() const;
    bool IsStringType() const;
    bool HasChildren() const;
    uint64_t EncodedFieldId() const;
// Encode field id used by ProtoOutputStream.
uint64_t encode_field_id(const Privacy* p);

    const Privacy* lookup(uint32_t fieldId) const;
};
// Look up the child with given fieldId, if not found, return NULL.
const Privacy* lookup(const Privacy* p, uint32_t fieldId);

/**
 * PrivacySpec defines the request has what level of privacy authorization.
 * For example, a device without user consent should only be able to upload AUTOMATIC fields.
 * DEST_UNSET are treated as DEST_EXPLICIT.
 */
class PrivacySpec {
public:
@@ -58,7 +69,10 @@ public:

    bool operator<(const PrivacySpec& other) const;

    bool CheckPremission(const Privacy* privacy) const;
    // check permission of a policy, if returns true, don't strip the data.
    bool CheckPremission(const Privacy* privacy, const uint8_t defaultDest = DEST_DEFAULT_VALUE) const;

    // if returns true, no data need to be stripped.
    bool RequireAll() const;
};

+17 −6
Original line number Diff line number Diff line
@@ -14,15 +14,18 @@
 * limitations under the License.
 */


#define LOG_TAG "incidentd"

#include "PrivacyBuffer.h"
#include "io_util.h"

#include <android/util/protobuf.h>
#include <cutils/log.h>

using namespace android::util;

const bool DEBUG = false;

/**
 * Write the field to buf based on the wire type, iterator will point to next field.
 * If skip is set to true, no data will be written to buf. Return number of bytes written.
@@ -30,6 +33,9 @@ using namespace android::util;
void
PrivacyBuffer::writeFieldOrSkip(uint32_t fieldTag, bool skip)
{
    if (DEBUG) ALOGD("%s field %d (wiretype = %d)", skip ? "skip" : "write",
        read_field_id(fieldTag), read_wire_type(fieldTag));

    uint8_t wireType = read_wire_type(fieldTag);
    size_t bytesToWrite = 0;
    uint32_t varint = 0;
@@ -55,6 +61,7 @@ PrivacyBuffer::writeFieldOrSkip(uint32_t fieldTag, bool skip)
            bytesToWrite = 4;
            break;
    }
    if (DEBUG) ALOGD("%s %d bytes of data", skip ? "skip" : "write", (int)bytesToWrite);
    if (skip) {
        mData.rp()->move(bytesToWrite);
    } else {
@@ -76,10 +83,13 @@ PrivacyBuffer::stripField(const Privacy* parentPolicy, const PrivacySpec& spec)
{
    if (!mData.hasNext() || parentPolicy == NULL) return BAD_VALUE;
    uint32_t fieldTag = mData.readRawVarint();
    const Privacy* policy = parentPolicy->lookup(read_field_id(fieldTag));
    const Privacy* policy = lookup(parentPolicy, read_field_id(fieldTag));

    if (policy == NULL || policy->children == NULL) {
        if (DEBUG) ALOGD("Not a message field %d: dest(%d)", read_field_id(fieldTag),
            policy != NULL ? policy->dest : parentPolicy->dest);

    if (policy == NULL || !policy->IsMessageType() || !policy->HasChildren()) {
        bool skip = !spec.CheckPremission(policy);
        bool skip = !spec.CheckPremission(policy, parentPolicy->dest);
        // iterator will point to head of next field
        writeFieldOrSkip(fieldTag, skip);
        return NO_ERROR;
@@ -87,7 +97,7 @@ PrivacyBuffer::stripField(const Privacy* parentPolicy, const PrivacySpec& spec)
    // current field is message type and its sub-fields have extra privacy policies
    uint32_t msgSize = mData.readRawVarint();
    EncodedBuffer::Pointer start = mData.rp()->copy();
    long long token = mProto.start(policy->EncodedFieldId());
    long long token = mProto.start(encode_field_id(policy));
    while (mData.rp()->pos() - start.pos() != msgSize) {
        status_t err = stripField(policy, spec);
        if (err != NO_ERROR) return err;
@@ -112,8 +122,9 @@ PrivacyBuffer::~PrivacyBuffer()
status_t
PrivacyBuffer::strip(const PrivacySpec& spec)
{
    if (DEBUG) ALOGD("Strip with spec %d", spec.dest);
    // optimization when no strip happens
    if (mPolicy == NULL || !mPolicy->HasChildren() || spec.RequireAll()) {
    if (mPolicy == NULL || mPolicy->children == NULL || spec.RequireAll()) {
        if (spec.CheckPremission(mPolicy)) mSize = mData.size();
        return NO_ERROR;
    }
+2 −2
Original line number Diff line number Diff line
@@ -210,9 +210,9 @@ HeaderSection::Execute(ReportRequestSet* requests) const
{
    for (ReportRequestSet::iterator it=requests->begin(); it!=requests->end(); it++) {
        const sp<ReportRequest> request = *it;
        const vector<vector<int8_t>>& headers = request->args.headers();
        const vector<vector<uint8_t>>& headers = request->args.headers();

        for (vector<vector<int8_t>>::const_iterator buf=headers.begin(); buf!=headers.end(); buf++) {
        for (vector<vector<uint8_t>>::const_iterator buf=headers.begin(); buf!=headers.end(); buf++) {
            if (buf->empty()) continue;

            // So the idea is only requests with negative fd are written to dropbox file.
Loading