blob: bbfb220d17f12b1366d46c5b78944bbecd22e35d [file] [log] [blame]
David Brazdilafc9a9e2023-01-12 16:08:10 +00001// Copyright 2021, 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
15//! Implementation of the AIDL interface of the VirtualizationService.
16
David Brazdil33a31022023-01-12 16:55:16 +000017use crate::atom::{forward_vm_booted_atom, forward_vm_creation_atom, forward_vm_exited_atom};
David Drysdale79af2662024-02-19 14:50:31 +000018use crate::maintenance;
Alice Wange64dd182024-01-17 15:57:55 +000019use crate::remote_provisioning;
Alan Stokesac667072024-02-19 16:26:00 +000020use crate::rkpvm::{generate_ecdsa_p256_key_pair, request_attestation};
21use crate::{get_calling_pid, get_calling_uid, REMOTELY_PROVISIONED_COMPONENT_SERVICE_NAME};
David Brazdilafc9a9e2023-01-12 16:08:10 +000022use android_os_permissions_aidl::aidl::android::os::IPermissionController;
Alan Stokesac667072024-02-19 16:26:00 +000023use android_system_virtualizationcommon::aidl::android::system::virtualizationcommon;
David Drysdale79af2662024-02-19 14:50:31 +000024use android_system_virtualizationmaintenance::aidl::android::system::virtualizationmaintenance;
Alan Stokesac667072024-02-19 16:26:00 +000025use android_system_virtualizationservice::aidl::android::system::virtualizationservice;
26use android_system_virtualizationservice_internal as android_vs_internal;
27use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice;
28use android_vs_internal::aidl::android::system::virtualizationservice_internal;
Alice Wangd1b11a02023-04-18 12:30:20 +000029use anyhow::{anyhow, ensure, Context, Result};
Jiyong Parkd7bd2f22023-08-10 20:41:19 +090030use avflog::LogResult;
Alan Stokesac667072024-02-19 16:26:00 +000031use binder::{
32 self, wait_for_interface, BinderFeatures, ExceptionCode, Interface, IntoBinderResult,
33 LazyServiceGuard, ParcelFileDescriptor, Status, Strong,
34};
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +000035use lazy_static::lazy_static;
David Brazdilafc9a9e2023-01-12 16:08:10 +000036use libc::VMADDR_CID_HOST;
37use log::{error, info, warn};
Alan Stokesac667072024-02-19 16:26:00 +000038use nix::unistd::{chown, Uid};
39use openssl::x509::X509;
Shikha Panwar61a74b52024-02-16 13:17:01 +000040use rand::Fill;
Alice Wangbff017f2023-11-09 14:43:28 +000041use rkpd_client::get_rkpd_attestation_key;
David Brazdilafc9a9e2023-01-12 16:08:10 +000042use rustutils::system_properties;
Inseob Kimc4a774d2023-08-30 12:48:43 +090043use serde::Deserialize;
Alan Stokesac667072024-02-19 16:26:00 +000044use service_vm_comm::Response;
Inseob Kimc4a774d2023-08-30 12:48:43 +090045use std::collections::{HashMap, HashSet};
David Brazdil2dfefd12023-11-17 14:07:36 +000046use std::fs::{self, create_dir, remove_dir_all, remove_file, set_permissions, File, Permissions};
David Brazdilafc9a9e2023-01-12 16:08:10 +000047use std::io::{Read, Write};
48use std::os::unix::fs::PermissionsExt;
49use std::os::unix::raw::{pid_t, uid_t};
Inseob Kim55438b22023-08-09 20:16:01 +090050use std::path::{Path, PathBuf};
David Brazdilafc9a9e2023-01-12 16:08:10 +000051use std::sync::{Arc, Mutex, Weak};
52use tombstoned_client::{DebuggerdDumpType, TombstonedConnection};
Alan Stokesac667072024-02-19 16:26:00 +000053use virtualizationcommon::Certificate::Certificate;
Alan Stokes30ccacb2024-02-20 14:59:02 +000054use virtualizationmaintenance::{
55 IVirtualizationMaintenance::IVirtualizationMaintenance,
56 IVirtualizationReconciliationCallback::IVirtualizationReconciliationCallback,
57};
Alan Stokesac667072024-02-19 16:26:00 +000058use virtualizationservice::{
59 AssignableDevice::AssignableDevice, VirtualMachineDebugInfo::VirtualMachineDebugInfo,
60};
61use virtualizationservice_internal::{
62 AtomVmBooted::AtomVmBooted,
63 AtomVmCreationRequested::AtomVmCreationRequested,
64 AtomVmExited::AtomVmExited,
65 IBoundDevice::IBoundDevice,
66 IGlobalVmContext::{BnGlobalVmContext, IGlobalVmContext},
67 IVfioHandler::VfioDev::VfioDev,
68 IVfioHandler::{BpVfioHandler, IVfioHandler},
David Drysdale79af2662024-02-19 14:50:31 +000069 IVirtualizationServiceInternal::IVirtualizationServiceInternal,
Alan Stokesac667072024-02-19 16:26:00 +000070};
71use virtualmachineservice::IVirtualMachineService::VM_TOMBSTONES_SERVICE_PORT;
David Brazdilafc9a9e2023-01-12 16:08:10 +000072use vsock::{VsockListener, VsockStream};
David Brazdilafc9a9e2023-01-12 16:08:10 +000073
74/// The unique ID of a VM used (together with a port number) for vsock communication.
75pub type Cid = u32;
76
David Brazdilafc9a9e2023-01-12 16:08:10 +000077/// Directory in which to write disk image files used while running VMs.
78pub const TEMPORARY_DIRECTORY: &str = "/data/misc/virtualizationservice";
79
80/// The first CID to assign to a guest VM managed by the VirtualizationService. CIDs lower than this
81/// are reserved for the host or other usage.
82const GUEST_CID_MIN: Cid = 2048;
83const GUEST_CID_MAX: Cid = 65535;
84
85const SYSPROP_LAST_CID: &str = "virtualizationservice.state.last_cid";
86
87const CHUNK_RECV_MAX_LEN: usize = 1024;
88
Alice Wange64dd182024-01-17 15:57:55 +000089/// The fake certificate is used for testing only when a client VM requests attestation in test
90/// mode, it is a single certificate extracted on an unregistered device for testing.
91/// Here is the snapshot of the certificate:
92///
93/// ```
94/// Certificate:
95/// Data:
96/// Version: 3 (0x2)
97/// Serial Number:
98/// 59:ae:50:98:95:e1:34:25:f1:21:93:c0:4c:e5:24:66
99/// Signature Algorithm: ecdsa-with-SHA256
100/// Issuer: CN = Droid Unregistered Device CA, O = Google Test LLC
101/// Validity
102/// Not Before: Feb 5 14:39:39 2024 GMT
103/// Not After : Feb 14 14:39:39 2024 GMT
104/// Subject: CN = 59ae509895e13425f12193c04ce52466, O = TEE
105/// Subject Public Key Info:
106/// Public Key Algorithm: id-ecPublicKey
107/// Public-Key: (256 bit)
108/// pub:
109/// 04:30:32:cd:95:12:b0:71:8b:b7:14:44:26:58:d5:
110/// 82:8c:25:55:2c:6d:ef:98:e3:4f:88:d0:74:82:09:
111/// 3e:8d:6c:f0:f2:18:d5:83:0e:0d:f2:ce:c5:15:38:
112/// e5:6a:e6:4d:4d:95:15:b7:24:e7:cb:4b:63:42:21:
113/// bc:36:c6:0a:d8
114/// ASN1 OID: prime256v1
115/// NIST CURVE: P-256
116/// X509v3 extensions:
117/// ...
118/// ```
119const FAKE_CERTIFICATE_FOR_TESTING: &[u8] = &[
120 0x30, 0x82, 0x01, 0xee, 0x30, 0x82, 0x01, 0x94, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x59,
121 0xae, 0x50, 0x98, 0x95, 0xe1, 0x34, 0x25, 0xf1, 0x21, 0x93, 0xc0, 0x4c, 0xe5, 0x24, 0x66, 0x30,
122 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x41, 0x31, 0x25, 0x30,
123 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1c, 0x44, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x55, 0x6e,
124 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x44, 0x65, 0x76, 0x69, 0x63,
125 0x65, 0x20, 0x43, 0x41, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, 0x47,
126 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x4c, 0x4c, 0x43, 0x30, 0x1e,
127 0x17, 0x0d, 0x32, 0x34, 0x30, 0x32, 0x30, 0x35, 0x31, 0x34, 0x33, 0x39, 0x33, 0x39, 0x5a, 0x17,
128 0x0d, 0x32, 0x34, 0x30, 0x32, 0x31, 0x34, 0x31, 0x34, 0x33, 0x39, 0x33, 0x39, 0x5a, 0x30, 0x39,
129 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x20, 0x35, 0x39, 0x61, 0x65, 0x35,
130 0x30, 0x39, 0x38, 0x39, 0x35, 0x65, 0x31, 0x33, 0x34, 0x32, 0x35, 0x66, 0x31, 0x32, 0x31, 0x39,
131 0x33, 0x63, 0x30, 0x34, 0x63, 0x65, 0x35, 0x32, 0x34, 0x36, 0x36, 0x31, 0x0c, 0x30, 0x0a, 0x06,
132 0x03, 0x55, 0x04, 0x0a, 0x13, 0x03, 0x54, 0x45, 0x45, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a,
133 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
134 0x03, 0x42, 0x00, 0x04, 0x30, 0x32, 0xcd, 0x95, 0x12, 0xb0, 0x71, 0x8b, 0xb7, 0x14, 0x44, 0x26,
135 0x58, 0xd5, 0x82, 0x8c, 0x25, 0x55, 0x2c, 0x6d, 0xef, 0x98, 0xe3, 0x4f, 0x88, 0xd0, 0x74, 0x82,
136 0x09, 0x3e, 0x8d, 0x6c, 0xf0, 0xf2, 0x18, 0xd5, 0x83, 0x0e, 0x0d, 0xf2, 0xce, 0xc5, 0x15, 0x38,
137 0xe5, 0x6a, 0xe6, 0x4d, 0x4d, 0x95, 0x15, 0xb7, 0x24, 0xe7, 0xcb, 0x4b, 0x63, 0x42, 0x21, 0xbc,
138 0x36, 0xc6, 0x0a, 0xd8, 0xa3, 0x76, 0x30, 0x74, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
139 0x16, 0x04, 0x14, 0x39, 0x81, 0x41, 0x0a, 0xb9, 0xf3, 0xf4, 0x5b, 0x75, 0x97, 0x4a, 0x46, 0xd6,
140 0x30, 0x9e, 0x1d, 0x7a, 0x3b, 0xec, 0xa8, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
141 0x30, 0x16, 0x80, 0x14, 0x82, 0xbd, 0x00, 0xde, 0xcb, 0xc5, 0xe7, 0x72, 0x87, 0x3d, 0x1c, 0x0a,
142 0x1e, 0x78, 0x4f, 0xf5, 0xd3, 0xc1, 0x3e, 0xb8, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
143 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f,
144 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x11, 0x06, 0x0a, 0x2b, 0x06, 0x01,
145 0x04, 0x01, 0xd6, 0x79, 0x02, 0x01, 0x1e, 0x04, 0x03, 0xa1, 0x01, 0x08, 0x30, 0x0a, 0x06, 0x08,
146 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00,
147 0xae, 0xd8, 0x40, 0x9e, 0x37, 0x3e, 0x5c, 0x9c, 0xe2, 0x93, 0x3d, 0x8c, 0xf7, 0x05, 0x10, 0xe7,
148 0xd1, 0x2b, 0x87, 0x8a, 0xee, 0xd6, 0x1e, 0x6c, 0x3b, 0xd2, 0x91, 0x3e, 0xa5, 0xdf, 0x91, 0x20,
149 0x02, 0x20, 0x7f, 0x0f, 0x29, 0x54, 0x60, 0x80, 0x07, 0x50, 0x5f, 0x56, 0x6b, 0x9f, 0xe0, 0x94,
150 0xb4, 0x3f, 0x3b, 0x0f, 0x61, 0xa0, 0x33, 0x40, 0xe6, 0x1a, 0x42, 0xda, 0x4b, 0xa4, 0xfd, 0x92,
151 0xb9, 0x0f,
152];
153
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000154lazy_static! {
Alice Wange64dd182024-01-17 15:57:55 +0000155 static ref FAKE_PROVISIONED_KEY_BLOB_FOR_TESTING: Mutex<Option<Vec<u8>>> = Mutex::new(None);
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000156 static ref VFIO_SERVICE: Strong<dyn IVfioHandler> =
157 wait_for_interface(<BpVfioHandler as IVfioHandler>::get_descriptor())
158 .expect("Could not connect to VfioHandler");
159}
160
David Brazdilafc9a9e2023-01-12 16:08:10 +0000161fn is_valid_guest_cid(cid: Cid) -> bool {
162 (GUEST_CID_MIN..=GUEST_CID_MAX).contains(&cid)
163}
164
165/// Singleton service for allocating globally-unique VM resources, such as the CID, and running
166/// singleton servers, like tombstone receiver.
David Drysdale79af2662024-02-19 14:50:31 +0000167#[derive(Clone)]
David Brazdilafc9a9e2023-01-12 16:08:10 +0000168pub struct VirtualizationServiceInternal {
169 state: Arc<Mutex<GlobalState>>,
170}
171
172impl VirtualizationServiceInternal {
David Drysdale79af2662024-02-19 14:50:31 +0000173 pub fn init() -> VirtualizationServiceInternal {
174 let service =
175 VirtualizationServiceInternal { state: Arc::new(Mutex::new(GlobalState::new())) };
David Brazdilafc9a9e2023-01-12 16:08:10 +0000176
177 std::thread::spawn(|| {
178 if let Err(e) = handle_stream_connection_tombstoned() {
179 warn!("Error receiving tombstone from guest or writing them. Error: {:?}", e);
180 }
181 });
182
David Drysdale79af2662024-02-19 14:50:31 +0000183 service
David Brazdilafc9a9e2023-01-12 16:08:10 +0000184 }
185}
186
187impl Interface for VirtualizationServiceInternal {}
188
189impl IVirtualizationServiceInternal for VirtualizationServiceInternal {
190 fn removeMemlockRlimit(&self) -> binder::Result<()> {
191 let pid = get_calling_pid();
192 let lim = libc::rlimit { rlim_cur: libc::RLIM_INFINITY, rlim_max: libc::RLIM_INFINITY };
193
Andrew Walbranb58d1b42023-07-07 13:54:49 +0100194 // SAFETY: borrowing the new limit struct only
David Brazdilafc9a9e2023-01-12 16:08:10 +0000195 let ret = unsafe { libc::prlimit(pid, libc::RLIMIT_MEMLOCK, &lim, std::ptr::null_mut()) };
196
197 match ret {
198 0 => Ok(()),
Jiyong Park2227eaa2023-08-04 11:59:18 +0900199 -1 => Err(std::io::Error::last_os_error().into()),
200 n => Err(anyhow!("Unexpected return value from prlimit(): {n}")),
David Brazdilafc9a9e2023-01-12 16:08:10 +0000201 }
Jiyong Park2227eaa2023-08-04 11:59:18 +0900202 .or_binder_exception(ExceptionCode::ILLEGAL_STATE)
David Brazdilafc9a9e2023-01-12 16:08:10 +0000203 }
204
205 fn allocateGlobalVmContext(
206 &self,
207 requester_debug_pid: i32,
208 ) -> binder::Result<Strong<dyn IGlobalVmContext>> {
209 check_manage_access()?;
210
211 let requester_uid = get_calling_uid();
212 let requester_debug_pid = requester_debug_pid as pid_t;
213 let state = &mut *self.state.lock().unwrap();
Jiyong Park2227eaa2023-08-04 11:59:18 +0900214 state
215 .allocate_vm_context(requester_uid, requester_debug_pid)
216 .or_binder_exception(ExceptionCode::ILLEGAL_STATE)
David Brazdilafc9a9e2023-01-12 16:08:10 +0000217 }
218
219 fn atomVmBooted(&self, atom: &AtomVmBooted) -> Result<(), Status> {
220 forward_vm_booted_atom(atom);
221 Ok(())
222 }
223
224 fn atomVmCreationRequested(&self, atom: &AtomVmCreationRequested) -> Result<(), Status> {
225 forward_vm_creation_atom(atom);
226 Ok(())
227 }
228
229 fn atomVmExited(&self, atom: &AtomVmExited) -> Result<(), Status> {
230 forward_vm_exited_atom(atom);
231 Ok(())
232 }
233
234 fn debugListVms(&self) -> binder::Result<Vec<VirtualMachineDebugInfo>> {
235 check_debug_access()?;
236
237 let state = &mut *self.state.lock().unwrap();
238 let cids = state
239 .held_contexts
240 .iter()
241 .filter_map(|(_, inst)| Weak::upgrade(inst))
242 .map(|vm| VirtualMachineDebugInfo {
243 cid: vm.cid as i32,
244 temporaryDirectory: vm.get_temp_dir().to_string_lossy().to_string(),
245 requesterUid: vm.requester_uid as i32,
Charisee96113f32023-01-26 09:00:42 +0000246 requesterPid: vm.requester_debug_pid,
David Brazdilafc9a9e2023-01-12 16:08:10 +0000247 })
248 .collect();
249 Ok(cids)
250 }
Alice Wangc2fec932023-02-23 16:24:02 +0000251
Alice Wange64dd182024-01-17 15:57:55 +0000252 fn enableTestAttestation(&self) -> binder::Result<()> {
253 check_manage_access()?;
254 check_use_custom_virtual_machine()?;
255 if !cfg!(remote_attestation) {
256 return Err(Status::new_exception_str(
257 ExceptionCode::UNSUPPORTED_OPERATION,
258 Some(
259 "enableTestAttestation is not supported with the remote_attestation \
260 feature disabled",
261 ),
262 ))
263 .with_log();
264 }
265 let res = generate_ecdsa_p256_key_pair()
266 .context("Failed to generate ECDSA P-256 key pair for testing")
267 .with_log()
268 .or_service_specific_exception(-1)?;
269 match res {
270 Response::GenerateEcdsaP256KeyPair(key_pair) => {
271 FAKE_PROVISIONED_KEY_BLOB_FOR_TESTING
272 .lock()
273 .unwrap()
274 .replace(key_pair.key_blob.to_vec());
275 Ok(())
276 }
277 _ => Err(remote_provisioning::to_service_specific_error(res)),
278 }
279 .with_log()
280 }
281
Alice Wangbff017f2023-11-09 14:43:28 +0000282 fn requestAttestation(
283 &self,
284 csr: &[u8],
285 requester_uid: i32,
Alice Wange64dd182024-01-17 15:57:55 +0000286 test_mode: bool,
Alice Wangbff017f2023-11-09 14:43:28 +0000287 ) -> binder::Result<Vec<Certificate>> {
Alice Wangc2fec932023-02-23 16:24:02 +0000288 check_manage_access()?;
Alice Wang4c6c5582023-11-23 15:07:18 +0000289 if !cfg!(remote_attestation) {
290 return Err(Status::new_exception_str(
Alice Wange9ac2db2023-09-08 15:13:13 +0000291 ExceptionCode::UNSUPPORTED_OPERATION,
292 Some(
Alice Wanga410b642023-10-18 09:05:15 +0000293 "requestAttestation is not supported with the remote_attestation feature \
294 disabled",
Alice Wange9ac2db2023-09-08 15:13:13 +0000295 ),
296 ))
Alice Wang4c6c5582023-11-23 15:07:18 +0000297 .with_log();
Alice Wange9ac2db2023-09-08 15:13:13 +0000298 }
Alice Wang4c6c5582023-11-23 15:07:18 +0000299 info!("Received csr. Requestting attestation...");
Alice Wange64dd182024-01-17 15:57:55 +0000300 let (key_blob, certificate_chain) = if test_mode {
301 check_use_custom_virtual_machine()?;
302 info!("Using the fake key blob for testing...");
303 (
304 FAKE_PROVISIONED_KEY_BLOB_FOR_TESTING
305 .lock()
306 .unwrap()
307 .clone()
308 .ok_or_else(|| anyhow!("No key blob for testing"))
309 .with_log()
310 .or_service_specific_exception(-1)?,
311 FAKE_CERTIFICATE_FOR_TESTING.to_vec(),
312 )
313 } else {
314 info!("Retrieving the remotely provisioned keys from RKPD...");
315 let attestation_key = get_rkpd_attestation_key(
316 REMOTELY_PROVISIONED_COMPONENT_SERVICE_NAME,
317 requester_uid as u32,
318 )
319 .context("Failed to retrieve the remotely provisioned keys")
320 .with_log()
321 .or_service_specific_exception(-1)?;
322 (attestation_key.keyBlob, attestation_key.encodedCertChain)
323 };
324 let mut certificate_chain = split_x509_certificate_chain(&certificate_chain)
Alice Wang4c6c5582023-11-23 15:07:18 +0000325 .context("Failed to split the remotely provisioned certificate chain")
326 .with_log()
327 .or_service_specific_exception(-1)?;
328 if certificate_chain.is_empty() {
329 return Err(Status::new_service_specific_error_str(
330 -1,
331 Some("The certificate chain should contain at least 1 certificate"),
332 ))
333 .with_log();
334 }
Alice Wang20b8ebc2023-11-17 09:54:47 +0000335 let certificate = request_attestation(
336 csr.to_vec(),
Alice Wange64dd182024-01-17 15:57:55 +0000337 key_blob,
Alice Wang20b8ebc2023-11-17 09:54:47 +0000338 certificate_chain[0].encodedCertificate.clone(),
339 )
340 .context("Failed to request attestation")
341 .with_log()
342 .or_service_specific_exception(-1)?;
Alice Wang4c6c5582023-11-23 15:07:18 +0000343 certificate_chain.insert(0, Certificate { encodedCertificate: certificate });
344
345 Ok(certificate_chain)
Alice Wangc2fec932023-02-23 16:24:02 +0000346 }
Inseob Kim53d0b212023-07-20 16:58:37 +0900347
348 fn getAssignableDevices(&self) -> binder::Result<Vec<AssignableDevice>> {
349 check_use_custom_virtual_machine()?;
350
Inseob Kim7307a892023-09-14 13:37:58 +0900351 Ok(get_assignable_devices()?
352 .device
353 .into_iter()
354 .map(|x| AssignableDevice { node: x.sysfs_path, kind: x.kind })
355 .collect::<Vec<_>>())
Inseob Kim53d0b212023-07-20 16:58:37 +0900356 }
Inseob Kim1ca0f652023-07-20 17:18:12 +0900357
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000358 fn bindDevicesToVfioDriver(
359 &self,
360 devices: &[String],
361 ) -> binder::Result<Vec<Strong<dyn IBoundDevice>>> {
Inseob Kim1ca0f652023-07-20 17:18:12 +0900362 check_use_custom_virtual_machine()?;
363
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000364 let devices = get_assignable_devices()?
Inseob Kim7307a892023-09-14 13:37:58 +0900365 .device
366 .into_iter()
367 .filter_map(|x| {
368 if devices.contains(&x.sysfs_path) {
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000369 Some(VfioDev { sysfsPath: x.sysfs_path, dtboLabel: x.dtbo_label })
Inseob Kim7307a892023-09-14 13:37:58 +0900370 } else {
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000371 warn!("device {} is not assignable", x.sysfs_path);
Inseob Kim7307a892023-09-14 13:37:58 +0900372 None
373 }
374 })
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000375 .collect::<Vec<VfioDev>>();
376
377 VFIO_SERVICE.bindDevicesToVfioDriver(devices.as_slice())
Inseob Kim1ca0f652023-07-20 17:18:12 +0900378 }
David Brazdil2dfefd12023-11-17 14:07:36 +0000379
380 fn getDtboFile(&self) -> binder::Result<ParcelFileDescriptor> {
381 check_use_custom_virtual_machine()?;
382
383 let state = &mut *self.state.lock().unwrap();
384 let file = state.get_dtbo_file().or_service_specific_exception(-1)?;
385 Ok(ParcelFileDescriptor::new(file))
386 }
Shikha Panwar61a74b52024-02-16 13:17:01 +0000387
388 // TODO(b/294177871) Persist this Id, along with client uuid.
389 fn allocateInstanceId(&self) -> binder::Result<[u8; 64]> {
390 let mut id = [0u8; 64];
391 id.try_fill(&mut rand::thread_rng())
392 .context("Failed to allocate instance_id")
393 .or_service_specific_exception(-1)?;
394 let uid = get_calling_uid();
395 info!("Allocated a VM's instance_id: {:?}, for uid: {:?}", hex::encode(id), uid);
396 Ok(id)
397 }
David Drysdale79af2662024-02-19 14:50:31 +0000398
399 fn removeVmInstance(&self, instance_id: &[u8; 64]) -> binder::Result<()> {
400 let state = &mut *self.state.lock().unwrap();
401 if let Some(sk_state) = &mut state.sk_state {
402 info!("removeVmInstance(): delete secret");
403 sk_state.delete_ids(&[*instance_id]);
404 } else {
405 info!("ignoring removeVmInstance() as no ISecretkeeper");
406 }
407 Ok(())
408 }
409}
410
411impl IVirtualizationMaintenance for VirtualizationServiceInternal {
412 fn appRemoved(&self, user_id: i32, app_id: i32) -> binder::Result<()> {
413 let state = &mut *self.state.lock().unwrap();
414 if let Some(sk_state) = &mut state.sk_state {
415 info!("packageRemoved(user_id={user_id}, app_id={app_id})");
416 sk_state.delete_ids_for_app(user_id, app_id).or_service_specific_exception(-1)?;
417 } else {
418 info!("ignoring packageRemoved(user_id={user_id}, app_id={app_id})");
419 }
420 Ok(())
421 }
422
423 fn userRemoved(&self, user_id: i32) -> binder::Result<()> {
424 let state = &mut *self.state.lock().unwrap();
425 if let Some(sk_state) = &mut state.sk_state {
426 info!("userRemoved({user_id})");
427 sk_state.delete_ids_for_user(user_id).or_service_specific_exception(-1)?;
428 } else {
429 info!("ignoring userRemoved(user_id={user_id})");
430 }
431 Ok(())
432 }
Alan Stokes30ccacb2024-02-20 14:59:02 +0000433
434 fn performReconciliation(
435 &self,
436 _callback: &Strong<dyn IVirtualizationReconciliationCallback>,
437 ) -> binder::Result<()> {
438 Err(anyhow!("performReconciliation not supported"))
439 .or_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION)
440 }
Inseob Kim1ca0f652023-07-20 17:18:12 +0900441}
442
Inseob Kimc4a774d2023-08-30 12:48:43 +0900443// KEEP IN SYNC WITH assignable_devices.xsd
444#[derive(Debug, Deserialize)]
445struct Device {
446 kind: String,
Jaewan Kim35e818d2023-10-18 05:36:38 +0000447 dtbo_label: String,
Inseob Kimc4a774d2023-08-30 12:48:43 +0900448 sysfs_path: String,
449}
450
Inseob Kim7307a892023-09-14 13:37:58 +0900451#[derive(Debug, Default, Deserialize)]
Inseob Kimc4a774d2023-08-30 12:48:43 +0900452struct Devices {
453 device: Vec<Device>,
454}
455
Inseob Kim7307a892023-09-14 13:37:58 +0900456fn get_assignable_devices() -> binder::Result<Devices> {
457 let xml_path = Path::new("/vendor/etc/avf/assignable_devices.xml");
458 if !xml_path.exists() {
459 return Ok(Devices { ..Default::default() });
460 }
461
462 let xml = fs::read(xml_path)
463 .context("Failed to read assignable_devices.xml")
464 .with_log()
465 .or_service_specific_exception(-1)?;
466
467 let xml = String::from_utf8(xml)
468 .context("assignable_devices.xml is not a valid UTF-8 file")
469 .with_log()
470 .or_service_specific_exception(-1)?;
471
472 let mut devices: Devices = serde_xml_rs::from_str(&xml)
473 .context("can't parse assignable_devices.xml")
474 .with_log()
475 .or_service_specific_exception(-1)?;
476
477 let mut device_set = HashSet::new();
478 devices.device.retain(move |device| {
479 if device_set.contains(&device.sysfs_path) {
480 warn!("duplicated assignable device {device:?}; ignoring...");
481 return false;
482 }
483
484 if !Path::new(&device.sysfs_path).exists() {
485 warn!("assignable device {device:?} doesn't exist; ignoring...");
486 return false;
487 }
488
489 device_set.insert(device.sysfs_path.clone());
490 true
491 });
492 Ok(devices)
493}
494
Alice Wang4c6c5582023-11-23 15:07:18 +0000495fn split_x509_certificate_chain(mut cert_chain: &[u8]) -> Result<Vec<Certificate>> {
496 let mut out = Vec::new();
497 while !cert_chain.is_empty() {
Alice Wangfc5a44a2023-12-21 12:22:40 +0000498 let cert = X509::from_der(cert_chain)?;
499 let end = cert.to_der()?.len();
Alice Wang4c6c5582023-11-23 15:07:18 +0000500 out.push(Certificate { encodedCertificate: cert_chain[..end].to_vec() });
Alice Wangfc5a44a2023-12-21 12:22:40 +0000501 cert_chain = &cert_chain[end..];
Alice Wang4c6c5582023-11-23 15:07:18 +0000502 }
503 Ok(out)
504}
505
David Brazdilafc9a9e2023-01-12 16:08:10 +0000506#[derive(Debug, Default)]
507struct GlobalVmInstance {
508 /// The unique CID assigned to the VM for vsock communication.
509 cid: Cid,
510 /// UID of the client who requested this VM instance.
511 requester_uid: uid_t,
512 /// PID of the client who requested this VM instance.
513 requester_debug_pid: pid_t,
514}
515
516impl GlobalVmInstance {
517 fn get_temp_dir(&self) -> PathBuf {
518 let cid = self.cid;
519 format!("{TEMPORARY_DIRECTORY}/{cid}").into()
520 }
521}
522
523/// The mutable state of the VirtualizationServiceInternal. There should only be one instance
524/// of this struct.
David Brazdilafc9a9e2023-01-12 16:08:10 +0000525struct GlobalState {
526 /// VM contexts currently allocated to running VMs. A CID is never recycled as long
527 /// as there is a strong reference held by a GlobalVmContext.
528 held_contexts: HashMap<Cid, Weak<GlobalVmInstance>>,
David Brazdil2dfefd12023-11-17 14:07:36 +0000529
530 /// Cached read-only FD of VM DTBO file. Also serves as a lock for creating the file.
531 dtbo_file: Mutex<Option<File>>,
David Drysdale79af2662024-02-19 14:50:31 +0000532
533 /// State relating to secrets held by (optional) Secretkeeper instance on behalf of VMs.
534 sk_state: Option<maintenance::State>,
David Brazdilafc9a9e2023-01-12 16:08:10 +0000535}
536
537impl GlobalState {
David Drysdale79af2662024-02-19 14:50:31 +0000538 fn new() -> Self {
539 Self {
540 held_contexts: HashMap::new(),
541 dtbo_file: Mutex::new(None),
542 sk_state: maintenance::State::new(),
543 }
544 }
545
David Brazdilafc9a9e2023-01-12 16:08:10 +0000546 /// Get the next available CID, or an error if we have run out. The last CID used is stored in
547 /// a system property so that restart of virtualizationservice doesn't reuse CID while the host
548 /// Android is up.
549 fn get_next_available_cid(&mut self) -> Result<Cid> {
550 // Start trying to find a CID from the last used CID + 1. This ensures
551 // that we do not eagerly recycle CIDs. It makes debugging easier but
552 // also means that retrying to allocate a CID, eg. because it is
553 // erroneously occupied by a process, will not recycle the same CID.
554 let last_cid_prop =
555 system_properties::read(SYSPROP_LAST_CID)?.and_then(|val| match val.parse::<Cid>() {
556 Ok(num) => {
557 if is_valid_guest_cid(num) {
558 Some(num)
559 } else {
560 error!("Invalid value '{}' of property '{}'", num, SYSPROP_LAST_CID);
561 None
562 }
563 }
564 Err(_) => {
565 error!("Invalid value '{}' of property '{}'", val, SYSPROP_LAST_CID);
566 None
567 }
568 });
569
570 let first_cid = if let Some(last_cid) = last_cid_prop {
571 if last_cid == GUEST_CID_MAX {
572 GUEST_CID_MIN
573 } else {
574 last_cid + 1
575 }
576 } else {
577 GUEST_CID_MIN
578 };
579
580 let cid = self
581 .find_available_cid(first_cid..=GUEST_CID_MAX)
582 .or_else(|| self.find_available_cid(GUEST_CID_MIN..first_cid))
583 .ok_or_else(|| anyhow!("Could not find an available CID."))?;
584
585 system_properties::write(SYSPROP_LAST_CID, &format!("{}", cid))?;
586 Ok(cid)
587 }
588
589 fn find_available_cid<I>(&self, mut range: I) -> Option<Cid>
590 where
591 I: Iterator<Item = Cid>,
592 {
593 range.find(|cid| !self.held_contexts.contains_key(cid))
594 }
595
596 fn allocate_vm_context(
597 &mut self,
598 requester_uid: uid_t,
599 requester_debug_pid: pid_t,
600 ) -> Result<Strong<dyn IGlobalVmContext>> {
601 // Garbage collect unused VM contexts.
602 self.held_contexts.retain(|_, instance| instance.strong_count() > 0);
603
604 let cid = self.get_next_available_cid()?;
605 let instance = Arc::new(GlobalVmInstance { cid, requester_uid, requester_debug_pid });
David Brazdil2dfefd12023-11-17 14:07:36 +0000606 create_temporary_directory(&instance.get_temp_dir(), Some(requester_uid))?;
David Brazdilafc9a9e2023-01-12 16:08:10 +0000607
608 self.held_contexts.insert(cid, Arc::downgrade(&instance));
609 let binder = GlobalVmContext { instance, ..Default::default() };
610 Ok(BnGlobalVmContext::new_binder(binder, BinderFeatures::default()))
611 }
David Brazdil2dfefd12023-11-17 14:07:36 +0000612
613 fn get_dtbo_file(&mut self) -> Result<File> {
614 let mut file = self.dtbo_file.lock().unwrap();
615
616 let fd = if let Some(ref_fd) = &*file {
617 ref_fd.try_clone()?
618 } else {
619 let path = get_or_create_common_dir()?.join("vm.dtbo");
620 if path.exists() {
621 // All temporary files are deleted when the service is started.
622 // If the file exists but the FD is not cached, the file is
623 // likely corrupted.
624 remove_file(&path).context("Failed to clone cached VM DTBO file descriptor")?;
625 }
626
627 // Open a write-only file descriptor for vfio_handler.
628 let write_fd = File::create(&path).context("Failed to create VM DTBO file")?;
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000629 VFIO_SERVICE.writeVmDtbo(&ParcelFileDescriptor::new(write_fd))?;
David Brazdil2dfefd12023-11-17 14:07:36 +0000630
631 // Open read-only. This FD will be cached and returned to clients.
632 let read_fd = File::open(&path).context("Failed to open VM DTBO file")?;
633 let read_fd_clone =
634 read_fd.try_clone().context("Failed to clone VM DTBO file descriptor")?;
635 *file = Some(read_fd);
636 read_fd_clone
637 };
638
639 Ok(fd)
640 }
David Brazdilafc9a9e2023-01-12 16:08:10 +0000641}
642
David Brazdil2dfefd12023-11-17 14:07:36 +0000643fn create_temporary_directory(path: &PathBuf, requester_uid: Option<uid_t>) -> Result<()> {
644 // Directory may exist if previous attempt to create it had failed.
645 // Delete it before trying again.
David Brazdilafc9a9e2023-01-12 16:08:10 +0000646 if path.as_path().exists() {
647 remove_temporary_dir(path).unwrap_or_else(|e| {
648 warn!("Could not delete temporary directory {:?}: {}", path, e);
649 });
650 }
David Brazdil2dfefd12023-11-17 14:07:36 +0000651 // Create directory.
652 create_dir(path).with_context(|| format!("Could not create temporary directory {:?}", path))?;
653 // If provided, change ownership to client's UID but system's GID, and permissions 0700.
David Brazdilafc9a9e2023-01-12 16:08:10 +0000654 // If the chown() fails, this will leave behind an empty directory that will get removed
655 // at the next attempt, or if virtualizationservice is restarted.
David Brazdil2dfefd12023-11-17 14:07:36 +0000656 if let Some(uid) = requester_uid {
657 chown(path, Some(Uid::from_raw(uid)), None).with_context(|| {
658 format!("Could not set ownership of temporary directory {:?}", path)
659 })?;
660 }
David Brazdilafc9a9e2023-01-12 16:08:10 +0000661 Ok(())
662}
663
664/// Removes a directory owned by a different user by first changing its owner back
665/// to VirtualizationService.
666pub fn remove_temporary_dir(path: &PathBuf) -> Result<()> {
Alice Wangd1b11a02023-04-18 12:30:20 +0000667 ensure!(path.as_path().is_dir(), "Path {:?} is not a directory", path);
David Brazdilafc9a9e2023-01-12 16:08:10 +0000668 chown(path, Some(Uid::current()), None)?;
669 set_permissions(path, Permissions::from_mode(0o700))?;
Alice Wangd1b11a02023-04-18 12:30:20 +0000670 remove_dir_all(path)?;
David Brazdilafc9a9e2023-01-12 16:08:10 +0000671 Ok(())
672}
673
David Brazdil2dfefd12023-11-17 14:07:36 +0000674fn get_or_create_common_dir() -> Result<PathBuf> {
675 let path = Path::new(TEMPORARY_DIRECTORY).join("common");
676 if !path.exists() {
677 create_temporary_directory(&path, None)?;
678 }
679 Ok(path)
680}
681
David Brazdilafc9a9e2023-01-12 16:08:10 +0000682/// Implementation of the AIDL `IGlobalVmContext` interface.
683#[derive(Debug, Default)]
684struct GlobalVmContext {
685 /// Strong reference to the context's instance data structure.
686 instance: Arc<GlobalVmInstance>,
687 /// Keeps our service process running as long as this VM context exists.
688 #[allow(dead_code)]
689 lazy_service_guard: LazyServiceGuard,
690}
691
692impl Interface for GlobalVmContext {}
693
694impl IGlobalVmContext for GlobalVmContext {
695 fn getCid(&self) -> binder::Result<i32> {
696 Ok(self.instance.cid as i32)
697 }
698
699 fn getTemporaryDirectory(&self) -> binder::Result<String> {
700 Ok(self.instance.get_temp_dir().to_string_lossy().to_string())
701 }
702}
703
704fn handle_stream_connection_tombstoned() -> Result<()> {
705 // Should not listen for tombstones on a guest VM's port.
706 assert!(!is_valid_guest_cid(VM_TOMBSTONES_SERVICE_PORT as Cid));
707 let listener =
708 VsockListener::bind_with_cid_port(VMADDR_CID_HOST, VM_TOMBSTONES_SERVICE_PORT as Cid)?;
709 for incoming_stream in listener.incoming() {
710 let mut incoming_stream = match incoming_stream {
711 Err(e) => {
712 warn!("invalid incoming connection: {:?}", e);
713 continue;
714 }
715 Ok(s) => s,
716 };
717 std::thread::spawn(move || {
718 if let Err(e) = handle_tombstone(&mut incoming_stream) {
719 error!("Failed to write tombstone- {:?}", e);
720 }
721 });
722 }
723 Ok(())
724}
725
726fn handle_tombstone(stream: &mut VsockStream) -> Result<()> {
727 if let Ok(addr) = stream.peer_addr() {
728 info!("Vsock Stream connected to cid={} for tombstones", addr.cid());
729 }
730 let tb_connection =
731 TombstonedConnection::connect(std::process::id() as i32, DebuggerdDumpType::Tombstone)
732 .context("Failed to connect to tombstoned")?;
733 let mut text_output = tb_connection
734 .text_output
735 .as_ref()
736 .ok_or_else(|| anyhow!("Could not get file to write the tombstones on"))?;
737 let mut num_bytes_read = 0;
738 loop {
739 let mut chunk_recv = [0; CHUNK_RECV_MAX_LEN];
740 let n = stream
741 .read(&mut chunk_recv)
742 .context("Failed to read tombstone data from Vsock stream")?;
743 if n == 0 {
744 break;
745 }
746 num_bytes_read += n;
747 text_output.write_all(&chunk_recv[0..n]).context("Failed to write guests tombstones")?;
748 }
749 info!("Received {} bytes from guest & wrote to tombstone file", num_bytes_read);
750 tb_connection.notify_completion()?;
751 Ok(())
752}
753
754/// Checks whether the caller has a specific permission
755fn check_permission(perm: &str) -> binder::Result<()> {
756 let calling_pid = get_calling_pid();
757 let calling_uid = get_calling_uid();
758 // Root can do anything
759 if calling_uid == 0 {
760 return Ok(());
761 }
762 let perm_svc: Strong<dyn IPermissionController::IPermissionController> =
763 binder::get_interface("permission")?;
764 if perm_svc.checkPermission(perm, calling_pid, calling_uid as i32)? {
765 Ok(())
766 } else {
Jiyong Park2227eaa2023-08-04 11:59:18 +0900767 Err(anyhow!("does not have the {} permission", perm))
768 .or_binder_exception(ExceptionCode::SECURITY)
David Brazdilafc9a9e2023-01-12 16:08:10 +0000769 }
770}
771
772/// Check whether the caller of the current Binder method is allowed to call debug methods.
773fn check_debug_access() -> binder::Result<()> {
774 check_permission("android.permission.DEBUG_VIRTUAL_MACHINE")
775}
776
777/// Check whether the caller of the current Binder method is allowed to manage VMs
778fn check_manage_access() -> binder::Result<()> {
779 check_permission("android.permission.MANAGE_VIRTUAL_MACHINE")
780}
Inseob Kim53d0b212023-07-20 16:58:37 +0900781
782/// Check whether the caller of the current Binder method is allowed to use custom VMs
783fn check_use_custom_virtual_machine() -> binder::Result<()> {
784 check_permission("android.permission.USE_CUSTOM_VIRTUAL_MACHINE")
785}
Alice Wang4c6c5582023-11-23 15:07:18 +0000786
787#[cfg(test)]
788mod tests {
789 use super::*;
Alice Wang4c6c5582023-11-23 15:07:18 +0000790
791 const TEST_RKP_CERT_CHAIN_PATH: &str = "testdata/rkp_cert_chain.der";
792
793 #[test]
794 fn splitting_x509_certificate_chain_succeeds() -> Result<()> {
795 let bytes = fs::read(TEST_RKP_CERT_CHAIN_PATH)?;
796 let cert_chain = split_x509_certificate_chain(&bytes)?;
797
798 assert_eq!(4, cert_chain.len());
799 for cert in cert_chain {
Alice Wangfc5a44a2023-12-21 12:22:40 +0000800 let x509_cert = X509::from_der(&cert.encodedCertificate)?;
801 assert_eq!(x509_cert.to_der()?.len(), cert.encodedCertificate.len());
Alice Wang4c6c5582023-11-23 15:07:18 +0000802 }
803 Ok(())
804 }
805}