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