Don't allow disk images labeled as app_data_file
At least for T, we don't want to have a VM that is running a disk image
that is not protected by AVB (Android Verified Boot). This means that
the disk images must be from file in the built-in partitions (like
system) or their updates (because updates are guaranteed to be from the
same signer).
This rule is currently being enforced by selinux policies around crosvm.
However, there is one exception. It has the following allow rule.
allow crosvm app_data_file:file { read ...};
app_data_file is for any file that is owned and dynamically created by
apps. They could be a file downloaded from Internet, and therefore is
definitely not protected by AVB. The only reason we have the above allow
rule is the instance image. The file is mutable because it has per-VM
identity information that is written when a pVM is first created. The
file is owned by the owning app, otherwise other apps would be able to
start the same VM. In other words, we don't intend to allow any
app_data_file to be loadable in a pVM. But such an intention can't be
expressed in sepolicy.
This CL augments the sepolicy by adding a runtime check in
virtualizationservice. Specifically, it rejects to spawn a VM if any of
the disk images is labeled as app_data_file, except for the disk image
for the instance partition.
Bug: 204852957
Test: adb shell chcon u:object_r:app_data_file:s0 /data/local/tmp/virt/MicrodroidDemoApp.apk
adb shell /apex/com.android.virt/bin/vm run-app --debug full \
/data/local/tmp/virt/MicrodroidDemoApp.apk \
/data/local/tmp/virt/MicrodroidDemoApp.apk.idsig \
/data/local/tmp/virt/instance.img assets/vm_config.json \
gives the following error as expected.
Status(-8, EX_SERVICE_SPECIFIC): '-1: Partition microdroid-apk shouldn't
be labeld as u:object_r:app_data_file:s0'
Change-Id: Ia7081b8ecb2db1ecc1f7d4941a305ccff6016f3e
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index 1c88174..af420f6 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -18,6 +18,7 @@
use crate::crosvm::{CrosvmConfig, DiskFile, PayloadState, VmInstance, VmState};
use crate::payload::add_microdroid_images;
use crate::{Cid, FIRST_GUEST_CID, SYSPROP_LAST_CID};
+use crate::selinux::{SeContext, getfilecon};
use ::binder::unstable_api::AsNative;
use android_os_permissions_aidl::aidl::android::os::IPermissionController;
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::{
@@ -25,6 +26,7 @@
IVirtualMachine::{BnVirtualMachine, IVirtualMachine},
IVirtualMachineCallback::IVirtualMachineCallback,
IVirtualizationService::IVirtualizationService,
+ Partition::Partition,
PartitionType::PartitionType,
VirtualMachineAppConfig::DebugLevel::DebugLevel,
VirtualMachineAppConfig::VirtualMachineAppConfig,
@@ -169,6 +171,8 @@
}
}
+ let is_app_config = matches!(config, VirtualMachineConfig::AppConfig(_));
+
let config = match config {
VirtualMachineConfig::AppConfig(config) => BorrowedOrOwned::Owned(
load_app_config(config, &temporary_directory).map_err(|e| {
@@ -183,6 +187,25 @@
};
let config = config.as_ref();
+ // Check if partition images are labeled incorrectly. This is to prevent random images
+ // which are not protected by the Android Verified Boot (e.g. bits downloaded by apps) from
+ // being loaded in a pVM. Specifically, for images in the raw config, nothing is allowed
+ // to be labeled as app_data_file. For images in the app config, nothing but the instance
+ // partition is allowed to be labeled as such.
+ config
+ .disks
+ .iter()
+ .flat_map(|disk| disk.partitions.iter())
+ .filter(|partition| {
+ if is_app_config {
+ partition.label != "vm-instance"
+ } else {
+ true // all partitions are checked
+ }
+ })
+ .try_for_each(check_label_for_partition)
+ .map_err(|e| new_binder_exception(ExceptionCode::SERVICE_SPECIFIC, e.to_string()))?;
+
let zero_filler_path = temporary_directory.join("zero.img");
write_zero_filler(&zero_filler_path).map_err(|e| {
error!("Failed to make composite image: {}", e);
@@ -606,6 +629,16 @@
check_permission("android.permission.MANAGE_VIRTUAL_MACHINE")
}
+/// Check if a partition has selinux labels that are not allowed
+fn check_label_for_partition(partition: &Partition) -> Result<()> {
+ let ctx = getfilecon(partition.image.as_ref().unwrap().as_ref())?;
+ if ctx == SeContext::new("u:object_r:app_data_file:s0").unwrap() {
+ Err(anyhow!("Partition {} shouldn't be labeled as {}", &partition.label, ctx))
+ } else {
+ Ok(())
+ }
+}
+
/// Implementation of the AIDL `IVirtualMachine` interface. Used as a handle to a VM.
#[derive(Debug)]
struct VirtualMachine {