aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPrimiano Tucci <primiano@google.com>2023-06-13 13:17:15 +0100
committerCherrypicker Worker <android-build-cherrypicker-worker@google.com>2023-06-13 15:51:36 +0000
commit72f3d346122320676cc61620d531f07cc467b59e (patch)
treefefad33ef3a1ec43e3e319dd7f53a84b39a3d98e
parent9bf4017e70115c08316b0c197972a1f736abcf25 (diff)
downloadperfetto-72f3d346122320676cc61620d531f07cc467b59e.tar.gz
traced: allow cross-session cloning for bugreports
Prior changed introduced generalized support for CloneSession and rewrote the --save-for-bugreport feature on top of that. Unfortunately we didn't notice that the CloneSession feature is very strict on UID checking, enforcing that source and target consumer UID match. This is good in general but not desirable (And a regression) for the case of bugreports, where the two uids differ. In this case bugreport_score acts as an "I am fine exporting this trace to other uids". Bug: 286908237 Bug: 260112703 (cherry picked from https://android-review.googlesource.com/q/commit:5457722190e8cad7dddbedc71b8957ab45402a6c) Merged-In: I99bd22aef0bfa402cb24559b8515c5bdf0b48ba9 Change-Id: I99bd22aef0bfa402cb24559b8515c5bdf0b48ba9
-rw-r--r--protos/perfetto/config/perfetto_config.proto11
-rw-r--r--protos/perfetto/config/trace_config.proto11
-rw-r--r--protos/perfetto/trace/perfetto_trace.proto11
-rw-r--r--src/tracing/core/tracing_service_impl.cc7
-rw-r--r--src/tracing/core/tracing_service_impl_unittest.cc58
5 files changed, 88 insertions, 10 deletions
diff --git a/protos/perfetto/config/perfetto_config.proto b/protos/perfetto/config/perfetto_config.proto
index 85f1de780..5fbcf8dc2 100644
--- a/protos/perfetto/config/perfetto_config.proto
+++ b/protos/perfetto/config/perfetto_config.proto
@@ -2935,13 +2935,18 @@ message TraceConfig {
// trace ends to notify it about the trace readiness.
optional bool notify_traceur = 16;
+ // This field was introduced in Android S.
// Android-only. If set to a value > 0, marks the trace session as a candidate
// for being attached to a bugreport. This field effectively acts as a z-index
// for bugreports. When Android's dumpstate runs perfetto
// --save-for-bugreport, traced will pick the tracing session with the highest
- // score (score <= 0 is ignored), will steal its contents, save the trace into
- // a known path and stop prematurely.
- // This field was introduced in Android S.
+ // score (score <= 0 is ignored) and:
+ // On Android S, T: will steal its contents, save the trace into
+ // a known path and stop prematurely.
+ // On Android U+: will create a read-only snapshot and save that into a known
+ // path, without stoppin the original tracing session.
+ // When this field is set the tracing session becomes eligible to be cloned
+ // by other UIDs.
optional int32 bugreport_score = 30;
// Triggers allow producers to start or stop the tracing session when an event
diff --git a/protos/perfetto/config/trace_config.proto b/protos/perfetto/config/trace_config.proto
index 4fe3ea974..67c5f3d87 100644
--- a/protos/perfetto/config/trace_config.proto
+++ b/protos/perfetto/config/trace_config.proto
@@ -256,13 +256,18 @@ message TraceConfig {
// trace ends to notify it about the trace readiness.
optional bool notify_traceur = 16;
+ // This field was introduced in Android S.
// Android-only. If set to a value > 0, marks the trace session as a candidate
// for being attached to a bugreport. This field effectively acts as a z-index
// for bugreports. When Android's dumpstate runs perfetto
// --save-for-bugreport, traced will pick the tracing session with the highest
- // score (score <= 0 is ignored), will steal its contents, save the trace into
- // a known path and stop prematurely.
- // This field was introduced in Android S.
+ // score (score <= 0 is ignored) and:
+ // On Android S, T: will steal its contents, save the trace into
+ // a known path and stop prematurely.
+ // On Android U+: will create a read-only snapshot and save that into a known
+ // path, without stoppin the original tracing session.
+ // When this field is set the tracing session becomes eligible to be cloned
+ // by other UIDs.
optional int32 bugreport_score = 30;
// Triggers allow producers to start or stop the tracing session when an event
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index e886311d7..77ff04114 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -2935,13 +2935,18 @@ message TraceConfig {
// trace ends to notify it about the trace readiness.
optional bool notify_traceur = 16;
+ // This field was introduced in Android S.
// Android-only. If set to a value > 0, marks the trace session as a candidate
// for being attached to a bugreport. This field effectively acts as a z-index
// for bugreports. When Android's dumpstate runs perfetto
// --save-for-bugreport, traced will pick the tracing session with the highest
- // score (score <= 0 is ignored), will steal its contents, save the trace into
- // a known path and stop prematurely.
- // This field was introduced in Android S.
+ // score (score <= 0 is ignored) and:
+ // On Android S, T: will steal its contents, save the trace into
+ // a known path and stop prematurely.
+ // On Android U+: will create a read-only snapshot and save that into a known
+ // path, without stoppin the original tracing session.
+ // When this field is set the tracing session becomes eligible to be cloned
+ // by other UIDs.
optional int32 bugreport_score = 30;
// Triggers allow producers to start or stop the tracing session when an event
diff --git a/src/tracing/core/tracing_service_impl.cc b/src/tracing/core/tracing_service_impl.cc
index b32a65854..7c687f5d7 100644
--- a/src/tracing/core/tracing_service_impl.cc
+++ b/src/tracing/core/tracing_service_impl.cc
@@ -3580,8 +3580,13 @@ base::Status TracingServiceImpl::DoCloneSession(ConsumerEndpointImpl* consumer,
"The consumer is already attached to another tracing session");
}
- if (src->consumer_uid != consumer->uid_ && consumer->uid_ != 0)
+ // Skip the UID check for sessions marked with a bugreport_score > 0.
+ // Those sessions, by design, can be stolen by any other consumer for the
+ // sake of creating snapshots for bugreports.
+ if (src->config.bugreport_score() <= 0 &&
+ src->consumer_uid != consumer->uid_ && consumer->uid_ != 0) {
return PERFETTO_SVC_ERR("Not allowed to clone a session from another UID");
+ }
// First clone all TraceBuffer(s). This can fail because of ENOMEM. If it
// happens bail out early before creating any session.
diff --git a/src/tracing/core/tracing_service_impl_unittest.cc b/src/tracing/core/tracing_service_impl_unittest.cc
index fb175e990..9b6b6ae54 100644
--- a/src/tracing/core/tracing_service_impl_unittest.cc
+++ b/src/tracing/core/tracing_service_impl_unittest.cc
@@ -4529,6 +4529,64 @@ TEST_F(TracingServiceImplTest, CloneSession) {
Property(&protos::gen::TraceUuid::lsb, Eq(clone_uuid.lsb()))))));
}
+// Test that a consumer cannot clone a session from a consumer with a different
+// uid (unless it's marked as eligible for bugreport, see next test).
+TEST_F(TracingServiceImplTest, CloneSessionAcrossUidDenied) {
+ // The consumer the creates the initial tracing session.
+ std::unique_ptr<MockConsumer> consumer = CreateMockConsumer();
+ consumer->Connect(svc.get());
+
+ // The consumer that clones it and reads back the data.
+ std::unique_ptr<MockConsumer> consumer2 = CreateMockConsumer();
+ consumer2->Connect(svc.get(), 1234);
+
+ TraceConfig trace_config;
+ trace_config.add_buffers()->set_size_kb(32);
+
+ consumer->EnableTracing(trace_config);
+ auto flush_request = consumer->Flush();
+ ASSERT_TRUE(flush_request.WaitForReply());
+
+ auto clone_done = task_runner.CreateCheckpoint("clone_done");
+ EXPECT_CALL(*consumer2, OnSessionCloned(_))
+ .WillOnce(Invoke([clone_done](const Consumer::OnSessionClonedArgs& args) {
+ clone_done();
+ ASSERT_FALSE(args.success);
+ ASSERT_TRUE(base::Contains(args.error, "session from another UID"));
+ }));
+ consumer2->CloneSession(1);
+ task_runner.RunUntilCheckpoint("clone_done");
+}
+
+// Test that a consumer can clone a session from a different uid if the trace is
+// marked as eligible for bugreport.
+TEST_F(TracingServiceImplTest, CloneSessionAcrossUidForBugreport) {
+ // The consumer the creates the initial tracing session.
+ std::unique_ptr<MockConsumer> consumer = CreateMockConsumer();
+ consumer->Connect(svc.get());
+
+ // The consumer that clones it and reads back the data.
+ std::unique_ptr<MockConsumer> consumer2 = CreateMockConsumer();
+ consumer2->Connect(svc.get(), 1234);
+
+ TraceConfig trace_config;
+ trace_config.add_buffers()->set_size_kb(32);
+ trace_config.set_bugreport_score(1);
+
+ consumer->EnableTracing(trace_config);
+ auto flush_request = consumer->Flush();
+ ASSERT_TRUE(flush_request.WaitForReply());
+
+ auto clone_done = task_runner.CreateCheckpoint("clone_done");
+ EXPECT_CALL(*consumer2, OnSessionCloned(_))
+ .WillOnce(Invoke([clone_done](const Consumer::OnSessionClonedArgs& args) {
+ clone_done();
+ ASSERT_TRUE(args.success);
+ }));
+ consumer2->CloneSession(1);
+ task_runner.RunUntilCheckpoint("clone_done");
+}
+
TEST_F(TracingServiceImplTest, InvalidBufferSizes) {
std::unique_ptr<MockConsumer> consumer = CreateMockConsumer();
consumer->Connect(svc.get());