blob: 7cdfdc67826541b27aef4dc1ff87fa3d6ec7bb19 [file] [log] [blame]
David Brazdilafc9a9e2023-01-12 16:08:10 +00001// Copyright 2021, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Implementation of the AIDL interface of the VirtualizationService.
16
Alice Wangbff017f2023-11-09 14:43:28 +000017use crate::{get_calling_pid, get_calling_uid, REMOTELY_PROVISIONED_COMPONENT_SERVICE_NAME};
David Brazdil33a31022023-01-12 16:55:16 +000018use crate::atom::{forward_vm_booted_atom, forward_vm_creation_atom, forward_vm_exited_atom};
Alice Wanga410b642023-10-18 09:05:15 +000019use crate::rkpvm::request_attestation;
David Brazdilafc9a9e2023-01-12 16:08:10 +000020use android_os_permissions_aidl::aidl::android::os::IPermissionController;
Alice Wang4e3015d2023-10-10 09:35:37 +000021use android_system_virtualizationcommon::aidl::android::system::virtualizationcommon::Certificate::Certificate;
Alice Wangc2fec932023-02-23 16:24:02 +000022use android_system_virtualizationservice::{
Inseob Kim53d0b212023-07-20 16:58:37 +090023 aidl::android::system::virtualizationservice::AssignableDevice::AssignableDevice,
Alice Wangc2fec932023-02-23 16:24:02 +000024 aidl::android::system::virtualizationservice::VirtualMachineDebugInfo::VirtualMachineDebugInfo,
25 binder::ParcelFileDescriptor,
26};
David Brazdilafc9a9e2023-01-12 16:08:10 +000027use android_system_virtualizationservice_internal::aidl::android::system::virtualizationservice_internal::{
28 AtomVmBooted::AtomVmBooted,
29 AtomVmCreationRequested::AtomVmCreationRequested,
30 AtomVmExited::AtomVmExited,
31 IGlobalVmContext::{BnGlobalVmContext, IGlobalVmContext},
Inseob Kim7307a892023-09-14 13:37:58 +090032 IVirtualizationServiceInternal::BoundDevice::BoundDevice,
David Brazdilafc9a9e2023-01-12 16:08:10 +000033 IVirtualizationServiceInternal::IVirtualizationServiceInternal,
Inseob Kimbdca0472023-07-28 19:20:56 +090034 IVfioHandler::{BpVfioHandler, IVfioHandler},
David Brazdilafc9a9e2023-01-12 16:08:10 +000035};
36use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::VM_TOMBSTONES_SERVICE_PORT;
Alice Wangd1b11a02023-04-18 12:30:20 +000037use anyhow::{anyhow, ensure, Context, Result};
Jiyong Parkd7bd2f22023-08-10 20:41:19 +090038use avflog::LogResult;
Jiyong Park2227eaa2023-08-04 11:59:18 +090039use binder::{self, wait_for_interface, BinderFeatures, ExceptionCode, Interface, LazyServiceGuard, Status, Strong, IntoBinderResult};
David Brazdilafc9a9e2023-01-12 16:08:10 +000040use libc::VMADDR_CID_HOST;
41use log::{error, info, warn};
Alice Wangbff017f2023-11-09 14:43:28 +000042use rkpd_client::get_rkpd_attestation_key;
David Brazdilafc9a9e2023-01-12 16:08:10 +000043use rustutils::system_properties;
Inseob Kimc4a774d2023-08-30 12:48:43 +090044use serde::Deserialize;
45use std::collections::{HashMap, HashSet};
David Brazdil2dfefd12023-11-17 14:07:36 +000046use std::fs::{self, create_dir, remove_dir_all, remove_file, set_permissions, File, Permissions};
David Brazdilafc9a9e2023-01-12 16:08:10 +000047use std::io::{Read, Write};
48use std::os::unix::fs::PermissionsExt;
49use std::os::unix::raw::{pid_t, uid_t};
Inseob Kim55438b22023-08-09 20:16:01 +090050use std::path::{Path, PathBuf};
David Brazdilafc9a9e2023-01-12 16:08:10 +000051use std::sync::{Arc, Mutex, Weak};
52use tombstoned_client::{DebuggerdDumpType, TombstonedConnection};
53use vsock::{VsockListener, VsockStream};
Inseob Kimbdca0472023-07-28 19:20:56 +090054use nix::unistd::{chown, Uid};
David Brazdilafc9a9e2023-01-12 16:08:10 +000055
56/// The unique ID of a VM used (together with a port number) for vsock communication.
57pub type Cid = u32;
58
59pub const BINDER_SERVICE_IDENTIFIER: &str = "android.system.virtualizationservice";
60
61/// Directory in which to write disk image files used while running VMs.
62pub const TEMPORARY_DIRECTORY: &str = "/data/misc/virtualizationservice";
63
64/// The first CID to assign to a guest VM managed by the VirtualizationService. CIDs lower than this
65/// are reserved for the host or other usage.
66const GUEST_CID_MIN: Cid = 2048;
67const GUEST_CID_MAX: Cid = 65535;
68
69const SYSPROP_LAST_CID: &str = "virtualizationservice.state.last_cid";
70
71const CHUNK_RECV_MAX_LEN: usize = 1024;
72
73fn is_valid_guest_cid(cid: Cid) -> bool {
74 (GUEST_CID_MIN..=GUEST_CID_MAX).contains(&cid)
75}
76
77/// Singleton service for allocating globally-unique VM resources, such as the CID, and running
78/// singleton servers, like tombstone receiver.
79#[derive(Debug, Default)]
80pub struct VirtualizationServiceInternal {
81 state: Arc<Mutex<GlobalState>>,
82}
83
84impl VirtualizationServiceInternal {
85 pub fn init() -> VirtualizationServiceInternal {
86 let service = VirtualizationServiceInternal::default();
87
88 std::thread::spawn(|| {
89 if let Err(e) = handle_stream_connection_tombstoned() {
90 warn!("Error receiving tombstone from guest or writing them. Error: {:?}", e);
91 }
92 });
93
94 service
95 }
96}
97
98impl Interface for VirtualizationServiceInternal {}
99
100impl IVirtualizationServiceInternal for VirtualizationServiceInternal {
101 fn removeMemlockRlimit(&self) -> binder::Result<()> {
102 let pid = get_calling_pid();
103 let lim = libc::rlimit { rlim_cur: libc::RLIM_INFINITY, rlim_max: libc::RLIM_INFINITY };
104
Andrew Walbranb58d1b42023-07-07 13:54:49 +0100105 // SAFETY: borrowing the new limit struct only
David Brazdilafc9a9e2023-01-12 16:08:10 +0000106 let ret = unsafe { libc::prlimit(pid, libc::RLIMIT_MEMLOCK, &lim, std::ptr::null_mut()) };
107
108 match ret {
109 0 => Ok(()),
Jiyong Park2227eaa2023-08-04 11:59:18 +0900110 -1 => Err(std::io::Error::last_os_error().into()),
111 n => Err(anyhow!("Unexpected return value from prlimit(): {n}")),
David Brazdilafc9a9e2023-01-12 16:08:10 +0000112 }
Jiyong Park2227eaa2023-08-04 11:59:18 +0900113 .or_binder_exception(ExceptionCode::ILLEGAL_STATE)
David Brazdilafc9a9e2023-01-12 16:08:10 +0000114 }
115
116 fn allocateGlobalVmContext(
117 &self,
118 requester_debug_pid: i32,
119 ) -> binder::Result<Strong<dyn IGlobalVmContext>> {
120 check_manage_access()?;
121
122 let requester_uid = get_calling_uid();
123 let requester_debug_pid = requester_debug_pid as pid_t;
124 let state = &mut *self.state.lock().unwrap();
Jiyong Park2227eaa2023-08-04 11:59:18 +0900125 state
126 .allocate_vm_context(requester_uid, requester_debug_pid)
127 .or_binder_exception(ExceptionCode::ILLEGAL_STATE)
David Brazdilafc9a9e2023-01-12 16:08:10 +0000128 }
129
130 fn atomVmBooted(&self, atom: &AtomVmBooted) -> Result<(), Status> {
131 forward_vm_booted_atom(atom);
132 Ok(())
133 }
134
135 fn atomVmCreationRequested(&self, atom: &AtomVmCreationRequested) -> Result<(), Status> {
136 forward_vm_creation_atom(atom);
137 Ok(())
138 }
139
140 fn atomVmExited(&self, atom: &AtomVmExited) -> Result<(), Status> {
141 forward_vm_exited_atom(atom);
142 Ok(())
143 }
144
145 fn debugListVms(&self) -> binder::Result<Vec<VirtualMachineDebugInfo>> {
146 check_debug_access()?;
147
148 let state = &mut *self.state.lock().unwrap();
149 let cids = state
150 .held_contexts
151 .iter()
152 .filter_map(|(_, inst)| Weak::upgrade(inst))
153 .map(|vm| VirtualMachineDebugInfo {
154 cid: vm.cid as i32,
155 temporaryDirectory: vm.get_temp_dir().to_string_lossy().to_string(),
156 requesterUid: vm.requester_uid as i32,
Charisee96113f32023-01-26 09:00:42 +0000157 requesterPid: vm.requester_debug_pid,
David Brazdilafc9a9e2023-01-12 16:08:10 +0000158 })
159 .collect();
160 Ok(cids)
161 }
Alice Wangc2fec932023-02-23 16:24:02 +0000162
Alice Wangbff017f2023-11-09 14:43:28 +0000163 fn requestAttestation(
164 &self,
165 csr: &[u8],
166 requester_uid: i32,
167 ) -> binder::Result<Vec<Certificate>> {
Alice Wangc2fec932023-02-23 16:24:02 +0000168 check_manage_access()?;
Alice Wanga410b642023-10-18 09:05:15 +0000169 info!("Received csr. Requestting attestation...");
Alice Wange9ac2db2023-09-08 15:13:13 +0000170 if cfg!(remote_attestation) {
Alice Wangbff017f2023-11-09 14:43:28 +0000171 let attestation_key = get_rkpd_attestation_key(
172 REMOTELY_PROVISIONED_COMPONENT_SERVICE_NAME,
173 requester_uid as u32,
174 )
175 .context("Failed to retrieve the remotely provisioned keys")
176 .with_log()
177 .or_service_specific_exception(-1)?;
178 let certificate = request_attestation(csr, &attestation_key.keyBlob)
Alice Wanga410b642023-10-18 09:05:15 +0000179 .context("Failed to request attestation")
Alice Wange9ac2db2023-09-08 15:13:13 +0000180 .with_log()
Alice Wangbff017f2023-11-09 14:43:28 +0000181 .or_service_specific_exception(-1)?;
182 // TODO(b/309780089): Parse the remotely provisioned certificate chain into
183 // individual certificates.
184 let mut certificate_chain =
185 vec![Certificate { encodedCertificate: attestation_key.encodedCertChain }];
186 certificate_chain.push(Certificate { encodedCertificate: certificate });
187 Ok(certificate_chain)
Alice Wange9ac2db2023-09-08 15:13:13 +0000188 } else {
189 Err(Status::new_exception_str(
190 ExceptionCode::UNSUPPORTED_OPERATION,
191 Some(
Alice Wanga410b642023-10-18 09:05:15 +0000192 "requestAttestation is not supported with the remote_attestation feature \
193 disabled",
Alice Wange9ac2db2023-09-08 15:13:13 +0000194 ),
195 ))
Jiyong Park2227eaa2023-08-04 11:59:18 +0900196 .with_log()
Alice Wange9ac2db2023-09-08 15:13:13 +0000197 }
Alice Wangc2fec932023-02-23 16:24:02 +0000198 }
Inseob Kim53d0b212023-07-20 16:58:37 +0900199
200 fn getAssignableDevices(&self) -> binder::Result<Vec<AssignableDevice>> {
201 check_use_custom_virtual_machine()?;
202
Inseob Kim7307a892023-09-14 13:37:58 +0900203 Ok(get_assignable_devices()?
204 .device
205 .into_iter()
206 .map(|x| AssignableDevice { node: x.sysfs_path, kind: x.kind })
207 .collect::<Vec<_>>())
Inseob Kim53d0b212023-07-20 16:58:37 +0900208 }
Inseob Kim1ca0f652023-07-20 17:18:12 +0900209
Inseob Kim7307a892023-09-14 13:37:58 +0900210 fn bindDevicesToVfioDriver(&self, devices: &[String]) -> binder::Result<Vec<BoundDevice>> {
Inseob Kim1ca0f652023-07-20 17:18:12 +0900211 check_use_custom_virtual_machine()?;
212
Inseob Kimbdca0472023-07-28 19:20:56 +0900213 let vfio_service: Strong<dyn IVfioHandler> =
214 wait_for_interface(<BpVfioHandler as IVfioHandler>::get_descriptor())?;
Seungjae Yoo9d3c20a2023-09-07 15:36:44 +0900215 vfio_service.bindDevicesToVfioDriver(devices)?;
216
Inseob Kim7307a892023-09-14 13:37:58 +0900217 Ok(get_assignable_devices()?
218 .device
219 .into_iter()
220 .filter_map(|x| {
221 if devices.contains(&x.sysfs_path) {
Jaewan Kim35e818d2023-10-18 05:36:38 +0000222 Some(BoundDevice { sysfsPath: x.sysfs_path, dtboLabel: x.dtbo_label })
Inseob Kim7307a892023-09-14 13:37:58 +0900223 } else {
224 None
225 }
226 })
227 .collect::<Vec<_>>())
Inseob Kim1ca0f652023-07-20 17:18:12 +0900228 }
David Brazdil2dfefd12023-11-17 14:07:36 +0000229
230 fn getDtboFile(&self) -> binder::Result<ParcelFileDescriptor> {
231 check_use_custom_virtual_machine()?;
232
233 let state = &mut *self.state.lock().unwrap();
234 let file = state.get_dtbo_file().or_service_specific_exception(-1)?;
235 Ok(ParcelFileDescriptor::new(file))
236 }
Inseob Kim1ca0f652023-07-20 17:18:12 +0900237}
238
Inseob Kimc4a774d2023-08-30 12:48:43 +0900239// KEEP IN SYNC WITH assignable_devices.xsd
240#[derive(Debug, Deserialize)]
241struct Device {
242 kind: String,
Jaewan Kim35e818d2023-10-18 05:36:38 +0000243 dtbo_label: String,
Inseob Kimc4a774d2023-08-30 12:48:43 +0900244 sysfs_path: String,
245}
246
Inseob Kim7307a892023-09-14 13:37:58 +0900247#[derive(Debug, Default, Deserialize)]
Inseob Kimc4a774d2023-08-30 12:48:43 +0900248struct Devices {
249 device: Vec<Device>,
250}
251
Inseob Kim7307a892023-09-14 13:37:58 +0900252fn get_assignable_devices() -> binder::Result<Devices> {
253 let xml_path = Path::new("/vendor/etc/avf/assignable_devices.xml");
254 if !xml_path.exists() {
255 return Ok(Devices { ..Default::default() });
256 }
257
258 let xml = fs::read(xml_path)
259 .context("Failed to read assignable_devices.xml")
260 .with_log()
261 .or_service_specific_exception(-1)?;
262
263 let xml = String::from_utf8(xml)
264 .context("assignable_devices.xml is not a valid UTF-8 file")
265 .with_log()
266 .or_service_specific_exception(-1)?;
267
268 let mut devices: Devices = serde_xml_rs::from_str(&xml)
269 .context("can't parse assignable_devices.xml")
270 .with_log()
271 .or_service_specific_exception(-1)?;
272
273 let mut device_set = HashSet::new();
274 devices.device.retain(move |device| {
275 if device_set.contains(&device.sysfs_path) {
276 warn!("duplicated assignable device {device:?}; ignoring...");
277 return false;
278 }
279
280 if !Path::new(&device.sysfs_path).exists() {
281 warn!("assignable device {device:?} doesn't exist; ignoring...");
282 return false;
283 }
284
285 device_set.insert(device.sysfs_path.clone());
286 true
287 });
288 Ok(devices)
289}
290
David Brazdilafc9a9e2023-01-12 16:08:10 +0000291#[derive(Debug, Default)]
292struct GlobalVmInstance {
293 /// The unique CID assigned to the VM for vsock communication.
294 cid: Cid,
295 /// UID of the client who requested this VM instance.
296 requester_uid: uid_t,
297 /// PID of the client who requested this VM instance.
298 requester_debug_pid: pid_t,
299}
300
301impl GlobalVmInstance {
302 fn get_temp_dir(&self) -> PathBuf {
303 let cid = self.cid;
304 format!("{TEMPORARY_DIRECTORY}/{cid}").into()
305 }
306}
307
308/// The mutable state of the VirtualizationServiceInternal. There should only be one instance
309/// of this struct.
310#[derive(Debug, Default)]
311struct GlobalState {
312 /// VM contexts currently allocated to running VMs. A CID is never recycled as long
313 /// as there is a strong reference held by a GlobalVmContext.
314 held_contexts: HashMap<Cid, Weak<GlobalVmInstance>>,
David Brazdil2dfefd12023-11-17 14:07:36 +0000315
316 /// Cached read-only FD of VM DTBO file. Also serves as a lock for creating the file.
317 dtbo_file: Mutex<Option<File>>,
David Brazdilafc9a9e2023-01-12 16:08:10 +0000318}
319
320impl GlobalState {
321 /// Get the next available CID, or an error if we have run out. The last CID used is stored in
322 /// a system property so that restart of virtualizationservice doesn't reuse CID while the host
323 /// Android is up.
324 fn get_next_available_cid(&mut self) -> Result<Cid> {
325 // Start trying to find a CID from the last used CID + 1. This ensures
326 // that we do not eagerly recycle CIDs. It makes debugging easier but
327 // also means that retrying to allocate a CID, eg. because it is
328 // erroneously occupied by a process, will not recycle the same CID.
329 let last_cid_prop =
330 system_properties::read(SYSPROP_LAST_CID)?.and_then(|val| match val.parse::<Cid>() {
331 Ok(num) => {
332 if is_valid_guest_cid(num) {
333 Some(num)
334 } else {
335 error!("Invalid value '{}' of property '{}'", num, SYSPROP_LAST_CID);
336 None
337 }
338 }
339 Err(_) => {
340 error!("Invalid value '{}' of property '{}'", val, SYSPROP_LAST_CID);
341 None
342 }
343 });
344
345 let first_cid = if let Some(last_cid) = last_cid_prop {
346 if last_cid == GUEST_CID_MAX {
347 GUEST_CID_MIN
348 } else {
349 last_cid + 1
350 }
351 } else {
352 GUEST_CID_MIN
353 };
354
355 let cid = self
356 .find_available_cid(first_cid..=GUEST_CID_MAX)
357 .or_else(|| self.find_available_cid(GUEST_CID_MIN..first_cid))
358 .ok_or_else(|| anyhow!("Could not find an available CID."))?;
359
360 system_properties::write(SYSPROP_LAST_CID, &format!("{}", cid))?;
361 Ok(cid)
362 }
363
364 fn find_available_cid<I>(&self, mut range: I) -> Option<Cid>
365 where
366 I: Iterator<Item = Cid>,
367 {
368 range.find(|cid| !self.held_contexts.contains_key(cid))
369 }
370
371 fn allocate_vm_context(
372 &mut self,
373 requester_uid: uid_t,
374 requester_debug_pid: pid_t,
375 ) -> Result<Strong<dyn IGlobalVmContext>> {
376 // Garbage collect unused VM contexts.
377 self.held_contexts.retain(|_, instance| instance.strong_count() > 0);
378
379 let cid = self.get_next_available_cid()?;
380 let instance = Arc::new(GlobalVmInstance { cid, requester_uid, requester_debug_pid });
David Brazdil2dfefd12023-11-17 14:07:36 +0000381 create_temporary_directory(&instance.get_temp_dir(), Some(requester_uid))?;
David Brazdilafc9a9e2023-01-12 16:08:10 +0000382
383 self.held_contexts.insert(cid, Arc::downgrade(&instance));
384 let binder = GlobalVmContext { instance, ..Default::default() };
385 Ok(BnGlobalVmContext::new_binder(binder, BinderFeatures::default()))
386 }
David Brazdil2dfefd12023-11-17 14:07:36 +0000387
388 fn get_dtbo_file(&mut self) -> Result<File> {
389 let mut file = self.dtbo_file.lock().unwrap();
390
391 let fd = if let Some(ref_fd) = &*file {
392 ref_fd.try_clone()?
393 } else {
394 let path = get_or_create_common_dir()?.join("vm.dtbo");
395 if path.exists() {
396 // All temporary files are deleted when the service is started.
397 // If the file exists but the FD is not cached, the file is
398 // likely corrupted.
399 remove_file(&path).context("Failed to clone cached VM DTBO file descriptor")?;
400 }
401
402 // Open a write-only file descriptor for vfio_handler.
403 let write_fd = File::create(&path).context("Failed to create VM DTBO file")?;
404
405 let vfio_service: Strong<dyn IVfioHandler> =
406 wait_for_interface(<BpVfioHandler as IVfioHandler>::get_descriptor())?;
407 vfio_service.writeVmDtbo(&ParcelFileDescriptor::new(write_fd))?;
408
409 // Open read-only. This FD will be cached and returned to clients.
410 let read_fd = File::open(&path).context("Failed to open VM DTBO file")?;
411 let read_fd_clone =
412 read_fd.try_clone().context("Failed to clone VM DTBO file descriptor")?;
413 *file = Some(read_fd);
414 read_fd_clone
415 };
416
417 Ok(fd)
418 }
David Brazdilafc9a9e2023-01-12 16:08:10 +0000419}
420
David Brazdil2dfefd12023-11-17 14:07:36 +0000421fn create_temporary_directory(path: &PathBuf, requester_uid: Option<uid_t>) -> Result<()> {
422 // Directory may exist if previous attempt to create it had failed.
423 // Delete it before trying again.
David Brazdilafc9a9e2023-01-12 16:08:10 +0000424 if path.as_path().exists() {
425 remove_temporary_dir(path).unwrap_or_else(|e| {
426 warn!("Could not delete temporary directory {:?}: {}", path, e);
427 });
428 }
David Brazdil2dfefd12023-11-17 14:07:36 +0000429 // Create directory.
430 create_dir(path).with_context(|| format!("Could not create temporary directory {:?}", path))?;
431 // If provided, change ownership to client's UID but system's GID, and permissions 0700.
David Brazdilafc9a9e2023-01-12 16:08:10 +0000432 // If the chown() fails, this will leave behind an empty directory that will get removed
433 // at the next attempt, or if virtualizationservice is restarted.
David Brazdil2dfefd12023-11-17 14:07:36 +0000434 if let Some(uid) = requester_uid {
435 chown(path, Some(Uid::from_raw(uid)), None).with_context(|| {
436 format!("Could not set ownership of temporary directory {:?}", path)
437 })?;
438 }
David Brazdilafc9a9e2023-01-12 16:08:10 +0000439 Ok(())
440}
441
442/// Removes a directory owned by a different user by first changing its owner back
443/// to VirtualizationService.
444pub fn remove_temporary_dir(path: &PathBuf) -> Result<()> {
Alice Wangd1b11a02023-04-18 12:30:20 +0000445 ensure!(path.as_path().is_dir(), "Path {:?} is not a directory", path);
David Brazdilafc9a9e2023-01-12 16:08:10 +0000446 chown(path, Some(Uid::current()), None)?;
447 set_permissions(path, Permissions::from_mode(0o700))?;
Alice Wangd1b11a02023-04-18 12:30:20 +0000448 remove_dir_all(path)?;
David Brazdilafc9a9e2023-01-12 16:08:10 +0000449 Ok(())
450}
451
David Brazdil2dfefd12023-11-17 14:07:36 +0000452fn get_or_create_common_dir() -> Result<PathBuf> {
453 let path = Path::new(TEMPORARY_DIRECTORY).join("common");
454 if !path.exists() {
455 create_temporary_directory(&path, None)?;
456 }
457 Ok(path)
458}
459
David Brazdilafc9a9e2023-01-12 16:08:10 +0000460/// Implementation of the AIDL `IGlobalVmContext` interface.
461#[derive(Debug, Default)]
462struct GlobalVmContext {
463 /// Strong reference to the context's instance data structure.
464 instance: Arc<GlobalVmInstance>,
465 /// Keeps our service process running as long as this VM context exists.
466 #[allow(dead_code)]
467 lazy_service_guard: LazyServiceGuard,
468}
469
470impl Interface for GlobalVmContext {}
471
472impl IGlobalVmContext for GlobalVmContext {
473 fn getCid(&self) -> binder::Result<i32> {
474 Ok(self.instance.cid as i32)
475 }
476
477 fn getTemporaryDirectory(&self) -> binder::Result<String> {
478 Ok(self.instance.get_temp_dir().to_string_lossy().to_string())
479 }
480}
481
482fn handle_stream_connection_tombstoned() -> Result<()> {
483 // Should not listen for tombstones on a guest VM's port.
484 assert!(!is_valid_guest_cid(VM_TOMBSTONES_SERVICE_PORT as Cid));
485 let listener =
486 VsockListener::bind_with_cid_port(VMADDR_CID_HOST, VM_TOMBSTONES_SERVICE_PORT as Cid)?;
487 for incoming_stream in listener.incoming() {
488 let mut incoming_stream = match incoming_stream {
489 Err(e) => {
490 warn!("invalid incoming connection: {:?}", e);
491 continue;
492 }
493 Ok(s) => s,
494 };
495 std::thread::spawn(move || {
496 if let Err(e) = handle_tombstone(&mut incoming_stream) {
497 error!("Failed to write tombstone- {:?}", e);
498 }
499 });
500 }
501 Ok(())
502}
503
504fn handle_tombstone(stream: &mut VsockStream) -> Result<()> {
505 if let Ok(addr) = stream.peer_addr() {
506 info!("Vsock Stream connected to cid={} for tombstones", addr.cid());
507 }
508 let tb_connection =
509 TombstonedConnection::connect(std::process::id() as i32, DebuggerdDumpType::Tombstone)
510 .context("Failed to connect to tombstoned")?;
511 let mut text_output = tb_connection
512 .text_output
513 .as_ref()
514 .ok_or_else(|| anyhow!("Could not get file to write the tombstones on"))?;
515 let mut num_bytes_read = 0;
516 loop {
517 let mut chunk_recv = [0; CHUNK_RECV_MAX_LEN];
518 let n = stream
519 .read(&mut chunk_recv)
520 .context("Failed to read tombstone data from Vsock stream")?;
521 if n == 0 {
522 break;
523 }
524 num_bytes_read += n;
525 text_output.write_all(&chunk_recv[0..n]).context("Failed to write guests tombstones")?;
526 }
527 info!("Received {} bytes from guest & wrote to tombstone file", num_bytes_read);
528 tb_connection.notify_completion()?;
529 Ok(())
530}
531
532/// Checks whether the caller has a specific permission
533fn check_permission(perm: &str) -> binder::Result<()> {
534 let calling_pid = get_calling_pid();
535 let calling_uid = get_calling_uid();
536 // Root can do anything
537 if calling_uid == 0 {
538 return Ok(());
539 }
540 let perm_svc: Strong<dyn IPermissionController::IPermissionController> =
541 binder::get_interface("permission")?;
542 if perm_svc.checkPermission(perm, calling_pid, calling_uid as i32)? {
543 Ok(())
544 } else {
Jiyong Park2227eaa2023-08-04 11:59:18 +0900545 Err(anyhow!("does not have the {} permission", perm))
546 .or_binder_exception(ExceptionCode::SECURITY)
David Brazdilafc9a9e2023-01-12 16:08:10 +0000547 }
548}
549
550/// Check whether the caller of the current Binder method is allowed to call debug methods.
551fn check_debug_access() -> binder::Result<()> {
552 check_permission("android.permission.DEBUG_VIRTUAL_MACHINE")
553}
554
555/// Check whether the caller of the current Binder method is allowed to manage VMs
556fn check_manage_access() -> binder::Result<()> {
557 check_permission("android.permission.MANAGE_VIRTUAL_MACHINE")
558}
Inseob Kim53d0b212023-07-20 16:58:37 +0900559
560/// Check whether the caller of the current Binder method is allowed to use custom VMs
561fn check_use_custom_virtual_machine() -> binder::Result<()> {
562 check_permission("android.permission.USE_CUSTOM_VIRTUAL_MACHINE")
563}