Remove onPayloadStarted stream argument
microdroid_manager creates a vsock connection with the host and
redirects the payload's stdin/stdout/stderr streams over it. This may
not necessarily be a securiy issue if the app never writes any secrets
to its standard output, but it would be safer to not open up
a communication channel like that by default. If the payload wishes to
pass its logs to the host, it should open up the connection explicitly.
Remove the vsock connection, the virtualizationservice server and the
corresponding file descriptor argument of onPayloadStarted() callback.
Instead, provide onPayloadStdio() that the payload can optinally call
to set up the connection.
Bug: 245727626
Bug: 253221932
Test: atest -p packages/modules/Virtualization:avf-presubmit
Change-Id: I89fd3a52aae9272db7300224b88d87c6f4d8a8a7
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachineCallback.aidl b/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachineCallback.aidl
index 8d6ed08..521cf12 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachineCallback.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice/IVirtualMachineCallback.aidl
@@ -24,13 +24,14 @@
*/
oneway interface IVirtualMachineCallback {
/**
- * Called when the payload starts in the VM. `stream` is the input/output port of the payload.
- *
- * <p>Note: when the virtual machine object is shared to multiple processes and they register
- * this callback to the same virtual machine object, the processes will compete to access the
- * same payload stream. Keep only one process to access the stream.
+ * Called when the payload starts in the VM.
*/
- void onPayloadStarted(int cid, in @nullable ParcelFileDescriptor stream);
+ void onPayloadStarted(int cid);
+
+ /**
+ * Called when the payload provides access to its standard input/output via a socket.
+ */
+ void onPayloadStdio(int cid, in ParcelFileDescriptor fd);
/**
* Called when the payload in the VM is ready to serve.
diff --git a/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl b/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
index e8c1724..deee662 100644
--- a/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
+++ b/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
@@ -21,12 +21,6 @@
interface IVirtualMachineService {
/**
* Port number that VirtualMachineService listens on connections from the guest VMs for the
- * payload input and output.
- */
- const int VM_STREAM_SERVICE_PORT = 3000;
-
- /**
- * Port number that VirtualMachineService listens on connections from the guest VMs for the
* VirtualMachineService binder service.
*/
const int VM_BINDER_SERVICE_PORT = 5000;
@@ -53,7 +47,12 @@
void notifyPayloadFinished(int exitCode);
/**
- * Notifies that an error has occurred inside the VM..
+ * Notifies that an error has occurred inside the VM.
*/
void notifyError(ErrorCode errorCode, in String message);
+
+ /**
+ * Notifies that the guest has started a stdio proxy on the given port.
+ */
+ void connectPayloadStdioProxy(int port);
}
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index bc697e3..340fc68 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -38,7 +38,7 @@
};
use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::{
BnVirtualMachineService, IVirtualMachineService, VM_BINDER_SERVICE_PORT,
- VM_STREAM_SERVICE_PORT, VM_TOMBSTONES_SERVICE_PORT,
+ VM_TOMBSTONES_SERVICE_PORT,
};
use anyhow::{anyhow, bail, Context, Result};
use apkverify::{HashAlgorithm, V4Signature};
@@ -301,12 +301,6 @@
pub fn init() -> VirtualizationService {
let service = VirtualizationService::default();
- // server for payload output
- let state = service.state.clone(); // reference to state (not the state itself) is copied
- std::thread::spawn(move || {
- handle_stream_connection_from_vm(state).unwrap();
- });
-
std::thread::spawn(|| {
if let Err(e) = handle_stream_connection_tombstoned() {
warn!("Error receiving tombstone from guest or writing them. Error: {:?}", e);
@@ -488,33 +482,6 @@
}
}
-/// Waits for incoming connections from VM. If a new connection is made, stores the stream in the
-/// corresponding `VmInstance`.
-fn handle_stream_connection_from_vm(state: Arc<Mutex<State>>) -> Result<()> {
- let listener =
- VsockListener::bind_with_cid_port(VMADDR_CID_HOST, VM_STREAM_SERVICE_PORT as u32)?;
- for stream in listener.incoming() {
- let stream = match stream {
- Err(e) => {
- warn!("invalid incoming connection: {:?}", e);
- continue;
- }
- Ok(s) => s,
- };
- if let Ok(addr) = stream.peer_addr() {
- let cid = addr.cid();
- let port = addr.port();
- info!("payload stream connected from cid={}, port={}", cid, port);
- if let Some(vm) = state.lock().unwrap().get_vm(cid) {
- *vm.stream.lock().unwrap() = Some(stream);
- } else {
- error!("connection from cid={} is not from a guest VM", cid);
- }
- }
- }
- Ok(())
-}
-
fn write_zero_filler(zero_filler_path: &Path) -> Result<()> {
let file = OpenOptions::new()
.create_new(true)
@@ -854,11 +821,10 @@
impl VirtualMachineCallbacks {
/// Call all registered callbacks to notify that the payload has started.
- pub fn notify_payload_started(&self, cid: Cid, stream: Option<VsockStream>) {
+ pub fn notify_payload_started(&self, cid: Cid) {
let callbacks = &*self.0.lock().unwrap();
- let pfd = stream.map(vsock_stream_to_pfd);
for callback in callbacks {
- if let Err(e) = callback.onPayloadStarted(cid as i32, pfd.as_ref()) {
+ if let Err(e) = callback.onPayloadStarted(cid as i32) {
error!("Error notifying payload start event from VM CID {}: {:?}", cid, e);
}
}
@@ -894,6 +860,16 @@
}
}
+ /// Call all registered callbacks to notify that the payload has provided a standard I/O proxy.
+ pub fn notify_payload_stdio(&self, cid: Cid, fd: ParcelFileDescriptor) {
+ let callbacks = &*self.0.lock().unwrap();
+ for callback in callbacks {
+ if let Err(e) = callback.onPayloadStdio(cid as i32, &fd) {
+ error!("Error notifying payload stdio event from VM CID {}: {:?}", cid, e);
+ }
+ }
+ }
+
/// Call all registered callbacks to say that the VM has died.
pub fn callback_on_died(&self, cid: Cid, reason: DeathReason) {
let callbacks = &*self.0.lock().unwrap();
@@ -1072,8 +1048,7 @@
vm.update_payload_state(PayloadState::Started).map_err(|e| {
Status::new_exception_str(ExceptionCode::ILLEGAL_STATE, Some(e.to_string()))
})?;
- let stream = vm.stream.lock().unwrap().take();
- vm.callbacks.notify_payload_started(cid, stream);
+ vm.callbacks.notify_payload_started(cid);
let vm_start_timestamp = vm.vm_start_timestamp.lock().unwrap();
write_vm_booted_stats(vm.requester_uid as i32, &vm.name, *vm_start_timestamp);
@@ -1140,6 +1115,27 @@
))
}
}
+
+ fn connectPayloadStdioProxy(&self, port: i32) -> binder::Result<()> {
+ let cid = self.cid;
+ if let Some(vm) = self.state.lock().unwrap().get_vm(cid) {
+ info!("VM with CID {} started a stdio proxy", cid);
+ let stream = VsockStream::connect_with_cid_port(cid, port as u32).map_err(|e| {
+ Status::new_service_specific_error_str(
+ -1,
+ Some(format!("Failed to connect to guest stdio proxy: {:?}", e)),
+ )
+ })?;
+ vm.callbacks.notify_payload_stdio(cid, vsock_stream_to_pfd(stream));
+ Ok(())
+ } else {
+ error!("connectPayloadStdioProxy is called from an unknown CID {}", cid);
+ Err(Status::new_service_specific_error_str(
+ -1,
+ Some(format!("cannot find a VM with CID {}", cid)),
+ ))
+ }
+ }
}
impl VirtualMachineService {
diff --git a/virtualizationservice/src/crosvm.rs b/virtualizationservice/src/crosvm.rs
index 1b8061e..29040b7 100644
--- a/virtualizationservice/src/crosvm.rs
+++ b/virtualizationservice/src/crosvm.rs
@@ -35,7 +35,6 @@
use std::sync::{Arc, Condvar, Mutex};
use std::time::{Duration, SystemTime};
use std::thread;
-use vsock::VsockStream;
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::DeathReason::DeathReason;
use binder::Strong;
use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::IVirtualMachineService;
@@ -190,8 +189,6 @@
pub requester_debug_pid: i32,
/// Callbacks to clients of the VM.
pub callbacks: VirtualMachineCallbacks,
- /// Input/output stream of the payload run in the VM.
- pub stream: Mutex<Option<VsockStream>>,
/// VirtualMachineService binder object for the VM.
pub vm_service: Mutex<Option<Strong<dyn IVirtualMachineService>>>,
/// Recorded timestamp when the VM is started.
@@ -223,7 +220,6 @@
requester_uid,
requester_debug_pid,
callbacks: Default::default(),
- stream: Mutex::new(None),
vm_service: Mutex::new(None),
vm_start_timestamp: Mutex::new(None),
payload_state: Mutex::new(PayloadState::Starting),