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