blob: 1fa634d3cf3893807ef5fe5f34c3e071dd026c93 [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 Drysdalee64de8e2024-02-29 11:54:29 +000042use rustutils::{
43 system_properties,
44 users::{multiuser_get_app_id, multiuser_get_user_id},
45};
Inseob Kimc4a774d2023-08-30 12:48:43 +090046use serde::Deserialize;
Alan Stokesac667072024-02-19 16:26:00 +000047use service_vm_comm::Response;
Inseob Kimc4a774d2023-08-30 12:48:43 +090048use std::collections::{HashMap, HashSet};
David Brazdil2dfefd12023-11-17 14:07:36 +000049use std::fs::{self, create_dir, remove_dir_all, remove_file, set_permissions, File, Permissions};
David Brazdilafc9a9e2023-01-12 16:08:10 +000050use std::io::{Read, Write};
51use std::os::unix::fs::PermissionsExt;
52use std::os::unix::raw::{pid_t, uid_t};
Inseob Kim55438b22023-08-09 20:16:01 +090053use std::path::{Path, PathBuf};
Jeongik Cha7add2a42024-04-02 14:52:39 +090054use std::sync::{Arc, Condvar, Mutex, Weak};
David Brazdilafc9a9e2023-01-12 16:08:10 +000055use tombstoned_client::{DebuggerdDumpType, TombstonedConnection};
Alan Stokesac667072024-02-19 16:26:00 +000056use virtualizationcommon::Certificate::Certificate;
Alan Stokes30ccacb2024-02-20 14:59:02 +000057use virtualizationmaintenance::{
58 IVirtualizationMaintenance::IVirtualizationMaintenance,
59 IVirtualizationReconciliationCallback::IVirtualizationReconciliationCallback,
60};
Alan Stokesac667072024-02-19 16:26:00 +000061use virtualizationservice::{
62 AssignableDevice::AssignableDevice, VirtualMachineDebugInfo::VirtualMachineDebugInfo,
63};
64use virtualizationservice_internal::{
65 AtomVmBooted::AtomVmBooted,
66 AtomVmCreationRequested::AtomVmCreationRequested,
67 AtomVmExited::AtomVmExited,
68 IBoundDevice::IBoundDevice,
69 IGlobalVmContext::{BnGlobalVmContext, IGlobalVmContext},
70 IVfioHandler::VfioDev::VfioDev,
71 IVfioHandler::{BpVfioHandler, IVfioHandler},
David Drysdale79af2662024-02-19 14:50:31 +000072 IVirtualizationServiceInternal::IVirtualizationServiceInternal,
Alan Stokesac667072024-02-19 16:26:00 +000073};
74use virtualmachineservice::IVirtualMachineService::VM_TOMBSTONES_SERVICE_PORT;
David Brazdilafc9a9e2023-01-12 16:08:10 +000075use vsock::{VsockListener, VsockStream};
David Brazdilafc9a9e2023-01-12 16:08:10 +000076
77/// The unique ID of a VM used (together with a port number) for vsock communication.
78pub type Cid = u32;
79
David Brazdilafc9a9e2023-01-12 16:08:10 +000080/// Directory in which to write disk image files used while running VMs.
81pub const TEMPORARY_DIRECTORY: &str = "/data/misc/virtualizationservice";
82
83/// The first CID to assign to a guest VM managed by the VirtualizationService. CIDs lower than this
84/// are reserved for the host or other usage.
85const GUEST_CID_MIN: Cid = 2048;
86const GUEST_CID_MAX: Cid = 65535;
87
88const SYSPROP_LAST_CID: &str = "virtualizationservice.state.last_cid";
89
90const CHUNK_RECV_MAX_LEN: usize = 1024;
91
Alice Wange64dd182024-01-17 15:57:55 +000092/// The fake certificate is used for testing only when a client VM requests attestation in test
93/// mode, it is a single certificate extracted on an unregistered device for testing.
94/// Here is the snapshot of the certificate:
95///
96/// ```
97/// Certificate:
98/// Data:
99/// Version: 3 (0x2)
100/// Serial Number:
101/// 59:ae:50:98:95:e1:34:25:f1:21:93:c0:4c:e5:24:66
102/// Signature Algorithm: ecdsa-with-SHA256
103/// Issuer: CN = Droid Unregistered Device CA, O = Google Test LLC
104/// Validity
105/// Not Before: Feb 5 14:39:39 2024 GMT
106/// Not After : Feb 14 14:39:39 2024 GMT
107/// Subject: CN = 59ae509895e13425f12193c04ce52466, O = TEE
108/// Subject Public Key Info:
109/// Public Key Algorithm: id-ecPublicKey
110/// Public-Key: (256 bit)
111/// pub:
112/// 04:30:32:cd:95:12:b0:71:8b:b7:14:44:26:58:d5:
113/// 82:8c:25:55:2c:6d:ef:98:e3:4f:88:d0:74:82:09:
114/// 3e:8d:6c:f0:f2:18:d5:83:0e:0d:f2:ce:c5:15:38:
115/// e5:6a:e6:4d:4d:95:15:b7:24:e7:cb:4b:63:42:21:
116/// bc:36:c6:0a:d8
117/// ASN1 OID: prime256v1
118/// NIST CURVE: P-256
119/// X509v3 extensions:
120/// ...
121/// ```
122const FAKE_CERTIFICATE_FOR_TESTING: &[u8] = &[
123 0x30, 0x82, 0x01, 0xee, 0x30, 0x82, 0x01, 0x94, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x59,
124 0xae, 0x50, 0x98, 0x95, 0xe1, 0x34, 0x25, 0xf1, 0x21, 0x93, 0xc0, 0x4c, 0xe5, 0x24, 0x66, 0x30,
125 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x41, 0x31, 0x25, 0x30,
126 0x23, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1c, 0x44, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x55, 0x6e,
127 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x44, 0x65, 0x76, 0x69, 0x63,
128 0x65, 0x20, 0x43, 0x41, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0f, 0x47,
129 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x4c, 0x4c, 0x43, 0x30, 0x1e,
130 0x17, 0x0d, 0x32, 0x34, 0x30, 0x32, 0x30, 0x35, 0x31, 0x34, 0x33, 0x39, 0x33, 0x39, 0x5a, 0x17,
131 0x0d, 0x32, 0x34, 0x30, 0x32, 0x31, 0x34, 0x31, 0x34, 0x33, 0x39, 0x33, 0x39, 0x5a, 0x30, 0x39,
132 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x20, 0x35, 0x39, 0x61, 0x65, 0x35,
133 0x30, 0x39, 0x38, 0x39, 0x35, 0x65, 0x31, 0x33, 0x34, 0x32, 0x35, 0x66, 0x31, 0x32, 0x31, 0x39,
134 0x33, 0x63, 0x30, 0x34, 0x63, 0x65, 0x35, 0x32, 0x34, 0x36, 0x36, 0x31, 0x0c, 0x30, 0x0a, 0x06,
135 0x03, 0x55, 0x04, 0x0a, 0x13, 0x03, 0x54, 0x45, 0x45, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a,
136 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
137 0x03, 0x42, 0x00, 0x04, 0x30, 0x32, 0xcd, 0x95, 0x12, 0xb0, 0x71, 0x8b, 0xb7, 0x14, 0x44, 0x26,
138 0x58, 0xd5, 0x82, 0x8c, 0x25, 0x55, 0x2c, 0x6d, 0xef, 0x98, 0xe3, 0x4f, 0x88, 0xd0, 0x74, 0x82,
139 0x09, 0x3e, 0x8d, 0x6c, 0xf0, 0xf2, 0x18, 0xd5, 0x83, 0x0e, 0x0d, 0xf2, 0xce, 0xc5, 0x15, 0x38,
140 0xe5, 0x6a, 0xe6, 0x4d, 0x4d, 0x95, 0x15, 0xb7, 0x24, 0xe7, 0xcb, 0x4b, 0x63, 0x42, 0x21, 0xbc,
141 0x36, 0xc6, 0x0a, 0xd8, 0xa3, 0x76, 0x30, 0x74, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
142 0x16, 0x04, 0x14, 0x39, 0x81, 0x41, 0x0a, 0xb9, 0xf3, 0xf4, 0x5b, 0x75, 0x97, 0x4a, 0x46, 0xd6,
143 0x30, 0x9e, 0x1d, 0x7a, 0x3b, 0xec, 0xa8, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
144 0x30, 0x16, 0x80, 0x14, 0x82, 0xbd, 0x00, 0xde, 0xcb, 0xc5, 0xe7, 0x72, 0x87, 0x3d, 0x1c, 0x0a,
145 0x1e, 0x78, 0x4f, 0xf5, 0xd3, 0xc1, 0x3e, 0xb8, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
146 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f,
147 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x11, 0x06, 0x0a, 0x2b, 0x06, 0x01,
148 0x04, 0x01, 0xd6, 0x79, 0x02, 0x01, 0x1e, 0x04, 0x03, 0xa1, 0x01, 0x08, 0x30, 0x0a, 0x06, 0x08,
149 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00,
150 0xae, 0xd8, 0x40, 0x9e, 0x37, 0x3e, 0x5c, 0x9c, 0xe2, 0x93, 0x3d, 0x8c, 0xf7, 0x05, 0x10, 0xe7,
151 0xd1, 0x2b, 0x87, 0x8a, 0xee, 0xd6, 0x1e, 0x6c, 0x3b, 0xd2, 0x91, 0x3e, 0xa5, 0xdf, 0x91, 0x20,
152 0x02, 0x20, 0x7f, 0x0f, 0x29, 0x54, 0x60, 0x80, 0x07, 0x50, 0x5f, 0x56, 0x6b, 0x9f, 0xe0, 0x94,
153 0xb4, 0x3f, 0x3b, 0x0f, 0x61, 0xa0, 0x33, 0x40, 0xe6, 0x1a, 0x42, 0xda, 0x4b, 0xa4, 0xfd, 0x92,
154 0xb9, 0x0f,
155];
156
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000157lazy_static! {
Alice Wange64dd182024-01-17 15:57:55 +0000158 static ref FAKE_PROVISIONED_KEY_BLOB_FOR_TESTING: Mutex<Option<Vec<u8>>> = Mutex::new(None);
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000159 static ref VFIO_SERVICE: Strong<dyn IVfioHandler> =
160 wait_for_interface(<BpVfioHandler as IVfioHandler>::get_descriptor())
161 .expect("Could not connect to VfioHandler");
162}
163
David Brazdilafc9a9e2023-01-12 16:08:10 +0000164fn is_valid_guest_cid(cid: Cid) -> bool {
165 (GUEST_CID_MIN..=GUEST_CID_MAX).contains(&cid)
166}
167
168/// Singleton service for allocating globally-unique VM resources, such as the CID, and running
169/// singleton servers, like tombstone receiver.
David Drysdale79af2662024-02-19 14:50:31 +0000170#[derive(Clone)]
David Brazdilafc9a9e2023-01-12 16:08:10 +0000171pub struct VirtualizationServiceInternal {
172 state: Arc<Mutex<GlobalState>>,
Jeongik Cha7add2a42024-04-02 14:52:39 +0900173 display_service_set: Arc<Condvar>,
David Brazdilafc9a9e2023-01-12 16:08:10 +0000174}
175
176impl VirtualizationServiceInternal {
David Drysdale79af2662024-02-19 14:50:31 +0000177 pub fn init() -> VirtualizationServiceInternal {
Jeongik Cha7add2a42024-04-02 14:52:39 +0900178 let service = VirtualizationServiceInternal {
179 state: Arc::new(Mutex::new(GlobalState::new())),
180 display_service_set: Arc::new(Condvar::new()),
181 };
David Brazdilafc9a9e2023-01-12 16:08:10 +0000182
183 std::thread::spawn(|| {
184 if let Err(e) = handle_stream_connection_tombstoned() {
185 warn!("Error receiving tombstone from guest or writing them. Error: {:?}", e);
186 }
187 });
188
David Drysdale79af2662024-02-19 14:50:31 +0000189 service
David Brazdilafc9a9e2023-01-12 16:08:10 +0000190 }
191}
192
193impl Interface for VirtualizationServiceInternal {}
194
195impl IVirtualizationServiceInternal for VirtualizationServiceInternal {
Jeongik Cha7add2a42024-04-02 14:52:39 +0900196 fn setDisplayService(
197 &self,
198 ibinder: &binder::SpIBinder,
199 ) -> std::result::Result<(), binder::Status> {
200 check_manage_access()?;
201 check_use_custom_virtual_machine()?;
202 let state = &mut *self.state.lock().unwrap();
203 state.display_service = Some(ibinder.clone());
204 self.display_service_set.notify_all();
205 Ok(())
206 }
207
Jeongik Chaeee137d2024-04-03 22:13:14 +0900208 fn clearDisplayService(&self) -> std::result::Result<(), binder::Status> {
209 check_manage_access()?;
210 check_use_custom_virtual_machine()?;
211 let state = &mut *self.state.lock().unwrap();
212 state.display_service = None;
213 self.display_service_set.notify_all();
214 Ok(())
215 }
216
Jeongik Cha7add2a42024-04-02 14:52:39 +0900217 fn waitDisplayService(&self) -> std::result::Result<binder::SpIBinder, binder::Status> {
218 check_manage_access()?;
219 check_use_custom_virtual_machine()?;
220 let state = self
221 .display_service_set
222 .wait_while(self.state.lock().unwrap(), |state| state.display_service.is_none())
223 .unwrap();
224 Ok((state.display_service)
225 .as_ref()
226 .cloned()
227 .expect("Display service cannot be None in this context"))
228 }
David Brazdilafc9a9e2023-01-12 16:08:10 +0000229 fn removeMemlockRlimit(&self) -> binder::Result<()> {
230 let pid = get_calling_pid();
231 let lim = libc::rlimit { rlim_cur: libc::RLIM_INFINITY, rlim_max: libc::RLIM_INFINITY };
232
Andrew Walbranb58d1b42023-07-07 13:54:49 +0100233 // SAFETY: borrowing the new limit struct only
David Brazdilafc9a9e2023-01-12 16:08:10 +0000234 let ret = unsafe { libc::prlimit(pid, libc::RLIMIT_MEMLOCK, &lim, std::ptr::null_mut()) };
235
236 match ret {
237 0 => Ok(()),
Jiyong Park2227eaa2023-08-04 11:59:18 +0900238 -1 => Err(std::io::Error::last_os_error().into()),
239 n => Err(anyhow!("Unexpected return value from prlimit(): {n}")),
David Brazdilafc9a9e2023-01-12 16:08:10 +0000240 }
Jiyong Park2227eaa2023-08-04 11:59:18 +0900241 .or_binder_exception(ExceptionCode::ILLEGAL_STATE)
David Brazdilafc9a9e2023-01-12 16:08:10 +0000242 }
243
244 fn allocateGlobalVmContext(
245 &self,
246 requester_debug_pid: i32,
247 ) -> binder::Result<Strong<dyn IGlobalVmContext>> {
248 check_manage_access()?;
249
250 let requester_uid = get_calling_uid();
251 let requester_debug_pid = requester_debug_pid as pid_t;
252 let state = &mut *self.state.lock().unwrap();
Jiyong Park2227eaa2023-08-04 11:59:18 +0900253 state
254 .allocate_vm_context(requester_uid, requester_debug_pid)
255 .or_binder_exception(ExceptionCode::ILLEGAL_STATE)
David Brazdilafc9a9e2023-01-12 16:08:10 +0000256 }
257
258 fn atomVmBooted(&self, atom: &AtomVmBooted) -> Result<(), Status> {
259 forward_vm_booted_atom(atom);
260 Ok(())
261 }
262
263 fn atomVmCreationRequested(&self, atom: &AtomVmCreationRequested) -> Result<(), Status> {
264 forward_vm_creation_atom(atom);
265 Ok(())
266 }
267
268 fn atomVmExited(&self, atom: &AtomVmExited) -> Result<(), Status> {
269 forward_vm_exited_atom(atom);
270 Ok(())
271 }
272
273 fn debugListVms(&self) -> binder::Result<Vec<VirtualMachineDebugInfo>> {
274 check_debug_access()?;
275
276 let state = &mut *self.state.lock().unwrap();
277 let cids = state
278 .held_contexts
279 .iter()
280 .filter_map(|(_, inst)| Weak::upgrade(inst))
281 .map(|vm| VirtualMachineDebugInfo {
282 cid: vm.cid as i32,
283 temporaryDirectory: vm.get_temp_dir().to_string_lossy().to_string(),
284 requesterUid: vm.requester_uid as i32,
Charisee96113f32023-01-26 09:00:42 +0000285 requesterPid: vm.requester_debug_pid,
David Brazdilafc9a9e2023-01-12 16:08:10 +0000286 })
287 .collect();
288 Ok(cids)
289 }
Alice Wangc2fec932023-02-23 16:24:02 +0000290
Alice Wange64dd182024-01-17 15:57:55 +0000291 fn enableTestAttestation(&self) -> binder::Result<()> {
292 check_manage_access()?;
293 check_use_custom_virtual_machine()?;
294 if !cfg!(remote_attestation) {
295 return Err(Status::new_exception_str(
296 ExceptionCode::UNSUPPORTED_OPERATION,
297 Some(
298 "enableTestAttestation is not supported with the remote_attestation \
299 feature disabled",
300 ),
301 ))
302 .with_log();
303 }
304 let res = generate_ecdsa_p256_key_pair()
305 .context("Failed to generate ECDSA P-256 key pair for testing")
306 .with_log()
307 .or_service_specific_exception(-1)?;
Alice Wang5daec072024-03-15 15:31:17 +0000308 // Wait until the service VM shuts down, so that the Service VM will be restarted when
309 // the key generated in the current session will be used for attestation.
310 // This ensures that different Service VM sessions have the same KEK for the key blob.
311 service_vm_manager::wait_until_service_vm_shuts_down()
312 .context("Failed to wait until the service VM shuts down")
313 .with_log()
314 .or_service_specific_exception(-1)?;
Alice Wange64dd182024-01-17 15:57:55 +0000315 match res {
316 Response::GenerateEcdsaP256KeyPair(key_pair) => {
317 FAKE_PROVISIONED_KEY_BLOB_FOR_TESTING
318 .lock()
319 .unwrap()
320 .replace(key_pair.key_blob.to_vec());
321 Ok(())
322 }
323 _ => Err(remote_provisioning::to_service_specific_error(res)),
324 }
325 .with_log()
326 }
327
Alice Wangbff017f2023-11-09 14:43:28 +0000328 fn requestAttestation(
329 &self,
330 csr: &[u8],
331 requester_uid: i32,
Alice Wange64dd182024-01-17 15:57:55 +0000332 test_mode: bool,
Alice Wangbff017f2023-11-09 14:43:28 +0000333 ) -> binder::Result<Vec<Certificate>> {
Alice Wangc2fec932023-02-23 16:24:02 +0000334 check_manage_access()?;
Alice Wang4c6c5582023-11-23 15:07:18 +0000335 if !cfg!(remote_attestation) {
336 return Err(Status::new_exception_str(
Alice Wange9ac2db2023-09-08 15:13:13 +0000337 ExceptionCode::UNSUPPORTED_OPERATION,
338 Some(
Alice Wanga410b642023-10-18 09:05:15 +0000339 "requestAttestation is not supported with the remote_attestation feature \
340 disabled",
Alice Wange9ac2db2023-09-08 15:13:13 +0000341 ),
342 ))
Alice Wang4c6c5582023-11-23 15:07:18 +0000343 .with_log();
Alice Wange9ac2db2023-09-08 15:13:13 +0000344 }
Alice Wang0dcab552024-03-20 14:42:30 +0000345 if !remotely_provisioned_component_service_exists()? {
346 return Err(Status::new_exception_str(
347 ExceptionCode::UNSUPPORTED_OPERATION,
348 Some("AVF remotely provisioned component service is not declared"),
349 ))
350 .with_log();
351 }
Alice Wang4c6c5582023-11-23 15:07:18 +0000352 info!("Received csr. Requestting attestation...");
Alice Wange64dd182024-01-17 15:57:55 +0000353 let (key_blob, certificate_chain) = if test_mode {
354 check_use_custom_virtual_machine()?;
355 info!("Using the fake key blob for testing...");
356 (
357 FAKE_PROVISIONED_KEY_BLOB_FOR_TESTING
358 .lock()
359 .unwrap()
360 .clone()
361 .ok_or_else(|| anyhow!("No key blob for testing"))
362 .with_log()
363 .or_service_specific_exception(-1)?,
364 FAKE_CERTIFICATE_FOR_TESTING.to_vec(),
365 )
366 } else {
367 info!("Retrieving the remotely provisioned keys from RKPD...");
368 let attestation_key = get_rkpd_attestation_key(
369 REMOTELY_PROVISIONED_COMPONENT_SERVICE_NAME,
370 requester_uid as u32,
371 )
372 .context("Failed to retrieve the remotely provisioned keys")
373 .with_log()
374 .or_service_specific_exception(-1)?;
375 (attestation_key.keyBlob, attestation_key.encodedCertChain)
376 };
377 let mut certificate_chain = split_x509_certificate_chain(&certificate_chain)
Alice Wang4c6c5582023-11-23 15:07:18 +0000378 .context("Failed to split the remotely provisioned certificate chain")
379 .with_log()
380 .or_service_specific_exception(-1)?;
381 if certificate_chain.is_empty() {
382 return Err(Status::new_service_specific_error_str(
383 -1,
384 Some("The certificate chain should contain at least 1 certificate"),
385 ))
386 .with_log();
387 }
Alice Wang20b8ebc2023-11-17 09:54:47 +0000388 let certificate = request_attestation(
389 csr.to_vec(),
Alice Wange64dd182024-01-17 15:57:55 +0000390 key_blob,
Alice Wang20b8ebc2023-11-17 09:54:47 +0000391 certificate_chain[0].encodedCertificate.clone(),
392 )
393 .context("Failed to request attestation")
394 .with_log()
395 .or_service_specific_exception(-1)?;
Alice Wang4c6c5582023-11-23 15:07:18 +0000396 certificate_chain.insert(0, Certificate { encodedCertificate: certificate });
397
398 Ok(certificate_chain)
Alice Wangc2fec932023-02-23 16:24:02 +0000399 }
Inseob Kim53d0b212023-07-20 16:58:37 +0900400
Alice Wang0362f7f2024-03-21 08:16:26 +0000401 fn isRemoteAttestationSupported(&self) -> binder::Result<bool> {
402 remotely_provisioned_component_service_exists()
403 }
404
Inseob Kim53d0b212023-07-20 16:58:37 +0900405 fn getAssignableDevices(&self) -> binder::Result<Vec<AssignableDevice>> {
406 check_use_custom_virtual_machine()?;
407
Inseob Kim7307a892023-09-14 13:37:58 +0900408 Ok(get_assignable_devices()?
409 .device
410 .into_iter()
Jaewan Kim0c99c612024-03-23 00:44:14 +0900411 .map(|x| AssignableDevice { node: x.sysfs_path, dtbo_label: x.dtbo_label })
Inseob Kim7307a892023-09-14 13:37:58 +0900412 .collect::<Vec<_>>())
Inseob Kim53d0b212023-07-20 16:58:37 +0900413 }
Inseob Kim1ca0f652023-07-20 17:18:12 +0900414
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000415 fn bindDevicesToVfioDriver(
416 &self,
417 devices: &[String],
418 ) -> binder::Result<Vec<Strong<dyn IBoundDevice>>> {
Inseob Kim1ca0f652023-07-20 17:18:12 +0900419 check_use_custom_virtual_machine()?;
420
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000421 let devices = get_assignable_devices()?
Inseob Kim7307a892023-09-14 13:37:58 +0900422 .device
423 .into_iter()
424 .filter_map(|x| {
425 if devices.contains(&x.sysfs_path) {
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000426 Some(VfioDev { sysfsPath: x.sysfs_path, dtboLabel: x.dtbo_label })
Inseob Kim7307a892023-09-14 13:37:58 +0900427 } else {
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000428 warn!("device {} is not assignable", x.sysfs_path);
Inseob Kim7307a892023-09-14 13:37:58 +0900429 None
430 }
431 })
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000432 .collect::<Vec<VfioDev>>();
433
434 VFIO_SERVICE.bindDevicesToVfioDriver(devices.as_slice())
Inseob Kim1ca0f652023-07-20 17:18:12 +0900435 }
David Brazdil2dfefd12023-11-17 14:07:36 +0000436
437 fn getDtboFile(&self) -> binder::Result<ParcelFileDescriptor> {
438 check_use_custom_virtual_machine()?;
439
440 let state = &mut *self.state.lock().unwrap();
441 let file = state.get_dtbo_file().or_service_specific_exception(-1)?;
442 Ok(ParcelFileDescriptor::new(file))
443 }
Shikha Panwar61a74b52024-02-16 13:17:01 +0000444
Shikha Panwar61a74b52024-02-16 13:17:01 +0000445 fn allocateInstanceId(&self) -> binder::Result<[u8; 64]> {
446 let mut id = [0u8; 64];
447 id.try_fill(&mut rand::thread_rng())
448 .context("Failed to allocate instance_id")
449 .or_service_specific_exception(-1)?;
450 let uid = get_calling_uid();
451 info!("Allocated a VM's instance_id: {:?}, for uid: {:?}", hex::encode(id), uid);
David Drysdalee64de8e2024-02-29 11:54:29 +0000452 let state = &mut *self.state.lock().unwrap();
453 if let Some(sk_state) = &mut state.sk_state {
454 let user_id = multiuser_get_user_id(uid);
455 let app_id = multiuser_get_app_id(uid);
David Drysdale1138fa02024-03-19 13:06:23 +0000456 info!("Recording possible existence of state for (user_id={user_id}, app_id={app_id})");
David Drysdalee64de8e2024-02-29 11:54:29 +0000457 if let Err(e) = sk_state.add_id(&id, user_id, app_id) {
458 error!("Failed to record the instance_id: {e:?}");
459 }
460 }
461
Shikha Panwar61a74b52024-02-16 13:17:01 +0000462 Ok(id)
463 }
David Drysdale79af2662024-02-19 14:50:31 +0000464
465 fn removeVmInstance(&self, instance_id: &[u8; 64]) -> binder::Result<()> {
466 let state = &mut *self.state.lock().unwrap();
467 if let Some(sk_state) = &mut state.sk_state {
468 info!("removeVmInstance(): delete secret");
469 sk_state.delete_ids(&[*instance_id]);
470 } else {
471 info!("ignoring removeVmInstance() as no ISecretkeeper");
472 }
473 Ok(())
474 }
David Drysdale3aa62b32024-03-25 12:31:48 +0000475
476 fn claimVmInstance(&self, instance_id: &[u8; 64]) -> binder::Result<()> {
477 let state = &mut *self.state.lock().unwrap();
478 if let Some(sk_state) = &mut state.sk_state {
479 let uid = get_calling_uid();
480 info!(
481 "Claiming a VM's instance_id: {:?}, for uid: {:?}",
482 hex::encode(instance_id),
483 uid
484 );
485
486 let user_id = multiuser_get_user_id(uid);
487 let app_id = multiuser_get_app_id(uid);
488 info!("Recording possible new owner of state for (user_id={user_id}, app_id={app_id})");
489 if let Err(e) = sk_state.add_id(instance_id, user_id, app_id) {
490 error!("Failed to update the instance_id owner: {e:?}");
491 }
492 } else {
493 info!("ignoring claimVmInstance() as no ISecretkeeper");
494 }
495 Ok(())
496 }
David Drysdale79af2662024-02-19 14:50:31 +0000497}
498
499impl IVirtualizationMaintenance for VirtualizationServiceInternal {
500 fn appRemoved(&self, user_id: i32, app_id: i32) -> binder::Result<()> {
501 let state = &mut *self.state.lock().unwrap();
502 if let Some(sk_state) = &mut state.sk_state {
503 info!("packageRemoved(user_id={user_id}, app_id={app_id})");
504 sk_state.delete_ids_for_app(user_id, app_id).or_service_specific_exception(-1)?;
505 } else {
506 info!("ignoring packageRemoved(user_id={user_id}, app_id={app_id})");
507 }
508 Ok(())
509 }
510
511 fn userRemoved(&self, user_id: i32) -> binder::Result<()> {
512 let state = &mut *self.state.lock().unwrap();
513 if let Some(sk_state) = &mut state.sk_state {
514 info!("userRemoved({user_id})");
515 sk_state.delete_ids_for_user(user_id).or_service_specific_exception(-1)?;
516 } else {
517 info!("ignoring userRemoved(user_id={user_id})");
518 }
519 Ok(())
520 }
Alan Stokes30ccacb2024-02-20 14:59:02 +0000521
522 fn performReconciliation(
523 &self,
David Drysdale1138fa02024-03-19 13:06:23 +0000524 callback: &Strong<dyn IVirtualizationReconciliationCallback>,
Alan Stokes30ccacb2024-02-20 14:59:02 +0000525 ) -> binder::Result<()> {
David Drysdale1138fa02024-03-19 13:06:23 +0000526 let state = &mut *self.state.lock().unwrap();
527 if let Some(sk_state) = &mut state.sk_state {
528 info!("performReconciliation()");
529 sk_state.reconcile(callback).or_service_specific_exception(-1)?;
530 } else {
531 info!("ignoring performReconciliation()");
532 }
533 Ok(())
Alan Stokes30ccacb2024-02-20 14:59:02 +0000534 }
Inseob Kim1ca0f652023-07-20 17:18:12 +0900535}
536
Inseob Kimc4a774d2023-08-30 12:48:43 +0900537#[derive(Debug, Deserialize)]
538struct Device {
Jaewan Kim35e818d2023-10-18 05:36:38 +0000539 dtbo_label: String,
Inseob Kimc4a774d2023-08-30 12:48:43 +0900540 sysfs_path: String,
541}
542
Inseob Kim7307a892023-09-14 13:37:58 +0900543#[derive(Debug, Default, Deserialize)]
Inseob Kimc4a774d2023-08-30 12:48:43 +0900544struct Devices {
545 device: Vec<Device>,
546}
547
Inseob Kim7307a892023-09-14 13:37:58 +0900548fn get_assignable_devices() -> binder::Result<Devices> {
549 let xml_path = Path::new("/vendor/etc/avf/assignable_devices.xml");
550 if !xml_path.exists() {
551 return Ok(Devices { ..Default::default() });
552 }
553
554 let xml = fs::read(xml_path)
555 .context("Failed to read assignable_devices.xml")
556 .with_log()
557 .or_service_specific_exception(-1)?;
558
559 let xml = String::from_utf8(xml)
560 .context("assignable_devices.xml is not a valid UTF-8 file")
561 .with_log()
562 .or_service_specific_exception(-1)?;
563
564 let mut devices: Devices = serde_xml_rs::from_str(&xml)
565 .context("can't parse assignable_devices.xml")
566 .with_log()
567 .or_service_specific_exception(-1)?;
568
569 let mut device_set = HashSet::new();
570 devices.device.retain(move |device| {
571 if device_set.contains(&device.sysfs_path) {
572 warn!("duplicated assignable device {device:?}; ignoring...");
573 return false;
574 }
575
576 if !Path::new(&device.sysfs_path).exists() {
577 warn!("assignable device {device:?} doesn't exist; ignoring...");
578 return false;
579 }
580
581 device_set.insert(device.sysfs_path.clone());
582 true
583 });
584 Ok(devices)
585}
586
Alice Wang4c6c5582023-11-23 15:07:18 +0000587fn split_x509_certificate_chain(mut cert_chain: &[u8]) -> Result<Vec<Certificate>> {
588 let mut out = Vec::new();
589 while !cert_chain.is_empty() {
Alice Wangfc5a44a2023-12-21 12:22:40 +0000590 let cert = X509::from_der(cert_chain)?;
591 let end = cert.to_der()?.len();
Alice Wang4c6c5582023-11-23 15:07:18 +0000592 out.push(Certificate { encodedCertificate: cert_chain[..end].to_vec() });
Alice Wangfc5a44a2023-12-21 12:22:40 +0000593 cert_chain = &cert_chain[end..];
Alice Wang4c6c5582023-11-23 15:07:18 +0000594 }
595 Ok(out)
596}
597
David Brazdilafc9a9e2023-01-12 16:08:10 +0000598#[derive(Debug, Default)]
599struct GlobalVmInstance {
600 /// The unique CID assigned to the VM for vsock communication.
601 cid: Cid,
602 /// UID of the client who requested this VM instance.
603 requester_uid: uid_t,
604 /// PID of the client who requested this VM instance.
605 requester_debug_pid: pid_t,
606}
607
608impl GlobalVmInstance {
609 fn get_temp_dir(&self) -> PathBuf {
610 let cid = self.cid;
611 format!("{TEMPORARY_DIRECTORY}/{cid}").into()
612 }
613}
614
615/// The mutable state of the VirtualizationServiceInternal. There should only be one instance
616/// of this struct.
David Brazdilafc9a9e2023-01-12 16:08:10 +0000617struct GlobalState {
618 /// VM contexts currently allocated to running VMs. A CID is never recycled as long
619 /// as there is a strong reference held by a GlobalVmContext.
620 held_contexts: HashMap<Cid, Weak<GlobalVmInstance>>,
David Brazdil2dfefd12023-11-17 14:07:36 +0000621
622 /// Cached read-only FD of VM DTBO file. Also serves as a lock for creating the file.
623 dtbo_file: Mutex<Option<File>>,
David Drysdale79af2662024-02-19 14:50:31 +0000624
625 /// State relating to secrets held by (optional) Secretkeeper instance on behalf of VMs.
626 sk_state: Option<maintenance::State>,
Jeongik Cha7add2a42024-04-02 14:52:39 +0900627
628 display_service: Option<binder::SpIBinder>,
David Brazdilafc9a9e2023-01-12 16:08:10 +0000629}
630
631impl GlobalState {
David Drysdale79af2662024-02-19 14:50:31 +0000632 fn new() -> Self {
633 Self {
634 held_contexts: HashMap::new(),
635 dtbo_file: Mutex::new(None),
636 sk_state: maintenance::State::new(),
Jeongik Cha7add2a42024-04-02 14:52:39 +0900637 display_service: None,
David Drysdale79af2662024-02-19 14:50:31 +0000638 }
639 }
640
David Brazdilafc9a9e2023-01-12 16:08:10 +0000641 /// Get the next available CID, or an error if we have run out. The last CID used is stored in
642 /// a system property so that restart of virtualizationservice doesn't reuse CID while the host
643 /// Android is up.
644 fn get_next_available_cid(&mut self) -> Result<Cid> {
645 // Start trying to find a CID from the last used CID + 1. This ensures
646 // that we do not eagerly recycle CIDs. It makes debugging easier but
647 // also means that retrying to allocate a CID, eg. because it is
648 // erroneously occupied by a process, will not recycle the same CID.
649 let last_cid_prop =
650 system_properties::read(SYSPROP_LAST_CID)?.and_then(|val| match val.parse::<Cid>() {
651 Ok(num) => {
652 if is_valid_guest_cid(num) {
653 Some(num)
654 } else {
655 error!("Invalid value '{}' of property '{}'", num, SYSPROP_LAST_CID);
656 None
657 }
658 }
659 Err(_) => {
660 error!("Invalid value '{}' of property '{}'", val, SYSPROP_LAST_CID);
661 None
662 }
663 });
664
665 let first_cid = if let Some(last_cid) = last_cid_prop {
666 if last_cid == GUEST_CID_MAX {
667 GUEST_CID_MIN
668 } else {
669 last_cid + 1
670 }
671 } else {
672 GUEST_CID_MIN
673 };
674
675 let cid = self
676 .find_available_cid(first_cid..=GUEST_CID_MAX)
677 .or_else(|| self.find_available_cid(GUEST_CID_MIN..first_cid))
678 .ok_or_else(|| anyhow!("Could not find an available CID."))?;
679
680 system_properties::write(SYSPROP_LAST_CID, &format!("{}", cid))?;
681 Ok(cid)
682 }
683
684 fn find_available_cid<I>(&self, mut range: I) -> Option<Cid>
685 where
686 I: Iterator<Item = Cid>,
687 {
688 range.find(|cid| !self.held_contexts.contains_key(cid))
689 }
690
691 fn allocate_vm_context(
692 &mut self,
693 requester_uid: uid_t,
694 requester_debug_pid: pid_t,
695 ) -> Result<Strong<dyn IGlobalVmContext>> {
696 // Garbage collect unused VM contexts.
697 self.held_contexts.retain(|_, instance| instance.strong_count() > 0);
698
699 let cid = self.get_next_available_cid()?;
700 let instance = Arc::new(GlobalVmInstance { cid, requester_uid, requester_debug_pid });
David Brazdil2dfefd12023-11-17 14:07:36 +0000701 create_temporary_directory(&instance.get_temp_dir(), Some(requester_uid))?;
David Brazdilafc9a9e2023-01-12 16:08:10 +0000702
703 self.held_contexts.insert(cid, Arc::downgrade(&instance));
704 let binder = GlobalVmContext { instance, ..Default::default() };
705 Ok(BnGlobalVmContext::new_binder(binder, BinderFeatures::default()))
706 }
David Brazdil2dfefd12023-11-17 14:07:36 +0000707
708 fn get_dtbo_file(&mut self) -> Result<File> {
709 let mut file = self.dtbo_file.lock().unwrap();
710
711 let fd = if let Some(ref_fd) = &*file {
712 ref_fd.try_clone()?
713 } else {
714 let path = get_or_create_common_dir()?.join("vm.dtbo");
715 if path.exists() {
716 // All temporary files are deleted when the service is started.
717 // If the file exists but the FD is not cached, the file is
718 // likely corrupted.
719 remove_file(&path).context("Failed to clone cached VM DTBO file descriptor")?;
720 }
721
722 // Open a write-only file descriptor for vfio_handler.
723 let write_fd = File::create(&path).context("Failed to create VM DTBO file")?;
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000724 VFIO_SERVICE.writeVmDtbo(&ParcelFileDescriptor::new(write_fd))?;
David Brazdil2dfefd12023-11-17 14:07:36 +0000725
726 // Open read-only. This FD will be cached and returned to clients.
727 let read_fd = File::open(&path).context("Failed to open VM DTBO file")?;
728 let read_fd_clone =
729 read_fd.try_clone().context("Failed to clone VM DTBO file descriptor")?;
730 *file = Some(read_fd);
731 read_fd_clone
732 };
733
734 Ok(fd)
735 }
David Brazdilafc9a9e2023-01-12 16:08:10 +0000736}
737
David Brazdil2dfefd12023-11-17 14:07:36 +0000738fn create_temporary_directory(path: &PathBuf, requester_uid: Option<uid_t>) -> Result<()> {
739 // Directory may exist if previous attempt to create it had failed.
740 // Delete it before trying again.
David Brazdilafc9a9e2023-01-12 16:08:10 +0000741 if path.as_path().exists() {
742 remove_temporary_dir(path).unwrap_or_else(|e| {
743 warn!("Could not delete temporary directory {:?}: {}", path, e);
744 });
745 }
David Brazdil2dfefd12023-11-17 14:07:36 +0000746 // Create directory.
747 create_dir(path).with_context(|| format!("Could not create temporary directory {:?}", path))?;
748 // If provided, change ownership to client's UID but system's GID, and permissions 0700.
David Brazdilafc9a9e2023-01-12 16:08:10 +0000749 // If the chown() fails, this will leave behind an empty directory that will get removed
750 // at the next attempt, or if virtualizationservice is restarted.
David Brazdil2dfefd12023-11-17 14:07:36 +0000751 if let Some(uid) = requester_uid {
752 chown(path, Some(Uid::from_raw(uid)), None).with_context(|| {
753 format!("Could not set ownership of temporary directory {:?}", path)
754 })?;
755 }
David Brazdilafc9a9e2023-01-12 16:08:10 +0000756 Ok(())
757}
758
759/// Removes a directory owned by a different user by first changing its owner back
760/// to VirtualizationService.
761pub fn remove_temporary_dir(path: &PathBuf) -> Result<()> {
Alice Wangd1b11a02023-04-18 12:30:20 +0000762 ensure!(path.as_path().is_dir(), "Path {:?} is not a directory", path);
David Brazdilafc9a9e2023-01-12 16:08:10 +0000763 chown(path, Some(Uid::current()), None)?;
764 set_permissions(path, Permissions::from_mode(0o700))?;
Alice Wangd1b11a02023-04-18 12:30:20 +0000765 remove_dir_all(path)?;
David Brazdilafc9a9e2023-01-12 16:08:10 +0000766 Ok(())
767}
768
David Brazdil2dfefd12023-11-17 14:07:36 +0000769fn get_or_create_common_dir() -> Result<PathBuf> {
770 let path = Path::new(TEMPORARY_DIRECTORY).join("common");
771 if !path.exists() {
772 create_temporary_directory(&path, None)?;
773 }
774 Ok(path)
775}
776
David Brazdilafc9a9e2023-01-12 16:08:10 +0000777/// Implementation of the AIDL `IGlobalVmContext` interface.
778#[derive(Debug, Default)]
779struct GlobalVmContext {
780 /// Strong reference to the context's instance data structure.
781 instance: Arc<GlobalVmInstance>,
782 /// Keeps our service process running as long as this VM context exists.
783 #[allow(dead_code)]
784 lazy_service_guard: LazyServiceGuard,
785}
786
787impl Interface for GlobalVmContext {}
788
789impl IGlobalVmContext for GlobalVmContext {
790 fn getCid(&self) -> binder::Result<i32> {
791 Ok(self.instance.cid as i32)
792 }
793
794 fn getTemporaryDirectory(&self) -> binder::Result<String> {
795 Ok(self.instance.get_temp_dir().to_string_lossy().to_string())
796 }
797}
798
799fn handle_stream_connection_tombstoned() -> Result<()> {
800 // Should not listen for tombstones on a guest VM's port.
801 assert!(!is_valid_guest_cid(VM_TOMBSTONES_SERVICE_PORT as Cid));
802 let listener =
803 VsockListener::bind_with_cid_port(VMADDR_CID_HOST, VM_TOMBSTONES_SERVICE_PORT as Cid)?;
804 for incoming_stream in listener.incoming() {
805 let mut incoming_stream = match incoming_stream {
806 Err(e) => {
807 warn!("invalid incoming connection: {:?}", e);
808 continue;
809 }
810 Ok(s) => s,
811 };
812 std::thread::spawn(move || {
813 if let Err(e) = handle_tombstone(&mut incoming_stream) {
814 error!("Failed to write tombstone- {:?}", e);
815 }
816 });
817 }
818 Ok(())
819}
820
821fn handle_tombstone(stream: &mut VsockStream) -> Result<()> {
822 if let Ok(addr) = stream.peer_addr() {
823 info!("Vsock Stream connected to cid={} for tombstones", addr.cid());
824 }
825 let tb_connection =
826 TombstonedConnection::connect(std::process::id() as i32, DebuggerdDumpType::Tombstone)
827 .context("Failed to connect to tombstoned")?;
828 let mut text_output = tb_connection
829 .text_output
830 .as_ref()
831 .ok_or_else(|| anyhow!("Could not get file to write the tombstones on"))?;
832 let mut num_bytes_read = 0;
833 loop {
834 let mut chunk_recv = [0; CHUNK_RECV_MAX_LEN];
835 let n = stream
836 .read(&mut chunk_recv)
837 .context("Failed to read tombstone data from Vsock stream")?;
838 if n == 0 {
839 break;
840 }
841 num_bytes_read += n;
842 text_output.write_all(&chunk_recv[0..n]).context("Failed to write guests tombstones")?;
843 }
844 info!("Received {} bytes from guest & wrote to tombstone file", num_bytes_read);
845 tb_connection.notify_completion()?;
846 Ok(())
847}
848
Alice Wang0dcab552024-03-20 14:42:30 +0000849fn remotely_provisioned_component_service_exists() -> binder::Result<bool> {
850 Ok(binder::is_declared(REMOTELY_PROVISIONED_COMPONENT_SERVICE_NAME)?)
851}
852
David Brazdilafc9a9e2023-01-12 16:08:10 +0000853/// Checks whether the caller has a specific permission
854fn check_permission(perm: &str) -> binder::Result<()> {
855 let calling_pid = get_calling_pid();
856 let calling_uid = get_calling_uid();
857 // Root can do anything
858 if calling_uid == 0 {
859 return Ok(());
860 }
861 let perm_svc: Strong<dyn IPermissionController::IPermissionController> =
862 binder::get_interface("permission")?;
863 if perm_svc.checkPermission(perm, calling_pid, calling_uid as i32)? {
864 Ok(())
865 } else {
Jiyong Park2227eaa2023-08-04 11:59:18 +0900866 Err(anyhow!("does not have the {} permission", perm))
867 .or_binder_exception(ExceptionCode::SECURITY)
David Brazdilafc9a9e2023-01-12 16:08:10 +0000868 }
869}
870
871/// Check whether the caller of the current Binder method is allowed to call debug methods.
872fn check_debug_access() -> binder::Result<()> {
873 check_permission("android.permission.DEBUG_VIRTUAL_MACHINE")
874}
875
876/// Check whether the caller of the current Binder method is allowed to manage VMs
877fn check_manage_access() -> binder::Result<()> {
878 check_permission("android.permission.MANAGE_VIRTUAL_MACHINE")
879}
Inseob Kim53d0b212023-07-20 16:58:37 +0900880
881/// Check whether the caller of the current Binder method is allowed to use custom VMs
882fn check_use_custom_virtual_machine() -> binder::Result<()> {
883 check_permission("android.permission.USE_CUSTOM_VIRTUAL_MACHINE")
884}
Alice Wang4c6c5582023-11-23 15:07:18 +0000885
886#[cfg(test)]
887mod tests {
888 use super::*;
Alice Wang4c6c5582023-11-23 15:07:18 +0000889
890 const TEST_RKP_CERT_CHAIN_PATH: &str = "testdata/rkp_cert_chain.der";
891
892 #[test]
893 fn splitting_x509_certificate_chain_succeeds() -> Result<()> {
894 let bytes = fs::read(TEST_RKP_CERT_CHAIN_PATH)?;
895 let cert_chain = split_x509_certificate_chain(&bytes)?;
896
897 assert_eq!(4, cert_chain.len());
898 for cert in cert_chain {
Alice Wangfc5a44a2023-12-21 12:22:40 +0000899 let x509_cert = X509::from_der(&cert.encodedCertificate)?;
900 assert_eq!(x509_cert.to_der()?.len(), cert.encodedCertificate.len());
Alice Wang4c6c5582023-11-23 15:07:18 +0000901 }
902 Ok(())
903 }
904}