Snap for 12289667 from 56bdc50419a5fa813cc433938f8b86a76ec188f6 to 24Q4-release
Change-Id: Ib215a95c11a5705a7633ffa41ed16f781ddf3906
diff --git a/android/virtmgr/Android.bp b/android/virtmgr/Android.bp
index a21ee6c..4828057 100644
--- a/android/virtmgr/Android.bp
+++ b/android/virtmgr/Android.bp
@@ -55,6 +55,7 @@
"libregex",
"librpcbinder_rs",
"librustutils",
+ "libsafe_ownedfd",
"libsemver",
"libselinux_bindgen",
"libserde",
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index 144524f..7a357f3 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -73,6 +73,7 @@
use nix::unistd::pipe;
use rpcbinder::RpcServer;
use rustutils::system_properties;
+use safe_ownedfd::take_fd_ownership;
use semver::VersionReq;
use std::collections::HashSet;
use std::convert::TryInto;
@@ -82,7 +83,7 @@
use std::io::{BufRead, BufReader, Error, ErrorKind, Seek, SeekFrom, Write};
use std::iter;
use std::num::{NonZeroU16, NonZeroU32};
-use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};
+use std::os::unix::io::{AsRawFd, IntoRawFd};
use std::os::unix::raw::pid_t;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex, Weak};
@@ -1274,7 +1275,7 @@
let stream = VsockStream::connect_with_cid_port(self.instance.cid, port)
.context("Failed to connect")
.or_service_specific_exception(-1)?;
- Ok(vsock_stream_to_pfd(stream))
+ vsock_stream_to_pfd(stream)
}
fn setHostConsoleName(&self, ptsname: &str) -> binder::Result<()> {
@@ -1433,10 +1434,12 @@
}
/// Converts a `VsockStream` to a `ParcelFileDescriptor`.
-fn vsock_stream_to_pfd(stream: VsockStream) -> ParcelFileDescriptor {
- // SAFETY: ownership is transferred from stream to f
- let f = unsafe { File::from_raw_fd(stream.into_raw_fd()) };
- ParcelFileDescriptor::new(f)
+fn vsock_stream_to_pfd(stream: VsockStream) -> binder::Result<ParcelFileDescriptor> {
+ let owned_fd = take_fd_ownership(stream.into_raw_fd())
+ .context("Failed to take ownership of the vsock stream")
+ .with_log()
+ .or_service_specific_exception(-1)?;
+ Ok(ParcelFileDescriptor::new(owned_fd))
}
/// Parses the platform version requirement string.
diff --git a/android/virtmgr/src/main.rs b/android/virtmgr/src/main.rs
index 445260f..7d29685 100644
--- a/android/virtmgr/src/main.rs
+++ b/android/virtmgr/src/main.rs
@@ -25,16 +25,16 @@
use crate::aidl::{GLOBAL_SERVICE, VirtualizationService};
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualizationService::BnVirtualizationService;
-use anyhow::{bail, Context, Result};
+use anyhow::{bail, Result};
use binder::{BinderFeatures, ProcessState};
use lazy_static::lazy_static;
use log::{info, LevelFilter};
use rpcbinder::{FileDescriptorTransportMode, RpcServer};
-use std::os::unix::io::{AsFd, FromRawFd, OwnedFd, RawFd};
+use std::os::unix::io::{AsFd, RawFd};
use clap::Parser;
-use nix::fcntl::{fcntl, F_GETFD, F_SETFD, FdFlag};
use nix::unistd::{write, Pid, Uid};
use std::os::unix::raw::{pid_t, uid_t};
+use safe_ownedfd::take_fd_ownership;
const LOG_TAG: &str = "virtmgr";
@@ -73,32 +73,6 @@
ready_fd: RawFd,
}
-fn take_fd_ownership(raw_fd: RawFd, owned_fds: &mut Vec<RawFd>) -> Result<OwnedFd, anyhow::Error> {
- // Basic check that the integer value does correspond to a file descriptor.
- fcntl(raw_fd, F_GETFD).with_context(|| format!("Invalid file descriptor {raw_fd}"))?;
-
- // The file descriptor had CLOEXEC disabled to be inherited from the parent.
- // Re-enable it to make sure it is not accidentally inherited further.
- fcntl(raw_fd, F_SETFD(FdFlag::FD_CLOEXEC))
- .with_context(|| format!("Could not set CLOEXEC on file descriptor {raw_fd}"))?;
-
- // Creating OwnedFd for stdio FDs is not safe.
- if [libc::STDIN_FILENO, libc::STDOUT_FILENO, libc::STDERR_FILENO].contains(&raw_fd) {
- bail!("File descriptor {raw_fd} is standard I/O descriptor");
- }
-
- // Reject RawFds that already have a corresponding OwnedFd.
- if owned_fds.contains(&raw_fd) {
- bail!("File descriptor {raw_fd} already owned");
- }
- owned_fds.push(raw_fd);
-
- // SAFETY: Initializing OwnedFd for a RawFd provided in cmdline arguments.
- // We checked that the integer value corresponds to a valid FD and that this
- // is the first argument to claim its ownership.
- Ok(unsafe { OwnedFd::from_raw_fd(raw_fd) })
-}
-
fn check_vm_support() -> Result<()> {
if hypervisor_props::is_any_vm_supported()? {
Ok(())
@@ -122,11 +96,9 @@
let args = Args::parse();
- let mut owned_fds = vec![];
- let rpc_server_fd = take_fd_ownership(args.rpc_server_fd, &mut owned_fds)
- .expect("Failed to take ownership of rpc_server_fd");
- let ready_fd = take_fd_ownership(args.ready_fd, &mut owned_fds)
- .expect("Failed to take ownership of ready_fd");
+ let rpc_server_fd =
+ take_fd_ownership(args.rpc_server_fd).expect("Failed to take ownership of rpc_server_fd");
+ let ready_fd = take_fd_ownership(args.ready_fd).expect("Failed to take ownership of ready_fd");
// Start thread pool for kernel Binder connection to VirtualizationServiceInternal.
ProcessState::start_thread_pool();
diff --git a/docs/custom_vm.md b/docs/custom_vm.md
index 6a1cc00..b02fbf7 100644
--- a/docs/custom_vm.md
+++ b/docs/custom_vm.md
@@ -110,12 +110,11 @@
## Graphical VMs
To run OSes with graphics support, simply
-`packages/modules/Virtualization/tests/ferrochrome/ferrochrome.sh`. It prepares
-and launches the ChromiumOS, which is the only officially supported guest
-payload. We will be adding more OSes in the future.
+`packages/modules/Virtualization/tests/ferrochrome/ferrochrome.sh --forever`.
+It prepares and launches the ChromiumOS, which is the only officially supported
+guest payload. We will be adding more OSes in the future.
-If you want to do so by yourself (e.g. boot with your build), follow the
-instruction below.
+If you want to do so by yourself, follow the instruction below.
### Prepare a guest image
@@ -306,9 +305,6 @@
```
To see console logs only, check
-`/data/data/com{,.google}.android.virtualization.vmlauncher/files/${vm_name}.log`
-
-For HSUM enabled devices,
`/data/user/${current_user_id}/com{,.google}.android.virtualization.vmlauncher/files/${vm_name}.log`
You can monitor console out as follows
diff --git a/guest/microdroid_manager/Android.bp b/guest/microdroid_manager/Android.bp
index 9c9a3d0..82e26b7 100644
--- a/guest/microdroid_manager/Android.bp
+++ b/guest/microdroid_manager/Android.bp
@@ -48,6 +48,7 @@
"libprotobuf",
"librpcbinder_rs",
"librustutils",
+ "libsafe_ownedfd",
"libsecretkeeper_client",
"libsecretkeeper_comm_nostd",
"libscopeguard",
@@ -59,6 +60,7 @@
"libvsock",
"librand",
"libzeroize",
+ "libsafe_ownedfd",
],
init_rc: ["microdroid_manager.rc"],
multilib: {
diff --git a/guest/microdroid_manager/src/main.rs b/guest/microdroid_manager/src/main.rs
index 990d27a..8b676b8 100644
--- a/guest/microdroid_manager/src/main.rs
+++ b/guest/microdroid_manager/src/main.rs
@@ -50,13 +50,14 @@
use rustutils::sockets::android_get_control_socket;
use rustutils::system_properties;
use rustutils::system_properties::PropertyWatcher;
+use safe_ownedfd::take_fd_ownership;
use secretkeeper_comm::data_types::ID_SIZE;
use std::borrow::Cow::{Borrowed, Owned};
use std::env;
use std::ffi::CString;
use std::fs::{self, create_dir, File, OpenOptions};
use std::io::{Read, Write};
-use std::os::unix::io::{FromRawFd, OwnedFd};
+use std::os::unix::io::OwnedFd;
use std::os::unix::process::CommandExt;
use std::os::unix::process::ExitStatusExt;
use std::path::Path;
@@ -199,13 +200,7 @@
);
info!("started.");
- // SAFETY: This is the only place we take the ownership of the fd of the vm payload service.
- //
- // To ensure that the CLOEXEC flag is set on the file descriptor as early as possible,
- // it is necessary to fetch the socket corresponding to vm_payload_service at the
- // very beginning, as android_get_control_socket() sets the CLOEXEC flag on the file
- // descriptor.
- let vm_payload_service_fd = unsafe { prepare_vm_payload_service_socket()? };
+ let vm_payload_service_fd = prepare_vm_payload_service_socket()?;
load_crashkernel_if_supported().context("Failed to load crashkernel")?;
@@ -487,22 +482,9 @@
}
/// Prepares a socket file descriptor for the vm payload service.
-///
-/// # Safety
-///
-/// The caller must ensure that this function is the only place that claims ownership
-/// of the file descriptor and it is called only once.
-unsafe fn prepare_vm_payload_service_socket() -> Result<OwnedFd> {
+fn prepare_vm_payload_service_socket() -> Result<OwnedFd> {
let raw_fd = android_get_control_socket(VM_PAYLOAD_SERVICE_SOCKET_NAME)?;
-
- // Creating OwnedFd for stdio FDs is not safe.
- if [libc::STDIN_FILENO, libc::STDOUT_FILENO, libc::STDERR_FILENO].contains(&raw_fd) {
- bail!("File descriptor {raw_fd} is standard I/O descriptor");
- }
- // SAFETY: Initializing OwnedFd for a RawFd created by the init.
- // We checked that the integer value corresponds to a valid FD and that the caller
- // ensures that this is the only place to claim its ownership.
- Ok(unsafe { OwnedFd::from_raw_fd(raw_fd) })
+ Ok(take_fd_ownership(raw_fd)?)
}
fn is_strict_boot() -> bool {
diff --git a/guest/rialto/tests/test.rs b/guest/rialto/tests/test.rs
index 7c0d9dc..42a4284 100644
--- a/guest/rialto/tests/test.rs
+++ b/guest/rialto/tests/test.rs
@@ -288,7 +288,9 @@
}
fn check_csr(csr: Vec<u8>) -> Result<()> {
- let _csr = rkp::Csr::from_cbor(&Session::default(), &csr[..]).context("Failed to parse CSR")?;
+ let mut session = Session::default();
+ session.set_allow_any_mode(true);
+ let _csr = rkp::Csr::from_cbor(&session, &csr[..]).context("Failed to parse CSR")?;
Ok(())
}
diff --git a/libs/libsafe_ownedfd/Android.bp b/libs/libsafe_ownedfd/Android.bp
index 1f14578..53e14dc 100644
--- a/libs/libsafe_ownedfd/Android.bp
+++ b/libs/libsafe_ownedfd/Android.bp
@@ -18,6 +18,7 @@
defaults: ["libsafe_ownedfd.defaults"],
apex_available: [
"com.android.compos",
+ "com.android.microfuchsia",
"com.android.virt",
],
}
diff --git a/microfuchsia/microfuchsiad/Android.bp b/microfuchsia/microfuchsiad/Android.bp
index ddf360d..ab3f865 100644
--- a/microfuchsia/microfuchsiad/Android.bp
+++ b/microfuchsia/microfuchsiad/Android.bp
@@ -15,8 +15,9 @@
"libandroid_logger",
"libanyhow",
"libbinder_rs",
- "liblog_rust",
"liblibc",
+ "liblog_rust",
+ "libsafe_ownedfd",
"libvmclient",
],
apex_available: [
diff --git a/microfuchsia/microfuchsiad/src/instance_starter.rs b/microfuchsia/microfuchsiad/src/instance_starter.rs
index 15fcc06..6688447 100644
--- a/microfuchsia/microfuchsiad/src/instance_starter.rs
+++ b/microfuchsia/microfuchsiad/src/instance_starter.rs
@@ -23,9 +23,10 @@
use anyhow::{ensure, Context, Result};
use binder::{LazyServiceGuard, ParcelFileDescriptor};
use log::info;
+use safe_ownedfd::take_fd_ownership;
use std::ffi::CStr;
use std::fs::File;
-use std::os::fd::FromRawFd;
+use std::os::fd::AsRawFd;
use vmclient::VmInstance;
pub struct MicrofuchsiaInstance {
@@ -133,6 +134,7 @@
"failed to openpty"
);
}
+ let leader = take_fd_ownership(leader)?;
// SAFETY: calling these libc functions with valid+initialized variables is safe.
unsafe {
@@ -145,24 +147,25 @@
c_line: 0,
c_cc: [0u8; 19],
};
- ensure!(libc::tcgetattr(leader, &mut attr) == 0, "failed to get termios attributes");
+ ensure!(
+ libc::tcgetattr(leader.as_raw_fd(), &mut attr) == 0,
+ "failed to get termios attributes"
+ );
// Force it to be a raw pty and re-set it.
libc::cfmakeraw(&mut attr);
ensure!(
- libc::tcsetattr(leader, libc::TCSANOW, &attr) == 0,
+ libc::tcsetattr(leader.as_raw_fd(), libc::TCSANOW, &attr) == 0,
"failed to set termios attributes"
);
}
// Construct the return value.
- // SAFETY: The file descriptors are valid because openpty returned without error (above).
- let leader = unsafe { File::from_raw_fd(leader) };
let follower_name: Vec<u8> = follower_name.iter_mut().map(|x| *x as _).collect();
let follower_name = CStr::from_bytes_until_nul(&follower_name)
.context("pty filename missing NUL")?
.to_str()
.context("pty filename invalid utf8")?
.to_string();
- Ok(Pty { leader, follower_name })
+ Ok(Pty { leader: File::from(leader), follower_name })
}
diff --git a/tests/ComposHostTestCases/java/android/compos/test/ComposTestCase.java b/tests/ComposHostTestCases/java/android/compos/test/ComposTestCase.java
index 7a35829..6e583c0 100644
--- a/tests/ComposHostTestCases/java/android/compos/test/ComposTestCase.java
+++ b/tests/ComposHostTestCases/java/android/compos/test/ComposTestCase.java
@@ -200,6 +200,7 @@
10000,
validator.getAbsolutePath(),
"dice-chain",
+ "--allow-any-mode",
bcc_file.getAbsolutePath());
assertWithMessage("hwtrust failed").about(command_results()).that(result).isSuccess();
}
diff --git a/tests/ferrochrome/ferrochrome.sh b/tests/ferrochrome/ferrochrome.sh
index 6e23204..03630dd 100755
--- a/tests/ferrochrome/ferrochrome.sh
+++ b/tests/ferrochrome/ferrochrome.sh
@@ -65,6 +65,7 @@
echo " --version \${version}: ferrochrome version to be downloaded"
echo " --keep: Keep downloaded ferrochrome image"
echo " --test: Download test image instead"
+ echo " --forever: Keep ferrochrome running forever. Used for manual test"
}
fecr_version="${FECR_DEFAULT_VERSION}"
@@ -76,6 +77,7 @@
fecr_image="${FECR_DEFAULT_IMAGE}"
fecr_boot_completed_log="${FECR_DEFAULT_BOOT_COMPLETED_LOG}"
fecr_screenshot_dir="${FECR_DEFAULT_SCREENSHOT_DIR}"
+fecr_forever=""
# Parse parameters
while (( "${#}" )); do
@@ -102,6 +104,9 @@
fecr_image="${FECR_TEST_IMAGE}"
fecr_boot_completed_log="${FECR_TEST_IMAGE_BOOT_COMPLETED_LOG}"
;;
+ --forever)
+ fecr_forever="true"
+ ;;
-h|--help)
print_usage
exit 0
@@ -134,9 +139,9 @@
current_user=$(adb shell am get-current-user)
echo "Reset app & granting permission"
+adb shell pm clear --user ${current_user} ${pkg_name} > /dev/null
adb shell pm grant --user ${current_user} ${pkg_name} android.permission.RECORD_AUDIO
adb shell pm grant --user ${current_user} ${pkg_name} android.permission.USE_CUSTOM_VIRTUAL_MACHINE > /dev/null
-adb shell pm clear --user ${current_user} ${pkg_name} > /dev/null
if [[ -z "${fecr_skip}" ]]; then
if [[ -z "${fecr_dir}" ]]; then
@@ -165,15 +170,23 @@
log_path="/data/user/${current_user}/${pkg_name}/${FECR_CONSOLE_LOG_PATH}"
fecr_start_time=${EPOCHSECONDS}
-adb shell mkdir -p "${fecr_screenshot_dir}"
-while [[ $((EPOCHSECONDS - fecr_start_time)) -lt ${FECR_BOOT_TIMEOUT} ]]; do
- adb shell screencap -p "${fecr_screenshot_dir}/screenshot-${EPOCHSECONDS}.png"
- adb shell grep -soF \""${fecr_boot_completed_log}"\" "${log_path}" && exit 0 || true
- sleep 10
-done
+echo "Check ${log_path} on device for console log"
->&2 echo "Ferrochrome failed to boot. Dumping console log"
->&2 adb shell cat ${log_path}
+if [[ "${fecr_forever}" == "true" ]]; then
+ echo "Ctrl+C to stop running"
+ echo "To open interactive serial console, use following command:"
+ echo "adb shell -t /apex/com.android.virt/bin/vm console"
+else
+ adb shell mkdir -p "${fecr_screenshot_dir}"
+ while [[ $((EPOCHSECONDS - fecr_start_time)) -lt ${FECR_BOOT_TIMEOUT} ]]; do
+ adb shell screencap -p "${fecr_screenshot_dir}/screenshot-${EPOCHSECONDS}.png"
+ adb shell grep -soF \""${fecr_boot_completed_log}"\" "${log_path}" && exit 0 || true
+ sleep 10
+ done
-exit 1
+ >&2 echo "Ferrochrome failed to boot. Dumping console log"
+ >&2 adb shell cat ${log_path}
+
+ exit 1
+fi
diff --git a/tests/testapk/src/java/com/android/microdroid/test/HwTrustJni.java b/tests/testapk/src/java/com/android/microdroid/test/HwTrustJni.java
index 3b237aa..0cf0606 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/HwTrustJni.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/HwTrustJni.java
@@ -25,7 +25,8 @@
* Validates a DICE chain.
*
* @param diceChain The dice chain to validate.
+ * @param allowAnyMode Allow the chain's certificates to have any mode.
* @return true if the dice chain is valid, false otherwise.
*/
- public static native boolean validateDiceChain(byte[] diceChain);
+ public static native boolean validateDiceChain(byte[] diceChain, boolean allowAnyMode);
}
diff --git a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
index 7089b33..d38af45 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -1305,7 +1305,7 @@
}
@Test
- @VsrTest(requirements = {"VSR-7.1-001.005"})
+ @VsrTest(requirements = {"VSR-7.1-001.004"})
public void protectedVmHasValidDiceChain() throws Exception {
// This test validates two things regarding the pVM DICE chain:
// 1. The DICE chain is well-formed that all the entries conform to the DICE spec.
@@ -1313,12 +1313,12 @@
assumeSupportedDevice();
assumeProtectedVM();
assumeVsrCompliant();
- assumeTrue("Vendor API must be at least 202404", getVendorApiLevel() >= 202404);
+ assumeTrue("Vendor API must be newer than 202404", getVendorApiLevel() > 202404);
grantPermission(VirtualMachine.USE_CUSTOM_VIRTUAL_MACHINE_PERMISSION);
VirtualMachineConfig config =
newVmConfigBuilderWithPayloadConfig("assets/vm_config.json")
- .setDebugLevel(DEBUG_LEVEL_FULL)
+ .setDebugLevel(DEBUG_LEVEL_NONE)
.build();
VirtualMachine vm = forceCreateNewVirtualMachine("bcc_vm_for_vsr", config);
TestResults testResults =
@@ -1331,7 +1331,11 @@
testResults.assertNoException();
byte[] bccBytes = testResults.mBcc;
assertThat(bccBytes).isNotNull();
- assertThat(HwTrustJni.validateDiceChain(bccBytes)).isTrue();
+
+ String buildType = SystemProperties.get("ro.build.type");
+ boolean nonUserBuild = !buildType.isEmpty() && buildType != "user";
+
+ assertThat(HwTrustJni.validateDiceChain(bccBytes, nonUserBuild)).isTrue();
}
@Test
diff --git a/tests/testapk/src/native/hwtrust_jni.rs b/tests/testapk/src/native/hwtrust_jni.rs
index 3b00364..058b1a6 100644
--- a/tests/testapk/src/native/hwtrust_jni.rs
+++ b/tests/testapk/src/native/hwtrust_jni.rs
@@ -29,6 +29,7 @@
env: JNIEnv,
_class: JClass,
dice_chain: JByteArray,
+ allow_any_mode: jboolean,
) -> jboolean {
android_logger::init_once(
android_logger::Config::default()
@@ -36,7 +37,7 @@
.with_max_level(log::LevelFilter::Debug),
);
debug!("Starting the DICE chain validation ...");
- match validate_dice_chain(env, dice_chain) {
+ match validate_dice_chain(env, dice_chain, allow_any_mode) {
Ok(_) => {
info!("DICE chain validated successfully");
true
@@ -49,9 +50,14 @@
.into()
}
-fn validate_dice_chain(env: JNIEnv, jdice_chain: JByteArray) -> Result<()> {
+fn validate_dice_chain(
+ env: JNIEnv,
+ jdice_chain: JByteArray,
+ allow_any_mode: jboolean,
+) -> Result<()> {
let dice_chain = env.convert_byte_array(jdice_chain)?;
- let session = Session::default();
+ let mut session = Session::default();
+ session.set_allow_any_mode(allow_any_mode == jboolean::from(true));
let _chain = dice::Chain::from_cbor(&session, &dice_chain)?;
Ok(())
}