blob: 9258b82429796f0b0c76a68d02f62bf19b7fbc9e [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
208 fn waitDisplayService(&self) -> std::result::Result<binder::SpIBinder, binder::Status> {
209 check_manage_access()?;
210 check_use_custom_virtual_machine()?;
211 let state = self
212 .display_service_set
213 .wait_while(self.state.lock().unwrap(), |state| state.display_service.is_none())
214 .unwrap();
215 Ok((state.display_service)
216 .as_ref()
217 .cloned()
218 .expect("Display service cannot be None in this context"))
219 }
David Brazdilafc9a9e2023-01-12 16:08:10 +0000220 fn removeMemlockRlimit(&self) -> binder::Result<()> {
221 let pid = get_calling_pid();
222 let lim = libc::rlimit { rlim_cur: libc::RLIM_INFINITY, rlim_max: libc::RLIM_INFINITY };
223
Andrew Walbranb58d1b42023-07-07 13:54:49 +0100224 // SAFETY: borrowing the new limit struct only
David Brazdilafc9a9e2023-01-12 16:08:10 +0000225 let ret = unsafe { libc::prlimit(pid, libc::RLIMIT_MEMLOCK, &lim, std::ptr::null_mut()) };
226
227 match ret {
228 0 => Ok(()),
Jiyong Park2227eaa2023-08-04 11:59:18 +0900229 -1 => Err(std::io::Error::last_os_error().into()),
230 n => Err(anyhow!("Unexpected return value from prlimit(): {n}")),
David Brazdilafc9a9e2023-01-12 16:08:10 +0000231 }
Jiyong Park2227eaa2023-08-04 11:59:18 +0900232 .or_binder_exception(ExceptionCode::ILLEGAL_STATE)
David Brazdilafc9a9e2023-01-12 16:08:10 +0000233 }
234
235 fn allocateGlobalVmContext(
236 &self,
237 requester_debug_pid: i32,
238 ) -> binder::Result<Strong<dyn IGlobalVmContext>> {
239 check_manage_access()?;
240
241 let requester_uid = get_calling_uid();
242 let requester_debug_pid = requester_debug_pid as pid_t;
243 let state = &mut *self.state.lock().unwrap();
Jiyong Park2227eaa2023-08-04 11:59:18 +0900244 state
245 .allocate_vm_context(requester_uid, requester_debug_pid)
246 .or_binder_exception(ExceptionCode::ILLEGAL_STATE)
David Brazdilafc9a9e2023-01-12 16:08:10 +0000247 }
248
249 fn atomVmBooted(&self, atom: &AtomVmBooted) -> Result<(), Status> {
250 forward_vm_booted_atom(atom);
251 Ok(())
252 }
253
254 fn atomVmCreationRequested(&self, atom: &AtomVmCreationRequested) -> Result<(), Status> {
255 forward_vm_creation_atom(atom);
256 Ok(())
257 }
258
259 fn atomVmExited(&self, atom: &AtomVmExited) -> Result<(), Status> {
260 forward_vm_exited_atom(atom);
261 Ok(())
262 }
263
264 fn debugListVms(&self) -> binder::Result<Vec<VirtualMachineDebugInfo>> {
265 check_debug_access()?;
266
267 let state = &mut *self.state.lock().unwrap();
268 let cids = state
269 .held_contexts
270 .iter()
271 .filter_map(|(_, inst)| Weak::upgrade(inst))
272 .map(|vm| VirtualMachineDebugInfo {
273 cid: vm.cid as i32,
274 temporaryDirectory: vm.get_temp_dir().to_string_lossy().to_string(),
275 requesterUid: vm.requester_uid as i32,
Charisee96113f32023-01-26 09:00:42 +0000276 requesterPid: vm.requester_debug_pid,
David Brazdilafc9a9e2023-01-12 16:08:10 +0000277 })
278 .collect();
279 Ok(cids)
280 }
Alice Wangc2fec932023-02-23 16:24:02 +0000281
Alice Wange64dd182024-01-17 15:57:55 +0000282 fn enableTestAttestation(&self) -> binder::Result<()> {
283 check_manage_access()?;
284 check_use_custom_virtual_machine()?;
285 if !cfg!(remote_attestation) {
286 return Err(Status::new_exception_str(
287 ExceptionCode::UNSUPPORTED_OPERATION,
288 Some(
289 "enableTestAttestation is not supported with the remote_attestation \
290 feature disabled",
291 ),
292 ))
293 .with_log();
294 }
295 let res = generate_ecdsa_p256_key_pair()
296 .context("Failed to generate ECDSA P-256 key pair for testing")
297 .with_log()
298 .or_service_specific_exception(-1)?;
Alice Wang5daec072024-03-15 15:31:17 +0000299 // Wait until the service VM shuts down, so that the Service VM will be restarted when
300 // the key generated in the current session will be used for attestation.
301 // This ensures that different Service VM sessions have the same KEK for the key blob.
302 service_vm_manager::wait_until_service_vm_shuts_down()
303 .context("Failed to wait until the service VM shuts down")
304 .with_log()
305 .or_service_specific_exception(-1)?;
Alice Wange64dd182024-01-17 15:57:55 +0000306 match res {
307 Response::GenerateEcdsaP256KeyPair(key_pair) => {
308 FAKE_PROVISIONED_KEY_BLOB_FOR_TESTING
309 .lock()
310 .unwrap()
311 .replace(key_pair.key_blob.to_vec());
312 Ok(())
313 }
314 _ => Err(remote_provisioning::to_service_specific_error(res)),
315 }
316 .with_log()
317 }
318
Alice Wangbff017f2023-11-09 14:43:28 +0000319 fn requestAttestation(
320 &self,
321 csr: &[u8],
322 requester_uid: i32,
Alice Wange64dd182024-01-17 15:57:55 +0000323 test_mode: bool,
Alice Wangbff017f2023-11-09 14:43:28 +0000324 ) -> binder::Result<Vec<Certificate>> {
Alice Wangc2fec932023-02-23 16:24:02 +0000325 check_manage_access()?;
Alice Wang4c6c5582023-11-23 15:07:18 +0000326 if !cfg!(remote_attestation) {
327 return Err(Status::new_exception_str(
Alice Wange9ac2db2023-09-08 15:13:13 +0000328 ExceptionCode::UNSUPPORTED_OPERATION,
329 Some(
Alice Wanga410b642023-10-18 09:05:15 +0000330 "requestAttestation is not supported with the remote_attestation feature \
331 disabled",
Alice Wange9ac2db2023-09-08 15:13:13 +0000332 ),
333 ))
Alice Wang4c6c5582023-11-23 15:07:18 +0000334 .with_log();
Alice Wange9ac2db2023-09-08 15:13:13 +0000335 }
Alice Wang0dcab552024-03-20 14:42:30 +0000336 if !remotely_provisioned_component_service_exists()? {
337 return Err(Status::new_exception_str(
338 ExceptionCode::UNSUPPORTED_OPERATION,
339 Some("AVF remotely provisioned component service is not declared"),
340 ))
341 .with_log();
342 }
Alice Wang4c6c5582023-11-23 15:07:18 +0000343 info!("Received csr. Requestting attestation...");
Alice Wange64dd182024-01-17 15:57:55 +0000344 let (key_blob, certificate_chain) = if test_mode {
345 check_use_custom_virtual_machine()?;
346 info!("Using the fake key blob for testing...");
347 (
348 FAKE_PROVISIONED_KEY_BLOB_FOR_TESTING
349 .lock()
350 .unwrap()
351 .clone()
352 .ok_or_else(|| anyhow!("No key blob for testing"))
353 .with_log()
354 .or_service_specific_exception(-1)?,
355 FAKE_CERTIFICATE_FOR_TESTING.to_vec(),
356 )
357 } else {
358 info!("Retrieving the remotely provisioned keys from RKPD...");
359 let attestation_key = get_rkpd_attestation_key(
360 REMOTELY_PROVISIONED_COMPONENT_SERVICE_NAME,
361 requester_uid as u32,
362 )
363 .context("Failed to retrieve the remotely provisioned keys")
364 .with_log()
365 .or_service_specific_exception(-1)?;
366 (attestation_key.keyBlob, attestation_key.encodedCertChain)
367 };
368 let mut certificate_chain = split_x509_certificate_chain(&certificate_chain)
Alice Wang4c6c5582023-11-23 15:07:18 +0000369 .context("Failed to split the remotely provisioned certificate chain")
370 .with_log()
371 .or_service_specific_exception(-1)?;
372 if certificate_chain.is_empty() {
373 return Err(Status::new_service_specific_error_str(
374 -1,
375 Some("The certificate chain should contain at least 1 certificate"),
376 ))
377 .with_log();
378 }
Alice Wang20b8ebc2023-11-17 09:54:47 +0000379 let certificate = request_attestation(
380 csr.to_vec(),
Alice Wange64dd182024-01-17 15:57:55 +0000381 key_blob,
Alice Wang20b8ebc2023-11-17 09:54:47 +0000382 certificate_chain[0].encodedCertificate.clone(),
383 )
384 .context("Failed to request attestation")
385 .with_log()
386 .or_service_specific_exception(-1)?;
Alice Wang4c6c5582023-11-23 15:07:18 +0000387 certificate_chain.insert(0, Certificate { encodedCertificate: certificate });
388
389 Ok(certificate_chain)
Alice Wangc2fec932023-02-23 16:24:02 +0000390 }
Inseob Kim53d0b212023-07-20 16:58:37 +0900391
Alice Wang0362f7f2024-03-21 08:16:26 +0000392 fn isRemoteAttestationSupported(&self) -> binder::Result<bool> {
393 remotely_provisioned_component_service_exists()
394 }
395
Inseob Kim53d0b212023-07-20 16:58:37 +0900396 fn getAssignableDevices(&self) -> binder::Result<Vec<AssignableDevice>> {
397 check_use_custom_virtual_machine()?;
398
Inseob Kim7307a892023-09-14 13:37:58 +0900399 Ok(get_assignable_devices()?
400 .device
401 .into_iter()
Jaewan Kim0c99c612024-03-23 00:44:14 +0900402 .map(|x| AssignableDevice { node: x.sysfs_path, dtbo_label: x.dtbo_label })
Inseob Kim7307a892023-09-14 13:37:58 +0900403 .collect::<Vec<_>>())
Inseob Kim53d0b212023-07-20 16:58:37 +0900404 }
Inseob Kim1ca0f652023-07-20 17:18:12 +0900405
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000406 fn bindDevicesToVfioDriver(
407 &self,
408 devices: &[String],
409 ) -> binder::Result<Vec<Strong<dyn IBoundDevice>>> {
Inseob Kim1ca0f652023-07-20 17:18:12 +0900410 check_use_custom_virtual_machine()?;
411
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000412 let devices = get_assignable_devices()?
Inseob Kim7307a892023-09-14 13:37:58 +0900413 .device
414 .into_iter()
415 .filter_map(|x| {
416 if devices.contains(&x.sysfs_path) {
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000417 Some(VfioDev { sysfsPath: x.sysfs_path, dtboLabel: x.dtbo_label })
Inseob Kim7307a892023-09-14 13:37:58 +0900418 } else {
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000419 warn!("device {} is not assignable", x.sysfs_path);
Inseob Kim7307a892023-09-14 13:37:58 +0900420 None
421 }
422 })
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000423 .collect::<Vec<VfioDev>>();
424
425 VFIO_SERVICE.bindDevicesToVfioDriver(devices.as_slice())
Inseob Kim1ca0f652023-07-20 17:18:12 +0900426 }
David Brazdil2dfefd12023-11-17 14:07:36 +0000427
428 fn getDtboFile(&self) -> binder::Result<ParcelFileDescriptor> {
429 check_use_custom_virtual_machine()?;
430
431 let state = &mut *self.state.lock().unwrap();
432 let file = state.get_dtbo_file().or_service_specific_exception(-1)?;
433 Ok(ParcelFileDescriptor::new(file))
434 }
Shikha Panwar61a74b52024-02-16 13:17:01 +0000435
Shikha Panwar61a74b52024-02-16 13:17:01 +0000436 fn allocateInstanceId(&self) -> binder::Result<[u8; 64]> {
437 let mut id = [0u8; 64];
438 id.try_fill(&mut rand::thread_rng())
439 .context("Failed to allocate instance_id")
440 .or_service_specific_exception(-1)?;
441 let uid = get_calling_uid();
442 info!("Allocated a VM's instance_id: {:?}, for uid: {:?}", hex::encode(id), uid);
David Drysdalee64de8e2024-02-29 11:54:29 +0000443 let state = &mut *self.state.lock().unwrap();
444 if let Some(sk_state) = &mut state.sk_state {
445 let user_id = multiuser_get_user_id(uid);
446 let app_id = multiuser_get_app_id(uid);
David Drysdale1138fa02024-03-19 13:06:23 +0000447 info!("Recording possible existence of state for (user_id={user_id}, app_id={app_id})");
David Drysdalee64de8e2024-02-29 11:54:29 +0000448 if let Err(e) = sk_state.add_id(&id, user_id, app_id) {
449 error!("Failed to record the instance_id: {e:?}");
450 }
451 }
452
Shikha Panwar61a74b52024-02-16 13:17:01 +0000453 Ok(id)
454 }
David Drysdale79af2662024-02-19 14:50:31 +0000455
456 fn removeVmInstance(&self, instance_id: &[u8; 64]) -> binder::Result<()> {
457 let state = &mut *self.state.lock().unwrap();
458 if let Some(sk_state) = &mut state.sk_state {
459 info!("removeVmInstance(): delete secret");
460 sk_state.delete_ids(&[*instance_id]);
461 } else {
462 info!("ignoring removeVmInstance() as no ISecretkeeper");
463 }
464 Ok(())
465 }
David Drysdale3aa62b32024-03-25 12:31:48 +0000466
467 fn claimVmInstance(&self, instance_id: &[u8; 64]) -> binder::Result<()> {
468 let state = &mut *self.state.lock().unwrap();
469 if let Some(sk_state) = &mut state.sk_state {
470 let uid = get_calling_uid();
471 info!(
472 "Claiming a VM's instance_id: {:?}, for uid: {:?}",
473 hex::encode(instance_id),
474 uid
475 );
476
477 let user_id = multiuser_get_user_id(uid);
478 let app_id = multiuser_get_app_id(uid);
479 info!("Recording possible new owner of state for (user_id={user_id}, app_id={app_id})");
480 if let Err(e) = sk_state.add_id(instance_id, user_id, app_id) {
481 error!("Failed to update the instance_id owner: {e:?}");
482 }
483 } else {
484 info!("ignoring claimVmInstance() as no ISecretkeeper");
485 }
486 Ok(())
487 }
David Drysdale79af2662024-02-19 14:50:31 +0000488}
489
490impl IVirtualizationMaintenance for VirtualizationServiceInternal {
491 fn appRemoved(&self, user_id: i32, app_id: i32) -> binder::Result<()> {
492 let state = &mut *self.state.lock().unwrap();
493 if let Some(sk_state) = &mut state.sk_state {
494 info!("packageRemoved(user_id={user_id}, app_id={app_id})");
495 sk_state.delete_ids_for_app(user_id, app_id).or_service_specific_exception(-1)?;
496 } else {
497 info!("ignoring packageRemoved(user_id={user_id}, app_id={app_id})");
498 }
499 Ok(())
500 }
501
502 fn userRemoved(&self, user_id: i32) -> binder::Result<()> {
503 let state = &mut *self.state.lock().unwrap();
504 if let Some(sk_state) = &mut state.sk_state {
505 info!("userRemoved({user_id})");
506 sk_state.delete_ids_for_user(user_id).or_service_specific_exception(-1)?;
507 } else {
508 info!("ignoring userRemoved(user_id={user_id})");
509 }
510 Ok(())
511 }
Alan Stokes30ccacb2024-02-20 14:59:02 +0000512
513 fn performReconciliation(
514 &self,
David Drysdale1138fa02024-03-19 13:06:23 +0000515 callback: &Strong<dyn IVirtualizationReconciliationCallback>,
Alan Stokes30ccacb2024-02-20 14:59:02 +0000516 ) -> binder::Result<()> {
David Drysdale1138fa02024-03-19 13:06:23 +0000517 let state = &mut *self.state.lock().unwrap();
518 if let Some(sk_state) = &mut state.sk_state {
519 info!("performReconciliation()");
520 sk_state.reconcile(callback).or_service_specific_exception(-1)?;
521 } else {
522 info!("ignoring performReconciliation()");
523 }
524 Ok(())
Alan Stokes30ccacb2024-02-20 14:59:02 +0000525 }
Inseob Kim1ca0f652023-07-20 17:18:12 +0900526}
527
Inseob Kimc4a774d2023-08-30 12:48:43 +0900528#[derive(Debug, Deserialize)]
529struct Device {
Jaewan Kim35e818d2023-10-18 05:36:38 +0000530 dtbo_label: String,
Inseob Kimc4a774d2023-08-30 12:48:43 +0900531 sysfs_path: String,
532}
533
Inseob Kim7307a892023-09-14 13:37:58 +0900534#[derive(Debug, Default, Deserialize)]
Inseob Kimc4a774d2023-08-30 12:48:43 +0900535struct Devices {
536 device: Vec<Device>,
537}
538
Inseob Kim7307a892023-09-14 13:37:58 +0900539fn get_assignable_devices() -> binder::Result<Devices> {
540 let xml_path = Path::new("/vendor/etc/avf/assignable_devices.xml");
541 if !xml_path.exists() {
542 return Ok(Devices { ..Default::default() });
543 }
544
545 let xml = fs::read(xml_path)
546 .context("Failed to read assignable_devices.xml")
547 .with_log()
548 .or_service_specific_exception(-1)?;
549
550 let xml = String::from_utf8(xml)
551 .context("assignable_devices.xml is not a valid UTF-8 file")
552 .with_log()
553 .or_service_specific_exception(-1)?;
554
555 let mut devices: Devices = serde_xml_rs::from_str(&xml)
556 .context("can't parse assignable_devices.xml")
557 .with_log()
558 .or_service_specific_exception(-1)?;
559
560 let mut device_set = HashSet::new();
561 devices.device.retain(move |device| {
562 if device_set.contains(&device.sysfs_path) {
563 warn!("duplicated assignable device {device:?}; ignoring...");
564 return false;
565 }
566
567 if !Path::new(&device.sysfs_path).exists() {
568 warn!("assignable device {device:?} doesn't exist; ignoring...");
569 return false;
570 }
571
572 device_set.insert(device.sysfs_path.clone());
573 true
574 });
575 Ok(devices)
576}
577
Alice Wang4c6c5582023-11-23 15:07:18 +0000578fn split_x509_certificate_chain(mut cert_chain: &[u8]) -> Result<Vec<Certificate>> {
579 let mut out = Vec::new();
580 while !cert_chain.is_empty() {
Alice Wangfc5a44a2023-12-21 12:22:40 +0000581 let cert = X509::from_der(cert_chain)?;
582 let end = cert.to_der()?.len();
Alice Wang4c6c5582023-11-23 15:07:18 +0000583 out.push(Certificate { encodedCertificate: cert_chain[..end].to_vec() });
Alice Wangfc5a44a2023-12-21 12:22:40 +0000584 cert_chain = &cert_chain[end..];
Alice Wang4c6c5582023-11-23 15:07:18 +0000585 }
586 Ok(out)
587}
588
David Brazdilafc9a9e2023-01-12 16:08:10 +0000589#[derive(Debug, Default)]
590struct GlobalVmInstance {
591 /// The unique CID assigned to the VM for vsock communication.
592 cid: Cid,
593 /// UID of the client who requested this VM instance.
594 requester_uid: uid_t,
595 /// PID of the client who requested this VM instance.
596 requester_debug_pid: pid_t,
597}
598
599impl GlobalVmInstance {
600 fn get_temp_dir(&self) -> PathBuf {
601 let cid = self.cid;
602 format!("{TEMPORARY_DIRECTORY}/{cid}").into()
603 }
604}
605
606/// The mutable state of the VirtualizationServiceInternal. There should only be one instance
607/// of this struct.
David Brazdilafc9a9e2023-01-12 16:08:10 +0000608struct GlobalState {
609 /// VM contexts currently allocated to running VMs. A CID is never recycled as long
610 /// as there is a strong reference held by a GlobalVmContext.
611 held_contexts: HashMap<Cid, Weak<GlobalVmInstance>>,
David Brazdil2dfefd12023-11-17 14:07:36 +0000612
613 /// Cached read-only FD of VM DTBO file. Also serves as a lock for creating the file.
614 dtbo_file: Mutex<Option<File>>,
David Drysdale79af2662024-02-19 14:50:31 +0000615
616 /// State relating to secrets held by (optional) Secretkeeper instance on behalf of VMs.
617 sk_state: Option<maintenance::State>,
Jeongik Cha7add2a42024-04-02 14:52:39 +0900618
619 display_service: Option<binder::SpIBinder>,
David Brazdilafc9a9e2023-01-12 16:08:10 +0000620}
621
622impl GlobalState {
David Drysdale79af2662024-02-19 14:50:31 +0000623 fn new() -> Self {
624 Self {
625 held_contexts: HashMap::new(),
626 dtbo_file: Mutex::new(None),
627 sk_state: maintenance::State::new(),
Jeongik Cha7add2a42024-04-02 14:52:39 +0900628 display_service: None,
David Drysdale79af2662024-02-19 14:50:31 +0000629 }
630 }
631
David Brazdilafc9a9e2023-01-12 16:08:10 +0000632 /// Get the next available CID, or an error if we have run out. The last CID used is stored in
633 /// a system property so that restart of virtualizationservice doesn't reuse CID while the host
634 /// Android is up.
635 fn get_next_available_cid(&mut self) -> Result<Cid> {
636 // Start trying to find a CID from the last used CID + 1. This ensures
637 // that we do not eagerly recycle CIDs. It makes debugging easier but
638 // also means that retrying to allocate a CID, eg. because it is
639 // erroneously occupied by a process, will not recycle the same CID.
640 let last_cid_prop =
641 system_properties::read(SYSPROP_LAST_CID)?.and_then(|val| match val.parse::<Cid>() {
642 Ok(num) => {
643 if is_valid_guest_cid(num) {
644 Some(num)
645 } else {
646 error!("Invalid value '{}' of property '{}'", num, SYSPROP_LAST_CID);
647 None
648 }
649 }
650 Err(_) => {
651 error!("Invalid value '{}' of property '{}'", val, SYSPROP_LAST_CID);
652 None
653 }
654 });
655
656 let first_cid = if let Some(last_cid) = last_cid_prop {
657 if last_cid == GUEST_CID_MAX {
658 GUEST_CID_MIN
659 } else {
660 last_cid + 1
661 }
662 } else {
663 GUEST_CID_MIN
664 };
665
666 let cid = self
667 .find_available_cid(first_cid..=GUEST_CID_MAX)
668 .or_else(|| self.find_available_cid(GUEST_CID_MIN..first_cid))
669 .ok_or_else(|| anyhow!("Could not find an available CID."))?;
670
671 system_properties::write(SYSPROP_LAST_CID, &format!("{}", cid))?;
672 Ok(cid)
673 }
674
675 fn find_available_cid<I>(&self, mut range: I) -> Option<Cid>
676 where
677 I: Iterator<Item = Cid>,
678 {
679 range.find(|cid| !self.held_contexts.contains_key(cid))
680 }
681
682 fn allocate_vm_context(
683 &mut self,
684 requester_uid: uid_t,
685 requester_debug_pid: pid_t,
686 ) -> Result<Strong<dyn IGlobalVmContext>> {
687 // Garbage collect unused VM contexts.
688 self.held_contexts.retain(|_, instance| instance.strong_count() > 0);
689
690 let cid = self.get_next_available_cid()?;
691 let instance = Arc::new(GlobalVmInstance { cid, requester_uid, requester_debug_pid });
David Brazdil2dfefd12023-11-17 14:07:36 +0000692 create_temporary_directory(&instance.get_temp_dir(), Some(requester_uid))?;
David Brazdilafc9a9e2023-01-12 16:08:10 +0000693
694 self.held_contexts.insert(cid, Arc::downgrade(&instance));
695 let binder = GlobalVmContext { instance, ..Default::default() };
696 Ok(BnGlobalVmContext::new_binder(binder, BinderFeatures::default()))
697 }
David Brazdil2dfefd12023-11-17 14:07:36 +0000698
699 fn get_dtbo_file(&mut self) -> Result<File> {
700 let mut file = self.dtbo_file.lock().unwrap();
701
702 let fd = if let Some(ref_fd) = &*file {
703 ref_fd.try_clone()?
704 } else {
705 let path = get_or_create_common_dir()?.join("vm.dtbo");
706 if path.exists() {
707 // All temporary files are deleted when the service is started.
708 // If the file exists but the FD is not cached, the file is
709 // likely corrupted.
710 remove_file(&path).context("Failed to clone cached VM DTBO file descriptor")?;
711 }
712
713 // Open a write-only file descriptor for vfio_handler.
714 let write_fd = File::create(&path).context("Failed to create VM DTBO file")?;
Jakob Vukalovicd42aa2c2023-11-09 16:04:00 +0000715 VFIO_SERVICE.writeVmDtbo(&ParcelFileDescriptor::new(write_fd))?;
David Brazdil2dfefd12023-11-17 14:07:36 +0000716
717 // Open read-only. This FD will be cached and returned to clients.
718 let read_fd = File::open(&path).context("Failed to open VM DTBO file")?;
719 let read_fd_clone =
720 read_fd.try_clone().context("Failed to clone VM DTBO file descriptor")?;
721 *file = Some(read_fd);
722 read_fd_clone
723 };
724
725 Ok(fd)
726 }
David Brazdilafc9a9e2023-01-12 16:08:10 +0000727}
728
David Brazdil2dfefd12023-11-17 14:07:36 +0000729fn create_temporary_directory(path: &PathBuf, requester_uid: Option<uid_t>) -> Result<()> {
730 // Directory may exist if previous attempt to create it had failed.
731 // Delete it before trying again.
David Brazdilafc9a9e2023-01-12 16:08:10 +0000732 if path.as_path().exists() {
733 remove_temporary_dir(path).unwrap_or_else(|e| {
734 warn!("Could not delete temporary directory {:?}: {}", path, e);
735 });
736 }
David Brazdil2dfefd12023-11-17 14:07:36 +0000737 // Create directory.
738 create_dir(path).with_context(|| format!("Could not create temporary directory {:?}", path))?;
739 // If provided, change ownership to client's UID but system's GID, and permissions 0700.
David Brazdilafc9a9e2023-01-12 16:08:10 +0000740 // If the chown() fails, this will leave behind an empty directory that will get removed
741 // at the next attempt, or if virtualizationservice is restarted.
David Brazdil2dfefd12023-11-17 14:07:36 +0000742 if let Some(uid) = requester_uid {
743 chown(path, Some(Uid::from_raw(uid)), None).with_context(|| {
744 format!("Could not set ownership of temporary directory {:?}", path)
745 })?;
746 }
David Brazdilafc9a9e2023-01-12 16:08:10 +0000747 Ok(())
748}
749
750/// Removes a directory owned by a different user by first changing its owner back
751/// to VirtualizationService.
752pub fn remove_temporary_dir(path: &PathBuf) -> Result<()> {
Alice Wangd1b11a02023-04-18 12:30:20 +0000753 ensure!(path.as_path().is_dir(), "Path {:?} is not a directory", path);
David Brazdilafc9a9e2023-01-12 16:08:10 +0000754 chown(path, Some(Uid::current()), None)?;
755 set_permissions(path, Permissions::from_mode(0o700))?;
Alice Wangd1b11a02023-04-18 12:30:20 +0000756 remove_dir_all(path)?;
David Brazdilafc9a9e2023-01-12 16:08:10 +0000757 Ok(())
758}
759
David Brazdil2dfefd12023-11-17 14:07:36 +0000760fn get_or_create_common_dir() -> Result<PathBuf> {
761 let path = Path::new(TEMPORARY_DIRECTORY).join("common");
762 if !path.exists() {
763 create_temporary_directory(&path, None)?;
764 }
765 Ok(path)
766}
767
David Brazdilafc9a9e2023-01-12 16:08:10 +0000768/// Implementation of the AIDL `IGlobalVmContext` interface.
769#[derive(Debug, Default)]
770struct GlobalVmContext {
771 /// Strong reference to the context's instance data structure.
772 instance: Arc<GlobalVmInstance>,
773 /// Keeps our service process running as long as this VM context exists.
774 #[allow(dead_code)]
775 lazy_service_guard: LazyServiceGuard,
776}
777
778impl Interface for GlobalVmContext {}
779
780impl IGlobalVmContext for GlobalVmContext {
781 fn getCid(&self) -> binder::Result<i32> {
782 Ok(self.instance.cid as i32)
783 }
784
785 fn getTemporaryDirectory(&self) -> binder::Result<String> {
786 Ok(self.instance.get_temp_dir().to_string_lossy().to_string())
787 }
788}
789
790fn handle_stream_connection_tombstoned() -> Result<()> {
791 // Should not listen for tombstones on a guest VM's port.
792 assert!(!is_valid_guest_cid(VM_TOMBSTONES_SERVICE_PORT as Cid));
793 let listener =
794 VsockListener::bind_with_cid_port(VMADDR_CID_HOST, VM_TOMBSTONES_SERVICE_PORT as Cid)?;
795 for incoming_stream in listener.incoming() {
796 let mut incoming_stream = match incoming_stream {
797 Err(e) => {
798 warn!("invalid incoming connection: {:?}", e);
799 continue;
800 }
801 Ok(s) => s,
802 };
803 std::thread::spawn(move || {
804 if let Err(e) = handle_tombstone(&mut incoming_stream) {
805 error!("Failed to write tombstone- {:?}", e);
806 }
807 });
808 }
809 Ok(())
810}
811
812fn handle_tombstone(stream: &mut VsockStream) -> Result<()> {
813 if let Ok(addr) = stream.peer_addr() {
814 info!("Vsock Stream connected to cid={} for tombstones", addr.cid());
815 }
816 let tb_connection =
817 TombstonedConnection::connect(std::process::id() as i32, DebuggerdDumpType::Tombstone)
818 .context("Failed to connect to tombstoned")?;
819 let mut text_output = tb_connection
820 .text_output
821 .as_ref()
822 .ok_or_else(|| anyhow!("Could not get file to write the tombstones on"))?;
823 let mut num_bytes_read = 0;
824 loop {
825 let mut chunk_recv = [0; CHUNK_RECV_MAX_LEN];
826 let n = stream
827 .read(&mut chunk_recv)
828 .context("Failed to read tombstone data from Vsock stream")?;
829 if n == 0 {
830 break;
831 }
832 num_bytes_read += n;
833 text_output.write_all(&chunk_recv[0..n]).context("Failed to write guests tombstones")?;
834 }
835 info!("Received {} bytes from guest & wrote to tombstone file", num_bytes_read);
836 tb_connection.notify_completion()?;
837 Ok(())
838}
839
Alice Wang0dcab552024-03-20 14:42:30 +0000840fn remotely_provisioned_component_service_exists() -> binder::Result<bool> {
841 Ok(binder::is_declared(REMOTELY_PROVISIONED_COMPONENT_SERVICE_NAME)?)
842}
843
David Brazdilafc9a9e2023-01-12 16:08:10 +0000844/// Checks whether the caller has a specific permission
845fn check_permission(perm: &str) -> binder::Result<()> {
846 let calling_pid = get_calling_pid();
847 let calling_uid = get_calling_uid();
848 // Root can do anything
849 if calling_uid == 0 {
850 return Ok(());
851 }
852 let perm_svc: Strong<dyn IPermissionController::IPermissionController> =
853 binder::get_interface("permission")?;
854 if perm_svc.checkPermission(perm, calling_pid, calling_uid as i32)? {
855 Ok(())
856 } else {
Jiyong Park2227eaa2023-08-04 11:59:18 +0900857 Err(anyhow!("does not have the {} permission", perm))
858 .or_binder_exception(ExceptionCode::SECURITY)
David Brazdilafc9a9e2023-01-12 16:08:10 +0000859 }
860}
861
862/// Check whether the caller of the current Binder method is allowed to call debug methods.
863fn check_debug_access() -> binder::Result<()> {
864 check_permission("android.permission.DEBUG_VIRTUAL_MACHINE")
865}
866
867/// Check whether the caller of the current Binder method is allowed to manage VMs
868fn check_manage_access() -> binder::Result<()> {
869 check_permission("android.permission.MANAGE_VIRTUAL_MACHINE")
870}
Inseob Kim53d0b212023-07-20 16:58:37 +0900871
872/// Check whether the caller of the current Binder method is allowed to use custom VMs
873fn check_use_custom_virtual_machine() -> binder::Result<()> {
874 check_permission("android.permission.USE_CUSTOM_VIRTUAL_MACHINE")
875}
Alice Wang4c6c5582023-11-23 15:07:18 +0000876
877#[cfg(test)]
878mod tests {
879 use super::*;
Alice Wang4c6c5582023-11-23 15:07:18 +0000880
881 const TEST_RKP_CERT_CHAIN_PATH: &str = "testdata/rkp_cert_chain.der";
882
883 #[test]
884 fn splitting_x509_certificate_chain_succeeds() -> Result<()> {
885 let bytes = fs::read(TEST_RKP_CERT_CHAIN_PATH)?;
886 let cert_chain = split_x509_certificate_chain(&bytes)?;
887
888 assert_eq!(4, cert_chain.len());
889 for cert in cert_chain {
Alice Wangfc5a44a2023-12-21 12:22:40 +0000890 let x509_cert = X509::from_der(&cert.encodedCertificate)?;
891 assert_eq!(x509_cert.to_der()?.len(), cert.encodedCertificate.len());
Alice Wang4c6c5582023-11-23 15:07:18 +0000892 }
893 Ok(())
894 }
895}