blob: cebb3cd026241ff231c312b62628291d07bf7e31 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/tracing/perfetto/privacy_filtering_check.h"
#include <sstream>
#include "base/logging.h"
#include "services/tracing/perfetto/privacy_filtered_fields-inl.h"
#include "third_party/perfetto/protos/perfetto/trace/interned_data/interned_data.pbzero.h"
#include "third_party/perfetto/protos/perfetto/trace/trace.pbzero.h"
#include "third_party/perfetto/protos/perfetto/trace/trace_packet.pbzero.h"
#include "third_party/perfetto/protos/perfetto/trace/track_event/track_event.pbzero.h"
namespace tracing {
namespace {
using perfetto::protos::pbzero::InternedData;
using perfetto::protos::pbzero::TracePacket;
using perfetto::protos::pbzero::TrackEvent;
using protozero::ProtoDecoder;
int FindIndexOfValue(const int* const arr, uint32_t value) {
for (unsigned i = 0; arr[i] != -1; ++i) {
if (static_cast<int>(value) == arr[i])
return i;
}
return -1;
}
// Recursively verifies that the |proto| contains only accepted field IDs
// including all sub messages. Keeps track of |parent_ids| for printing error
// message.
void VerifyProtoRecursive(const MessageInfo* root,
ProtoDecoder* proto,
std::vector<uint32_t>* parent_ids) {
proto->Reset();
for (auto f = proto->ReadField(); f.valid(); f = proto->ReadField()) {
int index = FindIndexOfValue(root->accepted_field_ids, f.id());
if (index == -1) {
std::stringstream error;
error << " Unexpected field in TracePacket proto. IDs from root to child";
for (int a : *parent_ids) {
error << " : " << a;
}
error << " : " << f.id();
LOG(DFATAL) << error.rdbuf();
continue;
}
if (root->sub_messages && root->sub_messages[index] != nullptr) {
ProtoDecoder decoder(f.data(), f.size());
parent_ids->push_back(f.id());
VerifyProtoRecursive(root->sub_messages[index], &decoder, parent_ids);
parent_ids->pop_back();
}
}
}
// Verifies that the |proto| contains only accepted fields.
void VerifyProto(const MessageInfo* root, ProtoDecoder* proto) {
std::vector<uint32_t> parent_ids;
VerifyProtoRecursive(root, proto, &parent_ids);
}
} // namespace
PrivacyFilteringCheck::PrivacyFilteringCheck() = default;
PrivacyFilteringCheck::~PrivacyFilteringCheck() = default;
// static
void PrivacyFilteringCheck::CheckProtoForUnexpectedFields(
const std::string& serialized_trace_proto) {
perfetto::protos::pbzero::Trace::Decoder trace(
reinterpret_cast<const uint8_t*>(serialized_trace_proto.data()),
serialized_trace_proto.size());
for (auto it = trace.packet(); !!it; ++it) {
TracePacket::Decoder packet(it->data(), it->size());
const MessageInfo* root = &kTracePacket;
VerifyProto(root, &packet);
if (packet.has_track_event()) {
++stats_.track_event;
} else if (packet.has_process_descriptor()) {
++stats_.process_desc;
} else if (packet.has_thread_descriptor()) {
++stats_.thread_desc;
}
if (packet.has_interned_data()) {
InternedData::Decoder interned_data(packet.interned_data().data,
packet.interned_data().size);
stats_.has_interned_names |= interned_data.has_legacy_event_names();
stats_.has_interned_categories |= interned_data.has_event_categories();
stats_.has_interned_source_locations |=
interned_data.has_source_locations();
}
}
}
} // namespace tracing