blob: 6ca473ad48719df76533884fe53fccaefe22b578 [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 Brazdila2125dd2022-12-14 16:37:44 +000026use rpcbinder::{RpcSession, 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 {
David Brazdila2125dd2022-12-14 16:37:44 +000052 let new_connection: Strong<dyn IVmPayloadService> = RpcSession::new()
53 .setup_unix_domain_client(VM_PAYLOAD_SERVICE_SOCKET_NAME)
54 .context(format!("Failed to connect to service: {}", VM_PAYLOAD_SERVICE_SOCKET_NAME))?;
Alan Stokes0cbfdf92022-11-21 17:17:53 +000055 *connection = Some(new_connection.clone());
56 Ok(new_connection)
57 }
58}
59
60/// Make sure our logging goes to logcat. It is harmless to call this more than once.
Alan Stokesf30982b2022-11-18 11:50:32 +000061fn initialize_logging() {
62 android_logger::init_once(
Alan Stokes65bbb912022-11-23 09:39:34 +000063 android_logger::Config::default().with_tag("vm_payload").with_min_level(Level::Info),
Alan Stokesf30982b2022-11-18 11:50:32 +000064 );
65}
66
Alan Stokes65bbb912022-11-23 09:39:34 +000067/// In many cases clients can't do anything useful if API calls fail, and the failure
68/// generally indicates that the VM is exiting or otherwise doomed. So rather than
69/// returning a non-actionable error indication we just log the problem and abort
70/// the process.
71fn unwrap_or_abort<T, E: Debug>(result: Result<T, E>) -> T {
72 result.unwrap_or_else(|e| {
73 let msg = format!("{:?}", e);
74 error!("{msg}");
75 panic!("{msg}")
76 })
77}
78
Alice Wangfb46ee12022-09-30 13:08:52 +000079/// Notifies the host that the payload is ready.
Alan Stokes65bbb912022-11-23 09:39:34 +000080/// Panics on failure.
Alice Wangfb46ee12022-09-30 13:08:52 +000081#[no_mangle]
Alan Stokes65bbb912022-11-23 09:39:34 +000082pub extern "C" fn AVmPayload_notifyPayloadReady() {
Alan Stokesf30982b2022-11-18 11:50:32 +000083 initialize_logging();
84
Alan Stokes65bbb912022-11-23 09:39:34 +000085 if !ALREADY_NOTIFIED.swap(true, Ordering::Relaxed) {
86 unwrap_or_abort(try_notify_payload_ready());
87
Alice Wangfb46ee12022-09-30 13:08:52 +000088 info!("Notified host payload ready successfully");
Alice Wangfb46ee12022-09-30 13:08:52 +000089 }
90}
91
92/// Notifies the host that the payload is ready.
93/// Returns a `Result` containing error information if failed.
94fn try_notify_payload_ready() -> Result<()> {
Alice Wang59a9e562022-10-04 15:24:10 +000095 get_vm_payload_service()?.notifyPayloadReady().context("Cannot notify payload ready")
Alice Wangfb46ee12022-09-30 13:08:52 +000096}
97
Alice Wang2be64f32022-10-13 14:37:35 +000098/// Runs a binder RPC server, serving the supplied binder service implementation on the given vsock
99/// port.
100///
101/// If and when the server is ready for connections (it is listening on the port), `on_ready` is
102/// called to allow appropriate action to be taken - e.g. to notify clients that they may now
103/// attempt to connect.
104///
Alan Stokese0945ad2022-11-24 13:29:57 +0000105/// The current thread joins the binder thread pool to handle incoming messages.
106/// This function never returns.
Alice Wang2be64f32022-10-13 14:37:35 +0000107///
Alan Stokese0945ad2022-11-24 13:29:57 +0000108/// Panics on error (including unexpected server exit).
Alice Wang2be64f32022-10-13 14:37:35 +0000109///
110/// # Safety
111///
Alan Stokese0945ad2022-11-24 13:29:57 +0000112/// If present, the `on_ready` callback must be a valid function pointer, which will be called at
113/// most once, while this function is executing, with the `param` parameter.
Alice Wang2be64f32022-10-13 14:37:35 +0000114#[no_mangle]
115pub unsafe extern "C" fn AVmPayload_runVsockRpcServer(
116 service: *mut AIBinder,
117 port: u32,
118 on_ready: Option<unsafe extern "C" fn(param: *mut c_void)>,
119 param: *mut c_void,
Alan Stokese0945ad2022-11-24 13:29:57 +0000120) -> Infallible {
Alan Stokesf30982b2022-11-18 11:50:32 +0000121 initialize_logging();
122
Alan Stokese0945ad2022-11-24 13:29:57 +0000123 // SAFETY: try_run_vsock_server has the same requirements as this function
124 unwrap_or_abort(unsafe { try_run_vsock_server(service, port, on_ready, param) })
125}
126
127/// # Safety: Same as `AVmPayload_runVsockRpcServer`.
128unsafe fn try_run_vsock_server(
129 service: *mut AIBinder,
130 port: u32,
131 on_ready: Option<unsafe extern "C" fn(param: *mut c_void)>,
132 param: *mut c_void,
133) -> Result<Infallible> {
Alice Wang2be64f32022-10-13 14:37:35 +0000134 // SAFETY: AIBinder returned has correct reference count, and the ownership can
135 // safely be taken by new_spibinder.
Alan Stokese0945ad2022-11-24 13:29:57 +0000136 let service = unsafe { new_spibinder(service) };
Alice Wang2be64f32022-10-13 14:37:35 +0000137 if let Some(service) = service {
David Brazdil3238da42022-11-18 10:04:51 +0000138 match RpcServer::new_vsock(service, libc::VMADDR_CID_HOST, port) {
David Brazdil671e6142022-11-16 11:47:27 +0000139 Ok(server) => {
140 if let Some(on_ready) = on_ready {
Alan Stokese0945ad2022-11-24 13:29:57 +0000141 // SAFETY: We're calling the callback with the parameter specified within the
142 // allowed lifetime.
143 unsafe { on_ready(param) };
David Brazdil671e6142022-11-16 11:47:27 +0000144 }
145 server.join();
Alan Stokese0945ad2022-11-24 13:29:57 +0000146 bail!("RpcServer unexpectedly terminated");
Alice Wang2be64f32022-10-13 14:37:35 +0000147 }
David Brazdil671e6142022-11-16 11:47:27 +0000148 Err(err) => {
Alan Stokese0945ad2022-11-24 13:29:57 +0000149 bail!("Failed to start RpcServer: {:?}", err);
David Brazdil671e6142022-11-16 11:47:27 +0000150 }
151 }
Alice Wang2be64f32022-10-13 14:37:35 +0000152 } else {
Alan Stokese0945ad2022-11-24 13:29:57 +0000153 bail!("Failed to convert the given service from AIBinder to SpIBinder.");
Alice Wang2be64f32022-10-13 14:37:35 +0000154 }
155}
156
Andrew Scull102067a2022-10-07 00:34:40 +0000157/// Get a secret that is uniquely bound to this VM instance.
Alan Stokes65bbb912022-11-23 09:39:34 +0000158/// Panics on failure.
Andrew Scull102067a2022-10-07 00:34:40 +0000159///
160/// # Safety
161///
Andrew Scull655e98e2022-10-10 22:24:58 +0000162/// Behavior is undefined if any of the following conditions are violated:
163///
164/// * `identifier` must be [valid] for reads of `identifier_size` bytes.
165/// * `secret` must be [valid] for writes of `size` bytes.
166///
Alan Stokes65bbb912022-11-23 09:39:34 +0000167/// [valid]: ptr#safety
Andrew Scull102067a2022-10-07 00:34:40 +0000168#[no_mangle]
Andrew Scull655e98e2022-10-10 22:24:58 +0000169pub unsafe extern "C" fn AVmPayload_getVmInstanceSecret(
Andrew Scull102067a2022-10-07 00:34:40 +0000170 identifier: *const u8,
171 identifier_size: usize,
172 secret: *mut u8,
173 size: usize,
Alan Stokes65bbb912022-11-23 09:39:34 +0000174) {
Alan Stokesf30982b2022-11-18 11:50:32 +0000175 initialize_logging();
176
Alan Stokese0945ad2022-11-24 13:29:57 +0000177 // SAFETY: See the requirements on `identifier` above.
178 let identifier = unsafe { std::slice::from_raw_parts(identifier, identifier_size) };
Alan Stokes65bbb912022-11-23 09:39:34 +0000179 let vm_secret = unwrap_or_abort(try_get_vm_instance_secret(identifier, size));
Alan Stokese0945ad2022-11-24 13:29:57 +0000180
181 // SAFETY: See the requirements on `secret` above; `vm_secret` is known to have length `size`,
182 // and cannot overlap `secret` because we just allocated it.
183 unsafe {
184 ptr::copy_nonoverlapping(vm_secret.as_ptr(), secret, size);
185 }
Andrew Scull102067a2022-10-07 00:34:40 +0000186}
187
188fn try_get_vm_instance_secret(identifier: &[u8], size: usize) -> Result<Vec<u8>> {
Alan Stokes65bbb912022-11-23 09:39:34 +0000189 let vm_secret = get_vm_payload_service()?
Andrew Scull102067a2022-10-07 00:34:40 +0000190 .getVmInstanceSecret(identifier, i32::try_from(size)?)
Alan Stokes65bbb912022-11-23 09:39:34 +0000191 .context("Cannot get VM instance secret")?;
192 ensure!(
193 vm_secret.len() == size,
194 "Returned secret has {} bytes, expected {}",
195 vm_secret.len(),
196 size
197 );
198 Ok(vm_secret)
Andrew Scull102067a2022-10-07 00:34:40 +0000199}
200
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000201/// Get the VM's attestation chain.
Alan Stokes65bbb912022-11-23 09:39:34 +0000202/// Panics on failure.
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000203///
204/// # Safety
205///
Andrew Scull655e98e2022-10-10 22:24:58 +0000206/// Behavior is undefined if any of the following conditions are violated:
207///
Alan Stokes88805d52022-12-16 16:07:33 +0000208/// * `data` must be [valid] for writes of `size` bytes, if size > 0.
Andrew Scull655e98e2022-10-10 22:24:58 +0000209///
Alan Stokes65bbb912022-11-23 09:39:34 +0000210/// [valid]: ptr#safety
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000211#[no_mangle]
Alan Stokes65bbb912022-11-23 09:39:34 +0000212pub unsafe extern "C" fn AVmPayload_getDiceAttestationChain(data: *mut u8, size: usize) -> usize {
Alan Stokesf30982b2022-11-18 11:50:32 +0000213 initialize_logging();
214
Alan Stokes65bbb912022-11-23 09:39:34 +0000215 let chain = unwrap_or_abort(try_get_dice_attestation_chain());
Alan Stokes88805d52022-12-16 16:07:33 +0000216 if size != 0 {
217 // SAFETY: See the requirements on `data` above. The number of bytes copied doesn't exceed
218 // the length of either buffer, and `chain` cannot overlap `data` because we just allocated
219 // it. We allow data to be null, which is never valid, but only if size == 0 which is
220 // checked above.
221 unsafe { ptr::copy_nonoverlapping(chain.as_ptr(), data, std::cmp::min(chain.len(), size)) };
222 }
Alan Stokes65bbb912022-11-23 09:39:34 +0000223 chain.len()
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000224}
225
226fn try_get_dice_attestation_chain() -> Result<Vec<u8>> {
227 get_vm_payload_service()?.getDiceAttestationChain().context("Cannot get attestation chain")
228}
229
230/// Get the VM's attestation CDI.
Alan Stokes65bbb912022-11-23 09:39:34 +0000231/// Panics on failure.
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000232///
233/// # Safety
234///
Andrew Scull655e98e2022-10-10 22:24:58 +0000235/// Behavior is undefined if any of the following conditions are violated:
236///
Alan Stokes88805d52022-12-16 16:07:33 +0000237/// * `data` must be [valid] for writes of `size` bytes, if size > 0.
Andrew Scull655e98e2022-10-10 22:24:58 +0000238///
Alan Stokes65bbb912022-11-23 09:39:34 +0000239/// [valid]: ptr#safety
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000240#[no_mangle]
Alan Stokes65bbb912022-11-23 09:39:34 +0000241pub unsafe extern "C" fn AVmPayload_getDiceAttestationCdi(data: *mut u8, size: usize) -> usize {
Alan Stokesf30982b2022-11-18 11:50:32 +0000242 initialize_logging();
243
Alan Stokes65bbb912022-11-23 09:39:34 +0000244 let cdi = unwrap_or_abort(try_get_dice_attestation_cdi());
Alan Stokes88805d52022-12-16 16:07:33 +0000245 if size != 0 {
246 // SAFETY: See the requirements on `data` above. The number of bytes copied doesn't exceed
247 // the length of either buffer, and `cdi` cannot overlap `data` because we just allocated
248 // it. We allow data to be null, which is never valid, but only if size == 0 which is
249 // checked above.
250 unsafe { ptr::copy_nonoverlapping(cdi.as_ptr(), data, std::cmp::min(cdi.len(), size)) };
251 }
Alan Stokes65bbb912022-11-23 09:39:34 +0000252 cdi.len()
253}
254
255fn try_get_dice_attestation_cdi() -> Result<Vec<u8>> {
256 get_vm_payload_service()?.getDiceAttestationCdi().context("Cannot get attestation CDI")
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000257}
258
Alice Wangc2fec932023-02-23 16:24:02 +0000259/// Requests a certificate using the provided certificate signing request (CSR).
260/// Panics on failure.
261///
262/// # Safety
263///
264/// Behavior is undefined if any of the following conditions are violated:
265///
266/// * `csr` must be [valid] for reads of `csr_size` bytes.
267/// * `buffer` must be [valid] for writes of `size` bytes. `buffer` can be null if `size` is 0.
268///
269/// [valid]: ptr#safety
270#[no_mangle]
271pub unsafe extern "C" fn AVmPayload_requestCertificate(
272 csr: *const u8,
273 csr_size: usize,
274 buffer: *mut u8,
275 size: usize,
276) -> usize {
277 initialize_logging();
278
279 // SAFETY: See the requirements on `csr` above.
280 let csr = unsafe { std::slice::from_raw_parts(csr, csr_size) };
281 let certificate = unwrap_or_abort(try_request_certificate(csr));
282
283 if size != 0 || buffer.is_null() {
284 // SAFETY: See the requirements on `buffer` above. The number of bytes copied doesn't exceed
285 // the length of either buffer, and `certificate` cannot overlap `buffer` because we just
286 // allocated it.
287 unsafe {
288 ptr::copy_nonoverlapping(
289 certificate.as_ptr(),
290 buffer,
291 std::cmp::min(certificate.len(), size),
292 );
293 }
294 }
295 certificate.len()
296}
297
298fn try_request_certificate(csr: &[u8]) -> Result<Vec<u8>> {
299 let certificate = get_vm_payload_service()?
300 .requestCertificate(csr)
301 .context("Failed to request certificate")?;
302 Ok(certificate)
303}
304
Alice Wang6bbb6da2022-10-26 12:44:06 +0000305/// Gets the path to the APK contents.
306#[no_mangle]
307pub extern "C" fn AVmPayload_getApkContentsPath() -> *const c_char {
Shikha Panwarddc124b2022-11-28 19:17:54 +0000308 VM_APK_CONTENTS_PATH_C.as_ptr()
Alice Wang6bbb6da2022-10-26 12:44:06 +0000309}
310
Alan Stokes78d24702022-11-21 15:28:31 +0000311/// Gets the path to the VM's encrypted storage.
312#[no_mangle]
313pub extern "C" fn AVmPayload_getEncryptedStoragePath() -> *const c_char {
Shikha Panwarddc124b2022-11-28 19:17:54 +0000314 if Path::new(ENCRYPTEDSTORE_MOUNTPOINT).exists() {
315 VM_ENCRYPTED_STORAGE_PATH_C.as_ptr()
316 } else {
317 ptr::null()
318 }
Alan Stokes78d24702022-11-21 15:28:31 +0000319}