blob: a79c0bbe824515b1eb754e59effadcc47d751860 [file] [log] [blame]
Alice Wangfb46ee12022-09-30 13:08:52 +00001// Copyright 2022, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Alice Wang59a9e562022-10-04 15:24:10 +000015//! This module handles the interaction with virtual machine payload service.
Alice Wangfb46ee12022-09-30 13:08:52 +000016
Alan Stokese0945ad2022-11-24 13:29:57 +000017// We're implementing unsafe functions, but we still want warnings on unsafe usage within them.
18#![warn(unsafe_op_in_unsafe_fn)]
19
Alice Wang13a2b1b2022-10-07 07:57:08 +000020use android_system_virtualization_payload::aidl::android::system::virtualization::payload::IVmPayloadService::{
Alice Wang43c884b2022-10-24 09:42:40 +000021 IVmPayloadService, VM_PAYLOAD_SERVICE_SOCKET_NAME, VM_APK_CONTENTS_PATH};
Alan Stokese0945ad2022-11-24 13:29:57 +000022use anyhow::{ensure, bail, Context, Result};
Alice Wang43c884b2022-10-24 09:42:40 +000023use binder::{Strong, unstable_api::{AIBinder, new_spibinder}};
Alice Wang6bbb6da2022-10-26 12:44:06 +000024use lazy_static::lazy_static;
Alice Wangfb46ee12022-09-30 13:08:52 +000025use log::{error, info, Level};
David Brazdil671e6142022-11-16 11:47:27 +000026use rpcbinder::{get_unix_domain_rpc_interface, RpcServer};
Alan Stokese0945ad2022-11-24 13:29:57 +000027use std::convert::Infallible;
Alice Wang6bbb6da2022-10-26 12:44:06 +000028use std::ffi::CString;
Alan Stokes65bbb912022-11-23 09:39:34 +000029use std::fmt::Debug;
Alice Wang6bbb6da2022-10-26 12:44:06 +000030use std::os::raw::{c_char, c_void};
Alan Stokes78d24702022-11-21 15:28:31 +000031use std::ptr;
Alan Stokes65bbb912022-11-23 09:39:34 +000032use std::sync::{Mutex, atomic::{AtomicBool, Ordering}};
Alice Wang6bbb6da2022-10-26 12:44:06 +000033
34lazy_static! {
35 static ref VM_APK_CONTENTS_PATH_C: CString =
36 CString::new(VM_APK_CONTENTS_PATH).expect("CString::new failed");
Alan Stokes0cbfdf92022-11-21 17:17:53 +000037 static ref PAYLOAD_CONNECTION: Mutex<Option<Strong<dyn IVmPayloadService>>> = Mutex::default();
Alice Wang6bbb6da2022-10-26 12:44:06 +000038}
Alice Wangfb46ee12022-09-30 13:08:52 +000039
Alan Stokes65bbb912022-11-23 09:39:34 +000040static ALREADY_NOTIFIED: AtomicBool = AtomicBool::new(false);
41
Alan Stokes0cbfdf92022-11-21 17:17:53 +000042/// Return a connection to the payload service in Microdroid Manager. Uses the existing connection
43/// if there is one, otherwise attempts to create a new one.
44fn get_vm_payload_service() -> Result<Strong<dyn IVmPayloadService>> {
45 let mut connection = PAYLOAD_CONNECTION.lock().unwrap();
46 if let Some(strong) = &*connection {
47 Ok(strong.clone())
48 } else {
49 let new_connection: Strong<dyn IVmPayloadService> = get_unix_domain_rpc_interface(
50 VM_PAYLOAD_SERVICE_SOCKET_NAME,
51 )
52 .context(format!("Failed to connect to service: {}", VM_PAYLOAD_SERVICE_SOCKET_NAME))?;
53 *connection = Some(new_connection.clone());
54 Ok(new_connection)
55 }
56}
57
58/// Make sure our logging goes to logcat. It is harmless to call this more than once.
Alan Stokesf30982b2022-11-18 11:50:32 +000059fn initialize_logging() {
60 android_logger::init_once(
Alan Stokes65bbb912022-11-23 09:39:34 +000061 android_logger::Config::default().with_tag("vm_payload").with_min_level(Level::Info),
Alan Stokesf30982b2022-11-18 11:50:32 +000062 );
63}
64
Alan Stokes65bbb912022-11-23 09:39:34 +000065/// In many cases clients can't do anything useful if API calls fail, and the failure
66/// generally indicates that the VM is exiting or otherwise doomed. So rather than
67/// returning a non-actionable error indication we just log the problem and abort
68/// the process.
69fn unwrap_or_abort<T, E: Debug>(result: Result<T, E>) -> T {
70 result.unwrap_or_else(|e| {
71 let msg = format!("{:?}", e);
72 error!("{msg}");
73 panic!("{msg}")
74 })
75}
76
Alice Wangfb46ee12022-09-30 13:08:52 +000077/// Notifies the host that the payload is ready.
Alan Stokes65bbb912022-11-23 09:39:34 +000078/// Panics on failure.
Alice Wangfb46ee12022-09-30 13:08:52 +000079#[no_mangle]
Alan Stokes65bbb912022-11-23 09:39:34 +000080pub extern "C" fn AVmPayload_notifyPayloadReady() {
Alan Stokesf30982b2022-11-18 11:50:32 +000081 initialize_logging();
82
Alan Stokes65bbb912022-11-23 09:39:34 +000083 if !ALREADY_NOTIFIED.swap(true, Ordering::Relaxed) {
84 unwrap_or_abort(try_notify_payload_ready());
85
Alice Wangfb46ee12022-09-30 13:08:52 +000086 info!("Notified host payload ready successfully");
Alice Wangfb46ee12022-09-30 13:08:52 +000087 }
88}
89
90/// Notifies the host that the payload is ready.
91/// Returns a `Result` containing error information if failed.
92fn try_notify_payload_ready() -> Result<()> {
Alice Wang59a9e562022-10-04 15:24:10 +000093 get_vm_payload_service()?.notifyPayloadReady().context("Cannot notify payload ready")
Alice Wangfb46ee12022-09-30 13:08:52 +000094}
95
Alice Wang2be64f32022-10-13 14:37:35 +000096/// Runs a binder RPC server, serving the supplied binder service implementation on the given vsock
97/// port.
98///
99/// If and when the server is ready for connections (it is listening on the port), `on_ready` is
100/// called to allow appropriate action to be taken - e.g. to notify clients that they may now
101/// attempt to connect.
102///
Alan Stokese0945ad2022-11-24 13:29:57 +0000103/// The current thread joins the binder thread pool to handle incoming messages.
104/// This function never returns.
Alice Wang2be64f32022-10-13 14:37:35 +0000105///
Alan Stokese0945ad2022-11-24 13:29:57 +0000106/// Panics on error (including unexpected server exit).
Alice Wang2be64f32022-10-13 14:37:35 +0000107///
108/// # Safety
109///
Alan Stokese0945ad2022-11-24 13:29:57 +0000110/// If present, the `on_ready` callback must be a valid function pointer, which will be called at
111/// most once, while this function is executing, with the `param` parameter.
Alice Wang2be64f32022-10-13 14:37:35 +0000112#[no_mangle]
113pub unsafe extern "C" fn AVmPayload_runVsockRpcServer(
114 service: *mut AIBinder,
115 port: u32,
116 on_ready: Option<unsafe extern "C" fn(param: *mut c_void)>,
117 param: *mut c_void,
Alan Stokese0945ad2022-11-24 13:29:57 +0000118) -> Infallible {
Alan Stokesf30982b2022-11-18 11:50:32 +0000119 initialize_logging();
120
Alan Stokese0945ad2022-11-24 13:29:57 +0000121 // SAFETY: try_run_vsock_server has the same requirements as this function
122 unwrap_or_abort(unsafe { try_run_vsock_server(service, port, on_ready, param) })
123}
124
125/// # Safety: Same as `AVmPayload_runVsockRpcServer`.
126unsafe fn try_run_vsock_server(
127 service: *mut AIBinder,
128 port: u32,
129 on_ready: Option<unsafe extern "C" fn(param: *mut c_void)>,
130 param: *mut c_void,
131) -> Result<Infallible> {
Alice Wang2be64f32022-10-13 14:37:35 +0000132 // SAFETY: AIBinder returned has correct reference count, and the ownership can
133 // safely be taken by new_spibinder.
Alan Stokese0945ad2022-11-24 13:29:57 +0000134 let service = unsafe { new_spibinder(service) };
Alice Wang2be64f32022-10-13 14:37:35 +0000135 if let Some(service) = service {
David Brazdil671e6142022-11-16 11:47:27 +0000136 match RpcServer::new_vsock(service, port) {
137 Ok(server) => {
138 if let Some(on_ready) = on_ready {
Alan Stokese0945ad2022-11-24 13:29:57 +0000139 // SAFETY: We're calling the callback with the parameter specified within the
140 // allowed lifetime.
141 unsafe { on_ready(param) };
David Brazdil671e6142022-11-16 11:47:27 +0000142 }
143 server.join();
Alan Stokese0945ad2022-11-24 13:29:57 +0000144 bail!("RpcServer unexpectedly terminated");
Alice Wang2be64f32022-10-13 14:37:35 +0000145 }
David Brazdil671e6142022-11-16 11:47:27 +0000146 Err(err) => {
Alan Stokese0945ad2022-11-24 13:29:57 +0000147 bail!("Failed to start RpcServer: {:?}", err);
David Brazdil671e6142022-11-16 11:47:27 +0000148 }
149 }
Alice Wang2be64f32022-10-13 14:37:35 +0000150 } else {
Alan Stokese0945ad2022-11-24 13:29:57 +0000151 bail!("Failed to convert the given service from AIBinder to SpIBinder.");
Alice Wang2be64f32022-10-13 14:37:35 +0000152 }
153}
154
Andrew Scull102067a2022-10-07 00:34:40 +0000155/// Get a secret that is uniquely bound to this VM instance.
Alan Stokes65bbb912022-11-23 09:39:34 +0000156/// Panics on failure.
Andrew Scull102067a2022-10-07 00:34:40 +0000157///
158/// # Safety
159///
Andrew Scull655e98e2022-10-10 22:24:58 +0000160/// Behavior is undefined if any of the following conditions are violated:
161///
162/// * `identifier` must be [valid] for reads of `identifier_size` bytes.
163/// * `secret` must be [valid] for writes of `size` bytes.
164///
Alan Stokes65bbb912022-11-23 09:39:34 +0000165/// [valid]: ptr#safety
Andrew Scull102067a2022-10-07 00:34:40 +0000166#[no_mangle]
Andrew Scull655e98e2022-10-10 22:24:58 +0000167pub unsafe extern "C" fn AVmPayload_getVmInstanceSecret(
Andrew Scull102067a2022-10-07 00:34:40 +0000168 identifier: *const u8,
169 identifier_size: usize,
170 secret: *mut u8,
171 size: usize,
Alan Stokes65bbb912022-11-23 09:39:34 +0000172) {
Alan Stokesf30982b2022-11-18 11:50:32 +0000173 initialize_logging();
174
Alan Stokese0945ad2022-11-24 13:29:57 +0000175 // SAFETY: See the requirements on `identifier` above.
176 let identifier = unsafe { std::slice::from_raw_parts(identifier, identifier_size) };
Alan Stokes65bbb912022-11-23 09:39:34 +0000177 let vm_secret = unwrap_or_abort(try_get_vm_instance_secret(identifier, size));
Alan Stokese0945ad2022-11-24 13:29:57 +0000178
179 // SAFETY: See the requirements on `secret` above; `vm_secret` is known to have length `size`,
180 // and cannot overlap `secret` because we just allocated it.
181 unsafe {
182 ptr::copy_nonoverlapping(vm_secret.as_ptr(), secret, size);
183 }
Andrew Scull102067a2022-10-07 00:34:40 +0000184}
185
186fn try_get_vm_instance_secret(identifier: &[u8], size: usize) -> Result<Vec<u8>> {
Alan Stokes65bbb912022-11-23 09:39:34 +0000187 let vm_secret = get_vm_payload_service()?
Andrew Scull102067a2022-10-07 00:34:40 +0000188 .getVmInstanceSecret(identifier, i32::try_from(size)?)
Alan Stokes65bbb912022-11-23 09:39:34 +0000189 .context("Cannot get VM instance secret")?;
190 ensure!(
191 vm_secret.len() == size,
192 "Returned secret has {} bytes, expected {}",
193 vm_secret.len(),
194 size
195 );
196 Ok(vm_secret)
Andrew Scull102067a2022-10-07 00:34:40 +0000197}
198
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000199/// Get the VM's attestation chain.
Alan Stokes65bbb912022-11-23 09:39:34 +0000200/// Panics on failure.
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000201///
202/// # Safety
203///
Andrew Scull655e98e2022-10-10 22:24:58 +0000204/// Behavior is undefined if any of the following conditions are violated:
205///
206/// * `data` must be [valid] for writes of `size` bytes.
Andrew Scull655e98e2022-10-10 22:24:58 +0000207///
Alan Stokes65bbb912022-11-23 09:39:34 +0000208/// [valid]: ptr#safety
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000209#[no_mangle]
Alan Stokes65bbb912022-11-23 09:39:34 +0000210pub unsafe extern "C" fn AVmPayload_getDiceAttestationChain(data: *mut u8, size: usize) -> usize {
Alan Stokesf30982b2022-11-18 11:50:32 +0000211 initialize_logging();
212
Alan Stokes65bbb912022-11-23 09:39:34 +0000213 let chain = unwrap_or_abort(try_get_dice_attestation_chain());
Alan Stokese0945ad2022-11-24 13:29:57 +0000214 // SAFETY: See the requirements on `data` above. The number of bytes copied doesn't exceed
215 // the length of either buffer, and `chain` cannot overlap `data` because we just allocated it.
216 unsafe { ptr::copy_nonoverlapping(chain.as_ptr(), data, std::cmp::min(chain.len(), size)) };
Alan Stokes65bbb912022-11-23 09:39:34 +0000217 chain.len()
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000218}
219
220fn try_get_dice_attestation_chain() -> Result<Vec<u8>> {
221 get_vm_payload_service()?.getDiceAttestationChain().context("Cannot get attestation chain")
222}
223
224/// Get the VM's attestation CDI.
Alan Stokes65bbb912022-11-23 09:39:34 +0000225/// Panics on failure.
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000226///
227/// # Safety
228///
Andrew Scull655e98e2022-10-10 22:24:58 +0000229/// Behavior is undefined if any of the following conditions are violated:
230///
231/// * `data` must be [valid] for writes of `size` bytes.
Andrew Scull655e98e2022-10-10 22:24:58 +0000232///
Alan Stokes65bbb912022-11-23 09:39:34 +0000233/// [valid]: ptr#safety
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000234#[no_mangle]
Alan Stokes65bbb912022-11-23 09:39:34 +0000235pub unsafe extern "C" fn AVmPayload_getDiceAttestationCdi(data: *mut u8, size: usize) -> usize {
Alan Stokesf30982b2022-11-18 11:50:32 +0000236 initialize_logging();
237
Alan Stokes65bbb912022-11-23 09:39:34 +0000238 let cdi = unwrap_or_abort(try_get_dice_attestation_cdi());
Alan Stokese0945ad2022-11-24 13:29:57 +0000239 // SAFETY: See the requirements on `data` above. The number of bytes copied doesn't exceed
240 // the length of either buffer, and `cdi` cannot overlap `data` because we just allocated it.
241 unsafe { ptr::copy_nonoverlapping(cdi.as_ptr(), data, std::cmp::min(cdi.len(), size)) };
Alan Stokes65bbb912022-11-23 09:39:34 +0000242 cdi.len()
243}
244
245fn try_get_dice_attestation_cdi() -> Result<Vec<u8>> {
246 get_vm_payload_service()?.getDiceAttestationCdi().context("Cannot get attestation CDI")
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000247}
248
Alice Wang6bbb6da2022-10-26 12:44:06 +0000249/// Gets the path to the APK contents.
250#[no_mangle]
251pub extern "C" fn AVmPayload_getApkContentsPath() -> *const c_char {
252 (*VM_APK_CONTENTS_PATH_C).as_ptr()
253}
254
Alan Stokes78d24702022-11-21 15:28:31 +0000255/// Gets the path to the VM's encrypted storage.
256#[no_mangle]
257pub extern "C" fn AVmPayload_getEncryptedStoragePath() -> *const c_char {
258 // TODO(b/254454578): Return a real path if storage is present
259 ptr::null()
260}