Merge "sign_virt_apex: do not use truncate (/usr/bin)"
diff --git a/libs/vmconfig/Android.bp b/libs/vmconfig/Android.bp
index 321eba0..1aee1ce 100644
--- a/libs/vmconfig/Android.bp
+++ b/libs/vmconfig/Android.bp
@@ -10,8 +10,9 @@
rustlibs: [
"android.system.virtualizationservice-rust",
"libanyhow",
- "libserde_json",
+ "libsemver",
"libserde",
+ "libserde_json",
],
apex_available: [
"com.android.virt",
diff --git a/libs/vmconfig/src/lib.rs b/libs/vmconfig/src/lib.rs
index 9c3e671..607b347 100644
--- a/libs/vmconfig/src/lib.rs
+++ b/libs/vmconfig/src/lib.rs
@@ -22,6 +22,7 @@
};
use anyhow::{bail, Context, Error, Result};
+use semver::VersionReq;
use serde::{Deserialize, Serialize};
use std::convert::TryInto;
use std::fs::{File, OpenOptions};
@@ -51,6 +52,9 @@
/// The amount of RAM to give the VM, in MiB.
#[serde(default)]
pub memory_mib: Option<NonZeroU32>,
+ /// Version or range of versions of the virtual platform that this config is compatible with.
+ /// The format follows SemVer (https://semver.org).
+ pub platform_version: VersionReq,
}
impl VmConfig {
@@ -95,6 +99,7 @@
disks: self.disks.iter().map(DiskImage::to_parcelable).collect::<Result<_, Error>>()?,
protectedVm: self.protected,
memoryMib: memory_mib,
+ platformVersion: self.platform_version.to_string(),
..Default::default()
})
}
diff --git a/microdroid/microdroid.json b/microdroid/microdroid.json
index cb27a24..aff0b7b 100644
--- a/microdroid/microdroid.json
+++ b/microdroid/microdroid.json
@@ -37,5 +37,6 @@
"writable": true
}
],
- "memory_mib": 256
+ "memory_mib": 256,
+ "platform_version": "~1.0"
}
diff --git a/tests/hostside/java/android/virt/test/MicrodroidTestCase.java b/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
index 1218b68..58935d8 100644
--- a/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
+++ b/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
@@ -122,6 +122,7 @@
int memory_mib;
@SerializedName("protected")
boolean isProtected;
+ String platform_version;
}
static class Disk {
diff --git a/tests/vsock_test.cc b/tests/vsock_test.cc
index c478f64..0fc451d 100644
--- a/tests/vsock_test.cc
+++ b/tests/vsock_test.cc
@@ -48,6 +48,7 @@
static constexpr const char kVmInitrdPath[] = "/data/local/tmp/virt-test/initramfs";
static constexpr const char kVmParams[] = "rdinit=/bin/init bin/vsock_client 2 45678 HelloWorld";
static constexpr const char kTestMessage[] = "HelloWorld";
+static constexpr const char kPlatformVersion[] = "~1.0";
/** Returns true if the kernel supports unprotected VMs. */
bool isUnprotectedVmSupported() {
@@ -82,6 +83,7 @@
raw_config.initrd = ParcelFileDescriptor(unique_fd(open(kVmInitrdPath, O_RDONLY | O_CLOEXEC)));
raw_config.params = kVmParams;
raw_config.protectedVm = false;
+ raw_config.platformVersion = kPlatformVersion;
VirtualMachineConfig config(std::move(raw_config));
sp<IVirtualMachine> vm;
@@ -112,4 +114,17 @@
ASSERT_EQ(msg, kTestMessage);
}
+TEST_F(VirtualizationTest, RejectIncompatiblePlatformVersion) {
+ VirtualMachineRawConfig raw_config;
+ raw_config.kernel = ParcelFileDescriptor(unique_fd(open(kVmKernelPath, O_RDONLY | O_CLOEXEC)));
+ raw_config.initrd = ParcelFileDescriptor(unique_fd(open(kVmInitrdPath, O_RDONLY | O_CLOEXEC)));
+ raw_config.params = kVmParams;
+ raw_config.platformVersion = "~2.0"; // The current platform version is 1.0.0.
+
+ VirtualMachineConfig config(std::move(raw_config));
+ sp<IVirtualMachine> vm;
+ auto status = mVirtualizationService->createVm(config, std::nullopt, std::nullopt, &vm);
+ ASSERT_FALSE(status.isOk());
+}
+
} // namespace virt
diff --git a/virtualizationservice/Android.bp b/virtualizationservice/Android.bp
index b82064b..981a041 100644
--- a/virtualizationservice/Android.bp
+++ b/virtualizationservice/Android.bp
@@ -37,6 +37,7 @@
"libonce_cell",
"libregex",
"librustutils",
+ "libsemver",
"libselinux_bindgen",
"libserde",
"libserde_json",
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
index bb4eef0..dfd3bff 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/VirtualMachineRawConfig.aidl
@@ -57,4 +57,10 @@
* Default is no mask which means a vCPU can run on any host CPU.
*/
@nullable String cpuAffinity;
+
+ /**
+ * A version or range of versions of the virtual platform that this config is compatible with.
+ * The format follows SemVer.
+ */
+ @utf8InCpp String platformVersion;
}
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index 89c6e8a..d9825dc 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -52,6 +52,7 @@
use log::{debug, error, info, warn, trace};
use microdroid_payload_config::VmPayloadConfig;
use rustutils::system_properties;
+use semver::VersionReq;
use statslog_virtualization_rust::vm_creation_requested::{stats_write, Hypervisor};
use std::convert::TryInto;
use std::ffi::CStr;
@@ -239,6 +240,7 @@
console_fd,
log_fd,
indirect_files,
+ platform_version: parse_platform_version_req(&config.platformVersion)?,
};
let instance = Arc::new(
VmInstance::new(
@@ -893,6 +895,16 @@
ParcelFileDescriptor::new(f)
}
+/// Parses the platform version requirement string.
+fn parse_platform_version_req(s: &str) -> Result<VersionReq, Status> {
+ VersionReq::parse(s).map_err(|e| {
+ new_binder_exception(
+ ExceptionCode::BAD_PARCELABLE,
+ format!("Invalid platform version requirement {}: {}", s, e),
+ )
+ })
+}
+
/// Simple utility for referencing Borrowed or Owned. Similar to std::borrow::Cow, but
/// it doesn't require that T implements Clone.
enum BorrowedOrOwned<'a, T> {
diff --git a/virtualizationservice/src/crosvm.rs b/virtualizationservice/src/crosvm.rs
index df7a7d2..94cb78f 100644
--- a/virtualizationservice/src/crosvm.rs
+++ b/virtualizationservice/src/crosvm.rs
@@ -19,6 +19,7 @@
use anyhow::{bail, Error};
use command_fds::CommandFdExt;
use log::{debug, error, info};
+use semver::{Version, VersionReq};
use shared_child::SharedChild;
use std::fs::{remove_dir_all, File};
use std::io;
@@ -36,6 +37,12 @@
const CROSVM_PATH: &str = "/apex/com.android.virt/bin/crosvm";
+/// Version of the platform that crosvm currently implements. The format follows SemVer. This
+/// should be updated when there is a platform change in the crosvm side. Having this value here is
+/// fine because virtualizationservice and crosvm are supposed to be updated together in the virt
+/// APEX.
+const CROSVM_PLATFORM_VERSION: &str = "1.0.0";
+
/// The exit status which crosvm returns when it has an error starting a VM.
const CROSVM_ERROR_STATUS: i32 = 1;
/// The exit status which crosvm returns when a VM requests a reboot.
@@ -59,6 +66,7 @@
pub console_fd: Option<File>,
pub log_fd: Option<File>,
pub indirect_files: Vec<File>,
+ pub platform_version: VersionReq,
}
/// A disk image to pass to crosvm for a VM.
@@ -365,6 +373,16 @@
if config.bootloader.is_some() && (config.kernel.is_some() || config.initrd.is_some()) {
bail!("Can't have both bootloader and kernel/initrd image.");
}
+ let version = Version::parse(CROSVM_PLATFORM_VERSION).unwrap();
+ if !config.platform_version.matches(&version) {
+ bail!(
+ "Incompatible platform version. The config is compatible with platform version(s) \
+ {}, but the actual platform version is {}",
+ config.platform_version,
+ version
+ );
+ }
+
Ok(())
}