1 // 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 Virt Manager. 16 17 use crate::config::VmConfig; 18 use crate::crosvm::VmInstance; 19 use crate::{Cid, FIRST_GUEST_CID}; 20 use android_system_virtmanager::aidl::android::system::virtmanager::IVirtManager::IVirtManager; 21 use android_system_virtmanager::aidl::android::system::virtmanager::IVirtualMachine::{ 22 BnVirtualMachine, IVirtualMachine, 23 }; 24 use android_system_virtmanager::aidl::android::system::virtmanager::IVirtualMachineCallback::IVirtualMachineCallback; 25 use android_system_virtmanager::aidl::android::system::virtmanager::VirtualMachineDebugInfo::VirtualMachineDebugInfo; 26 use android_system_virtmanager::binder::{ 27 self, BinderFeatures, Interface, ParcelFileDescriptor, StatusCode, Strong, ThreadState, 28 }; 29 use log::{debug, error}; 30 use std::fs::File; 31 use std::sync::{Arc, Mutex, Weak}; 32 33 pub const BINDER_SERVICE_IDENTIFIER: &str = "android.system.virtmanager"; 34 35 // TODO(qwandor): Use PermissionController once it is available to Rust. 36 /// Only processes running with one of these UIDs are allowed to call debug methods. 37 const DEBUG_ALLOWED_UIDS: [u32; 2] = [0, 2000]; 38 39 /// Implementation of `IVirtManager`, the entry point of the AIDL service. 40 #[derive(Debug, Default)] 41 pub struct VirtManager { 42 state: Mutex<State>, 43 } 44 45 impl Interface for VirtManager {} 46 47 impl IVirtManager for VirtManager { 48 /// Create and start a new VM with the given configuration, assigning it the next available CID. 49 /// 50 /// Returns a binder `IVirtualMachine` object referring to it, as a handle for the client. 51 fn startVm( 52 &self, 53 config_fd: &ParcelFileDescriptor, 54 log_fd: Option<&ParcelFileDescriptor>, 55 ) -> binder::Result<Strong<dyn IVirtualMachine>> { 56 let state = &mut *self.state.lock().unwrap(); 57 let log_fd = log_fd 58 .map(|fd| fd.as_ref().try_clone().map_err(|_| StatusCode::UNKNOWN_ERROR)) 59 .transpose()?; 60 let requester_uid = ThreadState::get_calling_uid(); 61 let requester_sid = ThreadState::with_calling_sid(|sid| { 62 if let Some(sid) = sid { 63 match sid.to_str() { 64 Ok(sid) => Ok(sid.to_owned()), 65 Err(e) => { 66 error!("SID was not valid UTF-8: {:?}", e); 67 Err(StatusCode::BAD_VALUE) 68 } 69 } 70 } else { 71 error!("Missing SID on startVm"); 72 Err(StatusCode::UNKNOWN_ERROR) 73 } 74 })?; 75 let requester_debug_pid = ThreadState::get_calling_pid(); 76 let cid = state.allocate_cid()?; 77 let instance = start_vm( 78 config_fd.as_ref(), 79 cid, 80 log_fd, 81 requester_uid, 82 requester_sid, 83 requester_debug_pid, 84 )?; 85 state.add_vm(Arc::downgrade(&instance)); 86 Ok(VirtualMachine::create(instance)) 87 } 88 89 /// Get a list of all currently running VMs. This method is only intended for debug purposes, 90 /// and as such is only permitted from the shell user. 91 fn debugListVms(&self) -> binder::Result<Vec<VirtualMachineDebugInfo>> { 92 if !debug_access_allowed() { 93 return Err(StatusCode::PERMISSION_DENIED.into()); 94 } 95 96 let state = &mut *self.state.lock().unwrap(); 97 let vms = state.vms(); 98 let cids = vms 99 .into_iter() 100 .map(|vm| VirtualMachineDebugInfo { 101 cid: vm.cid as i32, 102 requesterUid: vm.requester_uid as i32, 103 requesterSid: vm.requester_sid.clone(), 104 requesterPid: vm.requester_debug_pid, 105 running: vm.running(), 106 }) 107 .collect(); 108 Ok(cids) 109 } 110 111 /// Hold a strong reference to a VM in Virt Manager. This method is only intended for debug 112 /// purposes, and as such is only permitted from the shell user. 113 fn debugHoldVmRef(&self, vmref: &Strong<dyn IVirtualMachine>) -> binder::Result<()> { 114 if !debug_access_allowed() { 115 return Err(StatusCode::PERMISSION_DENIED.into()); 116 } 117 118 let state = &mut *self.state.lock().unwrap(); 119 state.debug_hold_vm(vmref.clone()); 120 Ok(()) 121 } 122 123 /// Drop reference to a VM that is being held by Virt Manager. Returns the reference if VM was 124 /// found and None otherwise. This method is only intended for debug purposes, and as such is 125 /// only permitted from the shell user. 126 fn debugDropVmRef(&self, cid: i32) -> binder::Result<Option<Strong<dyn IVirtualMachine>>> { 127 if !debug_access_allowed() { 128 return Err(StatusCode::PERMISSION_DENIED.into()); 129 } 130 131 let state = &mut *self.state.lock().unwrap(); 132 Ok(state.debug_drop_vm(cid)) 133 } 134 } 135 136 /// Check whether the caller of the current Binder method is allowed to call debug methods. 137 fn debug_access_allowed() -> bool { 138 let uid = ThreadState::get_calling_uid(); 139 log::trace!("Debug method call from UID {}.", uid); 140 DEBUG_ALLOWED_UIDS.contains(&uid) 141 } 142 143 /// Implementation of the AIDL `IVirtualMachine` interface. Used as a handle to a VM. 144 #[derive(Debug)] 145 struct VirtualMachine { 146 instance: Arc<VmInstance>, 147 } 148 149 impl VirtualMachine { 150 fn create(instance: Arc<VmInstance>) -> Strong<dyn IVirtualMachine> { 151 let binder = VirtualMachine { instance }; 152 BnVirtualMachine::new_binder(binder, BinderFeatures::default()) 153 } 154 } 155 156 impl Interface for VirtualMachine {} 157 158 impl IVirtualMachine for VirtualMachine { 159 fn getCid(&self) -> binder::Result<i32> { 160 Ok(self.instance.cid as i32) 161 } 162 163 fn isRunning(&self) -> binder::Result<bool> { 164 Ok(self.instance.running()) 165 } 166 167 fn registerCallback( 168 &self, 169 callback: &Strong<dyn IVirtualMachineCallback>, 170 ) -> binder::Result<()> { 171 // TODO: Should this give an error if the VM is already dead? 172 self.instance.callbacks.add(callback.clone()); 173 Ok(()) 174 } 175 } 176 177 impl Drop for VirtualMachine { 178 fn drop(&mut self) { 179 debug!("Dropping {:?}", self); 180 self.instance.kill(); 181 } 182 } 183 184 /// A set of Binders to be called back in response to various events on the VM, such as when it 185 /// dies. 186 #[derive(Debug, Default)] 187 pub struct VirtualMachineCallbacks(Mutex<Vec<Strong<dyn IVirtualMachineCallback>>>); 188 189 impl VirtualMachineCallbacks { 190 /// Call all registered callbacks to say that the VM has died. 191 pub fn callback_on_died(&self, cid: Cid) { 192 let callbacks = &*self.0.lock().unwrap(); 193 for callback in callbacks { 194 if let Err(e) = callback.onDied(cid as i32) { 195 error!("Error calling callback: {}", e); 196 } 197 } 198 } 199 200 /// Add a new callback to the set. 201 fn add(&self, callback: Strong<dyn IVirtualMachineCallback>) { 202 self.0.lock().unwrap().push(callback); 203 } 204 } 205 206 /// The mutable state of the Virt Manager. There should only be one instance of this struct. 207 #[derive(Debug)] 208 struct State { 209 /// The next available unused CID. 210 next_cid: Cid, 211 212 /// The VMs which have been started. When VMs are started a weak reference is added to this list 213 /// while a strong reference is returned to the caller over Binder. Once all copies of the 214 /// Binder client are dropped the weak reference here will become invalid, and will be removed 215 /// from the list opportunistically the next time `add_vm` is called. 216 vms: Vec<Weak<VmInstance>>, 217 218 /// Vector of strong VM references held on behalf of users that cannot hold them themselves. 219 /// This is only used for debugging purposes. 220 debug_held_vms: Vec<Strong<dyn IVirtualMachine>>, 221 } 222 223 impl State { 224 /// Get a list of VMs which still have Binder references to them. 225 fn vms(&self) -> Vec<Arc<VmInstance>> { 226 // Attempt to upgrade the weak pointers to strong pointers. 227 self.vms.iter().filter_map(Weak::upgrade).collect() 228 } 229 230 /// Add a new VM to the list. 231 fn add_vm(&mut self, vm: Weak<VmInstance>) { 232 // Garbage collect any entries from the stored list which no longer exist. 233 self.vms.retain(|vm| vm.strong_count() > 0); 234 235 // Actually add the new VM. 236 self.vms.push(vm); 237 } 238 239 /// Store a strong VM reference. 240 fn debug_hold_vm(&mut self, vm: Strong<dyn IVirtualMachine>) { 241 self.debug_held_vms.push(vm); 242 } 243 244 /// Retrieve and remove a strong VM reference. 245 fn debug_drop_vm(&mut self, cid: i32) -> Option<Strong<dyn IVirtualMachine>> { 246 let pos = self.debug_held_vms.iter().position(|vm| vm.getCid() == Ok(cid))?; 247 Some(self.debug_held_vms.swap_remove(pos)) 248 } 249 250 /// Get the next available CID, or an error if we have run out. 251 fn allocate_cid(&mut self) -> binder::Result<Cid> { 252 // TODO(qwandor): keep track of which CIDs are currently in use so that we can reuse them. 253 let cid = self.next_cid; 254 self.next_cid = self.next_cid.checked_add(1).ok_or(StatusCode::UNKNOWN_ERROR)?; 255 Ok(cid) 256 } 257 } 258 259 impl Default for State { 260 fn default() -> Self { 261 State { next_cid: FIRST_GUEST_CID, vms: vec![], debug_held_vms: vec![] } 262 } 263 } 264 265 /// Start a new VM instance from the given VM config file. This assumes the VM is not already 266 /// running. 267 fn start_vm( 268 config_file: &File, 269 cid: Cid, 270 log_fd: Option<File>, 271 requester_uid: u32, 272 requester_sid: String, 273 requester_debug_pid: i32, 274 ) -> binder::Result<Arc<VmInstance>> { 275 let config = VmConfig::load(config_file).map_err(|e| { 276 error!("Failed to load VM config from {:?}: {:?}", config_file, e); 277 StatusCode::BAD_VALUE 278 })?; 279 Ok(VmInstance::start(&config, cid, log_fd, requester_uid, requester_sid, requester_debug_pid) 280 .map_err(|e| { 281 error!("Failed to start VM from {:?}: {:?}", config_file, e); 282 StatusCode::UNKNOWN_ERROR 283 })?) 284 } 285