From 15715aea32b85c933778b97a46de6ccab42ca7fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Sat, 21 May 2022 05:03:29 -0700 Subject: [PATCH] much more finegrained bpf selinux privs for networking mainline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Goal is to gain a better handle on who has access to which maps and to allow (with bpfloader changes to create in one directory and move into the target directory) per-map selection of selinux context, while still having reasonable defaults for stuff pinned directly into the target location. BPFFS (ie. /sys/fs/bpf) labelling is as follows: subdirectory selinux context mainline usecase / usable by / fs_bpf no (*) core operating system (ie. platform) /net_private fs_bpf_net_private yes, T+ network_stack /net_shared fs_bpf_net_shared yes, T+ network_stack & system_server /netd_readonly fs_bpf_netd_readonly yes, T+ network_stack & system_server & r/o to netd /netd_shared fs_bpf_netd_shared yes, T+ network_stack & system_server & netd [**] /tethering fs_bpf_tethering yes, S+ network_stack /vendor fs_bpf_vendor no, T+ vendor * initial support for bpf was added back in P, but things worked differently back then with no bpfloader, and instead netd doing stuff by hand, bpfloader with pinning into /sys/fs/bpf was (I believe) added in Q (and was definitely there in R) ** additionally bpf programs are accesible to netutils_wrapper for use by iptables xt_bpf extensions 'mainline yes' currently means shipped by the com.android.tethering apex, but this is really another case of bad naming, as it's really the 'networking/connectivity/tethering' apex / mainline module. Long term the plan is to merge a few other networking mainline modules into it (and maybe give it a saner name...). The reason for splitting net_private vs tethering is that: S+ must support 4.9+ kernels and S era bpfloader v0.2+ T+ must support 4.14+ kernels and T beta3 era bpfloader v0.13+ The kernel affects the intelligence of the in-kernel bpf verifier and the available bpf helper functions. Older kernels have a tendency to reject programs that newer kernels allow. / && /vendor are not shipped via mainline, so only need to work with the bpfloader that's part of the core os. Ignore-AOSP-First: will be cherrypicked from tm-dev to aosp/master Bug: 218408035 Test: TreeHugger, manually on cuttlefish Signed-off-by: Maciej Żenczykowski Change-Id: I674866ebe32aca4fc851818c1ffcbec12ac4f7d4 --- prebuilts/api/33.0/private/bpfloader.te | 28 +++++++----- prebuilts/api/33.0/private/file.te | 7 +++ prebuilts/api/33.0/private/genfs_contexts | 4 ++ prebuilts/api/33.0/private/netd.te | 4 ++ .../api/33.0/private/netutils_wrapper.te | 4 +- prebuilts/api/33.0/private/network_stack.te | 44 +++++++++++++++++-- prebuilts/api/33.0/private/system_server.te | 3 +- prebuilts/api/33.0/public/attributes | 3 ++ prebuilts/api/33.0/public/file.te | 7 +-- prebuilts/api/33.0/public/netd.te | 2 - private/bpfloader.te | 28 +++++++----- private/file.te | 7 +++ private/genfs_contexts | 4 ++ private/netd.te | 4 ++ private/netutils_wrapper.te | 4 +- private/network_stack.te | 44 +++++++++++++++++-- private/system_server.te | 3 +- public/attributes | 3 ++ public/file.te | 7 +-- public/netd.te | 2 - tests/sepolicy_tests.py | 6 +++ 21 files changed, 174 insertions(+), 44 deletions(-) diff --git a/prebuilts/api/33.0/private/bpfloader.te b/prebuilts/api/33.0/private/bpfloader.te index d7b27b556..54cc91666 100644 --- a/prebuilts/api/33.0/private/bpfloader.te +++ b/prebuilts/api/33.0/private/bpfloader.te @@ -6,9 +6,9 @@ typeattribute bpfloader bpfdomain; allow bpfloader kmsg_device:chr_file w_file_perms; # These permissions are required to pin ebpf maps & programs. -allow bpfloader { fs_bpf fs_bpf_tethering fs_bpf_vendor }:dir { add_name create search write }; -allow bpfloader { fs_bpf fs_bpf_tethering fs_bpf_vendor }:file { create read setattr }; -allow { fs_bpf_tethering fs_bpf_vendor } fs_bpf:filesystem associate; +allow bpfloader bpffs_type:dir { add_name create remove_name search write }; +allow bpfloader bpffs_type:file { create read rename setattr }; +allow { bpffs_type -fs_bpf } fs_bpf:filesystem associate; # Allow bpfloader to create bpf maps and programs. allow bpfloader self:bpf { map_create map_read map_write prog_load prog_run }; @@ -26,17 +26,21 @@ allow bpfloader bpfloader_exec:file execute_no_trans; ### # TODO: get rid of init & vendor_init; Note: we don't care about getattr/mounton/search -neverallow { domain -init -vendor_init } { fs_bpf fs_bpf_tethering fs_bpf_vendor }:dir { open read setattr }; -neverallow { domain -bpfloader } { fs_bpf fs_bpf_tethering fs_bpf_vendor }:dir { add_name create write }; -neverallow domain { fs_bpf fs_bpf_tethering fs_bpf_vendor }:dir ~{ add_name create getattr mounton open read search setattr write }; +neverallow { domain -init -vendor_init } bpffs_type:dir { open read setattr }; +neverallow { domain -bpfloader } bpffs_type:dir { add_name create remove_name write }; +neverallow domain bpffs_type:dir ~{ add_name create getattr mounton open read remove_name search setattr write }; # TODO: get rid of init & vendor_init -neverallow { domain -bpfloader -init -vendor_init } { fs_bpf fs_bpf_tethering fs_bpf_vendor }:file { map open setattr }; -neverallow { domain -bpfloader } { fs_bpf fs_bpf_tethering fs_bpf_vendor }:file create; -neverallow { domain -bpfloader -gpuservice -init -lmkd -mediaprovider_app -netd -netutils_wrapper -network_stack -system_server -vendor_init } { fs_bpf }:file read; -neverallow { domain -bpfloader -gpuservice -init -lmkd -netd -netutils_wrapper -network_stack -system_server -vendor_init } { fs_bpf_tethering }:file read; -neverallow { domain -bpfloader -gpuservice -netd -netutils_wrapper -network_stack -system_server } { fs_bpf fs_bpf_tethering }:file write; -neverallow domain { fs_bpf fs_bpf_tethering }:file ~{ create map open read setattr write }; +neverallow { domain -bpfloader -init -vendor_init } bpffs_type:file { map open setattr }; +neverallow { domain -bpfloader } bpffs_type:file { create rename }; +neverallow { domain -bpfloader -gpuservice -init -lmkd -mediaprovider_app -netd -netutils_wrapper -system_server -vendor_init } fs_bpf:file read; +neverallow { domain -bpfloader -init -network_stack -vendor_init } fs_bpf_net_private:file read; +neverallow { domain -bpfloader -init -network_stack -system_server -vendor_init } fs_bpf_net_shared:file read; +neverallow { domain -bpfloader -init -netd -network_stack -system_server -vendor_init } fs_bpf_netd_readonly:file read; +neverallow { domain -bpfloader -init -netd -netutils_wrapper -network_stack -system_server -vendor_init } fs_bpf_netd_shared:file read; +neverallow { domain -bpfloader -init -network_stack -vendor_init } fs_bpf_tethering:file read; +neverallow { domain -bpfloader -gpuservice -netd -netutils_wrapper -network_stack -system_server } { bpffs_type -fs_bpf_vendor }:file write; +neverallow domain bpffs_type:file ~{ create map open read rename setattr write }; neverallow { domain -bpfloader } *:bpf { map_create prog_load }; diff --git a/prebuilts/api/33.0/private/file.te b/prebuilts/api/33.0/private/file.te index 4161dc944..c4ee2aa1d 100644 --- a/prebuilts/api/33.0/private/file.te +++ b/prebuilts/api/33.0/private/file.te @@ -1,6 +1,13 @@ # /proc/config.gz type config_gz, fs_type, proc_type; +# /sys/fs/bpf/ for mainline tethering use +# TODO: move S+ fs_bpf_tethering here from public/file.te +type fs_bpf_net_private, fs_type, bpffs_type; +type fs_bpf_net_shared, fs_type, bpffs_type; +type fs_bpf_netd_readonly, fs_type, bpffs_type; +type fs_bpf_netd_shared, fs_type, bpffs_type; + # /data/misc/storaged type storaged_data_file, file_type, data_file_type, core_data_file_type; diff --git a/prebuilts/api/33.0/private/genfs_contexts b/prebuilts/api/33.0/private/genfs_contexts index 1c604fc34..65784709c 100644 --- a/prebuilts/api/33.0/private/genfs_contexts +++ b/prebuilts/api/33.0/private/genfs_contexts @@ -395,5 +395,9 @@ genfscon functionfs / u:object_r:functionfs:s0 genfscon usbfs / u:object_r:usbfs:s0 genfscon binfmt_misc / u:object_r:binfmt_miscfs:s0 genfscon bpf / u:object_r:fs_bpf:s0 +genfscon bpf /net_private u:object_r:fs_bpf_net_private:s0 +genfscon bpf /net_shared u:object_r:fs_bpf_net_shared:s0 +genfscon bpf /netd_readonly u:object_r:fs_bpf_netd_readonly:s0 +genfscon bpf /netd_shared u:object_r:fs_bpf_netd_shared:s0 genfscon bpf /tethering u:object_r:fs_bpf_tethering:s0 genfscon bpf /vendor u:object_r:fs_bpf_vendor:s0 diff --git a/prebuilts/api/33.0/private/netd.te b/prebuilts/api/33.0/private/netd.te index 30dcd084e..4aa288b33 100644 --- a/prebuilts/api/33.0/private/netd.te +++ b/prebuilts/api/33.0/private/netd.te @@ -6,6 +6,10 @@ init_daemon_domain(netd) # Allow netd to spawn dnsmasq in it's own domain domain_auto_trans(netd, dnsmasq_exec, dnsmasq) +allow netd { fs_bpf fs_bpf_netd_readonly fs_bpf_netd_shared }:dir search; +allow netd { fs_bpf fs_bpf_netd_readonly fs_bpf_netd_shared }:file read; +allow netd { fs_bpf fs_bpf_netd_shared }:file write; + # give netd permission to setup iptables rule with xt_bpf, attach program to cgroup, and read/write # the map created by bpfloader allow netd bpfloader:bpf { prog_run map_read map_write }; diff --git a/prebuilts/api/33.0/private/netutils_wrapper.te b/prebuilts/api/33.0/private/netutils_wrapper.te index af0360f20..900b35c63 100644 --- a/prebuilts/api/33.0/private/netutils_wrapper.te +++ b/prebuilts/api/33.0/private/netutils_wrapper.te @@ -25,7 +25,9 @@ binder_call(netutils_wrapper, netd); # For vendor code that update the iptables rules at runtime. They need to reload # the whole chain including the xt_bpf rules. They need to access to the pinned # program when reloading the rule. -allow netutils_wrapper fs_bpf:file { read write }; +allow netutils_wrapper { fs_bpf fs_bpf_netd_shared }:dir search; +allow netutils_wrapper { fs_bpf fs_bpf_netd_shared }:file read; +allow netutils_wrapper { fs_bpf }:file write; allow netutils_wrapper bpfloader:bpf prog_run; # For /data/misc/net access to ndc and ip diff --git a/prebuilts/api/33.0/private/network_stack.te b/prebuilts/api/33.0/private/network_stack.te index 24d2c66ed..3cdf884aa 100644 --- a/prebuilts/api/33.0/private/network_stack.te +++ b/prebuilts/api/33.0/private/network_stack.te @@ -60,8 +60,8 @@ hal_client_domain(network_stack, hal_tetheroffload) allow network_stack self:netlink_netfilter_socket create_socket_perms_no_ioctl; allow network_stack network_stack_service:service_manager find; # allow Tethering(network_stack process) to run/update/read the eBPF maps to offload tethering traffic by eBPF. -allow network_stack { fs_bpf fs_bpf_tethering }:dir search; -allow network_stack { fs_bpf fs_bpf_tethering }:file { read write }; +allow network_stack { fs_bpf_net_private fs_bpf_net_shared fs_bpf_netd_readonly fs_bpf_netd_shared fs_bpf_tethering }:dir search; +allow network_stack { fs_bpf_net_private fs_bpf_net_shared fs_bpf_netd_readonly fs_bpf_netd_shared fs_bpf_tethering }:file { read write }; allow network_stack bpfloader:bpf { map_read map_write prog_run }; # Use XFRM (IPsec) netlink sockets @@ -71,8 +71,46 @@ allow network_stack self:netlink_xfrm_socket { create_socket_perms_no_ioctl nlms allow network_stack tun_device:chr_file rw_file_perms; allowxperm network_stack tun_device:chr_file ioctl { TUNGETIFF TUNSETIFF TUNSETLINK TUNSETCARRIER }; -# Only the bpfloader and the network_stack should ever touch 'fs_bpf_tethering' programs/maps. +############### NEVER ALLOW RULES +# This place is as good as any for these rules, +# and it is probably the most appropriate because +# network_stack itself is entirely mainline code. +# # Unfortunately init/vendor_init have all sorts of extra privs + +# T+: Only the bpfloader and the network_stack should ever touch 'fs_bpf_net_private' programs/maps. +neverallow { domain -bpfloader -init -network_stack -vendor_init } fs_bpf_net_private:dir ~getattr; +neverallow { domain -bpfloader -init -network_stack -vendor_init } fs_bpf_net_private:file *; + +neverallow { domain -bpfloader -network_stack } fs_bpf_net_private:dir ~{ getattr open read search setattr }; +neverallow { domain -bpfloader -network_stack } fs_bpf_net_private:file ~{ map open read setattr }; + +# T+: Only the bpfloader, network_stack and system_server should ever touch 'fs_bpf_net_shared' programs/maps. +neverallow { domain -bpfloader -init -network_stack -system_server -vendor_init } fs_bpf_net_shared:dir ~getattr; +neverallow { domain -bpfloader -init -network_stack -system_server -vendor_init } fs_bpf_net_shared:file *; + +neverallow { domain -bpfloader -network_stack -system_server } fs_bpf_net_shared:dir ~{ getattr open read search setattr }; +neverallow { domain -bpfloader -network_stack -system_server } fs_bpf_net_shared:file ~{ map open read setattr }; + +# T+: Only the bpfloader, netd, network_stack and system_server should ever touch 'fs_bpf_netd_readonly' programs/maps. +# netd's access should be readonly +neverallow { domain -bpfloader -init -netd -network_stack -system_server -vendor_init } fs_bpf_netd_readonly:dir ~getattr; +neverallow { domain -bpfloader -init -netd -network_stack -system_server -vendor_init } fs_bpf_netd_readonly:file *; +neverallow netd fs_bpf_netd_readonly:file write; + +neverallow { domain -bpfloader -netd -network_stack -system_server } fs_bpf_netd_readonly:dir ~{ getattr open read search setattr }; +neverallow { domain -bpfloader -netd -network_stack -system_server } fs_bpf_netd_readonly:file ~{ map open read setattr }; + +# T+: Only the bpfloader, netd, netutils_wrapper, network_stack and system_server should ever touch 'fs_bpf_netd_shared' programs/maps. +# netutils_wrapper requires access to be able to run iptables and only needs readonly access +neverallow { domain -bpfloader -init -netd -netutils_wrapper -network_stack -system_server -vendor_init } fs_bpf_netd_shared:dir ~getattr; +neverallow { domain -bpfloader -init -netd -netutils_wrapper -network_stack -system_server -vendor_init } fs_bpf_netd_shared:file *; +neverallow netutils_wrapper fs_bpf_netd_shared:file write; + +neverallow { domain -bpfloader -netd -netutils_wrapper -network_stack -system_server } fs_bpf_netd_shared:dir ~{ getattr open read search setattr }; +neverallow { domain -bpfloader -netd -netutils_wrapper -network_stack -system_server } fs_bpf_netd_shared:file ~{ map open read setattr }; + +# S+: Only the bpfloader and the network_stack should ever touch 'fs_bpf_tethering' programs/maps. neverallow { domain -bpfloader -init -network_stack -vendor_init } fs_bpf_tethering:dir ~getattr; neverallow { domain -bpfloader -init -network_stack -vendor_init } fs_bpf_tethering:file *; diff --git a/prebuilts/api/33.0/private/system_server.te b/prebuilts/api/33.0/private/system_server.te index 3c49dc37d..bb02047cc 100644 --- a/prebuilts/api/33.0/private/system_server.te +++ b/prebuilts/api/33.0/private/system_server.te @@ -1154,7 +1154,8 @@ with_asan(` # allow system_server to read the eBPF maps that stores the traffic stats information and update # the map after snapshot is recorded, and to read, update and run the maps and programs used for # time in state accounting -allow system_server fs_bpf:file { read write }; +allow system_server { fs_bpf fs_bpf_net_shared fs_bpf_netd_readonly fs_bpf_netd_shared }:dir search; +allow system_server { fs_bpf fs_bpf_net_shared fs_bpf_netd_readonly fs_bpf_netd_shared }:file { read write }; allow system_server bpfloader:bpf { map_read map_write prog_run }; # in order to invoke side effect of close() on such a socket calling synchronize_rcu() allow system_server self:key_socket create; diff --git a/prebuilts/api/33.0/public/attributes b/prebuilts/api/33.0/public/attributes index 906dbcd14..742264a55 100644 --- a/prebuilts/api/33.0/public/attributes +++ b/prebuilts/api/33.0/public/attributes @@ -10,6 +10,9 @@ attribute dev_type; # TODO(b/202520796) Remove this attribute once the sc-dev branch stops using it. attribute bdev_type; +# Attribute for all bpf filesystem subtypes. +attribute bpffs_type; + # All types used for processes. attribute domain; diff --git a/prebuilts/api/33.0/public/file.te b/prebuilts/api/33.0/public/file.te index 9d333f5de..2bfa282fa 100644 --- a/prebuilts/api/33.0/public/file.te +++ b/prebuilts/api/33.0/public/file.te @@ -129,9 +129,10 @@ type sysfs_vendor_sched, sysfs_type, fs_type; userdebug_or_eng(` typeattribute sysfs_vendor_sched mlstrustedobject; ') -type fs_bpf, fs_type; -type fs_bpf_tethering, fs_type; -type fs_bpf_vendor, fs_type; +type fs_bpf, fs_type, bpffs_type; +# TODO: S+ fs_bpf_tethering (used by mainline) should be private +type fs_bpf_tethering, fs_type, bpffs_type; +type fs_bpf_vendor, fs_type, bpffs_type; type configfs, fs_type; # /sys/devices/cs_etm type sysfs_devices_cs_etm, fs_type, sysfs_type; diff --git a/prebuilts/api/33.0/public/netd.te b/prebuilts/api/33.0/public/netd.te index 64b4c7da5..7c7655eb9 100644 --- a/prebuilts/api/33.0/public/netd.te +++ b/prebuilts/api/33.0/public/netd.te @@ -64,8 +64,6 @@ allow netd sysfs_usb:file write; r_dir_file(netd, cgroup_v2) -allow netd fs_bpf:file { read write }; - # TODO: netd previously thought it needed these permissions to do WiFi related # work. However, after all the WiFi stuff is gone, we still need them. # Why? diff --git a/private/bpfloader.te b/private/bpfloader.te index d7b27b556..54cc91666 100644 --- a/private/bpfloader.te +++ b/private/bpfloader.te @@ -6,9 +6,9 @@ typeattribute bpfloader bpfdomain; allow bpfloader kmsg_device:chr_file w_file_perms; # These permissions are required to pin ebpf maps & programs. -allow bpfloader { fs_bpf fs_bpf_tethering fs_bpf_vendor }:dir { add_name create search write }; -allow bpfloader { fs_bpf fs_bpf_tethering fs_bpf_vendor }:file { create read setattr }; -allow { fs_bpf_tethering fs_bpf_vendor } fs_bpf:filesystem associate; +allow bpfloader bpffs_type:dir { add_name create remove_name search write }; +allow bpfloader bpffs_type:file { create read rename setattr }; +allow { bpffs_type -fs_bpf } fs_bpf:filesystem associate; # Allow bpfloader to create bpf maps and programs. allow bpfloader self:bpf { map_create map_read map_write prog_load prog_run }; @@ -26,17 +26,21 @@ allow bpfloader bpfloader_exec:file execute_no_trans; ### # TODO: get rid of init & vendor_init; Note: we don't care about getattr/mounton/search -neverallow { domain -init -vendor_init } { fs_bpf fs_bpf_tethering fs_bpf_vendor }:dir { open read setattr }; -neverallow { domain -bpfloader } { fs_bpf fs_bpf_tethering fs_bpf_vendor }:dir { add_name create write }; -neverallow domain { fs_bpf fs_bpf_tethering fs_bpf_vendor }:dir ~{ add_name create getattr mounton open read search setattr write }; +neverallow { domain -init -vendor_init } bpffs_type:dir { open read setattr }; +neverallow { domain -bpfloader } bpffs_type:dir { add_name create remove_name write }; +neverallow domain bpffs_type:dir ~{ add_name create getattr mounton open read remove_name search setattr write }; # TODO: get rid of init & vendor_init -neverallow { domain -bpfloader -init -vendor_init } { fs_bpf fs_bpf_tethering fs_bpf_vendor }:file { map open setattr }; -neverallow { domain -bpfloader } { fs_bpf fs_bpf_tethering fs_bpf_vendor }:file create; -neverallow { domain -bpfloader -gpuservice -init -lmkd -mediaprovider_app -netd -netutils_wrapper -network_stack -system_server -vendor_init } { fs_bpf }:file read; -neverallow { domain -bpfloader -gpuservice -init -lmkd -netd -netutils_wrapper -network_stack -system_server -vendor_init } { fs_bpf_tethering }:file read; -neverallow { domain -bpfloader -gpuservice -netd -netutils_wrapper -network_stack -system_server } { fs_bpf fs_bpf_tethering }:file write; -neverallow domain { fs_bpf fs_bpf_tethering }:file ~{ create map open read setattr write }; +neverallow { domain -bpfloader -init -vendor_init } bpffs_type:file { map open setattr }; +neverallow { domain -bpfloader } bpffs_type:file { create rename }; +neverallow { domain -bpfloader -gpuservice -init -lmkd -mediaprovider_app -netd -netutils_wrapper -system_server -vendor_init } fs_bpf:file read; +neverallow { domain -bpfloader -init -network_stack -vendor_init } fs_bpf_net_private:file read; +neverallow { domain -bpfloader -init -network_stack -system_server -vendor_init } fs_bpf_net_shared:file read; +neverallow { domain -bpfloader -init -netd -network_stack -system_server -vendor_init } fs_bpf_netd_readonly:file read; +neverallow { domain -bpfloader -init -netd -netutils_wrapper -network_stack -system_server -vendor_init } fs_bpf_netd_shared:file read; +neverallow { domain -bpfloader -init -network_stack -vendor_init } fs_bpf_tethering:file read; +neverallow { domain -bpfloader -gpuservice -netd -netutils_wrapper -network_stack -system_server } { bpffs_type -fs_bpf_vendor }:file write; +neverallow domain bpffs_type:file ~{ create map open read rename setattr write }; neverallow { domain -bpfloader } *:bpf { map_create prog_load }; diff --git a/private/file.te b/private/file.te index 4161dc944..c4ee2aa1d 100644 --- a/private/file.te +++ b/private/file.te @@ -1,6 +1,13 @@ # /proc/config.gz type config_gz, fs_type, proc_type; +# /sys/fs/bpf/ for mainline tethering use +# TODO: move S+ fs_bpf_tethering here from public/file.te +type fs_bpf_net_private, fs_type, bpffs_type; +type fs_bpf_net_shared, fs_type, bpffs_type; +type fs_bpf_netd_readonly, fs_type, bpffs_type; +type fs_bpf_netd_shared, fs_type, bpffs_type; + # /data/misc/storaged type storaged_data_file, file_type, data_file_type, core_data_file_type; diff --git a/private/genfs_contexts b/private/genfs_contexts index 1c604fc34..65784709c 100644 --- a/private/genfs_contexts +++ b/private/genfs_contexts @@ -395,5 +395,9 @@ genfscon functionfs / u:object_r:functionfs:s0 genfscon usbfs / u:object_r:usbfs:s0 genfscon binfmt_misc / u:object_r:binfmt_miscfs:s0 genfscon bpf / u:object_r:fs_bpf:s0 +genfscon bpf /net_private u:object_r:fs_bpf_net_private:s0 +genfscon bpf /net_shared u:object_r:fs_bpf_net_shared:s0 +genfscon bpf /netd_readonly u:object_r:fs_bpf_netd_readonly:s0 +genfscon bpf /netd_shared u:object_r:fs_bpf_netd_shared:s0 genfscon bpf /tethering u:object_r:fs_bpf_tethering:s0 genfscon bpf /vendor u:object_r:fs_bpf_vendor:s0 diff --git a/private/netd.te b/private/netd.te index 30dcd084e..4aa288b33 100644 --- a/private/netd.te +++ b/private/netd.te @@ -6,6 +6,10 @@ init_daemon_domain(netd) # Allow netd to spawn dnsmasq in it's own domain domain_auto_trans(netd, dnsmasq_exec, dnsmasq) +allow netd { fs_bpf fs_bpf_netd_readonly fs_bpf_netd_shared }:dir search; +allow netd { fs_bpf fs_bpf_netd_readonly fs_bpf_netd_shared }:file read; +allow netd { fs_bpf fs_bpf_netd_shared }:file write; + # give netd permission to setup iptables rule with xt_bpf, attach program to cgroup, and read/write # the map created by bpfloader allow netd bpfloader:bpf { prog_run map_read map_write }; diff --git a/private/netutils_wrapper.te b/private/netutils_wrapper.te index af0360f20..900b35c63 100644 --- a/private/netutils_wrapper.te +++ b/private/netutils_wrapper.te @@ -25,7 +25,9 @@ binder_call(netutils_wrapper, netd); # For vendor code that update the iptables rules at runtime. They need to reload # the whole chain including the xt_bpf rules. They need to access to the pinned # program when reloading the rule. -allow netutils_wrapper fs_bpf:file { read write }; +allow netutils_wrapper { fs_bpf fs_bpf_netd_shared }:dir search; +allow netutils_wrapper { fs_bpf fs_bpf_netd_shared }:file read; +allow netutils_wrapper { fs_bpf }:file write; allow netutils_wrapper bpfloader:bpf prog_run; # For /data/misc/net access to ndc and ip diff --git a/private/network_stack.te b/private/network_stack.te index 24d2c66ed..3cdf884aa 100644 --- a/private/network_stack.te +++ b/private/network_stack.te @@ -60,8 +60,8 @@ hal_client_domain(network_stack, hal_tetheroffload) allow network_stack self:netlink_netfilter_socket create_socket_perms_no_ioctl; allow network_stack network_stack_service:service_manager find; # allow Tethering(network_stack process) to run/update/read the eBPF maps to offload tethering traffic by eBPF. -allow network_stack { fs_bpf fs_bpf_tethering }:dir search; -allow network_stack { fs_bpf fs_bpf_tethering }:file { read write }; +allow network_stack { fs_bpf_net_private fs_bpf_net_shared fs_bpf_netd_readonly fs_bpf_netd_shared fs_bpf_tethering }:dir search; +allow network_stack { fs_bpf_net_private fs_bpf_net_shared fs_bpf_netd_readonly fs_bpf_netd_shared fs_bpf_tethering }:file { read write }; allow network_stack bpfloader:bpf { map_read map_write prog_run }; # Use XFRM (IPsec) netlink sockets @@ -71,8 +71,46 @@ allow network_stack self:netlink_xfrm_socket { create_socket_perms_no_ioctl nlms allow network_stack tun_device:chr_file rw_file_perms; allowxperm network_stack tun_device:chr_file ioctl { TUNGETIFF TUNSETIFF TUNSETLINK TUNSETCARRIER }; -# Only the bpfloader and the network_stack should ever touch 'fs_bpf_tethering' programs/maps. +############### NEVER ALLOW RULES +# This place is as good as any for these rules, +# and it is probably the most appropriate because +# network_stack itself is entirely mainline code. +# # Unfortunately init/vendor_init have all sorts of extra privs + +# T+: Only the bpfloader and the network_stack should ever touch 'fs_bpf_net_private' programs/maps. +neverallow { domain -bpfloader -init -network_stack -vendor_init } fs_bpf_net_private:dir ~getattr; +neverallow { domain -bpfloader -init -network_stack -vendor_init } fs_bpf_net_private:file *; + +neverallow { domain -bpfloader -network_stack } fs_bpf_net_private:dir ~{ getattr open read search setattr }; +neverallow { domain -bpfloader -network_stack } fs_bpf_net_private:file ~{ map open read setattr }; + +# T+: Only the bpfloader, network_stack and system_server should ever touch 'fs_bpf_net_shared' programs/maps. +neverallow { domain -bpfloader -init -network_stack -system_server -vendor_init } fs_bpf_net_shared:dir ~getattr; +neverallow { domain -bpfloader -init -network_stack -system_server -vendor_init } fs_bpf_net_shared:file *; + +neverallow { domain -bpfloader -network_stack -system_server } fs_bpf_net_shared:dir ~{ getattr open read search setattr }; +neverallow { domain -bpfloader -network_stack -system_server } fs_bpf_net_shared:file ~{ map open read setattr }; + +# T+: Only the bpfloader, netd, network_stack and system_server should ever touch 'fs_bpf_netd_readonly' programs/maps. +# netd's access should be readonly +neverallow { domain -bpfloader -init -netd -network_stack -system_server -vendor_init } fs_bpf_netd_readonly:dir ~getattr; +neverallow { domain -bpfloader -init -netd -network_stack -system_server -vendor_init } fs_bpf_netd_readonly:file *; +neverallow netd fs_bpf_netd_readonly:file write; + +neverallow { domain -bpfloader -netd -network_stack -system_server } fs_bpf_netd_readonly:dir ~{ getattr open read search setattr }; +neverallow { domain -bpfloader -netd -network_stack -system_server } fs_bpf_netd_readonly:file ~{ map open read setattr }; + +# T+: Only the bpfloader, netd, netutils_wrapper, network_stack and system_server should ever touch 'fs_bpf_netd_shared' programs/maps. +# netutils_wrapper requires access to be able to run iptables and only needs readonly access +neverallow { domain -bpfloader -init -netd -netutils_wrapper -network_stack -system_server -vendor_init } fs_bpf_netd_shared:dir ~getattr; +neverallow { domain -bpfloader -init -netd -netutils_wrapper -network_stack -system_server -vendor_init } fs_bpf_netd_shared:file *; +neverallow netutils_wrapper fs_bpf_netd_shared:file write; + +neverallow { domain -bpfloader -netd -netutils_wrapper -network_stack -system_server } fs_bpf_netd_shared:dir ~{ getattr open read search setattr }; +neverallow { domain -bpfloader -netd -netutils_wrapper -network_stack -system_server } fs_bpf_netd_shared:file ~{ map open read setattr }; + +# S+: Only the bpfloader and the network_stack should ever touch 'fs_bpf_tethering' programs/maps. neverallow { domain -bpfloader -init -network_stack -vendor_init } fs_bpf_tethering:dir ~getattr; neverallow { domain -bpfloader -init -network_stack -vendor_init } fs_bpf_tethering:file *; diff --git a/private/system_server.te b/private/system_server.te index 3c49dc37d..bb02047cc 100644 --- a/private/system_server.te +++ b/private/system_server.te @@ -1154,7 +1154,8 @@ with_asan(` # allow system_server to read the eBPF maps that stores the traffic stats information and update # the map after snapshot is recorded, and to read, update and run the maps and programs used for # time in state accounting -allow system_server fs_bpf:file { read write }; +allow system_server { fs_bpf fs_bpf_net_shared fs_bpf_netd_readonly fs_bpf_netd_shared }:dir search; +allow system_server { fs_bpf fs_bpf_net_shared fs_bpf_netd_readonly fs_bpf_netd_shared }:file { read write }; allow system_server bpfloader:bpf { map_read map_write prog_run }; # in order to invoke side effect of close() on such a socket calling synchronize_rcu() allow system_server self:key_socket create; diff --git a/public/attributes b/public/attributes index 906dbcd14..742264a55 100644 --- a/public/attributes +++ b/public/attributes @@ -10,6 +10,9 @@ attribute dev_type; # TODO(b/202520796) Remove this attribute once the sc-dev branch stops using it. attribute bdev_type; +# Attribute for all bpf filesystem subtypes. +attribute bpffs_type; + # All types used for processes. attribute domain; diff --git a/public/file.te b/public/file.te index 9d333f5de..2bfa282fa 100644 --- a/public/file.te +++ b/public/file.te @@ -129,9 +129,10 @@ type sysfs_vendor_sched, sysfs_type, fs_type; userdebug_or_eng(` typeattribute sysfs_vendor_sched mlstrustedobject; ') -type fs_bpf, fs_type; -type fs_bpf_tethering, fs_type; -type fs_bpf_vendor, fs_type; +type fs_bpf, fs_type, bpffs_type; +# TODO: S+ fs_bpf_tethering (used by mainline) should be private +type fs_bpf_tethering, fs_type, bpffs_type; +type fs_bpf_vendor, fs_type, bpffs_type; type configfs, fs_type; # /sys/devices/cs_etm type sysfs_devices_cs_etm, fs_type, sysfs_type; diff --git a/public/netd.te b/public/netd.te index 64b4c7da5..7c7655eb9 100644 --- a/public/netd.te +++ b/public/netd.te @@ -64,8 +64,6 @@ allow netd sysfs_usb:file write; r_dir_file(netd, cgroup_v2) -allow netd fs_bpf:file { read write }; - # TODO: netd previously thought it needed these permissions to do WiFi related # work. However, after all the WiFi stuff is gone, we still need them. # Why? diff --git a/tests/sepolicy_tests.py b/tests/sepolicy_tests.py index 0a87a1348..79c55de9d 100644 --- a/tests/sepolicy_tests.py +++ b/tests/sepolicy_tests.py @@ -44,6 +44,9 @@ def TestSystemTypeViolations(pol): return pol.AssertPathTypesHaveAttr(partitions, exceptions, "system_file_type") +def TestBpffsTypeViolations(pol): + return pol.AssertGenfsFilesystemTypesHaveAttr("bpf", "bpffs_type") + def TestProcTypeViolations(pol): return pol.AssertGenfsFilesystemTypesHaveAttr("proc", "proc_type") @@ -128,6 +131,7 @@ class MultipleOption(Option): Option.take_action(self, action, dest, opt, value, values, parser) Tests = [ + "TestBpffsTypeViolations", "TestDataTypeViolators", "TestProcTypeViolations", "TestSysfsTypeViolations", @@ -175,6 +179,8 @@ if __name__ == '__main__': results = "" # If an individual test is not specified, run all tests. + if options.test is None or "TestBpffsTypeViolations" in options.test: + results += TestBpffsTypeViolations(pol) if options.test is None or "TestDataTypeViolations" in options.test: results += TestDataTypeViolations(pol) if options.test is None or "TestProcTypeViolations" in options.test: