blob: cd3bb6d313faf11489c30c94fb8bed624180a3a3 [file] [log] [blame]
Andrew Walbrand6dce6f2021-03-05 16:39:08 +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 Virt Manager.
16
Andrew Walbrana2f8c232021-03-11 11:46:53 +000017use crate::config::VmConfig;
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000018use crate::crosvm::VmInstance;
19use crate::{Cid, FIRST_GUEST_CID};
20use android_system_virtmanager::aidl::android::system::virtmanager::IVirtManager::IVirtManager;
21use android_system_virtmanager::aidl::android::system::virtmanager::IVirtualMachine::{
22 BnVirtualMachine, IVirtualMachine,
23};
Andrew Walbrandae07162021-03-12 17:05:20 +000024use android_system_virtmanager::aidl::android::system::virtmanager::IVirtualMachineCallback::IVirtualMachineCallback;
Andrew Walbran320b5602021-03-04 16:11:12 +000025use android_system_virtmanager::aidl::android::system::virtmanager::VirtualMachineDebugInfo::VirtualMachineDebugInfo;
Andrew Walbrana89fc132021-03-17 17:08:36 +000026use android_system_virtmanager::binder::{
Andrew Walbran4de28782021-04-13 14:51:43 +000027 self, BinderFeatures, Interface, ParcelFileDescriptor, StatusCode, Strong, ThreadState,
Andrew Walbrana89fc132021-03-17 17:08:36 +000028};
Andrew Walbrandae07162021-03-12 17:05:20 +000029use log::{debug, error};
Andrew Walbranf6a1eb92021-04-01 11:16:02 +000030use std::ffi::CStr;
Andrew Walbrana89fc132021-03-17 17:08:36 +000031use std::fs::File;
Andrew Walbran320b5602021-03-04 16:11:12 +000032use std::sync::{Arc, Mutex, Weak};
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000033
34pub const BINDER_SERVICE_IDENTIFIER: &str = "android.system.virtmanager";
35
Andrew Walbran320b5602021-03-04 16:11:12 +000036// TODO(qwandor): Use PermissionController once it is available to Rust.
37/// Only processes running with one of these UIDs are allowed to call debug methods.
38const DEBUG_ALLOWED_UIDS: [u32; 2] = [0, 2000];
39
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000040/// Implementation of `IVirtManager`, the entry point of the AIDL service.
41#[derive(Debug, Default)]
42pub struct VirtManager {
Andrew Walbran9c01baa2021-03-08 18:23:50 +000043 state: Mutex<State>,
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000044}
45
46impl Interface for VirtManager {}
47
48impl IVirtManager for VirtManager {
49 /// Create and start a new VM with the given configuration, assigning it the next available CID.
50 ///
51 /// Returns a binder `IVirtualMachine` object referring to it, as a handle for the client.
Andrew Walbrana89fc132021-03-17 17:08:36 +000052 fn startVm(
53 &self,
Andrew Walbran06b5f5c2021-03-31 12:34:13 +000054 config_fd: &ParcelFileDescriptor,
Andrew Walbrana89fc132021-03-17 17:08:36 +000055 log_fd: Option<&ParcelFileDescriptor>,
56 ) -> binder::Result<Strong<dyn IVirtualMachine>> {
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000057 let state = &mut *self.state.lock().unwrap();
Andrew Walbrana89fc132021-03-17 17:08:36 +000058 let log_fd = log_fd
59 .map(|fd| fd.as_ref().try_clone().map_err(|_| StatusCode::UNKNOWN_ERROR))
60 .transpose()?;
Andrew Walbranf6a1eb92021-04-01 11:16:02 +000061 let requester_uid = ThreadState::get_calling_uid();
62 let requester_sid = ThreadState::with_calling_sid(|sid| {
63 sid.and_then(|sid: &CStr| match sid.to_str() {
64 Ok(s) => Some(s.to_owned()),
65 Err(e) => {
66 error!("SID was not valid UTF-8: {:?}", e);
67 None
68 }
69 })
70 });
71 let requester_pid = ThreadState::get_calling_pid();
Andrew Walbrandae07162021-03-12 17:05:20 +000072 let cid = state.allocate_cid()?;
73 let instance =
74 start_vm(config_fd.as_ref(), cid, log_fd, requester_uid, requester_sid, requester_pid)?;
Andrew Walbran320b5602021-03-04 16:11:12 +000075 state.add_vm(Arc::downgrade(&instance));
76 Ok(VirtualMachine::create(instance))
Andrew Walbrand6dce6f2021-03-05 16:39:08 +000077 }
Andrew Walbran320b5602021-03-04 16:11:12 +000078
79 /// Get a list of all currently running VMs. This method is only intended for debug purposes,
80 /// and as such is only permitted from the shell user.
81 fn debugListVms(&self) -> binder::Result<Vec<VirtualMachineDebugInfo>> {
82 if !debug_access_allowed() {
83 return Err(StatusCode::PERMISSION_DENIED.into());
84 }
85
86 let state = &mut *self.state.lock().unwrap();
87 let vms = state.vms();
Andrew Walbranf6a1eb92021-04-01 11:16:02 +000088 let cids = vms
89 .into_iter()
90 .map(|vm| VirtualMachineDebugInfo {
91 cid: vm.cid as i32,
Andrew Walbran1ef19ae2021-04-07 11:31:57 +000092 requesterUid: vm.requester_uid as i32,
93 requesterSid: vm.requester_sid.clone(),
94 requesterPid: vm.requester_pid,
Andrew Walbrandae07162021-03-12 17:05:20 +000095 running: vm.running(),
Andrew Walbranf6a1eb92021-04-01 11:16:02 +000096 })
97 .collect();
Andrew Walbran320b5602021-03-04 16:11:12 +000098 Ok(cids)
99 }
David Brazdil3c2ddef2021-03-18 13:09:57 +0000100
101 /// Hold a strong reference to a VM in Virt Manager. This method is only intended for debug
102 /// purposes, and as such is only permitted from the shell user.
Andrei Homescu1415c132021-03-24 02:39:55 +0000103 fn debugHoldVmRef(&self, vmref: &Strong<dyn IVirtualMachine>) -> binder::Result<()> {
David Brazdil3c2ddef2021-03-18 13:09:57 +0000104 if !debug_access_allowed() {
105 return Err(StatusCode::PERMISSION_DENIED.into());
106 }
107
David Brazdil3c2ddef2021-03-18 13:09:57 +0000108 let state = &mut *self.state.lock().unwrap();
Andrei Homescu1415c132021-03-24 02:39:55 +0000109 state.debug_hold_vm(vmref.clone());
David Brazdil3c2ddef2021-03-18 13:09:57 +0000110 Ok(())
111 }
112
113 /// Drop reference to a VM that is being held by Virt Manager. Returns the reference if VM was
114 /// found and None otherwise. This method is only intended for debug purposes, and as such is
115 /// only permitted from the shell user.
116 fn debugDropVmRef(&self, cid: i32) -> binder::Result<Option<Strong<dyn IVirtualMachine>>> {
117 if !debug_access_allowed() {
118 return Err(StatusCode::PERMISSION_DENIED.into());
119 }
120
121 let state = &mut *self.state.lock().unwrap();
122 Ok(state.debug_drop_vm(cid))
123 }
Andrew Walbran320b5602021-03-04 16:11:12 +0000124}
125
126/// Check whether the caller of the current Binder method is allowed to call debug methods.
127fn debug_access_allowed() -> bool {
128 let uid = ThreadState::get_calling_uid();
129 log::trace!("Debug method call from UID {}.", uid);
130 DEBUG_ALLOWED_UIDS.contains(&uid)
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000131}
132
133/// Implementation of the AIDL `IVirtualMachine` interface. Used as a handle to a VM.
134#[derive(Debug)]
135struct VirtualMachine {
136 instance: Arc<VmInstance>,
137}
138
139impl VirtualMachine {
140 fn create(instance: Arc<VmInstance>) -> Strong<dyn IVirtualMachine> {
141 let binder = VirtualMachine { instance };
Andrew Walbran4de28782021-04-13 14:51:43 +0000142 BnVirtualMachine::new_binder(binder, BinderFeatures::default())
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000143 }
144}
145
146impl Interface for VirtualMachine {}
147
148impl IVirtualMachine for VirtualMachine {
149 fn getCid(&self) -> binder::Result<i32> {
150 Ok(self.instance.cid as i32)
151 }
Andrew Walbrandae07162021-03-12 17:05:20 +0000152
153 fn isRunning(&self) -> binder::Result<bool> {
154 Ok(self.instance.running())
155 }
156
157 fn registerCallback(
158 &self,
159 callback: &Strong<dyn IVirtualMachineCallback>,
160 ) -> binder::Result<()> {
161 // TODO: Should this give an error if the VM is already dead?
162 self.instance.callbacks.add(callback.clone());
163 Ok(())
164 }
165}
166
167impl Drop for VirtualMachine {
168 fn drop(&mut self) {
169 debug!("Dropping {:?}", self);
170 self.instance.kill();
171 }
172}
173
174/// A set of Binders to be called back in response to various events on the VM, such as when it
175/// dies.
176#[derive(Debug, Default)]
177pub struct VirtualMachineCallbacks(Mutex<Vec<Strong<dyn IVirtualMachineCallback>>>);
178
179impl VirtualMachineCallbacks {
180 /// Call all registered callbacks to say that the VM has died.
181 pub fn callback_on_died(&self, cid: Cid) {
182 let callbacks = &*self.0.lock().unwrap();
183 for callback in callbacks {
184 if let Err(e) = callback.onDied(cid as i32) {
185 error!("Error calling callback: {}", e);
186 }
187 }
188 }
189
190 /// Add a new callback to the set.
191 fn add(&self, callback: Strong<dyn IVirtualMachineCallback>) {
192 self.0.lock().unwrap().push(callback);
193 }
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000194}
195
196/// The mutable state of the Virt Manager. There should only be one instance of this struct.
197#[derive(Debug)]
198struct State {
Andrew Walbran320b5602021-03-04 16:11:12 +0000199 /// The next available unused CID.
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000200 next_cid: Cid,
Andrew Walbran320b5602021-03-04 16:11:12 +0000201
202 /// The VMs which have been started. When VMs are started a weak reference is added to this list
203 /// while a strong reference is returned to the caller over Binder. Once all copies of the
204 /// Binder client are dropped the weak reference here will become invalid, and will be removed
205 /// from the list opportunistically the next time `add_vm` is called.
206 vms: Vec<Weak<VmInstance>>,
David Brazdil3c2ddef2021-03-18 13:09:57 +0000207
208 /// Vector of strong VM references held on behalf of users that cannot hold them themselves.
209 /// This is only used for debugging purposes.
210 debug_held_vms: Vec<Strong<dyn IVirtualMachine>>,
Andrew Walbran320b5602021-03-04 16:11:12 +0000211}
212
213impl State {
Andrew Walbrandae07162021-03-12 17:05:20 +0000214 /// Get a list of VMs which still have Binder references to them.
Andrew Walbran320b5602021-03-04 16:11:12 +0000215 fn vms(&self) -> Vec<Arc<VmInstance>> {
216 // Attempt to upgrade the weak pointers to strong pointers.
217 self.vms.iter().filter_map(Weak::upgrade).collect()
218 }
219
220 /// Add a new VM to the list.
221 fn add_vm(&mut self, vm: Weak<VmInstance>) {
222 // Garbage collect any entries from the stored list which no longer exist.
223 self.vms.retain(|vm| vm.strong_count() > 0);
224
225 // Actually add the new VM.
226 self.vms.push(vm);
227 }
David Brazdil3c2ddef2021-03-18 13:09:57 +0000228
229 /// Store a strong VM reference.
230 fn debug_hold_vm(&mut self, vm: Strong<dyn IVirtualMachine>) {
231 self.debug_held_vms.push(vm);
232 }
233
234 /// Retrieve and remove a strong VM reference.
235 fn debug_drop_vm(&mut self, cid: i32) -> Option<Strong<dyn IVirtualMachine>> {
236 let pos = self.debug_held_vms.iter().position(|vm| vm.getCid() == Ok(cid))?;
237 Some(self.debug_held_vms.swap_remove(pos))
238 }
Andrew Walbrandae07162021-03-12 17:05:20 +0000239
240 /// Get the next available CID, or an error if we have run out.
241 fn allocate_cid(&mut self) -> binder::Result<Cid> {
242 // TODO(qwandor): keep track of which CIDs are currently in use so that we can reuse them.
243 let cid = self.next_cid;
244 self.next_cid = self.next_cid.checked_add(1).ok_or(StatusCode::UNKNOWN_ERROR)?;
245 Ok(cid)
246 }
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000247}
248
249impl Default for State {
250 fn default() -> Self {
David Brazdil3c2ddef2021-03-18 13:09:57 +0000251 State { next_cid: FIRST_GUEST_CID, vms: vec![], debug_held_vms: vec![] }
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000252 }
253}
254
Andrew Walbranf6a1eb92021-04-01 11:16:02 +0000255/// Start a new VM instance from the given VM config file. This assumes the VM is not already
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000256/// running.
Andrew Walbranf6a1eb92021-04-01 11:16:02 +0000257fn start_vm(
258 config_file: &File,
259 cid: Cid,
260 log_fd: Option<File>,
261 requester_uid: u32,
262 requester_sid: Option<String>,
263 requester_pid: i32,
Andrew Walbrandae07162021-03-12 17:05:20 +0000264) -> binder::Result<Arc<VmInstance>> {
Andrew Walbran06b5f5c2021-03-31 12:34:13 +0000265 let config = VmConfig::load(config_file).map_err(|e| {
266 error!("Failed to load VM config from {:?}: {:?}", config_file, e);
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000267 StatusCode::BAD_VALUE
268 })?;
Andrew Walbranf6a1eb92021-04-01 11:16:02 +0000269 Ok(VmInstance::start(&config, cid, log_fd, requester_uid, requester_sid, requester_pid)
270 .map_err(|e| {
271 error!("Failed to start VM from {:?}: {:?}", config_file, e);
272 StatusCode::UNKNOWN_ERROR
273 })?)
Andrew Walbrand6dce6f2021-03-05 16:39:08 +0000274}