1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker * Copyright (C) 2024 The Android Open Source Projectf
3*6dbdd20aSAndroid Build Coastguard Worker *
4*6dbdd20aSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker
6*6dbdd20aSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
7*6dbdd20aSAndroid Build Coastguard Worker * You may obtain a copy of the License at
8*6dbdd20aSAndroid Build Coastguard Worker *
9*6dbdd20aSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
10*6dbdd20aSAndroid Build Coastguard Worker *
11*6dbdd20aSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
12*6dbdd20aSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
13*6dbdd20aSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*6dbdd20aSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
15*6dbdd20aSAndroid Build Coastguard Worker * limitations under the License.
16*6dbdd20aSAndroid Build Coastguard Worker */
17*6dbdd20aSAndroid Build Coastguard Worker
18*6dbdd20aSAndroid Build Coastguard Worker #include "src/trace_redaction/verify_integrity.h"
19*6dbdd20aSAndroid Build Coastguard Worker
20*6dbdd20aSAndroid Build Coastguard Worker #include "src/trace_processor/util/status_macros.h"
21*6dbdd20aSAndroid Build Coastguard Worker
22*6dbdd20aSAndroid Build Coastguard Worker #include "protos/perfetto/common/trace_stats.pbzero.h"
23*6dbdd20aSAndroid Build Coastguard Worker #include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h"
24*6dbdd20aSAndroid Build Coastguard Worker #include "protos/perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
25*6dbdd20aSAndroid Build Coastguard Worker #include "protos/perfetto/trace/trace_packet.pbzero.h"
26*6dbdd20aSAndroid Build Coastguard Worker
27*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto::trace_redaction {
28*6dbdd20aSAndroid Build Coastguard Worker
Collect(const protos::pbzero::TracePacket::Decoder & packet,Context *) const29*6dbdd20aSAndroid Build Coastguard Worker base::Status VerifyIntegrity::Collect(
30*6dbdd20aSAndroid Build Coastguard Worker const protos::pbzero::TracePacket::Decoder& packet,
31*6dbdd20aSAndroid Build Coastguard Worker Context*) const {
32*6dbdd20aSAndroid Build Coastguard Worker if (!packet.has_trusted_uid()) {
33*6dbdd20aSAndroid Build Coastguard Worker return base::ErrStatus(
34*6dbdd20aSAndroid Build Coastguard Worker "VerifyIntegrity: missing field (TracePacket::kTrustedUid).");
35*6dbdd20aSAndroid Build Coastguard Worker }
36*6dbdd20aSAndroid Build Coastguard Worker
37*6dbdd20aSAndroid Build Coastguard Worker if (packet.trusted_uid() > Context::kMaxTrustedUid) {
38*6dbdd20aSAndroid Build Coastguard Worker return base::ErrStatus("VerifyIntegrity: untrusted uid found (uid = %d).",
39*6dbdd20aSAndroid Build Coastguard Worker packet.trusted_uid());
40*6dbdd20aSAndroid Build Coastguard Worker }
41*6dbdd20aSAndroid Build Coastguard Worker
42*6dbdd20aSAndroid Build Coastguard Worker if (packet.has_ftrace_events()) {
43*6dbdd20aSAndroid Build Coastguard Worker RETURN_IF_ERROR(OnFtraceEvents(packet.ftrace_events()));
44*6dbdd20aSAndroid Build Coastguard Worker }
45*6dbdd20aSAndroid Build Coastguard Worker
46*6dbdd20aSAndroid Build Coastguard Worker // If there is a process tree, there should be a timestamp on the packet. This
47*6dbdd20aSAndroid Build Coastguard Worker // is the only way to know when the process tree was collected.
48*6dbdd20aSAndroid Build Coastguard Worker if (packet.has_process_tree() && !packet.has_timestamp()) {
49*6dbdd20aSAndroid Build Coastguard Worker return base::ErrStatus(
50*6dbdd20aSAndroid Build Coastguard Worker "VerifyIntegrity: missing fields (TracePacket::kProcessTree + "
51*6dbdd20aSAndroid Build Coastguard Worker "TracePacket::kTimestamp).");
52*6dbdd20aSAndroid Build Coastguard Worker }
53*6dbdd20aSAndroid Build Coastguard Worker
54*6dbdd20aSAndroid Build Coastguard Worker // If there are a process stats, there should be a timestamp on the packet.
55*6dbdd20aSAndroid Build Coastguard Worker // This is the only way to know when the stats were collected.
56*6dbdd20aSAndroid Build Coastguard Worker if (packet.has_process_stats() && !packet.has_timestamp()) {
57*6dbdd20aSAndroid Build Coastguard Worker return base::ErrStatus(
58*6dbdd20aSAndroid Build Coastguard Worker "VerifyIntegrity: missing fields (TracePacket::kProcessStats + "
59*6dbdd20aSAndroid Build Coastguard Worker "TracePacket::kTimestamp).");
60*6dbdd20aSAndroid Build Coastguard Worker }
61*6dbdd20aSAndroid Build Coastguard Worker
62*6dbdd20aSAndroid Build Coastguard Worker if (packet.has_trace_stats()) {
63*6dbdd20aSAndroid Build Coastguard Worker RETURN_IF_ERROR(OnTraceStats(packet.trace_stats()));
64*6dbdd20aSAndroid Build Coastguard Worker }
65*6dbdd20aSAndroid Build Coastguard Worker
66*6dbdd20aSAndroid Build Coastguard Worker return base::OkStatus();
67*6dbdd20aSAndroid Build Coastguard Worker }
68*6dbdd20aSAndroid Build Coastguard Worker
OnFtraceEvents(const protozero::ConstBytes bytes) const69*6dbdd20aSAndroid Build Coastguard Worker base::Status VerifyIntegrity::OnFtraceEvents(
70*6dbdd20aSAndroid Build Coastguard Worker const protozero::ConstBytes bytes) const {
71*6dbdd20aSAndroid Build Coastguard Worker protos::pbzero::FtraceEventBundle::Decoder events(bytes);
72*6dbdd20aSAndroid Build Coastguard Worker
73*6dbdd20aSAndroid Build Coastguard Worker // Any ftrace lost events should cause the trace to be dropped:
74*6dbdd20aSAndroid Build Coastguard Worker // protos/perfetto/trace/ftrace/ftrace_event_bundle.proto
75*6dbdd20aSAndroid Build Coastguard Worker if (events.has_lost_events() && events.has_lost_events()) {
76*6dbdd20aSAndroid Build Coastguard Worker return base::ErrStatus(
77*6dbdd20aSAndroid Build Coastguard Worker "VerifyIntegrity: detected FtraceEventBundle error.");
78*6dbdd20aSAndroid Build Coastguard Worker }
79*6dbdd20aSAndroid Build Coastguard Worker
80*6dbdd20aSAndroid Build Coastguard Worker // The other clocks in ftrace are only used on very old kernel versions. No
81*6dbdd20aSAndroid Build Coastguard Worker // device with V should have such an old version. As a failsafe though,
82*6dbdd20aSAndroid Build Coastguard Worker // check that the ftrace_clock field is unset to ensure no invalid
83*6dbdd20aSAndroid Build Coastguard Worker // timestamps get by.
84*6dbdd20aSAndroid Build Coastguard Worker if (events.has_ftrace_clock()) {
85*6dbdd20aSAndroid Build Coastguard Worker return base::ErrStatus(
86*6dbdd20aSAndroid Build Coastguard Worker "VerifyIntegrity: unexpected field (FtraceEventBundle::kFtraceClock).");
87*6dbdd20aSAndroid Build Coastguard Worker }
88*6dbdd20aSAndroid Build Coastguard Worker
89*6dbdd20aSAndroid Build Coastguard Worker // Every ftrace event bundle should have a CPU field. This is necessary for
90*6dbdd20aSAndroid Build Coastguard Worker // switch/waking redaction to work.
91*6dbdd20aSAndroid Build Coastguard Worker if (!events.has_cpu()) {
92*6dbdd20aSAndroid Build Coastguard Worker return base::ErrStatus(
93*6dbdd20aSAndroid Build Coastguard Worker "VerifyIntegrity: missing field (FtraceEventBundle::kCpu).");
94*6dbdd20aSAndroid Build Coastguard Worker }
95*6dbdd20aSAndroid Build Coastguard Worker
96*6dbdd20aSAndroid Build Coastguard Worker // Any ftrace errors should cause the trace to be dropped:
97*6dbdd20aSAndroid Build Coastguard Worker // protos/perfetto/trace/ftrace/ftrace_event_bundle.proto
98*6dbdd20aSAndroid Build Coastguard Worker if (events.has_error()) {
99*6dbdd20aSAndroid Build Coastguard Worker return base::ErrStatus("VerifyIntegrity: detected FtraceEvent errors.");
100*6dbdd20aSAndroid Build Coastguard Worker }
101*6dbdd20aSAndroid Build Coastguard Worker
102*6dbdd20aSAndroid Build Coastguard Worker for (auto it = events.event(); it; ++it) {
103*6dbdd20aSAndroid Build Coastguard Worker RETURN_IF_ERROR(OnFtraceEvent(*it));
104*6dbdd20aSAndroid Build Coastguard Worker }
105*6dbdd20aSAndroid Build Coastguard Worker
106*6dbdd20aSAndroid Build Coastguard Worker return base::OkStatus();
107*6dbdd20aSAndroid Build Coastguard Worker }
108*6dbdd20aSAndroid Build Coastguard Worker
OnFtraceEvent(const protozero::ConstBytes bytes) const109*6dbdd20aSAndroid Build Coastguard Worker base::Status VerifyIntegrity::OnFtraceEvent(
110*6dbdd20aSAndroid Build Coastguard Worker const protozero::ConstBytes bytes) const {
111*6dbdd20aSAndroid Build Coastguard Worker protos::pbzero::FtraceEvent::Decoder event(bytes);
112*6dbdd20aSAndroid Build Coastguard Worker
113*6dbdd20aSAndroid Build Coastguard Worker if (!event.has_timestamp()) {
114*6dbdd20aSAndroid Build Coastguard Worker return base::ErrStatus(
115*6dbdd20aSAndroid Build Coastguard Worker "VerifyIntegrity: missing field (FtraceEvent::kTimestamp).");
116*6dbdd20aSAndroid Build Coastguard Worker }
117*6dbdd20aSAndroid Build Coastguard Worker
118*6dbdd20aSAndroid Build Coastguard Worker if (!event.has_pid()) {
119*6dbdd20aSAndroid Build Coastguard Worker return base::ErrStatus(
120*6dbdd20aSAndroid Build Coastguard Worker "VerifyIntegrity: missing field (FtraceEvent::kPid).");
121*6dbdd20aSAndroid Build Coastguard Worker }
122*6dbdd20aSAndroid Build Coastguard Worker
123*6dbdd20aSAndroid Build Coastguard Worker return base::OkStatus();
124*6dbdd20aSAndroid Build Coastguard Worker }
125*6dbdd20aSAndroid Build Coastguard Worker
OnTraceStats(const protozero::ConstBytes bytes) const126*6dbdd20aSAndroid Build Coastguard Worker base::Status VerifyIntegrity::OnTraceStats(
127*6dbdd20aSAndroid Build Coastguard Worker const protozero::ConstBytes bytes) const {
128*6dbdd20aSAndroid Build Coastguard Worker protos::pbzero::TraceStats::Decoder trace_stats(bytes);
129*6dbdd20aSAndroid Build Coastguard Worker
130*6dbdd20aSAndroid Build Coastguard Worker if (trace_stats.has_flushes_failed() && trace_stats.flushes_failed()) {
131*6dbdd20aSAndroid Build Coastguard Worker return base::ErrStatus("VerifyIntegrity: detected TraceStats flush fails.");
132*6dbdd20aSAndroid Build Coastguard Worker }
133*6dbdd20aSAndroid Build Coastguard Worker
134*6dbdd20aSAndroid Build Coastguard Worker if (trace_stats.has_final_flush_outcome() &&
135*6dbdd20aSAndroid Build Coastguard Worker trace_stats.final_flush_outcome() ==
136*6dbdd20aSAndroid Build Coastguard Worker protos::pbzero::TraceStats::FINAL_FLUSH_FAILED) {
137*6dbdd20aSAndroid Build Coastguard Worker return base::ErrStatus(
138*6dbdd20aSAndroid Build Coastguard Worker "VerifyIntegrity: TraceStats final_flush_outcome is "
139*6dbdd20aSAndroid Build Coastguard Worker "FINAL_FLUSH_FAILED.");
140*6dbdd20aSAndroid Build Coastguard Worker }
141*6dbdd20aSAndroid Build Coastguard Worker
142*6dbdd20aSAndroid Build Coastguard Worker for (auto it = trace_stats.buffer_stats(); it; ++it) {
143*6dbdd20aSAndroid Build Coastguard Worker RETURN_IF_ERROR(OnBufferStats(*it));
144*6dbdd20aSAndroid Build Coastguard Worker }
145*6dbdd20aSAndroid Build Coastguard Worker
146*6dbdd20aSAndroid Build Coastguard Worker return base::OkStatus();
147*6dbdd20aSAndroid Build Coastguard Worker }
148*6dbdd20aSAndroid Build Coastguard Worker
OnBufferStats(const protozero::ConstBytes bytes) const149*6dbdd20aSAndroid Build Coastguard Worker base::Status VerifyIntegrity::OnBufferStats(
150*6dbdd20aSAndroid Build Coastguard Worker const protozero::ConstBytes bytes) const {
151*6dbdd20aSAndroid Build Coastguard Worker protos::pbzero::TraceStats::BufferStats::Decoder stats(bytes);
152*6dbdd20aSAndroid Build Coastguard Worker
153*6dbdd20aSAndroid Build Coastguard Worker if (stats.has_patches_failed() && stats.patches_failed()) {
154*6dbdd20aSAndroid Build Coastguard Worker return base::ErrStatus(
155*6dbdd20aSAndroid Build Coastguard Worker "VerifyIntegrity: detected BufferStats patch fails.");
156*6dbdd20aSAndroid Build Coastguard Worker }
157*6dbdd20aSAndroid Build Coastguard Worker
158*6dbdd20aSAndroid Build Coastguard Worker if (stats.has_abi_violations() && stats.abi_violations()) {
159*6dbdd20aSAndroid Build Coastguard Worker return base::ErrStatus(
160*6dbdd20aSAndroid Build Coastguard Worker "VerifyIntegrity: detected BufferStats abi violations.");
161*6dbdd20aSAndroid Build Coastguard Worker }
162*6dbdd20aSAndroid Build Coastguard Worker
163*6dbdd20aSAndroid Build Coastguard Worker auto has_loss = stats.has_trace_writer_packet_loss();
164*6dbdd20aSAndroid Build Coastguard Worker auto value = stats.trace_writer_packet_loss();
165*6dbdd20aSAndroid Build Coastguard Worker
166*6dbdd20aSAndroid Build Coastguard Worker if (has_loss && value) {
167*6dbdd20aSAndroid Build Coastguard Worker return base::ErrStatus(
168*6dbdd20aSAndroid Build Coastguard Worker "VerifyIntegrity: detected BufferStats writer packet loss.");
169*6dbdd20aSAndroid Build Coastguard Worker }
170*6dbdd20aSAndroid Build Coastguard Worker
171*6dbdd20aSAndroid Build Coastguard Worker return base::OkStatus();
172*6dbdd20aSAndroid Build Coastguard Worker }
173*6dbdd20aSAndroid Build Coastguard Worker
174*6dbdd20aSAndroid Build Coastguard Worker } // namespace perfetto::trace_redaction
175