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