Add sepolicy for installing GSIs to external storage.

To install GSIs on external storage (such as sdcards), gsid needs some
additional privileges:
 - proc_cmdline and device-tree access to call ReadDefaultFstab().
   This is ultimately used to check whether system's dm-verity has
   check_at_most_once enabled, which is disallowed with sdcards.
 - vfat read/write access to write files to the sdcard. Note that
   adopted sdcards are not supported here.
 - read access to the sdcard block device. To enable this without
   providing access to vold_block_device, a new sdcard_block_device
   label was added. Devices must apply this label appropriately to
   enable gsid access.
 - FIBMAP access for VFAT filesystems, as they do not support FIEMAP.
   This only appears to work by granting SYS_RAWIO.

Bug: 126230649
Test: adb shell su root gsi_tool install --install_dir=/mnt/media_rw/...
      works without setenforce 0

Change-Id: I88d8d83e5f61d4c0490f912f226fe1fe38cd60ab
diff --git a/private/compat/28.0/28.0.ignore.cil b/private/compat/28.0/28.0.ignore.cil
index 8187e29..f4e2cd4 100644
--- a/private/compat/28.0/28.0.ignore.cil
+++ b/private/compat/28.0/28.0.ignore.cil
@@ -113,6 +113,7 @@
     runas_app
     runas_app_tmpfs
     runtime_service
+    sdcard_block_device
     sensor_privacy_service
     server_configurable_flags_data_file
     simpleperf_app_runner
diff --git a/private/domain.te b/private/domain.te
index f4fb407..037a7d5 100644
--- a/private/domain.te
+++ b/private/domain.te
@@ -297,3 +297,18 @@
     -vold
     -zygote
 } { fs_type -sdcard_type }:filesystem { mount remount relabelfrom relabelto };
+
+# Limit raw I/O to these whitelisted domains. Do not apply to debug builds.
+neverallow {
+  domain
+  userdebug_or_eng(`-domain')
+  -kernel
+  -gsid
+  -init
+  -recovery
+  -ueventd
+  -healthd
+  -uncrypt
+  -tee
+  -hal_bootctl_server
+} self:global_capability_class_set sys_rawio;
diff --git a/private/gsid.te b/private/gsid.te
index 62ac06b..5dcf746 100644
--- a/private/gsid.te
+++ b/private/gsid.te
@@ -22,17 +22,39 @@
 # file names.
 allow gsid sysfs_dm:dir r_dir_perms;
 
+# Needed to read fstab, which is used to validate that system verity does not
+# use check_once_at_most for sdcard installs. (Note: proc_cmdline is needed
+# to get the A/B slot suffix).
+allow gsid proc_cmdline:file r_file_perms;
+allow gsid sysfs_dt_firmware_android:dir r_dir_perms;
+allow gsid sysfs_dt_firmware_android:file r_file_perms;
+
 # Needed to stat /data/gsi/* and realpath on /dev/block/by-name/*
 allow gsid block_device:dir r_dir_perms;
 
 # liblp queries these block alignment properties.
-allowxperm gsid userdata_block_device:blk_file ioctl {
+allowxperm gsid { userdata_block_device sdcard_block_device }:blk_file ioctl {
   BLKIOMIN
   BLKALIGNOFF
 };
 
+# When installing images to an sdcard, gsid needs to be able to stat() the
+# block device. gsid also calls realpath() to remove symlinks.
+allow gsid mnt_media_rw_file:dir r_dir_perms;
+
+# When installing images to an sdcard, gsid must bypass sdcardfs and install
+# directly to vfat, which supports the FIBMAP ioctl.
+allow gsid vfat:dir rw_dir_perms;
+allow gsid vfat:file create_file_perms;
+allow gsid sdcard_block_device:blk_file r_file_perms;
+# This is needed for FIBMAP unfortunately. Oddly FIEMAP does not carry this
+# requirement, but the kernel does not implement FIEMAP support for VFAT.
+allow gsid self:global_capability_class_set sys_rawio;
+
 # gsi_tool passes the system image over the adb connection, via stdin.
 allow gsid adbd:fd use;
+# Needed when running gsi_tool through "su root" rather than adb root.
+allow gsid adbd:unix_stream_socket rw_socket_perms;
 
 neverallow { domain -gsid -init } gsid_prop:property_service set;
 
diff --git a/public/device.te b/public/device.te
index 41b4edb..e20a68b 100644
--- a/public/device.te
+++ b/public/device.te
@@ -105,3 +105,8 @@
 
 # 'super' partition to be used for logical partitioning.
 type super_block_device, super_block_device_type, dev_type;
+
+# sdcard devices; normally vold uses the vold_block_device label and creates a
+# separate device node. gsid, however, accesses the original devide node
+# created through uevents, so we use a separate label.
+type sdcard_block_device, dev_type;
diff --git a/public/domain.te b/public/domain.te
index 978c9bf..5a964c9 100644
--- a/public/domain.te
+++ b/public/domain.te
@@ -349,20 +349,6 @@
   -vold
 } self:global_capability_class_set mknod;
 
-# Limit raw I/O to these whitelisted domains. Do not apply to debug builds.
-neverallow {
-  domain
-  userdebug_or_eng(`-domain')
-  -kernel
-  -init
-  -recovery
-  -ueventd
-  -healthd
-  -uncrypt
-  -tee
-  -hal_bootctl_server
-} self:global_capability_class_set sys_rawio;
-
 # No process can map low memory (< CONFIG_LSM_MMAP_MIN_ADDR).
 neverallow * self:memprotect mmap_zero;