blob: d0c5d4a6b78d295d4d05c9931f58051b689dedf9 [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
Alice Wangbff017f2023-11-09 14:43:28 +000017use crate::{get_calling_pid, get_calling_uid, REMOTELY_PROVISIONED_COMPONENT_SERVICE_NAME};
David Brazdil33a31022023-01-12 16:55:16 +000018use crate::atom::{forward_vm_booted_atom, forward_vm_creation_atom, forward_vm_exited_atom};
Alice Wange64dd182024-01-17 15:57:55 +000019use crate::rkpvm::{request_attestation, generate_ecdsa_p256_key_pair};
20use crate::remote_provisioning;
David Brazdilafc9a9e2023-01-12 16:08:10 +000021use android_os_permissions_aidl::aidl::android::os::IPermissionController;
Alice Wang4e3015d2023-10-10 09:35:37 +000022use android_system_virtualizationcommon::aidl::android::system::virtualizationcommon::Certificate::Certificate;
Alice Wangc2fec932023-02-23 16:24:02 +000023use android_system_virtualizationservice::{
Inseob Kim53d0b212023-07-20 16:58:37 +090024 aidl::android::system::virtualizationservice::AssignableDevice::AssignableDevice,
Alice Wangc2fec932023-02-23 16:24:02 +000025 aidl::android::system::virtualizationservice::VirtualMachineDebugInfo::VirtualMachineDebugInfo,
26 binder::ParcelFileDescriptor,
27};
David Brazdilafc9a9e2023-01-12 16:08:10 +000028use android_system_virtualizationservice_internal::aidl::android::system::virtualizationservice_internal::{
29 AtomVmBooted::AtomVmBooted,
30 AtomVmCreationRequested::AtomVmCreationRequested,
31 AtomVmExited::AtomVmExited,
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +000032 IBoundDevice::IBoundDevice,
David Brazdilafc9a9e2023-01-12 16:08:10 +000033 IGlobalVmContext::{BnGlobalVmContext, IGlobalVmContext},
34 IVirtualizationServiceInternal::IVirtualizationServiceInternal,
Inseob Kimbdca0472023-07-28 19:20:56 +090035 IVfioHandler::{BpVfioHandler, IVfioHandler},
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +000036 IVfioHandler::VfioDev::VfioDev,
David Brazdilafc9a9e2023-01-12 16:08:10 +000037};
38use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::VM_TOMBSTONES_SERVICE_PORT;
Alice Wangd1b11a02023-04-18 12:30:20 +000039use anyhow::{anyhow, ensure, Context, Result};
Jiyong Parkd7bd2f22023-08-10 20:41:19 +090040use avflog::LogResult;
Jiyong Park2227eaa2023-08-04 11:59:18 +090041use binder::{self, wait_for_interface, BinderFeatures, ExceptionCode, Interface, LazyServiceGuard, Status, Strong, IntoBinderResult};
Alice Wange64dd182024-01-17 15:57:55 +000042use service_vm_comm::Response;
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +000043use lazy_static::lazy_static;
David Brazdilafc9a9e2023-01-12 16:08:10 +000044use libc::VMADDR_CID_HOST;
45use log::{error, info, warn};
Alice Wangbff017f2023-11-09 14:43:28 +000046use rkpd_client::get_rkpd_attestation_key;
David Brazdilafc9a9e2023-01-12 16:08:10 +000047use rustutils::system_properties;
Inseob Kimc4a774d2023-08-30 12:48:43 +090048use serde::Deserialize;
49use std::collections::{HashMap, HashSet};
David Brazdil2dfefd12023-11-17 14:07:36 +000050use std::fs::{self, create_dir, remove_dir_all, remove_file, set_permissions, File, Permissions};
David Brazdilafc9a9e2023-01-12 16:08:10 +000051use std::io::{Read, Write};
52use std::os::unix::fs::PermissionsExt;
53use std::os::unix::raw::{pid_t, uid_t};
Inseob Kim55438b22023-08-09 20:16:01 +090054use std::path::{Path, PathBuf};
David Brazdilafc9a9e2023-01-12 16:08:10 +000055use std::sync::{Arc, Mutex, Weak};
56use tombstoned_client::{DebuggerdDumpType, TombstonedConnection};
57use vsock::{VsockListener, VsockStream};
Inseob Kimbdca0472023-07-28 19:20:56 +090058use nix::unistd::{chown, Uid};
Alice Wangfc5a44a2023-12-21 12:22:40 +000059use openssl::x509::X509;
David Brazdilafc9a9e2023-01-12 16:08:10 +000060
61/// The unique ID of a VM used (together with a port number) for vsock communication.
62pub type Cid = u32;
63
64pub const BINDER_SERVICE_IDENTIFIER: &str = "android.system.virtualizationservice";
65
66/// Directory in which to write disk image files used while running VMs.
67pub const TEMPORARY_DIRECTORY: &str = "/data/misc/virtualizationservice";
68
69/// The first CID to assign to a guest VM managed by the VirtualizationService. CIDs lower than this
70/// are reserved for the host or other usage.
71const GUEST_CID_MIN: Cid = 2048;
72const GUEST_CID_MAX: Cid = 65535;
73
74const SYSPROP_LAST_CID: &str = "virtualizationservice.state.last_cid";
75
76const CHUNK_RECV_MAX_LEN: usize = 1024;
77
Alice Wange64dd182024-01-17 15:57:55 +000078/// The fake certificate is used for testing only when a client VM requests attestation in test
79/// mode, it is a single certificate extracted on an unregistered device for testing.
80/// Here is the snapshot of the certificate:
81///
82/// ```
83/// Certificate:
84/// Data:
85/// Version: 3 (0x2)
86/// Serial Number:
87/// 59:ae:50:98:95:e1:34:25:f1:21:93:c0:4c:e5:24:66
88/// Signature Algorithm: ecdsa-with-SHA256
89/// Issuer: CN = Droid Unregistered Device CA, O = Google Test LLC
90/// Validity
91/// Not Before: Feb 5 14:39:39 2024 GMT
92/// Not After : Feb 14 14:39:39 2024 GMT
93/// Subject: CN = 59ae509895e13425f12193c04ce52466, O = TEE
94/// Subject Public Key Info:
95/// Public Key Algorithm: id-ecPublicKey
96/// Public-Key: (256 bit)
97/// pub:
98/// 04:30:32:cd:95:12:b0:71:8b:b7:14:44:26:58:d5:
99/// 82:8c:25:55:2c:6d:ef:98:e3:4f:88:d0:74:82:09:
100/// 3e:8d:6c:f0:f2:18:d5:83:0e:0d:f2:ce:c5:15:38:
101/// e5:6a:e6:4d:4d:95:15:b7:24:e7:cb:4b:63:42:21:
102/// bc:36:c6:0a:d8
103/// ASN1 OID: prime256v1
104/// NIST CURVE: P-256
105/// X509v3 extensions:
106/// ...
107/// ```
108const FAKE_CERTIFICATE_FOR_TESTING: &[u8] = &[
109 0x30, 0x82, 0x01, 0xee, 0x30, 0x82, 0x01, 0x94, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x59,
110 0xae, 0x50, 0x98, 0x95, 0xe1, 0x34, 0x25, 0xf1, 0x21, 0x93, 0xc0, 0x4c, 0xe5, 0x24, 0x66, 0x30,
111 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x41, 0x31, 0x25, 0x30,
112 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1c, 0x44, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x55, 0x6e,
113 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x44, 0x65, 0x76, 0x69, 0x63,
114 0x65, 0x20, 0x43, 0x41, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, 0x47,
115 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x4c, 0x4c, 0x43, 0x30, 0x1e,
116 0x17, 0x0d, 0x32, 0x34, 0x30, 0x32, 0x30, 0x35, 0x31, 0x34, 0x33, 0x39, 0x33, 0x39, 0x5a, 0x17,
117 0x0d, 0x32, 0x34, 0x30, 0x32, 0x31, 0x34, 0x31, 0x34, 0x33, 0x39, 0x33, 0x39, 0x5a, 0x30, 0x39,
118 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x20, 0x35, 0x39, 0x61, 0x65, 0x35,
119 0x30, 0x39, 0x38, 0x39, 0x35, 0x65, 0x31, 0x33, 0x34, 0x32, 0x35, 0x66, 0x31, 0x32, 0x31, 0x39,
120 0x33, 0x63, 0x30, 0x34, 0x63, 0x65, 0x35, 0x32, 0x34, 0x36, 0x36, 0x31, 0x0c, 0x30, 0x0a, 0x06,
121 0x03, 0x55, 0x04, 0x0a, 0x13, 0x03, 0x54, 0x45, 0x45, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a,
122 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
123 0x03, 0x42, 0x00, 0x04, 0x30, 0x32, 0xcd, 0x95, 0x12, 0xb0, 0x71, 0x8b, 0xb7, 0x14, 0x44, 0x26,
124 0x58, 0xd5, 0x82, 0x8c, 0x25, 0x55, 0x2c, 0x6d, 0xef, 0x98, 0xe3, 0x4f, 0x88, 0xd0, 0x74, 0x82,
125 0x09, 0x3e, 0x8d, 0x6c, 0xf0, 0xf2, 0x18, 0xd5, 0x83, 0x0e, 0x0d, 0xf2, 0xce, 0xc5, 0x15, 0x38,
126 0xe5, 0x6a, 0xe6, 0x4d, 0x4d, 0x95, 0x15, 0xb7, 0x24, 0xe7, 0xcb, 0x4b, 0x63, 0x42, 0x21, 0xbc,
127 0x36, 0xc6, 0x0a, 0xd8, 0xa3, 0x76, 0x30, 0x74, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
128 0x16, 0x04, 0x14, 0x39, 0x81, 0x41, 0x0a, 0xb9, 0xf3, 0xf4, 0x5b, 0x75, 0x97, 0x4a, 0x46, 0xd6,
129 0x30, 0x9e, 0x1d, 0x7a, 0x3b, 0xec, 0xa8, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
130 0x30, 0x16, 0x80, 0x14, 0x82, 0xbd, 0x00, 0xde, 0xcb, 0xc5, 0xe7, 0x72, 0x87, 0x3d, 0x1c, 0x0a,
131 0x1e, 0x78, 0x4f, 0xf5, 0xd3, 0xc1, 0x3e, 0xb8, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
132 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f,
133 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x11, 0x06, 0x0a, 0x2b, 0x06, 0x01,
134 0x04, 0x01, 0xd6, 0x79, 0x02, 0x01, 0x1e, 0x04, 0x03, 0xa1, 0x01, 0x08, 0x30, 0x0a, 0x06, 0x08,
135 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00,
136 0xae, 0xd8, 0x40, 0x9e, 0x37, 0x3e, 0x5c, 0x9c, 0xe2, 0x93, 0x3d, 0x8c, 0xf7, 0x05, 0x10, 0xe7,
137 0xd1, 0x2b, 0x87, 0x8a, 0xee, 0xd6, 0x1e, 0x6c, 0x3b, 0xd2, 0x91, 0x3e, 0xa5, 0xdf, 0x91, 0x20,
138 0x02, 0x20, 0x7f, 0x0f, 0x29, 0x54, 0x60, 0x80, 0x07, 0x50, 0x5f, 0x56, 0x6b, 0x9f, 0xe0, 0x94,
139 0xb4, 0x3f, 0x3b, 0x0f, 0x61, 0xa0, 0x33, 0x40, 0xe6, 0x1a, 0x42, 0xda, 0x4b, 0xa4, 0xfd, 0x92,
140 0xb9, 0x0f,
141];
142
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000143lazy_static! {
Alice Wange64dd182024-01-17 15:57:55 +0000144 static ref FAKE_PROVISIONED_KEY_BLOB_FOR_TESTING: Mutex<Option<Vec<u8>>> = Mutex::new(None);
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000145 static ref VFIO_SERVICE: Strong<dyn IVfioHandler> =
146 wait_for_interface(<BpVfioHandler as IVfioHandler>::get_descriptor())
147 .expect("Could not connect to VfioHandler");
148}
149
David Brazdilafc9a9e2023-01-12 16:08:10 +0000150fn is_valid_guest_cid(cid: Cid) -> bool {
151 (GUEST_CID_MIN..=GUEST_CID_MAX).contains(&cid)
152}
153
154/// Singleton service for allocating globally-unique VM resources, such as the CID, and running
155/// singleton servers, like tombstone receiver.
156#[derive(Debug, Default)]
157pub struct VirtualizationServiceInternal {
158 state: Arc<Mutex<GlobalState>>,
159}
160
161impl VirtualizationServiceInternal {
162 pub fn init() -> VirtualizationServiceInternal {
163 let service = VirtualizationServiceInternal::default();
164
165 std::thread::spawn(|| {
166 if let Err(e) = handle_stream_connection_tombstoned() {
167 warn!("Error receiving tombstone from guest or writing them. Error: {:?}", e);
168 }
169 });
170
171 service
172 }
173}
174
175impl Interface for VirtualizationServiceInternal {}
176
177impl IVirtualizationServiceInternal for VirtualizationServiceInternal {
178 fn removeMemlockRlimit(&self) -> binder::Result<()> {
179 let pid = get_calling_pid();
180 let lim = libc::rlimit { rlim_cur: libc::RLIM_INFINITY, rlim_max: libc::RLIM_INFINITY };
181
Andrew Walbranb58d1b42023-07-07 13:54:49 +0100182 // SAFETY: borrowing the new limit struct only
David Brazdilafc9a9e2023-01-12 16:08:10 +0000183 let ret = unsafe { libc::prlimit(pid, libc::RLIMIT_MEMLOCK, &lim, std::ptr::null_mut()) };
184
185 match ret {
186 0 => Ok(()),
Jiyong Park2227eaa2023-08-04 11:59:18 +0900187 -1 => Err(std::io::Error::last_os_error().into()),
188 n => Err(anyhow!("Unexpected return value from prlimit(): {n}")),
David Brazdilafc9a9e2023-01-12 16:08:10 +0000189 }
Jiyong Park2227eaa2023-08-04 11:59:18 +0900190 .or_binder_exception(ExceptionCode::ILLEGAL_STATE)
David Brazdilafc9a9e2023-01-12 16:08:10 +0000191 }
192
193 fn allocateGlobalVmContext(
194 &self,
195 requester_debug_pid: i32,
196 ) -> binder::Result<Strong<dyn IGlobalVmContext>> {
197 check_manage_access()?;
198
199 let requester_uid = get_calling_uid();
200 let requester_debug_pid = requester_debug_pid as pid_t;
201 let state = &mut *self.state.lock().unwrap();
Jiyong Park2227eaa2023-08-04 11:59:18 +0900202 state
203 .allocate_vm_context(requester_uid, requester_debug_pid)
204 .or_binder_exception(ExceptionCode::ILLEGAL_STATE)
David Brazdilafc9a9e2023-01-12 16:08:10 +0000205 }
206
207 fn atomVmBooted(&self, atom: &AtomVmBooted) -> Result<(), Status> {
208 forward_vm_booted_atom(atom);
209 Ok(())
210 }
211
212 fn atomVmCreationRequested(&self, atom: &AtomVmCreationRequested) -> Result<(), Status> {
213 forward_vm_creation_atom(atom);
214 Ok(())
215 }
216
217 fn atomVmExited(&self, atom: &AtomVmExited) -> Result<(), Status> {
218 forward_vm_exited_atom(atom);
219 Ok(())
220 }
221
222 fn debugListVms(&self) -> binder::Result<Vec<VirtualMachineDebugInfo>> {
223 check_debug_access()?;
224
225 let state = &mut *self.state.lock().unwrap();
226 let cids = state
227 .held_contexts
228 .iter()
229 .filter_map(|(_, inst)| Weak::upgrade(inst))
230 .map(|vm| VirtualMachineDebugInfo {
231 cid: vm.cid as i32,
232 temporaryDirectory: vm.get_temp_dir().to_string_lossy().to_string(),
233 requesterUid: vm.requester_uid as i32,
Charisee96113f32023-01-26 09:00:42 +0000234 requesterPid: vm.requester_debug_pid,
David Brazdilafc9a9e2023-01-12 16:08:10 +0000235 })
236 .collect();
237 Ok(cids)
238 }
Alice Wangc2fec932023-02-23 16:24:02 +0000239
Alice Wange64dd182024-01-17 15:57:55 +0000240 fn enableTestAttestation(&self) -> binder::Result<()> {
241 check_manage_access()?;
242 check_use_custom_virtual_machine()?;
243 if !cfg!(remote_attestation) {
244 return Err(Status::new_exception_str(
245 ExceptionCode::UNSUPPORTED_OPERATION,
246 Some(
247 "enableTestAttestation is not supported with the remote_attestation \
248 feature disabled",
249 ),
250 ))
251 .with_log();
252 }
253 let res = generate_ecdsa_p256_key_pair()
254 .context("Failed to generate ECDSA P-256 key pair for testing")
255 .with_log()
256 .or_service_specific_exception(-1)?;
257 match res {
258 Response::GenerateEcdsaP256KeyPair(key_pair) => {
259 FAKE_PROVISIONED_KEY_BLOB_FOR_TESTING
260 .lock()
261 .unwrap()
262 .replace(key_pair.key_blob.to_vec());
263 Ok(())
264 }
265 _ => Err(remote_provisioning::to_service_specific_error(res)),
266 }
267 .with_log()
268 }
269
Alice Wangbff017f2023-11-09 14:43:28 +0000270 fn requestAttestation(
271 &self,
272 csr: &[u8],
273 requester_uid: i32,
Alice Wange64dd182024-01-17 15:57:55 +0000274 test_mode: bool,
Alice Wangbff017f2023-11-09 14:43:28 +0000275 ) -> binder::Result<Vec<Certificate>> {
Alice Wangc2fec932023-02-23 16:24:02 +0000276 check_manage_access()?;
Alice Wang4c6c5582023-11-23 15:07:18 +0000277 if !cfg!(remote_attestation) {
278 return Err(Status::new_exception_str(
Alice Wange9ac2db2023-09-08 15:13:13 +0000279 ExceptionCode::UNSUPPORTED_OPERATION,
280 Some(
Alice Wanga410b642023-10-18 09:05:15 +0000281 "requestAttestation is not supported with the remote_attestation feature \
282 disabled",
Alice Wange9ac2db2023-09-08 15:13:13 +0000283 ),
284 ))
Alice Wang4c6c5582023-11-23 15:07:18 +0000285 .with_log();
Alice Wange9ac2db2023-09-08 15:13:13 +0000286 }
Alice Wang4c6c5582023-11-23 15:07:18 +0000287 info!("Received csr. Requestting attestation...");
Alice Wange64dd182024-01-17 15:57:55 +0000288 let (key_blob, certificate_chain) = if test_mode {
289 check_use_custom_virtual_machine()?;
290 info!("Using the fake key blob for testing...");
291 (
292 FAKE_PROVISIONED_KEY_BLOB_FOR_TESTING
293 .lock()
294 .unwrap()
295 .clone()
296 .ok_or_else(|| anyhow!("No key blob for testing"))
297 .with_log()
298 .or_service_specific_exception(-1)?,
299 FAKE_CERTIFICATE_FOR_TESTING.to_vec(),
300 )
301 } else {
302 info!("Retrieving the remotely provisioned keys from RKPD...");
303 let attestation_key = get_rkpd_attestation_key(
304 REMOTELY_PROVISIONED_COMPONENT_SERVICE_NAME,
305 requester_uid as u32,
306 )
307 .context("Failed to retrieve the remotely provisioned keys")
308 .with_log()
309 .or_service_specific_exception(-1)?;
310 (attestation_key.keyBlob, attestation_key.encodedCertChain)
311 };
312 let mut certificate_chain = split_x509_certificate_chain(&certificate_chain)
Alice Wang4c6c5582023-11-23 15:07:18 +0000313 .context("Failed to split the remotely provisioned certificate chain")
314 .with_log()
315 .or_service_specific_exception(-1)?;
316 if certificate_chain.is_empty() {
317 return Err(Status::new_service_specific_error_str(
318 -1,
319 Some("The certificate chain should contain at least 1 certificate"),
320 ))
321 .with_log();
322 }
Alice Wang20b8ebc2023-11-17 09:54:47 +0000323 let certificate = request_attestation(
324 csr.to_vec(),
Alice Wange64dd182024-01-17 15:57:55 +0000325 key_blob,
Alice Wang20b8ebc2023-11-17 09:54:47 +0000326 certificate_chain[0].encodedCertificate.clone(),
327 )
328 .context("Failed to request attestation")
329 .with_log()
330 .or_service_specific_exception(-1)?;
Alice Wang4c6c5582023-11-23 15:07:18 +0000331 certificate_chain.insert(0, Certificate { encodedCertificate: certificate });
332
333 Ok(certificate_chain)
Alice Wangc2fec932023-02-23 16:24:02 +0000334 }
Inseob Kim53d0b212023-07-20 16:58:37 +0900335
336 fn getAssignableDevices(&self) -> binder::Result<Vec<AssignableDevice>> {
337 check_use_custom_virtual_machine()?;
338
Inseob Kim7307a892023-09-14 13:37:58 +0900339 Ok(get_assignable_devices()?
340 .device
341 .into_iter()
342 .map(|x| AssignableDevice { node: x.sysfs_path, kind: x.kind })
343 .collect::<Vec<_>>())
Inseob Kim53d0b212023-07-20 16:58:37 +0900344 }
Inseob Kim1ca0f652023-07-20 17:18:12 +0900345
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000346 fn bindDevicesToVfioDriver(
347 &self,
348 devices: &[String],
349 ) -> binder::Result<Vec<Strong<dyn IBoundDevice>>> {
Inseob Kim1ca0f652023-07-20 17:18:12 +0900350 check_use_custom_virtual_machine()?;
351
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000352 let devices = get_assignable_devices()?
Inseob Kim7307a892023-09-14 13:37:58 +0900353 .device
354 .into_iter()
355 .filter_map(|x| {
356 if devices.contains(&x.sysfs_path) {
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000357 Some(VfioDev { sysfsPath: x.sysfs_path, dtboLabel: x.dtbo_label })
Inseob Kim7307a892023-09-14 13:37:58 +0900358 } else {
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000359 warn!("device {} is not assignable", x.sysfs_path);
Inseob Kim7307a892023-09-14 13:37:58 +0900360 None
361 }
362 })
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000363 .collect::<Vec<VfioDev>>();
364
365 VFIO_SERVICE.bindDevicesToVfioDriver(devices.as_slice())
Inseob Kim1ca0f652023-07-20 17:18:12 +0900366 }
David Brazdil2dfefd12023-11-17 14:07:36 +0000367
368 fn getDtboFile(&self) -> binder::Result<ParcelFileDescriptor> {
369 check_use_custom_virtual_machine()?;
370
371 let state = &mut *self.state.lock().unwrap();
372 let file = state.get_dtbo_file().or_service_specific_exception(-1)?;
373 Ok(ParcelFileDescriptor::new(file))
374 }
Inseob Kim1ca0f652023-07-20 17:18:12 +0900375}
376
Inseob Kimc4a774d2023-08-30 12:48:43 +0900377// KEEP IN SYNC WITH assignable_devices.xsd
378#[derive(Debug, Deserialize)]
379struct Device {
380 kind: String,
Jaewan Kim35e818d2023-10-18 05:36:38 +0000381 dtbo_label: String,
Inseob Kimc4a774d2023-08-30 12:48:43 +0900382 sysfs_path: String,
383}
384
Inseob Kim7307a892023-09-14 13:37:58 +0900385#[derive(Debug, Default, Deserialize)]
Inseob Kimc4a774d2023-08-30 12:48:43 +0900386struct Devices {
387 device: Vec<Device>,
388}
389
Inseob Kim7307a892023-09-14 13:37:58 +0900390fn get_assignable_devices() -> binder::Result<Devices> {
391 let xml_path = Path::new("/vendor/etc/avf/assignable_devices.xml");
392 if !xml_path.exists() {
393 return Ok(Devices { ..Default::default() });
394 }
395
396 let xml = fs::read(xml_path)
397 .context("Failed to read assignable_devices.xml")
398 .with_log()
399 .or_service_specific_exception(-1)?;
400
401 let xml = String::from_utf8(xml)
402 .context("assignable_devices.xml is not a valid UTF-8 file")
403 .with_log()
404 .or_service_specific_exception(-1)?;
405
406 let mut devices: Devices = serde_xml_rs::from_str(&xml)
407 .context("can't parse assignable_devices.xml")
408 .with_log()
409 .or_service_specific_exception(-1)?;
410
411 let mut device_set = HashSet::new();
412 devices.device.retain(move |device| {
413 if device_set.contains(&device.sysfs_path) {
414 warn!("duplicated assignable device {device:?}; ignoring...");
415 return false;
416 }
417
418 if !Path::new(&device.sysfs_path).exists() {
419 warn!("assignable device {device:?} doesn't exist; ignoring...");
420 return false;
421 }
422
423 device_set.insert(device.sysfs_path.clone());
424 true
425 });
426 Ok(devices)
427}
428
Alice Wang4c6c5582023-11-23 15:07:18 +0000429fn split_x509_certificate_chain(mut cert_chain: &[u8]) -> Result<Vec<Certificate>> {
430 let mut out = Vec::new();
431 while !cert_chain.is_empty() {
Alice Wangfc5a44a2023-12-21 12:22:40 +0000432 let cert = X509::from_der(cert_chain)?;
433 let end = cert.to_der()?.len();
Alice Wang4c6c5582023-11-23 15:07:18 +0000434 out.push(Certificate { encodedCertificate: cert_chain[..end].to_vec() });
Alice Wangfc5a44a2023-12-21 12:22:40 +0000435 cert_chain = &cert_chain[end..];
Alice Wang4c6c5582023-11-23 15:07:18 +0000436 }
437 Ok(out)
438}
439
David Brazdilafc9a9e2023-01-12 16:08:10 +0000440#[derive(Debug, Default)]
441struct GlobalVmInstance {
442 /// The unique CID assigned to the VM for vsock communication.
443 cid: Cid,
444 /// UID of the client who requested this VM instance.
445 requester_uid: uid_t,
446 /// PID of the client who requested this VM instance.
447 requester_debug_pid: pid_t,
448}
449
450impl GlobalVmInstance {
451 fn get_temp_dir(&self) -> PathBuf {
452 let cid = self.cid;
453 format!("{TEMPORARY_DIRECTORY}/{cid}").into()
454 }
455}
456
457/// The mutable state of the VirtualizationServiceInternal. There should only be one instance
458/// of this struct.
459#[derive(Debug, Default)]
460struct GlobalState {
461 /// VM contexts currently allocated to running VMs. A CID is never recycled as long
462 /// as there is a strong reference held by a GlobalVmContext.
463 held_contexts: HashMap<Cid, Weak<GlobalVmInstance>>,
David Brazdil2dfefd12023-11-17 14:07:36 +0000464
465 /// Cached read-only FD of VM DTBO file. Also serves as a lock for creating the file.
466 dtbo_file: Mutex<Option<File>>,
David Brazdilafc9a9e2023-01-12 16:08:10 +0000467}
468
469impl GlobalState {
470 /// Get the next available CID, or an error if we have run out. The last CID used is stored in
471 /// a system property so that restart of virtualizationservice doesn't reuse CID while the host
472 /// Android is up.
473 fn get_next_available_cid(&mut self) -> Result<Cid> {
474 // Start trying to find a CID from the last used CID + 1. This ensures
475 // that we do not eagerly recycle CIDs. It makes debugging easier but
476 // also means that retrying to allocate a CID, eg. because it is
477 // erroneously occupied by a process, will not recycle the same CID.
478 let last_cid_prop =
479 system_properties::read(SYSPROP_LAST_CID)?.and_then(|val| match val.parse::<Cid>() {
480 Ok(num) => {
481 if is_valid_guest_cid(num) {
482 Some(num)
483 } else {
484 error!("Invalid value '{}' of property '{}'", num, SYSPROP_LAST_CID);
485 None
486 }
487 }
488 Err(_) => {
489 error!("Invalid value '{}' of property '{}'", val, SYSPROP_LAST_CID);
490 None
491 }
492 });
493
494 let first_cid = if let Some(last_cid) = last_cid_prop {
495 if last_cid == GUEST_CID_MAX {
496 GUEST_CID_MIN
497 } else {
498 last_cid + 1
499 }
500 } else {
501 GUEST_CID_MIN
502 };
503
504 let cid = self
505 .find_available_cid(first_cid..=GUEST_CID_MAX)
506 .or_else(|| self.find_available_cid(GUEST_CID_MIN..first_cid))
507 .ok_or_else(|| anyhow!("Could not find an available CID."))?;
508
509 system_properties::write(SYSPROP_LAST_CID, &format!("{}", cid))?;
510 Ok(cid)
511 }
512
513 fn find_available_cid<I>(&self, mut range: I) -> Option<Cid>
514 where
515 I: Iterator<Item = Cid>,
516 {
517 range.find(|cid| !self.held_contexts.contains_key(cid))
518 }
519
520 fn allocate_vm_context(
521 &mut self,
522 requester_uid: uid_t,
523 requester_debug_pid: pid_t,
524 ) -> Result<Strong<dyn IGlobalVmContext>> {
525 // Garbage collect unused VM contexts.
526 self.held_contexts.retain(|_, instance| instance.strong_count() > 0);
527
528 let cid = self.get_next_available_cid()?;
529 let instance = Arc::new(GlobalVmInstance { cid, requester_uid, requester_debug_pid });
David Brazdil2dfefd12023-11-17 14:07:36 +0000530 create_temporary_directory(&instance.get_temp_dir(), Some(requester_uid))?;
David Brazdilafc9a9e2023-01-12 16:08:10 +0000531
532 self.held_contexts.insert(cid, Arc::downgrade(&instance));
533 let binder = GlobalVmContext { instance, ..Default::default() };
534 Ok(BnGlobalVmContext::new_binder(binder, BinderFeatures::default()))
535 }
David Brazdil2dfefd12023-11-17 14:07:36 +0000536
537 fn get_dtbo_file(&mut self) -> Result<File> {
538 let mut file = self.dtbo_file.lock().unwrap();
539
540 let fd = if let Some(ref_fd) = &*file {
541 ref_fd.try_clone()?
542 } else {
543 let path = get_or_create_common_dir()?.join("vm.dtbo");
544 if path.exists() {
545 // All temporary files are deleted when the service is started.
546 // If the file exists but the FD is not cached, the file is
547 // likely corrupted.
548 remove_file(&path).context("Failed to clone cached VM DTBO file descriptor")?;
549 }
550
551 // Open a write-only file descriptor for vfio_handler.
552 let write_fd = File::create(&path).context("Failed to create VM DTBO file")?;
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000553 VFIO_SERVICE.writeVmDtbo(&ParcelFileDescriptor::new(write_fd))?;
David Brazdil2dfefd12023-11-17 14:07:36 +0000554
555 // Open read-only. This FD will be cached and returned to clients.
556 let read_fd = File::open(&path).context("Failed to open VM DTBO file")?;
557 let read_fd_clone =
558 read_fd.try_clone().context("Failed to clone VM DTBO file descriptor")?;
559 *file = Some(read_fd);
560 read_fd_clone
561 };
562
563 Ok(fd)
564 }
David Brazdilafc9a9e2023-01-12 16:08:10 +0000565}
566
David Brazdil2dfefd12023-11-17 14:07:36 +0000567fn create_temporary_directory(path: &PathBuf, requester_uid: Option<uid_t>) -> Result<()> {
568 // Directory may exist if previous attempt to create it had failed.
569 // Delete it before trying again.
David Brazdilafc9a9e2023-01-12 16:08:10 +0000570 if path.as_path().exists() {
571 remove_temporary_dir(path).unwrap_or_else(|e| {
572 warn!("Could not delete temporary directory {:?}: {}", path, e);
573 });
574 }
David Brazdil2dfefd12023-11-17 14:07:36 +0000575 // Create directory.
576 create_dir(path).with_context(|| format!("Could not create temporary directory {:?}", path))?;
577 // If provided, change ownership to client's UID but system's GID, and permissions 0700.
David Brazdilafc9a9e2023-01-12 16:08:10 +0000578 // If the chown() fails, this will leave behind an empty directory that will get removed
579 // at the next attempt, or if virtualizationservice is restarted.
David Brazdil2dfefd12023-11-17 14:07:36 +0000580 if let Some(uid) = requester_uid {
581 chown(path, Some(Uid::from_raw(uid)), None).with_context(|| {
582 format!("Could not set ownership of temporary directory {:?}", path)
583 })?;
584 }
David Brazdilafc9a9e2023-01-12 16:08:10 +0000585 Ok(())
586}
587
588/// Removes a directory owned by a different user by first changing its owner back
589/// to VirtualizationService.
590pub fn remove_temporary_dir(path: &PathBuf) -> Result<()> {
Alice Wangd1b11a02023-04-18 12:30:20 +0000591 ensure!(path.as_path().is_dir(), "Path {:?} is not a directory", path);
David Brazdilafc9a9e2023-01-12 16:08:10 +0000592 chown(path, Some(Uid::current()), None)?;
593 set_permissions(path, Permissions::from_mode(0o700))?;
Alice Wangd1b11a02023-04-18 12:30:20 +0000594 remove_dir_all(path)?;
David Brazdilafc9a9e2023-01-12 16:08:10 +0000595 Ok(())
596}
597
David Brazdil2dfefd12023-11-17 14:07:36 +0000598fn get_or_create_common_dir() -> Result<PathBuf> {
599 let path = Path::new(TEMPORARY_DIRECTORY).join("common");
600 if !path.exists() {
601 create_temporary_directory(&path, None)?;
602 }
603 Ok(path)
604}
605
David Brazdilafc9a9e2023-01-12 16:08:10 +0000606/// Implementation of the AIDL `IGlobalVmContext` interface.
607#[derive(Debug, Default)]
608struct GlobalVmContext {
609 /// Strong reference to the context's instance data structure.
610 instance: Arc<GlobalVmInstance>,
611 /// Keeps our service process running as long as this VM context exists.
612 #[allow(dead_code)]
613 lazy_service_guard: LazyServiceGuard,
614}
615
616impl Interface for GlobalVmContext {}
617
618impl IGlobalVmContext for GlobalVmContext {
619 fn getCid(&self) -> binder::Result<i32> {
620 Ok(self.instance.cid as i32)
621 }
622
623 fn getTemporaryDirectory(&self) -> binder::Result<String> {
624 Ok(self.instance.get_temp_dir().to_string_lossy().to_string())
625 }
626}
627
628fn handle_stream_connection_tombstoned() -> Result<()> {
629 // Should not listen for tombstones on a guest VM's port.
630 assert!(!is_valid_guest_cid(VM_TOMBSTONES_SERVICE_PORT as Cid));
631 let listener =
632 VsockListener::bind_with_cid_port(VMADDR_CID_HOST, VM_TOMBSTONES_SERVICE_PORT as Cid)?;
633 for incoming_stream in listener.incoming() {
634 let mut incoming_stream = match incoming_stream {
635 Err(e) => {
636 warn!("invalid incoming connection: {:?}", e);
637 continue;
638 }
639 Ok(s) => s,
640 };
641 std::thread::spawn(move || {
642 if let Err(e) = handle_tombstone(&mut incoming_stream) {
643 error!("Failed to write tombstone- {:?}", e);
644 }
645 });
646 }
647 Ok(())
648}
649
650fn handle_tombstone(stream: &mut VsockStream) -> Result<()> {
651 if let Ok(addr) = stream.peer_addr() {
652 info!("Vsock Stream connected to cid={} for tombstones", addr.cid());
653 }
654 let tb_connection =
655 TombstonedConnection::connect(std::process::id() as i32, DebuggerdDumpType::Tombstone)
656 .context("Failed to connect to tombstoned")?;
657 let mut text_output = tb_connection
658 .text_output
659 .as_ref()
660 .ok_or_else(|| anyhow!("Could not get file to write the tombstones on"))?;
661 let mut num_bytes_read = 0;
662 loop {
663 let mut chunk_recv = [0; CHUNK_RECV_MAX_LEN];
664 let n = stream
665 .read(&mut chunk_recv)
666 .context("Failed to read tombstone data from Vsock stream")?;
667 if n == 0 {
668 break;
669 }
670 num_bytes_read += n;
671 text_output.write_all(&chunk_recv[0..n]).context("Failed to write guests tombstones")?;
672 }
673 info!("Received {} bytes from guest & wrote to tombstone file", num_bytes_read);
674 tb_connection.notify_completion()?;
675 Ok(())
676}
677
678/// Checks whether the caller has a specific permission
679fn check_permission(perm: &str) -> binder::Result<()> {
680 let calling_pid = get_calling_pid();
681 let calling_uid = get_calling_uid();
682 // Root can do anything
683 if calling_uid == 0 {
684 return Ok(());
685 }
686 let perm_svc: Strong<dyn IPermissionController::IPermissionController> =
687 binder::get_interface("permission")?;
688 if perm_svc.checkPermission(perm, calling_pid, calling_uid as i32)? {
689 Ok(())
690 } else {
Jiyong Park2227eaa2023-08-04 11:59:18 +0900691 Err(anyhow!("does not have the {} permission", perm))
692 .or_binder_exception(ExceptionCode::SECURITY)
David Brazdilafc9a9e2023-01-12 16:08:10 +0000693 }
694}
695
696/// Check whether the caller of the current Binder method is allowed to call debug methods.
697fn check_debug_access() -> binder::Result<()> {
698 check_permission("android.permission.DEBUG_VIRTUAL_MACHINE")
699}
700
701/// Check whether the caller of the current Binder method is allowed to manage VMs
702fn check_manage_access() -> binder::Result<()> {
703 check_permission("android.permission.MANAGE_VIRTUAL_MACHINE")
704}
Inseob Kim53d0b212023-07-20 16:58:37 +0900705
706/// Check whether the caller of the current Binder method is allowed to use custom VMs
707fn check_use_custom_virtual_machine() -> binder::Result<()> {
708 check_permission("android.permission.USE_CUSTOM_VIRTUAL_MACHINE")
709}
Alice Wang4c6c5582023-11-23 15:07:18 +0000710
711#[cfg(test)]
712mod tests {
713 use super::*;
714 use std::fs;
715
716 const TEST_RKP_CERT_CHAIN_PATH: &str = "testdata/rkp_cert_chain.der";
717
718 #[test]
719 fn splitting_x509_certificate_chain_succeeds() -> Result<()> {
720 let bytes = fs::read(TEST_RKP_CERT_CHAIN_PATH)?;
721 let cert_chain = split_x509_certificate_chain(&bytes)?;
722
723 assert_eq!(4, cert_chain.len());
724 for cert in cert_chain {
Alice Wangfc5a44a2023-12-21 12:22:40 +0000725 let x509_cert = X509::from_der(&cert.encodedCertificate)?;
726 assert_eq!(x509_cert.to_der()?.len(), cert.encodedCertificate.len());
Alice Wang4c6c5582023-11-23 15:07:18 +0000727 }
728 Ok(())
729 }
730}