much more finegrained bpf selinux privs for networking mainline

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.

Bug: 218408035
Test: TreeHugger, manually on cuttlefish
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I674866ebe32aca4fc851818c1ffcbec12ac4f7d4
(cherry picked from commit 15715aea32b85c933778b97a46de6ccab42ca7fb)
diff --git a/private/bpfloader.te b/private/bpfloader.te
index d7b27b5..54cc916 100644
--- a/private/bpfloader.te
+++ b/private/bpfloader.te
@@ -6,9 +6,9 @@
 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 @@
 ###
 
 # 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 4161dc9..c4ee2aa 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/<dir> 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 1c604fc..6578470 100644
--- a/private/genfs_contexts
+++ b/private/genfs_contexts
@@ -395,5 +395,9 @@
 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 30dcd08..4aa288b 100644
--- a/private/netd.te
+++ b/private/netd.te
@@ -6,6 +6,10 @@
 # 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 af0360f..900b35c 100644
--- a/private/netutils_wrapper.te
+++ b/private/netutils_wrapper.te
@@ -25,7 +25,9 @@
 # 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 24d2c66..3cdf884 100644
--- a/private/network_stack.te
+++ b/private/network_stack.te
@@ -60,8 +60,8 @@
 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 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 c3be29c..4c3103c 100644
--- a/private/system_server.te
+++ b/private/system_server.te
@@ -1165,7 +1165,8 @@
 # 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;