From c80f9e037bedb09d08a261f255f87ea105fa371b Mon Sep 17 00:00:00 2001
From: Primiano Tucci <primiano@google.com>
Date: Thu, 21 Dec 2017 03:51:15 +0100
Subject: [PATCH] Perfetto SELinux policies

Perfetto is a performance instrumentation and logging framework,
living in AOSP's /external/pefetto.
Perfetto introduces in the system one binary and two daemons
(the binary can specialize in either depending on the cmdline).

1) traced: unprivileged daemon. This is architecturally similar to logd.
   It exposes two UNIX sockets:
   - /dev/socket/traced_producer : world-accessible, allows to stream
     tracing data. A tmpfs file descriptor is sent via SCM_RIGHTS
     from traced to each client process, which needs to be able to
     mmap it R/W (but not X)
   - /dev/socket/traced_consumer : privilege-accessible (only from:
     shell, statsd). It allows to configure tracing and read the trace
     buffer.
2) traced_probes: privileged daemon. This needs to:
   - access tracingfs (/d/tracing) to turn tracing on and off.
   - exec atrace
   - connect to traced_producer to stream data to traced.

init.rc file:
https://android-review.googlesource.com/c/platform/external/perfetto/+/575382/14/perfetto.rc

Bug: 70942310
Change-Id: Ia3b5fdacbd5a8e6e23b82f1d6fabfa07e4abc405
---
 private/compat/26.0/26.0.ignore.cil |  8 +++++
 private/domain.te                   |  1 +
 private/ephemeral_app.te            |  6 ++++
 private/file_contexts               |  4 +++
 private/isolated_app.te             |  6 ++++
 private/priv_app.te                 |  6 ++++
 private/shell.te                    | 10 ++++++
 private/statsd.te                   |  4 ++-
 private/traced.te                   | 38 ++++++++++++++++++++
 private/traced_probes.te            | 55 +++++++++++++++++++++++++++++
 private/untrusted_app_all.te        |  6 ++++
 private/untrusted_v2_app.te         |  6 ++++
 public/domain.te                    |  3 +-
 public/file.te                      |  2 ++
 14 files changed, 153 insertions(+), 2 deletions(-)
 create mode 100644 private/traced.te
 create mode 100644 private/traced_probes.te

diff --git a/private/compat/26.0/26.0.ignore.cil b/private/compat/26.0/26.0.ignore.cil
index 77d1b4fc1..f70cb7c75 100644
--- a/private/compat/26.0/26.0.ignore.cil
+++ b/private/compat/26.0/26.0.ignore.cil
@@ -55,6 +55,14 @@
     tombstone_wifi_data_file
     traceur_app
     traceur_app_tmpfs
+    traced
+    traced_consumer_socket
+    traced_exec
+    traced_probes
+    traced_probes_exec
+    traced_probes_tmpfs
+    traced_producer_socket
+    traced_tmpfs
     update_engine_log_data_file
     vendor_init
     vold_prepare_subdirs
diff --git a/private/domain.te b/private/domain.te
index 1fd75bc78..72c3855e3 100644
--- a/private/domain.te
+++ b/private/domain.te
@@ -71,6 +71,7 @@ full_treble_only(`
     -dumpstate
     -init
     userdebug_or_eng(`-perfprofd')
+    userdebug_or_eng(`-traced_probes')
     -shell
     userdebug_or_eng(`-traceur_app')
     -vendor_init
diff --git a/private/ephemeral_app.te b/private/ephemeral_app.te
index 7694739bd..dbfbcf9e8 100644
--- a/private/ephemeral_app.te
+++ b/private/ephemeral_app.te
@@ -35,6 +35,12 @@ allow ephemeral_app drmserver_service:service_manager find;
 allow ephemeral_app radio_service:service_manager find;
 allow ephemeral_app ephemeral_app_api_service:service_manager find;
 
+# Write app-specific trace data to the Perfetto traced damon. This requires
+# connecting to its producer socket and obtaining a (per-process) tmpfs fd.
+allow ephemeral_app traced:fd use;
+allow ephemeral_app traced_tmpfs:file { read write getattr map };
+unix_socket_connect(ephemeral_app, traced_producer, traced)
+
 ###
 ### neverallow rules
 ###
diff --git a/private/file_contexts b/private/file_contexts
index 0765ef0b4..de959d450 100644
--- a/private/file_contexts
+++ b/private/file_contexts
@@ -146,6 +146,8 @@
 /dev/socket/tombstoned_crash u:object_r:tombstoned_crash_socket:s0
 /dev/socket/tombstoned_java_trace u:object_r:tombstoned_java_trace_socket:s0
 /dev/socket/tombstoned_intercept u:object_r:tombstoned_intercept_socket:s0
+/dev/socket/traced_producer	u:object_r:traced_producer_socket:s0
+/dev/socket/traced_consumer	u:object_r:traced_consumer_socket:s0
 /dev/socket/uncrypt	u:object_r:uncrypt_socket:s0
 /dev/socket/vold	u:object_r:vold_socket:s0
 /dev/socket/webview_zygote	u:object_r:webview_zygote_socket:s0
@@ -240,6 +242,8 @@
 /system/bin/lmkd        u:object_r:lmkd_exec:s0
 /system/bin/inputflinger u:object_r:inputflinger_exec:s0
 /system/bin/logd        u:object_r:logd_exec:s0
+/system/bin/traced        u:object_r:traced_exec:s0
+/system/bin/traced_probes        u:object_r:traced_probes_exec:s0
 /system/bin/uncrypt     u:object_r:uncrypt_exec:s0
 /system/bin/update_verifier u:object_r:update_verifier_exec:s0
 /system/bin/logwrapper  u:object_r:system_file:s0
diff --git a/private/isolated_app.te b/private/isolated_app.te
index 30253af60..06ed2c82c 100644
--- a/private/isolated_app.te
+++ b/private/isolated_app.te
@@ -47,6 +47,12 @@ allow isolated_app webview_zygote_tmpfs:file read;
 # suppress denials to /data/local/tmp
 dontaudit isolated_app shell_data_file:dir search;
 
+# Write app-specific trace data to the Perfetto traced damon. This requires
+# connecting to its producer socket and obtaining a (per-process) tmpfs fd.
+allow isolated_app traced:fd use;
+allow isolated_app traced_tmpfs:file { read write getattr map };
+unix_socket_connect(isolated_app, traced_producer, traced)
+
 #####
 ##### Neverallow
 #####
diff --git a/private/priv_app.te b/private/priv_app.te
index ea1ce5b16..92bfc570a 100644
--- a/private/priv_app.te
+++ b/private/priv_app.te
@@ -116,6 +116,12 @@ allow priv_app selinuxfs:file r_file_perms;
 
 read_runtime_log_tags(priv_app)
 
+# Write app-specific trace data to the Perfetto traced damon. This requires
+# connecting to its producer socket and obtaining a (per-process) tmpfs fd.
+allow priv_app traced:fd use;
+allow priv_app traced_tmpfs:file { read write getattr map };
+unix_socket_connect(priv_app, traced_producer, traced)
+
 # suppress denials when safetynet scans /system
 dontaudit priv_app exec_type:file getattr;
 dontaudit priv_app device:dir read;
diff --git a/private/shell.te b/private/shell.te
index 5299532ac..a3c49db37 100644
--- a/private/shell.te
+++ b/private/shell.te
@@ -26,3 +26,13 @@ binder_call(shell, storaged)
 # Perform SELinux access checks, needed for CTS
 selinux_check_access(shell)
 selinux_check_context(shell)
+
+# Control Perfetto traced and obtain traces from it.
+# Needed for Studio and debugging.
+unix_socket_connect(shell, traced_consumer, traced)
+
+# Allow shell binaries to write trace data to Perfetto. Used for testing and
+# cmdline utils.
+allow shell traced:fd use;
+allow shell traced_tmpfs:file { read write getattr map };
+unix_socket_connect(shell, traced_producer, traced)
diff --git a/private/statsd.te b/private/statsd.te
index 9d78ebb40..6b7f8cdd7 100644
--- a/private/statsd.te
+++ b/private/statsd.te
@@ -30,6 +30,9 @@ binder_call(statsd, statscompanion_service)
 read_logd(statsd)
 control_logd(statsd)
 
+# Allow to control Perfetto traced and consume its traces.
+unix_socket_connect(statsd, traced_consumer, traced)
+
 # Grant statsd with permissions to register the services.
 allow statsd {
   statscompanion_service
@@ -71,4 +74,3 @@ neverallow { domain -statsd -init -vold -vendor_init } stats_data_file:file *;
 
 # Limited access to the directory itself.
 neverallow { domain -statsd -init -vold -vendor_init } stats_data_file:dir *;
-
diff --git a/private/traced.te b/private/traced.te
new file mode 100644
index 000000000..bb7a09191
--- /dev/null
+++ b/private/traced.te
@@ -0,0 +1,38 @@
+# Perfetto user-space tracing daemon (unprivileged)
+type traced, domain, coredomain;
+type traced_exec, exec_type, file_type;
+
+# Allow init to exec the daemon.
+init_daemon_domain(traced)
+
+# Allow traced to start with a lower scheduling class and change
+# class accordingly to what defined in the config provided by
+# the privileged process that controls it.
+allow traced self:global_capability_class_set { sys_nice };
+
+###
+### Neverallow rules
+###
+### traced should NEVER do any of this
+
+# Disallow mapping executable memory (execstack and exec are already disallowed
+# globally in domain.te).
+neverallow traced self:process execmem;
+
+# Block device access.
+neverallow traced dev_type:blk_file { read write };
+
+# ptrace any other process
+neverallow traced domain:process ptrace;
+
+# Disallows access to /data files, still allowing to write to file descriptors
+# passed through the socket.
+neverallow traced { data_file_type -system_data_file -zoneinfo_data_file }:dir *;
+neverallow traced system_data_file:dir ~{ getattr search };
+neverallow traced zoneinfo_data_file:dir ~r_dir_perms;
+neverallow traced { data_file_type -zoneinfo_data_file }:lnk_file *;
+neverallow traced { data_file_type -zoneinfo_data_file }:file ~write;
+
+# Only init is allowed to enter the traced domain via exec()
+neverallow { domain -init } traced:process transition;
+neverallow * traced:process dyntransition;
diff --git a/private/traced_probes.te b/private/traced_probes.te
new file mode 100644
index 000000000..15c51d4cd
--- /dev/null
+++ b/private/traced_probes.te
@@ -0,0 +1,55 @@
+# Perfetto tracing probes, has tracefs access.
+type traced_probes, domain, coredomain;
+type traced_probes_exec, exec_type, file_type;
+
+# Allow init to exec the daemon.
+init_daemon_domain(traced_probes)
+
+# Write trace data to the Perfetto traced damon. This requires connecting to its
+# producer socket and obtaining a (per-process) tmpfs fd.
+allow traced_probes traced:fd use;
+allow traced_probes traced_tmpfs:file { read write getattr map };
+unix_socket_connect(traced_probes, traced_producer, traced)
+
+# Allow traced_probes to access tracefs.
+# TODO(primiano): For the moment this is userdebug/eng only until we get an
+# approval for user builds.
+userdebug_or_eng(`
+allow traced_probes debugfs_tracing:dir r_dir_perms;
+allow traced_probes debugfs_tracing:file rw_file_perms;
+allow traced_probes debugfs_tracing_debug:file rw_file_perms;
+allow traced_probes debugfs_trace_marker:file getattr;
+')
+
+# Allow traced_probes to start with a higher scheduling class and then downgrade
+# itself.
+allow traced_probes self:global_capability_class_set { sys_nice };
+
+# Allow procfs access
+r_dir_file(traced_probes, domain)
+
+###
+### Neverallow rules
+###
+### traced_probes should NEVER do any of this
+
+# Disallow mapping executable memory (execstack and exec are already disallowed
+# globally in domain.te).
+neverallow traced_probes self:process execmem;
+
+# Block device access.
+neverallow traced_probes dev_type:blk_file { read write };
+
+# ptrace any other app
+neverallow traced_probes domain:process ptrace;
+
+# Disallows access to /data files.
+neverallow traced { data_file_type -system_data_file -zoneinfo_data_file }:dir *;
+neverallow traced system_data_file:dir ~{ getattr search };
+neverallow traced zoneinfo_data_file:dir ~r_dir_perms;
+neverallow traced { data_file_type -zoneinfo_data_file }:lnk_file *;
+neverallow traced { data_file_type -zoneinfo_data_file }:file *;
+
+# Only init is allowed to enter the traced_probes domain via exec()
+neverallow { domain -init } traced_probes:process transition;
+neverallow * traced_probes:process dyntransition;
diff --git a/private/untrusted_app_all.te b/private/untrusted_app_all.te
index f96cae0e1..e76407bc0 100644
--- a/private/untrusted_app_all.te
+++ b/private/untrusted_app_all.te
@@ -105,3 +105,9 @@ allow untrusted_app_all preloads_data_file:dir search;
 allow untrusted_app_all vendor_app_file:dir { open getattr read search };
 allow untrusted_app_all vendor_app_file:file { open getattr read execute };
 allow untrusted_app_all vendor_app_file:lnk_file { open getattr read };
+
+# Write app-specific trace data to the Perfetto traced damon. This requires
+# connecting to its producer socket and obtaining a (per-process) tmpfs fd.
+allow untrusted_app_all traced:fd use;
+allow untrusted_app_all traced_tmpfs:file { read write getattr map };
+unix_socket_connect(untrusted_app_all, traced_producer, traced)
diff --git a/private/untrusted_v2_app.te b/private/untrusted_v2_app.te
index 60634aefb..8f4bceb2c 100644
--- a/private/untrusted_v2_app.te
+++ b/private/untrusted_v2_app.te
@@ -39,3 +39,9 @@ allow untrusted_v2_app app_api_service:service_manager find;
 
 # gdbserver for ndk-gdb ptrace attaches to app process.
 allow untrusted_v2_app self:process ptrace;
+
+# Write app-specific trace data to the Perfetto traced damon. This requires
+# connecting to its producer socket and obtaining a (per-process) tmpfs fd.
+allow untrusted_v2_app traced:fd use;
+allow untrusted_v2_app traced_tmpfs:file { read write getattr map };
+unix_socket_connect(untrusted_v2_app, traced_producer, traced)
diff --git a/public/domain.te b/public/domain.te
index 142c10b20..70d8ae20f 100644
--- a/public/domain.te
+++ b/public/domain.te
@@ -149,7 +149,8 @@ allow domain sysfs:lnk_file { getattr read };
 
 # libc references /data/misc/zoneinfo for timezone related information
 # This directory is considered to be a VNDK-stable
-r_dir_file(domain, zoneinfo_data_file)
+allow domain zoneinfo_data_file:file r_file_perms;
+allow domain zoneinfo_data_file:dir r_dir_perms;
 
 # Lots of processes access current CPU information
 r_dir_file(domain, sysfs_devices_system_cpu)
diff --git a/public/file.te b/public/file.te
index c536a8a5a..9660da2c4 100644
--- a/public/file.te
+++ b/public/file.te
@@ -315,6 +315,8 @@ type system_ndebug_socket, file_type, data_file_type, core_data_file_type, cored
 type tombstoned_crash_socket, file_type, coredomain_socket, mlstrustedobject;
 type tombstoned_java_trace_socket, file_type, mlstrustedobject;
 type tombstoned_intercept_socket, file_type, coredomain_socket;
+type traced_producer_socket, file_type, coredomain_socket;
+type traced_consumer_socket, file_type, coredomain_socket;
 type uncrypt_socket, file_type, coredomain_socket;
 type vold_socket, file_type, coredomain_socket;
 type webview_zygote_socket, file_type, coredomain_socket;
-- 
GitLab