blob: 00d729966da9e17b363a7d2473ebedc99518ed1c [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
Alice Wang13a2b1b2022-10-07 07:57:08 +000017use android_system_virtualization_payload::aidl::android::system::virtualization::payload::IVmPayloadService::{
Shikha Panwarddc124b2022-11-28 19:17:54 +000018 ENCRYPTEDSTORE_MOUNTPOINT, IVmPayloadService, VM_PAYLOAD_SERVICE_SOCKET_NAME, VM_APK_CONTENTS_PATH};
Alan Stokese0945ad2022-11-24 13:29:57 +000019use anyhow::{ensure, bail, Context, Result};
Alice Wang43c884b2022-10-24 09:42:40 +000020use binder::{Strong, unstable_api::{AIBinder, new_spibinder}};
Alice Wang6bbb6da2022-10-26 12:44:06 +000021use lazy_static::lazy_static;
Alice Wangfb46ee12022-09-30 13:08:52 +000022use log::{error, info, Level};
David Brazdila2125dd2022-12-14 16:37:44 +000023use rpcbinder::{RpcSession, RpcServer};
Alan Stokese0945ad2022-11-24 13:29:57 +000024use std::convert::Infallible;
Alice Wang6bbb6da2022-10-26 12:44:06 +000025use std::ffi::CString;
Alan Stokes65bbb912022-11-23 09:39:34 +000026use std::fmt::Debug;
Alice Wang6bbb6da2022-10-26 12:44:06 +000027use std::os::raw::{c_char, c_void};
Shikha Panwarddc124b2022-11-28 19:17:54 +000028use std::path::Path;
Alan Stokes78d24702022-11-21 15:28:31 +000029use std::ptr;
Alan Stokes65bbb912022-11-23 09:39:34 +000030use std::sync::{Mutex, atomic::{AtomicBool, Ordering}};
Alice Wang6bbb6da2022-10-26 12:44:06 +000031
32lazy_static! {
33 static ref VM_APK_CONTENTS_PATH_C: CString =
34 CString::new(VM_APK_CONTENTS_PATH).expect("CString::new failed");
Alan Stokes0cbfdf92022-11-21 17:17:53 +000035 static ref PAYLOAD_CONNECTION: Mutex<Option<Strong<dyn IVmPayloadService>>> = Mutex::default();
Shikha Panwarddc124b2022-11-28 19:17:54 +000036 static ref VM_ENCRYPTED_STORAGE_PATH_C: CString =
37 CString::new(ENCRYPTEDSTORE_MOUNTPOINT).expect("CString::new failed");
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 {
David Brazdila2125dd2022-12-14 16:37:44 +000049 let new_connection: Strong<dyn IVmPayloadService> = RpcSession::new()
50 .setup_unix_domain_client(VM_PAYLOAD_SERVICE_SOCKET_NAME)
51 .context(format!("Failed to connect to service: {}", VM_PAYLOAD_SERVICE_SOCKET_NAME))?;
Alan Stokes0cbfdf92022-11-21 17:17:53 +000052 *connection = Some(new_connection.clone());
53 Ok(new_connection)
54 }
55}
56
57/// Make sure our logging goes to logcat. It is harmless to call this more than once.
Alan Stokesf30982b2022-11-18 11:50:32 +000058fn initialize_logging() {
59 android_logger::init_once(
Alan Stokes65bbb912022-11-23 09:39:34 +000060 android_logger::Config::default().with_tag("vm_payload").with_min_level(Level::Info),
Alan Stokesf30982b2022-11-18 11:50:32 +000061 );
62}
63
Alan Stokes65bbb912022-11-23 09:39:34 +000064/// In many cases clients can't do anything useful if API calls fail, and the failure
65/// generally indicates that the VM is exiting or otherwise doomed. So rather than
66/// returning a non-actionable error indication we just log the problem and abort
67/// the process.
68fn unwrap_or_abort<T, E: Debug>(result: Result<T, E>) -> T {
69 result.unwrap_or_else(|e| {
70 let msg = format!("{:?}", e);
71 error!("{msg}");
72 panic!("{msg}")
73 })
74}
75
Alice Wangfb46ee12022-09-30 13:08:52 +000076/// Notifies the host that the payload is ready.
Alan Stokes65bbb912022-11-23 09:39:34 +000077/// Panics on failure.
Alice Wangfb46ee12022-09-30 13:08:52 +000078#[no_mangle]
Alan Stokes65bbb912022-11-23 09:39:34 +000079pub extern "C" fn AVmPayload_notifyPayloadReady() {
Alan Stokesf30982b2022-11-18 11:50:32 +000080 initialize_logging();
81
Alan Stokes65bbb912022-11-23 09:39:34 +000082 if !ALREADY_NOTIFIED.swap(true, Ordering::Relaxed) {
83 unwrap_or_abort(try_notify_payload_ready());
84
Alice Wangfb46ee12022-09-30 13:08:52 +000085 info!("Notified host payload ready successfully");
Alice Wangfb46ee12022-09-30 13:08:52 +000086 }
87}
88
89/// Notifies the host that the payload is ready.
90/// Returns a `Result` containing error information if failed.
91fn try_notify_payload_ready() -> Result<()> {
Alice Wang59a9e562022-10-04 15:24:10 +000092 get_vm_payload_service()?.notifyPayloadReady().context("Cannot notify payload ready")
Alice Wangfb46ee12022-09-30 13:08:52 +000093}
94
Alice Wang2be64f32022-10-13 14:37:35 +000095/// Runs a binder RPC server, serving the supplied binder service implementation on the given vsock
96/// port.
97///
98/// If and when the server is ready for connections (it is listening on the port), `on_ready` is
99/// called to allow appropriate action to be taken - e.g. to notify clients that they may now
100/// attempt to connect.
101///
Alan Stokese0945ad2022-11-24 13:29:57 +0000102/// The current thread joins the binder thread pool to handle incoming messages.
103/// This function never returns.
Alice Wang2be64f32022-10-13 14:37:35 +0000104///
Alan Stokese0945ad2022-11-24 13:29:57 +0000105/// Panics on error (including unexpected server exit).
Alice Wang2be64f32022-10-13 14:37:35 +0000106///
107/// # Safety
108///
Alan Stokese0945ad2022-11-24 13:29:57 +0000109/// If present, the `on_ready` callback must be a valid function pointer, which will be called at
110/// most once, while this function is executing, with the `param` parameter.
Alice Wang2be64f32022-10-13 14:37:35 +0000111#[no_mangle]
112pub unsafe extern "C" fn AVmPayload_runVsockRpcServer(
113 service: *mut AIBinder,
114 port: u32,
115 on_ready: Option<unsafe extern "C" fn(param: *mut c_void)>,
116 param: *mut c_void,
Alan Stokese0945ad2022-11-24 13:29:57 +0000117) -> Infallible {
Alan Stokesf30982b2022-11-18 11:50:32 +0000118 initialize_logging();
119
Alan Stokese0945ad2022-11-24 13:29:57 +0000120 // SAFETY: try_run_vsock_server has the same requirements as this function
121 unwrap_or_abort(unsafe { try_run_vsock_server(service, port, on_ready, param) })
122}
123
124/// # Safety: Same as `AVmPayload_runVsockRpcServer`.
125unsafe fn try_run_vsock_server(
126 service: *mut AIBinder,
127 port: u32,
128 on_ready: Option<unsafe extern "C" fn(param: *mut c_void)>,
129 param: *mut c_void,
130) -> Result<Infallible> {
Alice Wang2be64f32022-10-13 14:37:35 +0000131 // SAFETY: AIBinder returned has correct reference count, and the ownership can
132 // safely be taken by new_spibinder.
Alan Stokese0945ad2022-11-24 13:29:57 +0000133 let service = unsafe { new_spibinder(service) };
Alice Wang2be64f32022-10-13 14:37:35 +0000134 if let Some(service) = service {
David Brazdil3238da42022-11-18 10:04:51 +0000135 match RpcServer::new_vsock(service, libc::VMADDR_CID_HOST, port) {
David Brazdil671e6142022-11-16 11:47:27 +0000136 Ok(server) => {
137 if let Some(on_ready) = on_ready {
Alan Stokese0945ad2022-11-24 13:29:57 +0000138 // SAFETY: We're calling the callback with the parameter specified within the
139 // allowed lifetime.
140 unsafe { on_ready(param) };
David Brazdil671e6142022-11-16 11:47:27 +0000141 }
142 server.join();
Alan Stokese0945ad2022-11-24 13:29:57 +0000143 bail!("RpcServer unexpectedly terminated");
Alice Wang2be64f32022-10-13 14:37:35 +0000144 }
David Brazdil671e6142022-11-16 11:47:27 +0000145 Err(err) => {
Alan Stokese0945ad2022-11-24 13:29:57 +0000146 bail!("Failed to start RpcServer: {:?}", err);
David Brazdil671e6142022-11-16 11:47:27 +0000147 }
148 }
Alice Wang2be64f32022-10-13 14:37:35 +0000149 } else {
Alan Stokese0945ad2022-11-24 13:29:57 +0000150 bail!("Failed to convert the given service from AIBinder to SpIBinder.");
Alice Wang2be64f32022-10-13 14:37:35 +0000151 }
152}
153
Andrew Scull102067a2022-10-07 00:34:40 +0000154/// Get a secret that is uniquely bound to this VM instance.
Alan Stokes65bbb912022-11-23 09:39:34 +0000155/// Panics on failure.
Andrew Scull102067a2022-10-07 00:34:40 +0000156///
157/// # Safety
158///
Andrew Scull655e98e2022-10-10 22:24:58 +0000159/// Behavior is undefined if any of the following conditions are violated:
160///
161/// * `identifier` must be [valid] for reads of `identifier_size` bytes.
162/// * `secret` must be [valid] for writes of `size` bytes.
163///
Alan Stokes65bbb912022-11-23 09:39:34 +0000164/// [valid]: ptr#safety
Andrew Scull102067a2022-10-07 00:34:40 +0000165#[no_mangle]
Andrew Scull655e98e2022-10-10 22:24:58 +0000166pub unsafe extern "C" fn AVmPayload_getVmInstanceSecret(
Andrew Scull102067a2022-10-07 00:34:40 +0000167 identifier: *const u8,
168 identifier_size: usize,
169 secret: *mut u8,
170 size: usize,
Alan Stokes65bbb912022-11-23 09:39:34 +0000171) {
Alan Stokesf30982b2022-11-18 11:50:32 +0000172 initialize_logging();
173
Alan Stokese0945ad2022-11-24 13:29:57 +0000174 // SAFETY: See the requirements on `identifier` above.
175 let identifier = unsafe { std::slice::from_raw_parts(identifier, identifier_size) };
Alan Stokes65bbb912022-11-23 09:39:34 +0000176 let vm_secret = unwrap_or_abort(try_get_vm_instance_secret(identifier, size));
Alan Stokese0945ad2022-11-24 13:29:57 +0000177
178 // SAFETY: See the requirements on `secret` above; `vm_secret` is known to have length `size`,
179 // and cannot overlap `secret` because we just allocated it.
180 unsafe {
181 ptr::copy_nonoverlapping(vm_secret.as_ptr(), secret, size);
182 }
Andrew Scull102067a2022-10-07 00:34:40 +0000183}
184
185fn try_get_vm_instance_secret(identifier: &[u8], size: usize) -> Result<Vec<u8>> {
Alan Stokes65bbb912022-11-23 09:39:34 +0000186 let vm_secret = get_vm_payload_service()?
Andrew Scull102067a2022-10-07 00:34:40 +0000187 .getVmInstanceSecret(identifier, i32::try_from(size)?)
Alan Stokes65bbb912022-11-23 09:39:34 +0000188 .context("Cannot get VM instance secret")?;
189 ensure!(
190 vm_secret.len() == size,
191 "Returned secret has {} bytes, expected {}",
192 vm_secret.len(),
193 size
194 );
195 Ok(vm_secret)
Andrew Scull102067a2022-10-07 00:34:40 +0000196}
197
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000198/// Get the VM's attestation chain.
Alan Stokes65bbb912022-11-23 09:39:34 +0000199/// Panics on failure.
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000200///
201/// # Safety
202///
Andrew Scull655e98e2022-10-10 22:24:58 +0000203/// Behavior is undefined if any of the following conditions are violated:
204///
Alan Stokes88805d52022-12-16 16:07:33 +0000205/// * `data` must be [valid] for writes of `size` bytes, if size > 0.
Andrew Scull655e98e2022-10-10 22:24:58 +0000206///
Alan Stokes65bbb912022-11-23 09:39:34 +0000207/// [valid]: ptr#safety
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000208#[no_mangle]
Alan Stokes65bbb912022-11-23 09:39:34 +0000209pub unsafe extern "C" fn AVmPayload_getDiceAttestationChain(data: *mut u8, size: usize) -> usize {
Alan Stokesf30982b2022-11-18 11:50:32 +0000210 initialize_logging();
211
Alan Stokes65bbb912022-11-23 09:39:34 +0000212 let chain = unwrap_or_abort(try_get_dice_attestation_chain());
Alan Stokes88805d52022-12-16 16:07:33 +0000213 if size != 0 {
214 // 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
216 // it. We allow data to be null, which is never valid, but only if size == 0 which is
217 // checked above.
218 unsafe { ptr::copy_nonoverlapping(chain.as_ptr(), data, std::cmp::min(chain.len(), size)) };
219 }
Alan Stokes65bbb912022-11-23 09:39:34 +0000220 chain.len()
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000221}
222
223fn try_get_dice_attestation_chain() -> Result<Vec<u8>> {
224 get_vm_payload_service()?.getDiceAttestationChain().context("Cannot get attestation chain")
225}
226
227/// Get the VM's attestation CDI.
Alan Stokes65bbb912022-11-23 09:39:34 +0000228/// Panics on failure.
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000229///
230/// # Safety
231///
Andrew Scull655e98e2022-10-10 22:24:58 +0000232/// Behavior is undefined if any of the following conditions are violated:
233///
Alan Stokes88805d52022-12-16 16:07:33 +0000234/// * `data` must be [valid] for writes of `size` bytes, if size > 0.
Andrew Scull655e98e2022-10-10 22:24:58 +0000235///
Alan Stokes65bbb912022-11-23 09:39:34 +0000236/// [valid]: ptr#safety
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000237#[no_mangle]
Alan Stokes65bbb912022-11-23 09:39:34 +0000238pub unsafe extern "C" fn AVmPayload_getDiceAttestationCdi(data: *mut u8, size: usize) -> usize {
Alan Stokesf30982b2022-11-18 11:50:32 +0000239 initialize_logging();
240
Alan Stokes65bbb912022-11-23 09:39:34 +0000241 let cdi = unwrap_or_abort(try_get_dice_attestation_cdi());
Alan Stokes88805d52022-12-16 16:07:33 +0000242 if size != 0 {
243 // SAFETY: See the requirements on `data` above. The number of bytes copied doesn't exceed
244 // the length of either buffer, and `cdi` cannot overlap `data` because we just allocated
245 // it. We allow data to be null, which is never valid, but only if size == 0 which is
246 // checked above.
247 unsafe { ptr::copy_nonoverlapping(cdi.as_ptr(), data, std::cmp::min(cdi.len(), size)) };
248 }
Alan Stokes65bbb912022-11-23 09:39:34 +0000249 cdi.len()
250}
251
252fn try_get_dice_attestation_cdi() -> Result<Vec<u8>> {
253 get_vm_payload_service()?.getDiceAttestationCdi().context("Cannot get attestation CDI")
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000254}
255
Alice Wangc2fec932023-02-23 16:24:02 +0000256/// Requests a certificate using the provided certificate signing request (CSR).
257/// Panics on failure.
258///
259/// # Safety
260///
261/// Behavior is undefined if any of the following conditions are violated:
262///
263/// * `csr` must be [valid] for reads of `csr_size` bytes.
264/// * `buffer` must be [valid] for writes of `size` bytes. `buffer` can be null if `size` is 0.
265///
266/// [valid]: ptr#safety
267#[no_mangle]
268pub unsafe extern "C" fn AVmPayload_requestCertificate(
269 csr: *const u8,
270 csr_size: usize,
271 buffer: *mut u8,
272 size: usize,
273) -> usize {
274 initialize_logging();
275
276 // SAFETY: See the requirements on `csr` above.
277 let csr = unsafe { std::slice::from_raw_parts(csr, csr_size) };
278 let certificate = unwrap_or_abort(try_request_certificate(csr));
279
280 if size != 0 || buffer.is_null() {
281 // SAFETY: See the requirements on `buffer` above. The number of bytes copied doesn't exceed
282 // the length of either buffer, and `certificate` cannot overlap `buffer` because we just
283 // allocated it.
284 unsafe {
285 ptr::copy_nonoverlapping(
286 certificate.as_ptr(),
287 buffer,
288 std::cmp::min(certificate.len(), size),
289 );
290 }
291 }
292 certificate.len()
293}
294
295fn try_request_certificate(csr: &[u8]) -> Result<Vec<u8>> {
296 let certificate = get_vm_payload_service()?
297 .requestCertificate(csr)
298 .context("Failed to request certificate")?;
299 Ok(certificate)
300}
301
Alice Wang6bbb6da2022-10-26 12:44:06 +0000302/// Gets the path to the APK contents.
303#[no_mangle]
304pub extern "C" fn AVmPayload_getApkContentsPath() -> *const c_char {
Shikha Panwarddc124b2022-11-28 19:17:54 +0000305 VM_APK_CONTENTS_PATH_C.as_ptr()
Alice Wang6bbb6da2022-10-26 12:44:06 +0000306}
307
Alan Stokes78d24702022-11-21 15:28:31 +0000308/// Gets the path to the VM's encrypted storage.
309#[no_mangle]
310pub extern "C" fn AVmPayload_getEncryptedStoragePath() -> *const c_char {
Shikha Panwarddc124b2022-11-28 19:17:54 +0000311 if Path::new(ENCRYPTEDSTORE_MOUNTPOINT).exists() {
312 VM_ENCRYPTED_STORAGE_PATH_C.as_ptr()
313 } else {
314 ptr::null()
315 }
Alan Stokes78d24702022-11-21 15:28:31 +0000316}