// Copyright 2022, The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Android Virtualization Manager mod aidl; mod atom; mod composite; mod crosvm; mod debug_config; mod dt_overlay; mod payload; mod selinux; use crate::aidl::{GLOBAL_SERVICE, VirtualizationService}; use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualizationService::BnVirtualizationService; use anyhow::{bail, Context, Result}; use binder::{BinderFeatures, ProcessState}; use lazy_static::lazy_static; use log::{info, LevelFilter}; use rpcbinder::{FileDescriptorTransportMode, RpcServer}; use std::os::unix::io::{AsFd, FromRawFd, OwnedFd, RawFd}; use clap::Parser; use nix::fcntl::{fcntl, F_GETFD, F_SETFD, FdFlag}; use nix::unistd::{write, Pid, Uid}; use std::os::unix::raw::{pid_t, uid_t}; const LOG_TAG: &str = "virtmgr"; lazy_static! { static ref PID_CURRENT: Pid = Pid::this(); static ref PID_PARENT: Pid = Pid::parent(); static ref UID_CURRENT: Uid = Uid::current(); } fn get_this_pid() -> pid_t { // Return the process ID of this process. PID_CURRENT.as_raw() } fn get_calling_pid() -> pid_t { // The caller is the parent of this process. PID_PARENT.as_raw() } fn get_calling_uid() -> uid_t { // The caller and this process share the same UID. UID_CURRENT.as_raw() } #[derive(Parser)] struct Args { /// File descriptor inherited from the caller to run RpcBinder server on. /// This should be one end of a socketpair() compatible with RpcBinder's /// UDS bootstrap transport. #[clap(long)] rpc_server_fd: RawFd, /// File descriptor inherited from the caller to signal RpcBinder server /// readiness. This should be one end of pipe() and the caller should be /// waiting for HUP on the other end. #[clap(long)] ready_fd: RawFd, } fn take_fd_ownership(raw_fd: RawFd, owned_fds: &mut Vec) -> Result { // Basic check that the integer value does correspond to a file descriptor. fcntl(raw_fd, F_GETFD).with_context(|| format!("Invalid file descriptor {raw_fd}"))?; // The file descriptor had CLOEXEC disabled to be inherited from the parent. // Re-enable it to make sure it is not accidentally inherited further. fcntl(raw_fd, F_SETFD(FdFlag::FD_CLOEXEC)) .with_context(|| format!("Could not set CLOEXEC on file descriptor {raw_fd}"))?; // Creating OwnedFd for stdio FDs is not safe. if [libc::STDIN_FILENO, libc::STDOUT_FILENO, libc::STDERR_FILENO].contains(&raw_fd) { bail!("File descriptor {raw_fd} is standard I/O descriptor"); } // Reject RawFds that already have a corresponding OwnedFd. if owned_fds.contains(&raw_fd) { bail!("File descriptor {raw_fd} already owned"); } owned_fds.push(raw_fd); // SAFETY: Initializing OwnedFd for a RawFd provided in cmdline arguments. // We checked that the integer value corresponds to a valid FD and that this // is the first argument to claim its ownership. Ok(unsafe { OwnedFd::from_raw_fd(raw_fd) }) } fn check_vm_support() -> Result<()> { if hypervisor_props::is_any_vm_supported()? { Ok(()) } else { // This should never happen, it indicates a misconfigured device where the virt APEX // is present but VMs are not supported. If it does happen, fail fast to avoid wasting // resources trying. bail!("Device doesn't support protected or non-protected VMs") } } fn main() { android_logger::init_once( android_logger::Config::default() .with_tag(LOG_TAG) .with_max_level(LevelFilter::Info) .with_log_buffer(android_logger::LogId::System), ); check_vm_support().unwrap(); let args = Args::parse(); let mut owned_fds = vec![]; let rpc_server_fd = take_fd_ownership(args.rpc_server_fd, &mut owned_fds) .expect("Failed to take ownership of rpc_server_fd"); let ready_fd = take_fd_ownership(args.ready_fd, &mut owned_fds) .expect("Failed to take ownership of ready_fd"); // Start thread pool for kernel Binder connection to VirtualizationServiceInternal. ProcessState::start_thread_pool(); GLOBAL_SERVICE.removeMemlockRlimit().expect("Failed to remove memlock rlimit"); let service = VirtualizationService::init(); let service = BnVirtualizationService::new_binder(service, BinderFeatures::default()).as_binder(); let server = RpcServer::new_unix_domain_bootstrap(service, rpc_server_fd) .expect("Failed to start RpcServer"); server.set_supported_file_descriptor_transport_modes(&[FileDescriptorTransportMode::Unix]); info!("Started VirtualizationService RpcServer. Ready to accept connections"); // Signal readiness to the caller by closing our end of the pipe. write(ready_fd.as_fd(), "o".as_bytes()) .expect("Failed to write a single character through ready_fd"); drop(ready_fd); server.join(); info!("Shutting down VirtualizationService RpcServer"); }