blob: a9b3abb7070e8b5c1a74b2cd7743dbe0d3e2b28f [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::{
Shikha Panwarddc124b2022-11-28 19:17:54 +000021 ENCRYPTEDSTORE_MOUNTPOINT, 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};
Shikha Panwarddc124b2022-11-28 19:17:54 +000031use std::path::Path;
Alan Stokes78d24702022-11-21 15:28:31 +000032use std::ptr;
Alan Stokes65bbb912022-11-23 09:39:34 +000033use std::sync::{Mutex, atomic::{AtomicBool, Ordering}};
Alice Wang6bbb6da2022-10-26 12:44:06 +000034
35lazy_static! {
36 static ref VM_APK_CONTENTS_PATH_C: CString =
37 CString::new(VM_APK_CONTENTS_PATH).expect("CString::new failed");
Alan Stokes0cbfdf92022-11-21 17:17:53 +000038 static ref PAYLOAD_CONNECTION: Mutex<Option<Strong<dyn IVmPayloadService>>> = Mutex::default();
Shikha Panwarddc124b2022-11-28 19:17:54 +000039 static ref VM_ENCRYPTED_STORAGE_PATH_C: CString =
40 CString::new(ENCRYPTEDSTORE_MOUNTPOINT).expect("CString::new failed");
Alice Wang6bbb6da2022-10-26 12:44:06 +000041}
Alice Wangfb46ee12022-09-30 13:08:52 +000042
Alan Stokes65bbb912022-11-23 09:39:34 +000043static ALREADY_NOTIFIED: AtomicBool = AtomicBool::new(false);
44
Alan Stokes0cbfdf92022-11-21 17:17:53 +000045/// Return a connection to the payload service in Microdroid Manager. Uses the existing connection
46/// if there is one, otherwise attempts to create a new one.
47fn get_vm_payload_service() -> Result<Strong<dyn IVmPayloadService>> {
48 let mut connection = PAYLOAD_CONNECTION.lock().unwrap();
49 if let Some(strong) = &*connection {
50 Ok(strong.clone())
51 } else {
52 let new_connection: Strong<dyn IVmPayloadService> = get_unix_domain_rpc_interface(
53 VM_PAYLOAD_SERVICE_SOCKET_NAME,
54 )
55 .context(format!("Failed to connect to service: {}", VM_PAYLOAD_SERVICE_SOCKET_NAME))?;
56 *connection = Some(new_connection.clone());
57 Ok(new_connection)
58 }
59}
60
61/// Make sure our logging goes to logcat. It is harmless to call this more than once.
Alan Stokesf30982b2022-11-18 11:50:32 +000062fn initialize_logging() {
63 android_logger::init_once(
Alan Stokes65bbb912022-11-23 09:39:34 +000064 android_logger::Config::default().with_tag("vm_payload").with_min_level(Level::Info),
Alan Stokesf30982b2022-11-18 11:50:32 +000065 );
66}
67
Alan Stokes65bbb912022-11-23 09:39:34 +000068/// In many cases clients can't do anything useful if API calls fail, and the failure
69/// generally indicates that the VM is exiting or otherwise doomed. So rather than
70/// returning a non-actionable error indication we just log the problem and abort
71/// the process.
72fn unwrap_or_abort<T, E: Debug>(result: Result<T, E>) -> T {
73 result.unwrap_or_else(|e| {
74 let msg = format!("{:?}", e);
75 error!("{msg}");
76 panic!("{msg}")
77 })
78}
79
Alice Wangfb46ee12022-09-30 13:08:52 +000080/// Notifies the host that the payload is ready.
Alan Stokes65bbb912022-11-23 09:39:34 +000081/// Panics on failure.
Alice Wangfb46ee12022-09-30 13:08:52 +000082#[no_mangle]
Alan Stokes65bbb912022-11-23 09:39:34 +000083pub extern "C" fn AVmPayload_notifyPayloadReady() {
Alan Stokesf30982b2022-11-18 11:50:32 +000084 initialize_logging();
85
Alan Stokes65bbb912022-11-23 09:39:34 +000086 if !ALREADY_NOTIFIED.swap(true, Ordering::Relaxed) {
87 unwrap_or_abort(try_notify_payload_ready());
88
Alice Wangfb46ee12022-09-30 13:08:52 +000089 info!("Notified host payload ready successfully");
Alice Wangfb46ee12022-09-30 13:08:52 +000090 }
91}
92
93/// Notifies the host that the payload is ready.
94/// Returns a `Result` containing error information if failed.
95fn try_notify_payload_ready() -> Result<()> {
Alice Wang59a9e562022-10-04 15:24:10 +000096 get_vm_payload_service()?.notifyPayloadReady().context("Cannot notify payload ready")
Alice Wangfb46ee12022-09-30 13:08:52 +000097}
98
Alice Wang2be64f32022-10-13 14:37:35 +000099/// Runs a binder RPC server, serving the supplied binder service implementation on the given vsock
100/// port.
101///
102/// If and when the server is ready for connections (it is listening on the port), `on_ready` is
103/// called to allow appropriate action to be taken - e.g. to notify clients that they may now
104/// attempt to connect.
105///
Alan Stokese0945ad2022-11-24 13:29:57 +0000106/// The current thread joins the binder thread pool to handle incoming messages.
107/// This function never returns.
Alice Wang2be64f32022-10-13 14:37:35 +0000108///
Alan Stokese0945ad2022-11-24 13:29:57 +0000109/// Panics on error (including unexpected server exit).
Alice Wang2be64f32022-10-13 14:37:35 +0000110///
111/// # Safety
112///
Alan Stokese0945ad2022-11-24 13:29:57 +0000113/// If present, the `on_ready` callback must be a valid function pointer, which will be called at
114/// most once, while this function is executing, with the `param` parameter.
Alice Wang2be64f32022-10-13 14:37:35 +0000115#[no_mangle]
116pub unsafe extern "C" fn AVmPayload_runVsockRpcServer(
117 service: *mut AIBinder,
118 port: u32,
119 on_ready: Option<unsafe extern "C" fn(param: *mut c_void)>,
120 param: *mut c_void,
Alan Stokese0945ad2022-11-24 13:29:57 +0000121) -> Infallible {
Alan Stokesf30982b2022-11-18 11:50:32 +0000122 initialize_logging();
123
Alan Stokese0945ad2022-11-24 13:29:57 +0000124 // SAFETY: try_run_vsock_server has the same requirements as this function
125 unwrap_or_abort(unsafe { try_run_vsock_server(service, port, on_ready, param) })
126}
127
128/// # Safety: Same as `AVmPayload_runVsockRpcServer`.
129unsafe fn try_run_vsock_server(
130 service: *mut AIBinder,
131 port: u32,
132 on_ready: Option<unsafe extern "C" fn(param: *mut c_void)>,
133 param: *mut c_void,
134) -> Result<Infallible> {
Alice Wang2be64f32022-10-13 14:37:35 +0000135 // SAFETY: AIBinder returned has correct reference count, and the ownership can
136 // safely be taken by new_spibinder.
Alan Stokese0945ad2022-11-24 13:29:57 +0000137 let service = unsafe { new_spibinder(service) };
Alice Wang2be64f32022-10-13 14:37:35 +0000138 if let Some(service) = service {
David Brazdil3238da42022-11-18 10:04:51 +0000139 match RpcServer::new_vsock(service, libc::VMADDR_CID_HOST, port) {
David Brazdil671e6142022-11-16 11:47:27 +0000140 Ok(server) => {
141 if let Some(on_ready) = on_ready {
Alan Stokese0945ad2022-11-24 13:29:57 +0000142 // SAFETY: We're calling the callback with the parameter specified within the
143 // allowed lifetime.
144 unsafe { on_ready(param) };
David Brazdil671e6142022-11-16 11:47:27 +0000145 }
146 server.join();
Alan Stokese0945ad2022-11-24 13:29:57 +0000147 bail!("RpcServer unexpectedly terminated");
Alice Wang2be64f32022-10-13 14:37:35 +0000148 }
David Brazdil671e6142022-11-16 11:47:27 +0000149 Err(err) => {
Alan Stokese0945ad2022-11-24 13:29:57 +0000150 bail!("Failed to start RpcServer: {:?}", err);
David Brazdil671e6142022-11-16 11:47:27 +0000151 }
152 }
Alice Wang2be64f32022-10-13 14:37:35 +0000153 } else {
Alan Stokese0945ad2022-11-24 13:29:57 +0000154 bail!("Failed to convert the given service from AIBinder to SpIBinder.");
Alice Wang2be64f32022-10-13 14:37:35 +0000155 }
156}
157
Andrew Scull102067a2022-10-07 00:34:40 +0000158/// Get a secret that is uniquely bound to this VM instance.
Alan Stokes65bbb912022-11-23 09:39:34 +0000159/// Panics on failure.
Andrew Scull102067a2022-10-07 00:34:40 +0000160///
161/// # Safety
162///
Andrew Scull655e98e2022-10-10 22:24:58 +0000163/// Behavior is undefined if any of the following conditions are violated:
164///
165/// * `identifier` must be [valid] for reads of `identifier_size` bytes.
166/// * `secret` must be [valid] for writes of `size` bytes.
167///
Alan Stokes65bbb912022-11-23 09:39:34 +0000168/// [valid]: ptr#safety
Andrew Scull102067a2022-10-07 00:34:40 +0000169#[no_mangle]
Andrew Scull655e98e2022-10-10 22:24:58 +0000170pub unsafe extern "C" fn AVmPayload_getVmInstanceSecret(
Andrew Scull102067a2022-10-07 00:34:40 +0000171 identifier: *const u8,
172 identifier_size: usize,
173 secret: *mut u8,
174 size: usize,
Alan Stokes65bbb912022-11-23 09:39:34 +0000175) {
Alan Stokesf30982b2022-11-18 11:50:32 +0000176 initialize_logging();
177
Alan Stokese0945ad2022-11-24 13:29:57 +0000178 // SAFETY: See the requirements on `identifier` above.
179 let identifier = unsafe { std::slice::from_raw_parts(identifier, identifier_size) };
Alan Stokes65bbb912022-11-23 09:39:34 +0000180 let vm_secret = unwrap_or_abort(try_get_vm_instance_secret(identifier, size));
Alan Stokese0945ad2022-11-24 13:29:57 +0000181
182 // SAFETY: See the requirements on `secret` above; `vm_secret` is known to have length `size`,
183 // and cannot overlap `secret` because we just allocated it.
184 unsafe {
185 ptr::copy_nonoverlapping(vm_secret.as_ptr(), secret, size);
186 }
Andrew Scull102067a2022-10-07 00:34:40 +0000187}
188
189fn try_get_vm_instance_secret(identifier: &[u8], size: usize) -> Result<Vec<u8>> {
Alan Stokes65bbb912022-11-23 09:39:34 +0000190 let vm_secret = get_vm_payload_service()?
Andrew Scull102067a2022-10-07 00:34:40 +0000191 .getVmInstanceSecret(identifier, i32::try_from(size)?)
Alan Stokes65bbb912022-11-23 09:39:34 +0000192 .context("Cannot get VM instance secret")?;
193 ensure!(
194 vm_secret.len() == size,
195 "Returned secret has {} bytes, expected {}",
196 vm_secret.len(),
197 size
198 );
199 Ok(vm_secret)
Andrew Scull102067a2022-10-07 00:34:40 +0000200}
201
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000202/// Get the VM's attestation chain.
Alan Stokes65bbb912022-11-23 09:39:34 +0000203/// Panics on failure.
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000204///
205/// # Safety
206///
Andrew Scull655e98e2022-10-10 22:24:58 +0000207/// Behavior is undefined if any of the following conditions are violated:
208///
Alan Stokes88805d52022-12-16 16:07:33 +0000209/// * `data` must be [valid] for writes of `size` bytes, if size > 0.
Andrew Scull655e98e2022-10-10 22:24:58 +0000210///
Alan Stokes65bbb912022-11-23 09:39:34 +0000211/// [valid]: ptr#safety
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000212#[no_mangle]
Alan Stokes65bbb912022-11-23 09:39:34 +0000213pub unsafe extern "C" fn AVmPayload_getDiceAttestationChain(data: *mut u8, size: usize) -> usize {
Alan Stokesf30982b2022-11-18 11:50:32 +0000214 initialize_logging();
215
Alan Stokes65bbb912022-11-23 09:39:34 +0000216 let chain = unwrap_or_abort(try_get_dice_attestation_chain());
Alan Stokes88805d52022-12-16 16:07:33 +0000217 if size != 0 {
218 // SAFETY: See the requirements on `data` above. The number of bytes copied doesn't exceed
219 // the length of either buffer, and `chain` cannot overlap `data` because we just allocated
220 // it. We allow data to be null, which is never valid, but only if size == 0 which is
221 // checked above.
222 unsafe { ptr::copy_nonoverlapping(chain.as_ptr(), data, std::cmp::min(chain.len(), size)) };
223 }
Alan Stokes65bbb912022-11-23 09:39:34 +0000224 chain.len()
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000225}
226
227fn try_get_dice_attestation_chain() -> Result<Vec<u8>> {
228 get_vm_payload_service()?.getDiceAttestationChain().context("Cannot get attestation chain")
229}
230
231/// Get the VM's attestation CDI.
Alan Stokes65bbb912022-11-23 09:39:34 +0000232/// Panics on failure.
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000233///
234/// # Safety
235///
Andrew Scull655e98e2022-10-10 22:24:58 +0000236/// Behavior is undefined if any of the following conditions are violated:
237///
Alan Stokes88805d52022-12-16 16:07:33 +0000238/// * `data` must be [valid] for writes of `size` bytes, if size > 0.
Andrew Scull655e98e2022-10-10 22:24:58 +0000239///
Alan Stokes65bbb912022-11-23 09:39:34 +0000240/// [valid]: ptr#safety
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000241#[no_mangle]
Alan Stokes65bbb912022-11-23 09:39:34 +0000242pub unsafe extern "C" fn AVmPayload_getDiceAttestationCdi(data: *mut u8, size: usize) -> usize {
Alan Stokesf30982b2022-11-18 11:50:32 +0000243 initialize_logging();
244
Alan Stokes65bbb912022-11-23 09:39:34 +0000245 let cdi = unwrap_or_abort(try_get_dice_attestation_cdi());
Alan Stokes88805d52022-12-16 16:07:33 +0000246 if size != 0 {
247 // SAFETY: See the requirements on `data` above. The number of bytes copied doesn't exceed
248 // the length of either buffer, and `cdi` cannot overlap `data` because we just allocated
249 // it. We allow data to be null, which is never valid, but only if size == 0 which is
250 // checked above.
251 unsafe { ptr::copy_nonoverlapping(cdi.as_ptr(), data, std::cmp::min(cdi.len(), size)) };
252 }
Alan Stokes65bbb912022-11-23 09:39:34 +0000253 cdi.len()
254}
255
256fn try_get_dice_attestation_cdi() -> Result<Vec<u8>> {
257 get_vm_payload_service()?.getDiceAttestationCdi().context("Cannot get attestation CDI")
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000258}
259
Alice Wang6bbb6da2022-10-26 12:44:06 +0000260/// Gets the path to the APK contents.
261#[no_mangle]
262pub extern "C" fn AVmPayload_getApkContentsPath() -> *const c_char {
Shikha Panwarddc124b2022-11-28 19:17:54 +0000263 VM_APK_CONTENTS_PATH_C.as_ptr()
Alice Wang6bbb6da2022-10-26 12:44:06 +0000264}
265
Alan Stokes78d24702022-11-21 15:28:31 +0000266/// Gets the path to the VM's encrypted storage.
267#[no_mangle]
268pub extern "C" fn AVmPayload_getEncryptedStoragePath() -> *const c_char {
Shikha Panwarddc124b2022-11-28 19:17:54 +0000269 if Path::new(ENCRYPTEDSTORE_MOUNTPOINT).exists() {
270 VM_ENCRYPTED_STORAGE_PATH_C.as_ptr()
271 } else {
272 ptr::null()
273 }
Alan Stokes78d24702022-11-21 15:28:31 +0000274}