Initial sepolicy for app_zygote.

The application zygote is a new sort of zygote process that is a
child of the regular zygote. Each application zygote is tied to the
application for which it's launched. Once it's started, it will
pre-load some of the code for that specific application, much like
the regular zygote does for framework code.

Once the application zygote is up and running, it can spawn
isolated service processes that run in the isolated_app domain. These
services can then benefit from already having the relevant
application code and data pre-loaded.

The policy is largely the same as the webview_zygote domain,
however there are a few crucial points where the policy is different.

1) The app_zygote runs under the UID of the application that spawned
   it.
2) During app_zygote launch, it will call a callback that is
   controlled by the application, that allows the application to
   pre-load code and data that it thinks is relevant.

Especially point 2 is imporant: it means that untrusted code can run
in the app_zygote context. This context is severely limited, and the
main concern is around the setgid/setuid capabilities. Those conerns
are mitigated by installing a seccomp filter that only allows
setgid/setuid to be called in a safe range.

Bug: 111434506
Test: app_zygote can start and fork children without denials.
Change-Id: I1cc49ee0042d41e5ac6eb81d8f8a10ba448d4832
diff --git a/private/app_zygote.te b/private/app_zygote.te
new file mode 100644
index 0000000..2cb7e0e
--- /dev/null
+++ b/private/app_zygote.te
@@ -0,0 +1,135 @@
+typeattribute app_zygote coredomain;
+
+######
+###### Policy below is different from regular zygote-spawned apps
+######
+
+# The app_zygote needs to be able to transition domains.
+typeattribute app_zygote mlstrustedsubject;
+
+# Allow access to temporary files, which is normally permitted through
+# a domain macro.
+tmpfs_domain(app_zygote);
+
+# Set the UID/GID of the process.
+# This will be further limited to a range of isolated UIDs with seccomp.
+allow app_zygote self:global_capability_class_set { setgid setuid };
+# Drop capabilities from bounding set.
+allow app_zygote self:global_capability_class_set setpcap;
+# Switch SELinux context to isolated app domain.
+allow app_zygote self:process setcurrent;
+allow app_zygote isolated_app:process dyntransition;
+
+# For JIT
+allow app_zygote self:process execmem;
+
+# Allow app_zygote to stat the files that it opens. It must
+# be able to inspect them so that it can reopen them on fork
+# if necessary: b/30963384.
+allow app_zygote debugfs_trace_marker:file getattr;
+
+# get system_server process group
+allow app_zygote system_server:process getpgid;
+
+# Interaction between the app_zygote and its children.
+allow app_zygote isolated_app:process setpgid;
+
+# TODO (b/63631799) fix this access
+dontaudit app_zygote mnt_expand_file:dir getattr;
+
+# Get seapp_contexts
+allow app_zygote seapp_contexts_file:file r_file_perms;
+# Check validity of SELinux context before use.
+selinux_check_context(app_zygote)
+# Check SELinux permissions.
+selinux_check_access(app_zygote)
+
+######
+###### Policy below is shared with regular zygote-spawned apps
+######
+
+# Child of zygote.
+allow app_zygote zygote:fd use;
+allow app_zygote zygote:process sigchld;
+
+# For ART (read /data/dalvik-cache).
+r_dir_file(app_zygote, dalvikcache_data_file);
+allow app_zygote dalvikcache_data_file:file execute;
+
+# Allow reading/executing installed binaries to enable preloading
+# application data
+allow app_zygote apk_data_file:dir r_dir_perms;
+allow app_zygote apk_data_file:file { r_file_perms execute };
+
+# Allow app_zygote access to /vendor/overlay
+r_dir_file(app_zygote, vendor_overlay_file)
+
+allow app_zygote system_data_file:lnk_file r_file_perms;
+allow app_zygote system_data_file:file { getattr read map };
+
+#####
+##### Neverallow
+#####
+
+# Only permit transition to isolated_app.
+neverallow app_zygote { domain -isolated_app }:process dyntransition;
+
+# Only setcon() transitions, no exec() based transitions, except for crash_dump.
+neverallow app_zygote { domain -crash_dump }:process transition;
+
+# Must not exec() a program without changing domains.
+# Having said that, exec() above is not allowed.
+neverallow app_zygote *:file execute_no_trans;
+
+# The only way to enter this domain is for the zygote to fork a new
+# app_zygote child.
+neverallow { domain -zygote } app_zygote:process dyntransition;
+
+# Disallow write access to properties.
+neverallow app_zygote property_socket:sock_file write;
+neverallow app_zygote property_type:property_service set;
+
+# Should not have any access to non-app data files.
+neverallow app_zygote {
+    bluetooth_data_file
+    nfc_data_file
+    radio_data_file
+    shell_data_file
+}:file { rwx_file_perms };
+
+neverallow app_zygote {
+    service_manager_type
+    -activity_service
+    -webviewupdate_service
+}:service_manager find;
+
+# Isolated apps should not be able to access the driver directly.
+neverallow app_zygote gpu_device:chr_file { rwx_file_perms };
+
+# Do not allow app_zygote access to /cache.
+neverallow app_zygote cache_file:dir ~{ r_dir_perms };
+neverallow app_zygote cache_file:file ~{ read getattr };
+
+# Do not allow most socket access. This is socket_class_set, excluding unix_dgram_socket,
+# unix_stream_socket, and netlink_selinux_socket.
+neverallow app_zygote domain:{
+  socket tcp_socket udp_socket rawip_socket netlink_socket packet_socket key_socket
+  appletalk_socket netlink_route_socket netlink_tcpdiag_socket
+  netlink_nflog_socket netlink_xfrm_socket netlink_audit_socket
+  netlink_dnrt_socket netlink_kobject_uevent_socket tun_socket netlink_iscsi_socket
+  netlink_fib_lookup_socket netlink_connector_socket netlink_netfilter_socket
+  netlink_generic_socket netlink_scsitransport_socket netlink_rdma_socket netlink_crypto_socket
+  sctp_socket icmp_socket ax25_socket ipx_socket netrom_socket atmpvc_socket
+  x25_socket rose_socket decnet_socket atmsvc_socket rds_socket irda_socket
+  pppox_socket llc_socket can_socket tipc_socket bluetooth_socket iucv_socket
+  rxrpc_socket isdn_socket phonet_socket ieee802154_socket caif_socket
+  alg_socket nfc_socket vsock_socket kcm_socket qipcrtr_socket smc_socket
+} *;
+
+# Do not allow access to Bluetooth-related system properties.
+# neverallow rules for Bluetooth-related data files are listed above.
+neverallow app_zygote {
+  bluetooth_a2dp_offload_prop
+  bluetooth_prop
+  exported_bluetooth_prop
+}:file create_file_perms;
diff --git a/private/compat/26.0/26.0.ignore.cil b/private/compat/26.0/26.0.ignore.cil
index ee9a99e..5d90832 100644
--- a/private/compat/26.0/26.0.ignore.cil
+++ b/private/compat/26.0/26.0.ignore.cil
@@ -17,6 +17,7 @@
     apexd_exec
     apexd_prop
     apexd_tmpfs
+    app_zygote
     atrace
     binder_calls_stats_service
     biometric_service
diff --git a/private/compat/27.0/27.0.ignore.cil b/private/compat/27.0/27.0.ignore.cil
index bf273f3..1ce8f4d 100644
--- a/private/compat/27.0/27.0.ignore.cil
+++ b/private/compat/27.0/27.0.ignore.cil
@@ -16,6 +16,7 @@
     apexd_exec
     apexd_prop
     apexd_tmpfs
+    app_zygote
     atrace
     binder_calls_stats_service
     biometric_service
diff --git a/private/compat/28.0/28.0.ignore.cil b/private/compat/28.0/28.0.ignore.cil
index 4ae2071..2040032 100644
--- a/private/compat/28.0/28.0.ignore.cil
+++ b/private/compat/28.0/28.0.ignore.cil
@@ -17,6 +17,7 @@
     apexd_exec
     apexd_prop
     apexd_tmpfs
+    app_zygote
     biometric_service
     bpf_progs_loaded_prop
     bugreport_service
diff --git a/private/coredomain.te b/private/coredomain.te
index 1fc3b8a..db62cb9 100644
--- a/private/coredomain.te
+++ b/private/coredomain.te
@@ -60,6 +60,7 @@
         -installd
         -rs # spawned by appdomain, so carryover the exception above
         -system_server
+        -app_zygote
         -webview_zygote
         -zygote
         userdebug_or_eng(`-heapprofd')
@@ -75,6 +76,7 @@
         -installd
         -rs # spawned by appdomain, so carryover the exception above
         -system_server
+        -app_zygote
         -webview_zygote
         -zygote
         userdebug_or_eng(`-heapprofd')
diff --git a/private/domain.te b/private/domain.te
index 6d62a59..326e62a 100644
--- a/private/domain.te
+++ b/private/domain.te
@@ -101,6 +101,7 @@
   domain
   -adbd
   -appdomain
+  -app_zygote
   -dexoptanalyzer
   -installd
   userdebug_or_eng(`-perfprofd')
@@ -123,6 +124,7 @@
 neverallow {
   domain
   -appdomain
+  -app_zygote
   -installd
   userdebug_or_eng(`-perfprofd')
   -rs # spawned by appdomain, so carryover the exception above
@@ -171,6 +173,7 @@
     -shell
     userdebug_or_eng(`-su')
     -system_server_startup # for memfd backed executable regions
+    -app_zygote
     -webview_zygote
     -zygote
     userdebug_or_eng(`-mediaextractor')
diff --git a/private/isolated_app.te b/private/isolated_app.te
index 3759488..3443dc4 100644
--- a/private/isolated_app.te
+++ b/private/isolated_app.te
@@ -43,6 +43,13 @@
 # Read system properties managed by webview_zygote.
 allow isolated_app webview_zygote_tmpfs:file read;
 
+# Inherit FDs from the app_zygote.
+allow isolated_app app_zygote:fd use;
+# Notify app_zygote of child death.
+allow isolated_app app_zygote:process sigchld;
+# Inherit logd write socket.
+allow isolated_app app_zygote:unix_dgram_socket write;
+
 # TODO (b/63631799) fix this access
 # suppress denials to /data/local/tmp
 dontaudit isolated_app shell_data_file:dir search;
diff --git a/private/seapp_contexts b/private/seapp_contexts
index 9fc6816..ae07a96 100644
--- a/private/seapp_contexts
+++ b/private/seapp_contexts
@@ -114,6 +114,7 @@
 user=shell seinfo=platform domain=shell name=com.android.shell type=shell_data_file
 user=webview_zygote seinfo=webview_zygote domain=webview_zygote
 user=_isolated domain=isolated_app levelFrom=all
+user=_app seinfo=app_zygote domain=app_zygote levelFrom=all
 user=_app seinfo=media domain=mediaprovider name=android.process.media type=app_data_file levelFrom=user
 user=_app seinfo=platform domain=platform_app type=app_data_file levelFrom=user
 user=_app isV2App=true isEphemeralApp=true domain=ephemeral_app type=app_data_file levelFrom=all
diff --git a/private/system_server.te b/private/system_server.te
index bb69796..e36d483 100644
--- a/private/system_server.te
+++ b/private/system_server.te
@@ -37,6 +37,7 @@
 allow system_server zygote:process sigkill;
 allow system_server crash_dump:process sigkill;
 allow system_server webview_zygote:process sigkill;
+allow system_server app_zygote:process sigkill;
 
 # Read /system/bin/app_process.
 allow system_server zygote_exec:file r_file_perms;
@@ -172,6 +173,9 @@
 # Communicate over a socket created by webview_zygote.
 allow system_server webview_zygote:unix_stream_socket { read write connectto setopt };
 
+# Communicate over a socket created by app_zygote.
+allow system_server app_zygote:unix_stream_socket { read write connectto setopt };
+
 # Perform Binder IPC.
 binder_use(system_server)
 binder_call(system_server, appdomain)
diff --git a/private/zygote.te b/private/zygote.te
index 0c1e0df..e23f36e 100644
--- a/private/zygote.te
+++ b/private/zygote.te
@@ -17,6 +17,7 @@
 allow zygote system_server_startup:process dyntransition;
 allow zygote appdomain:process dyntransition;
 allow zygote webview_zygote:process dyntransition;
+allow zygote app_zygote:process dyntransition;
 
 # Allow zygote to read app /proc/pid dirs (b/10455872).
 allow zygote appdomain:dir { getattr search };
@@ -26,6 +27,7 @@
 allow zygote system_server:process { getpgid setpgid };
 allow zygote appdomain:process { getpgid setpgid };
 allow zygote webview_zygote:process { getpgid setpgid };
+allow zygote app_zygote:process { getpgid setpgid };
 
 # Read system data.
 allow zygote system_data_file:dir r_dir_perms;
@@ -136,11 +138,13 @@
 # written on appdomain are applied to all app processes.
 # This is achieved by ensuring that it is impossible for zygote to
 # setcon (dyntransition) to any types other than those associated
-# with appdomain plus system_server_startup and webview_zygote.
+# with appdomain plus system_server_startup, webview_zygote and
+# app_zygote.
 neverallow zygote ~{
   appdomain
   system_server_startup
   webview_zygote
+  app_zygote
 }:process dyntransition;
 
 # Zygote should never execute anything from /data except for /data/dalvik-cache files.
diff --git a/public/app_zygote.te b/public/app_zygote.te
new file mode 100644
index 0000000..0d5fec1
--- /dev/null
+++ b/public/app_zygote.te
@@ -0,0 +1,5 @@
+# app_zygote is an auxiliary zygote process that is used to spawn
+# isolated service processes for individual applications. It is
+# spawned from the regular zygote process as a "child zygote".
+
+type app_zygote, domain;
diff --git a/public/domain.te b/public/domain.te
index 6592c7c..7c3a110 100644
--- a/public/domain.te
+++ b/public/domain.te
@@ -1073,8 +1073,9 @@
 neverallow { domain -zygote -system_server } zygote:unix_stream_socket connectto;
 neverallow { domain -system_server } zygote_socket:sock_file write;
 
-neverallow { domain -system_server -webview_zygote } webview_zygote:unix_stream_socket connectto;
+neverallow { domain -system_server -webview_zygote -app_zygote } webview_zygote:unix_stream_socket connectto;
 neverallow { domain -system_server } webview_zygote:sock_file write;
+neverallow { domain -system_server } app_zygote:sock_file write;
 
 neverallow {
   domain
@@ -1205,7 +1206,7 @@
 } shell:process { transition dyntransition };
 
 # Only domains spawned from zygote and runas may have the appdomain attribute.
-neverallow { domain -runas -webview_zygote -zygote } {
+neverallow { domain -runas -app_zygote -webview_zygote -zygote } {
   appdomain -shell userdebug_or_eng(`-su')
 }:process { transition dyntransition };