From 1bbda7e662039e0224667f6a67758e7ce29b1204 Mon Sep 17 00:00:00 2001 From: Martijn Coenen <maco@google.com> Date: Mon, 5 Nov 2018 11:39:15 +0100 Subject: [PATCH] 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 --- private/app_zygote.te | 135 ++++++++++++++++++++++++++++ private/compat/26.0/26.0.ignore.cil | 1 + private/compat/27.0/27.0.ignore.cil | 1 + private/compat/28.0/28.0.ignore.cil | 1 + private/coredomain.te | 2 + private/domain.te | 3 + private/isolated_app.te | 7 ++ private/seapp_contexts | 1 + private/system_server.te | 4 + private/zygote.te | 6 +- public/app_zygote.te | 5 ++ public/domain.te | 5 +- 12 files changed, 168 insertions(+), 3 deletions(-) create mode 100644 private/app_zygote.te create mode 100644 public/app_zygote.te diff --git a/private/app_zygote.te b/private/app_zygote.te new file mode 100644 index 000000000..2cb7e0e34 --- /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 ee9a99e2c..5d9083200 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 bf273f34c..1ce8f4d7a 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 4ae2071f3..2040032bf 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 1fc3b8a1c..db62cb9fe 100644 --- a/private/coredomain.te +++ b/private/coredomain.te @@ -60,6 +60,7 @@ full_treble_only(` -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 @@ full_treble_only(` -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 6d62a592e..326e62ae1 100644 --- a/private/domain.te +++ b/private/domain.te @@ -101,6 +101,7 @@ neverallow { domain -adbd -appdomain + -app_zygote -dexoptanalyzer -installd userdebug_or_eng(`-perfprofd') @@ -123,6 +124,7 @@ neverallow { neverallow { domain -appdomain + -app_zygote -installd userdebug_or_eng(`-perfprofd') -rs # spawned by appdomain, so carryover the exception above @@ -171,6 +173,7 @@ neverallow { -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 37594887f..3443dc439 100644 --- a/private/isolated_app.te +++ b/private/isolated_app.te @@ -43,6 +43,13 @@ allow isolated_app webview_zygote:unix_dgram_socket write; # 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 9fc6816e8..ae07a9610 100644 --- a/private/seapp_contexts +++ b/private/seapp_contexts @@ -114,6 +114,7 @@ user=shared_relro domain=shared_relro 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 bb6979606..e36d483e0 100644 --- a/private/system_server.te +++ b/private/system_server.te @@ -37,6 +37,7 @@ allow system_server zygote:process sigchld; 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 @@ allow system_server gpuservice:unix_stream_socket { read write setopt }; # 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 0c1e0df0d..e23f36e1f 100644 --- a/private/zygote.te +++ b/private/zygote.te @@ -17,6 +17,7 @@ allow zygote self:process setcurrent; 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 appdomain:file { r_file_perms }; 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 @@ dontaudit zygote self:global_capability_class_set sys_resource; # 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 000000000..0d5fec142 --- /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 6592c7ce5..7c3a1105f 100644 --- a/public/domain.te +++ b/public/domain.te @@ -1073,8 +1073,9 @@ neverallow { 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 @@ neverallow { } 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 }; -- GitLab