Allow vendor clients to use AVF API
* virtmgr now checks both clients and origins of FDs
* Early VMs are extended to vendors, regarding early_vms.xsd
* libavf now exports headers to vendor modules
Bug: 369588412
Bug: 383969737
Test: create a vendor binary using libavf and run a vm
Change-Id: Id212f4b9b86504f2081faa4e99baee22b860f481
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index cbae56b..daa755e 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -137,6 +137,21 @@
static SUPPORTED_OS_NAMES: LazyLock<HashSet<String>> =
LazyLock::new(|| get_supported_os_names().expect("Failed to get list of supported os names"));
+static CALLING_EXE_PATH: LazyLock<Option<PathBuf>> = LazyLock::new(|| {
+ let calling_exe_link = format!("/proc/{}/exe", get_calling_pid());
+ match fs::read_link(&calling_exe_link) {
+ Ok(calling_exe_path) => Some(calling_exe_path),
+ Err(e) => {
+ // virtmgr forked from apps fails to read /proc probably due to hidepid=2. As we
+ // discourage vendor apps, regarding such cases as system is safer.
+ // TODO(b/383969737): determine if this is okay. Or find a way how to track origins of
+ // apps.
+ warn!("can't read_link '{calling_exe_link}': {e:?}; regarding as system");
+ None
+ }
+ }
+});
+
fn create_or_update_idsig_file(
input_fd: &ParcelFileDescriptor,
idsig_fd: &ParcelFileDescriptor,
@@ -406,7 +421,11 @@
}
}
-fn find_partition(path: &Path) -> binder::Result<String> {
+fn find_partition(path: Option<&Path>) -> binder::Result<String> {
+ let path = match path {
+ Some(path) => path,
+ None => return Ok("system".to_owned()),
+ };
let mut components = path.components();
match components.nth(1) {
Some(std::path::Component::Normal(partition)) => {
@@ -448,24 +467,27 @@
fn create_early_vm_context(
&self,
config: &VirtualMachineConfig,
+ calling_exe_path: Option<&Path>,
) -> binder::Result<(VmContext, Cid, PathBuf)> {
- let calling_exe_path = format!("/proc/{}/exe", get_calling_pid());
- let link = fs::read_link(&calling_exe_path)
- .context(format!("can't read_link '{calling_exe_path}'"))
- .or_service_specific_exception(-1)?;
- let partition = find_partition(&link)?;
-
let name = match config {
VirtualMachineConfig::RawConfig(config) => &config.name,
VirtualMachineConfig::AppConfig(config) => &config.name,
};
- let early_vm =
- find_early_vm_for_partition(&partition, name).or_service_specific_exception(-1)?;
- if Path::new(&early_vm.path) != link {
+ let calling_partition = find_partition(calling_exe_path)?;
+ let early_vm = find_early_vm_for_partition(&calling_partition, name)
+ .or_service_specific_exception(-1)?;
+ let calling_exe_path = match calling_exe_path {
+ Some(path) => path,
+ None => {
+ return Err(anyhow!("Can't verify the path of PID {}", get_calling_pid()))
+ .or_service_specific_exception(-1)
+ }
+ };
+ if Path::new(&early_vm.path) != calling_exe_path {
return Err(anyhow!(
- "VM '{name}' in partition '{partition}' must be created with '{}', not '{}'",
+ "VM '{name}' in partition '{calling_partition}' must be created with '{}', not '{}'",
&early_vm.path,
- link.display()
+ calling_exe_path.display()
))
.or_service_specific_exception(-1);
}
@@ -549,7 +571,7 @@
// Allocating VM context checks the MANAGE_VIRTUAL_MACHINE permission.
let (vm_context, cid, temporary_directory) = if cfg!(early) {
- self.create_early_vm_context(config)?
+ self.create_early_vm_context(config, CALLING_EXE_PATH.as_deref())?
} else {
self.create_vm_context(requester_debug_pid, config)?
};
@@ -649,7 +671,8 @@
// Check if files for payloads and bases are NOT coming from /vendor and /odm, as they may
// have unstable interfaces.
// TODO(b/316431494): remove once Treble interfaces are stabilized.
- check_partitions_for_files(config).or_service_specific_exception(-1)?;
+ check_partitions_for_files(config, &find_partition(CALLING_EXE_PATH.as_deref())?)
+ .or_service_specific_exception(-1)?;
let zero_filler_path = temporary_directory.join("zero.img");
write_zero_filler(&zero_filler_path)
@@ -1285,7 +1308,7 @@
Ok(vm_config)
}
-fn check_partition_for_file(fd: &ParcelFileDescriptor) -> Result<()> {
+fn check_partition_for_file(fd: &ParcelFileDescriptor, calling_partition: &str) -> Result<()> {
let path = format!("/proc/self/fd/{}", fd.as_raw_fd());
let link = fs::read_link(&path).context(format!("can't read_link {path}"))?;
@@ -1295,24 +1318,39 @@
return Ok(());
}
- if link.starts_with("/vendor") || link.starts_with("/odm") {
- bail!("vendor or odm file {} can't be used for VM", link.display());
+ let is_fd_vendor = link.starts_with("/vendor") || link.starts_with("/odm");
+ let is_caller_vendor = calling_partition == "vendor" || calling_partition == "odm";
+
+ if is_fd_vendor != is_caller_vendor {
+ bail!("{} can't be used for VM client in {calling_partition}", link.display());
}
Ok(())
}
-fn check_partitions_for_files(config: &VirtualMachineRawConfig) -> Result<()> {
+fn check_partitions_for_files(
+ config: &VirtualMachineRawConfig,
+ calling_partition: &str,
+) -> Result<()> {
config
.disks
.iter()
.flat_map(|disk| disk.partitions.iter())
.filter_map(|partition| partition.image.as_ref())
- .try_for_each(check_partition_for_file)?;
+ .try_for_each(|fd| check_partition_for_file(fd, calling_partition))?;
- config.kernel.as_ref().map_or(Ok(()), check_partition_for_file)?;
- config.initrd.as_ref().map_or(Ok(()), check_partition_for_file)?;
- config.bootloader.as_ref().map_or(Ok(()), check_partition_for_file)?;
+ config
+ .disks
+ .iter()
+ .filter_map(|disk| disk.image.as_ref())
+ .try_for_each(|fd| check_partition_for_file(fd, calling_partition))?;
+
+ config.kernel.as_ref().map_or(Ok(()), |fd| check_partition_for_file(fd, calling_partition))?;
+ config.initrd.as_ref().map_or(Ok(()), |fd| check_partition_for_file(fd, calling_partition))?;
+ config
+ .bootloader
+ .as_ref()
+ .map_or(Ok(()), |fd| check_partition_for_file(fd, calling_partition))?;
Ok(())
}
@@ -2163,6 +2201,7 @@
match partition {
"system" => Ok(100..200),
"system_ext" | "product" => Ok(200..300),
+ "vendor" | "odm" => Ok(300..400),
_ => Err(anyhow!("Early VMs are not supported for {partition}")),
}
}
diff --git a/libs/libavf/Android.bp b/libs/libavf/Android.bp
index e143709..079f4ae 100644
--- a/libs/libavf/Android.bp
+++ b/libs/libavf/Android.bp
@@ -34,7 +34,6 @@
rust_ffi_static {
name: "libavf_impl",
defaults: ["libavf.default"],
- export_include_dirs: ["include"],
}
cc_library {
@@ -49,7 +48,7 @@
"libbinder_rpc_unstable",
"liblog",
],
- export_static_lib_headers: ["libavf_impl"],
+ export_include_dirs: ["include"],
apex_available: ["com.android.virt"],
version_script: "libavf.map.txt",
stubs: {