blob: 1c79452020e2616683c2cbddd2bd624be6638344 [file] [log] [blame]
Jooyung Han347d9f22021-05-28 00:05:14 +09001// 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//! Microdroid Manager
16
Andrew Sculld64ae7d2022-10-05 17:41:43 +000017mod dice;
Jiyong Park21ce2c52021-08-28 02:32:17 +090018mod instance;
Jooyung Hanf48ceb42021-06-01 18:00:04 +090019mod ioutil;
Jooyung Han7a343f92021-09-08 22:53:11 +090020mod payload;
Keir Fraser933f0ac2022-10-12 08:23:28 +000021mod swap;
Alice Wang59a9e562022-10-04 15:24:10 +000022mod vm_payload_service;
Jooyung Han347d9f22021-05-28 00:05:14 +090023
Alice Wang285a3d22023-03-01 11:36:29 +000024use crate::dice::{DiceDriver, derive_sealing_key, format_payload_config_descriptor};
Inseob Kime379e7d2022-07-22 18:55:18 +090025use crate::instance::{ApexData, ApkData, InstanceDisk, MicrodroidData, RootHash};
Alice Wang59a9e562022-10-04 15:24:10 +000026use crate::vm_payload_service::register_vm_payload_service;
Alan Stokes2bead0d2022-09-05 16:58:34 +010027use android_system_virtualizationcommon::aidl::android::system::virtualizationcommon::ErrorCode::ErrorCode;
David Brazdil73988ea2022-11-11 15:10:32 +000028use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::IVirtualMachineService;
Inseob Kim090b70b2022-11-16 20:01:14 +090029use android_system_virtualization_payload::aidl::android::system::virtualization::payload::IVmPayloadService::{
30 VM_APK_CONTENTS_PATH,
31 VM_PAYLOAD_SERVICE_SOCKET_NAME,
Shikha Panwarddc124b2022-11-28 19:17:54 +000032 ENCRYPTEDSTORE_MOUNTPOINT,
Inseob Kim090b70b2022-11-16 20:01:14 +090033};
Jooyung Handd0a1732021-11-23 15:26:20 +090034use anyhow::{anyhow, bail, ensure, Context, Error, Result};
Alice Wang1bf3d782022-09-28 07:56:36 +000035use apkverify::{get_public_key_der, verify, V4Signature};
Alice Wang43c884b2022-10-24 09:42:40 +000036use binder::Strong;
Alice Wang62f7e642023-02-10 09:55:13 +000037use diced_open_dice::OwnedDiceArtifacts;
Inseob Kim197748b2021-12-01 19:49:00 +090038use glob::glob;
Inseob Kim197748b2021-12-01 19:49:00 +090039use itertools::sorted;
David Brazdila07a1792022-10-25 13:37:57 +010040use libc::VMADDR_CID_HOST;
Alice Wang2a5306e2023-06-05 09:18:32 +000041use log::{error, info};
Alice Wang7e6c9352023-02-15 15:44:13 +000042use keystore2_crypto::ZVec;
Alan Stokes0d1ef782022-09-27 13:46:35 +010043use microdroid_metadata::{write_metadata, Metadata, PayloadMetadata};
Seungjae Yoofd9a0622022-10-14 10:01:29 +090044use microdroid_payload_config::{OsConfig, Task, TaskType, VmPayloadConfig};
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -080045use nix::sys::signal::Signal;
Andrew Sculla0d1b1a2022-05-24 19:32:47 +000046use openssl::sha::Sha512;
Jooyung Han4a9b3bf2021-09-10 17:19:00 +090047use payload::{get_apex_data_from_payload, load_metadata, to_metadata};
Andrew Scull34916a72022-01-30 21:34:24 +000048use rand::Fill;
David Brazdila2125dd2022-12-14 16:37:44 +000049use rpcbinder::RpcSession;
Inseob Kim090b70b2022-11-16 20:01:14 +090050use rustutils::sockets::android_get_control_socket;
Jiyong Parkbb4a9872021-09-06 15:59:21 +090051use rustutils::system_properties;
Joel Galenson482704c2021-07-29 15:53:53 -070052use rustutils::system_properties::PropertyWatcher;
Alan Stokes3ba10fd2022-10-06 15:46:51 +010053use std::borrow::Cow::{Borrowed, Owned};
Andrew Scullb2f44472022-01-21 14:41:34 +000054use std::convert::TryInto;
Inseob Kim7ff121c2022-11-14 18:13:23 +090055use std::env;
Shikha Panwardef7ef92023-01-06 08:35:48 +000056use std::ffi::CString;
Jaewan Kim3124ef02023-03-23 19:25:20 +090057use std::fs::{self, create_dir, OpenOptions, File};
58use std::io::{Read, Write};
Nikita Ioffe3452ee22022-12-15 00:31:56 +000059use std::os::unix::process::CommandExt;
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -080060use std::os::unix::process::ExitStatusExt;
Alice Wangfd222fd2023-05-25 09:37:38 +000061use std::os::unix::io::{FromRawFd, OwnedFd};
Jooyung Hanf48ceb42021-06-01 18:00:04 +090062use std::path::Path;
Inseob Kim217038e2021-11-25 11:15:06 +090063use std::process::{Child, Command, Stdio};
Jiyong Park8611a6c2021-07-09 18:17:44 +090064use std::str;
Jiyong Parkbb4a9872021-09-06 15:59:21 +090065use std::time::{Duration, SystemTime};
Jooyung Han634e2d72021-06-10 16:27:38 +090066
67const WAIT_TIMEOUT: Duration = Duration::from_secs(10);
Inseob Kim197748b2021-12-01 19:49:00 +090068const MAIN_APK_PATH: &str = "/dev/block/by-name/microdroid-apk";
69const MAIN_APK_IDSIG_PATH: &str = "/dev/block/by-name/microdroid-apk-idsig";
70const MAIN_APK_DEVICE_NAME: &str = "microdroid-apk";
71const EXTRA_APK_PATH_PATTERN: &str = "/dev/block/by-name/extra-apk-*";
72const EXTRA_IDSIG_PATH_PATTERN: &str = "/dev/block/by-name/extra-idsig-*";
Jooyung Han19c1d6c2021-08-06 14:08:16 +090073const DM_MOUNTED_APK_PATH: &str = "/dev/block/mapper/microdroid-apk";
Andrew Scullab72ec52022-03-14 09:10:52 +000074const AVF_STRICT_BOOT: &str = "/sys/firmware/devicetree/base/chosen/avf,strict-boot";
75const AVF_NEW_INSTANCE: &str = "/sys/firmware/devicetree/base/chosen/avf,new-instance";
Jaewan Kim3124ef02023-03-23 19:25:20 +090076const AVF_DEBUG_POLICY_RAMDUMP: &str = "/sys/firmware/devicetree/base/avf/guest/common/ramdump";
Inseob Kime379e7d2022-07-22 18:55:18 +090077const DEBUG_MICRODROID_NO_VERIFIED_BOOT: &str =
78 "/sys/firmware/devicetree/base/virtualization/guest/debug-microdroid,no-verified-boot";
Jooyung Han347d9f22021-05-28 00:05:14 +090079
Alan Stokes4fb201c2023-02-08 17:39:05 +000080const APKDMVERITY_BIN: &str = "/system/bin/apkdmverity";
81const ENCRYPTEDSTORE_BIN: &str = "/system/bin/encryptedstore";
82const ZIPFUSE_BIN: &str = "/system/bin/zipfuse";
83
Jiyong Parkbb4a9872021-09-06 15:59:21 +090084const APEX_CONFIG_DONE_PROP: &str = "apex_config.done";
Seungjae Yoofa22bb02022-12-08 16:38:42 +090085const DEBUGGABLE_PROP: &str = "ro.boot.microdroid.debuggable";
Jiyong Parkbb4a9872021-09-06 15:59:21 +090086
Inseob Kim11f40d02022-06-13 17:16:00 +090087// SYNC WITH virtualizationservice/src/crosvm.rs
88const FAILURE_SERIAL_DEVICE: &str = "/dev/ttyS1";
89
Shikha Panwar566c9672022-11-15 14:39:58 +000090const ENCRYPTEDSTORE_BACKING_DEVICE: &str = "/dev/block/by-name/encryptedstore";
Shikha Panwar566c9672022-11-15 14:39:58 +000091const ENCRYPTEDSTORE_KEY_IDENTIFIER: &str = "encryptedstore_key";
Alice Wang62f7e642023-02-10 09:55:13 +000092const ENCRYPTEDSTORE_KEYSIZE: usize = 32;
Shikha Panwar566c9672022-11-15 14:39:58 +000093
Jooyung Handd0a1732021-11-23 15:26:20 +090094#[derive(thiserror::Error, Debug)]
95enum MicrodroidError {
Inseob Kim11f40d02022-06-13 17:16:00 +090096 #[error("Cannot connect to virtualization service: {0}")]
97 FailedToConnectToVirtualizationService(String),
Jooyung Handd0a1732021-11-23 15:26:20 +090098 #[error("Payload has changed: {0}")]
99 PayloadChanged(String),
100 #[error("Payload verification has failed: {0}")]
101 PayloadVerificationFailed(String),
Jooyung Han5c6d4172021-12-06 14:17:52 +0900102 #[error("Payload config is invalid: {0}")]
103 InvalidConfig(String),
Jooyung Handd0a1732021-11-23 15:26:20 +0900104}
105
Alan Stokes2bead0d2022-09-05 16:58:34 +0100106fn translate_error(err: &Error) -> (ErrorCode, String) {
Jooyung Handd0a1732021-11-23 15:26:20 +0900107 if let Some(e) = err.downcast_ref::<MicrodroidError>() {
108 match e {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100109 MicrodroidError::PayloadChanged(msg) => (ErrorCode::PAYLOAD_CHANGED, msg.to_string()),
Jooyung Handd0a1732021-11-23 15:26:20 +0900110 MicrodroidError::PayloadVerificationFailed(msg) => {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100111 (ErrorCode::PAYLOAD_VERIFICATION_FAILED, msg.to_string())
Jooyung Handd0a1732021-11-23 15:26:20 +0900112 }
Alan Stokes2bead0d2022-09-05 16:58:34 +0100113 MicrodroidError::InvalidConfig(msg) => {
114 (ErrorCode::PAYLOAD_CONFIG_INVALID, msg.to_string())
115 }
Inseob Kim11f40d02022-06-13 17:16:00 +0900116
117 // Connection failure won't be reported to VS; return the default value
118 MicrodroidError::FailedToConnectToVirtualizationService(msg) => {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100119 (ErrorCode::UNKNOWN, msg.to_string())
Inseob Kim11f40d02022-06-13 17:16:00 +0900120 }
Jooyung Handd0a1732021-11-23 15:26:20 +0900121 }
122 } else {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100123 (ErrorCode::UNKNOWN, err.to_string())
Jooyung Handd0a1732021-11-23 15:26:20 +0900124 }
125}
126
Inseob Kim11f40d02022-06-13 17:16:00 +0900127fn write_death_reason_to_serial(err: &Error) -> Result<()> {
128 let death_reason = if let Some(e) = err.downcast_ref::<MicrodroidError>() {
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100129 Borrowed(match e {
Inseob Kim11f40d02022-06-13 17:16:00 +0900130 MicrodroidError::FailedToConnectToVirtualizationService(_) => {
131 "MICRODROID_FAILED_TO_CONNECT_TO_VIRTUALIZATION_SERVICE"
132 }
133 MicrodroidError::PayloadChanged(_) => "MICRODROID_PAYLOAD_HAS_CHANGED",
134 MicrodroidError::PayloadVerificationFailed(_) => {
135 "MICRODROID_PAYLOAD_VERIFICATION_FAILED"
136 }
137 MicrodroidError::InvalidConfig(_) => "MICRODROID_INVALID_PAYLOAD_CONFIG",
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100138 })
Inseob Kim11f40d02022-06-13 17:16:00 +0900139 } else {
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100140 // Send context information back after a separator, to ease diagnosis.
141 // These errors occur before the payload runs, so this should not leak sensitive
142 // information.
143 Owned(format!("MICRODROID_UNKNOWN_RUNTIME_ERROR|{:?}", err))
Inseob Kim11f40d02022-06-13 17:16:00 +0900144 };
145
146 let death_reason_bytes = death_reason.as_bytes();
147 let mut sent_total = 0;
148 while sent_total < death_reason_bytes.len() {
149 // TODO(b/220071963): Sometimes, sending more than 16 bytes at once makes MM hang.
150 let begin = sent_total;
151 let end = std::cmp::min(begin.saturating_add(16), death_reason_bytes.len());
152 OpenOptions::new()
153 .read(false)
154 .write(true)
155 .open(FAILURE_SERIAL_DEVICE)?
156 .write_all(&death_reason_bytes[begin..end])?;
157 sent_total = end;
158 }
159
160 Ok(())
161}
162
Inseob Kim1b95f2e2021-08-19 13:17:40 +0900163fn get_vms_rpc_binder() -> Result<Strong<dyn IVirtualMachineService>> {
David Brazdil73988ea2022-11-11 15:10:32 +0000164 // The host is running a VirtualMachineService for this VM on a port equal
165 // to the CID of this VM.
166 let port = vsock::get_local_cid().context("Could not determine local CID")?;
David Brazdila2125dd2022-12-14 16:37:44 +0000167 RpcSession::new()
168 .setup_vsock_client(VMADDR_CID_HOST, port)
David Brazdil73988ea2022-11-11 15:10:32 +0000169 .context("Could not connect to IVirtualMachineService")
Inseob Kim1b95f2e2021-08-19 13:17:40 +0900170}
171
Inseob Kim437f1052022-06-21 11:30:22 +0900172fn main() -> Result<()> {
Inseob Kim7ff121c2022-11-14 18:13:23 +0900173 // If debuggable, print full backtrace to console log with stdio_to_kmsg
Seungjae Yoofa22bb02022-12-08 16:38:42 +0900174 if system_properties::read_bool(DEBUGGABLE_PROP, true)? {
Inseob Kim7ff121c2022-11-14 18:13:23 +0900175 env::set_var("RUST_BACKTRACE", "full");
176 }
177
Inseob Kim437f1052022-06-21 11:30:22 +0900178 scopeguard::defer! {
179 info!("Shutting down...");
Jooyung Hanbfe086f2021-10-28 10:15:45 +0900180 if let Err(e) = system_properties::write("sys.powerctl", "shutdown") {
181 error!("failed to shutdown {:?}", e);
182 }
Jooyung Han311b1202021-09-14 22:00:16 +0900183 }
Inseob Kim437f1052022-06-21 11:30:22 +0900184
185 try_main().map_err(|e| {
186 error!("Failed with {:?}.", e);
187 if let Err(e) = write_death_reason_to_serial(&e) {
188 error!("Failed to write death reason {:?}", e);
189 }
190 e
191 })
Jooyung Han311b1202021-09-14 22:00:16 +0900192}
193
Alice Wangfd222fd2023-05-25 09:37:38 +0000194/// Prepares a socket file descriptor for the vm payload service.
195///
Andrew Walbranae3350d2023-07-21 19:01:18 +0100196/// # Safety
Alice Wangfd222fd2023-05-25 09:37:38 +0000197///
198/// The caller must ensure that this function is the only place that claims ownership
199/// of the file descriptor and it is called only once.
200unsafe fn prepare_vm_payload_service_socket() -> Result<OwnedFd> {
201 let raw_fd = android_get_control_socket(VM_PAYLOAD_SERVICE_SOCKET_NAME)?;
Inseob Kim090b70b2022-11-16 20:01:14 +0900202
Alice Wangfd222fd2023-05-25 09:37:38 +0000203 // Creating OwnedFd for stdio FDs is not safe.
204 if [libc::STDIN_FILENO, libc::STDOUT_FILENO, libc::STDERR_FILENO].contains(&raw_fd) {
205 bail!("File descriptor {raw_fd} is standard I/O descriptor");
206 }
207 // SAFETY: Initializing OwnedFd for a RawFd created by the init.
208 // We checked that the integer value corresponds to a valid FD and that the caller
209 // ensures that this is the only place to claim its ownership.
210 Ok(unsafe { OwnedFd::from_raw_fd(raw_fd) })
Inseob Kim090b70b2022-11-16 20:01:14 +0900211}
212
Jooyung Han311b1202021-09-14 22:00:16 +0900213fn try_main() -> Result<()> {
Jiyong Park2b6346d2023-06-19 13:37:42 +0900214 android_logger::init_once(
215 android_logger::Config::default()
216 .with_tag("microdroid_manager")
217 .with_min_level(log::Level::Info),
218 );
Jooyung Han347d9f22021-05-28 00:05:14 +0900219 info!("started.");
220
Alice Wangfd222fd2023-05-25 09:37:38 +0000221 // SAFETY: This is the only place we take the ownership of the fd of the vm payload service.
222 //
Alice Wang2a5306e2023-06-05 09:18:32 +0000223 // To ensure that the CLOEXEC flag is set on the file descriptor as early as possible,
224 // it is necessary to fetch the socket corresponding to vm_payload_service at the
225 // very beginning, as android_get_control_socket() sets the CLOEXEC flag on the file
226 // descriptor.
Alice Wangfd222fd2023-05-25 09:37:38 +0000227 let vm_payload_service_fd = unsafe { prepare_vm_payload_service_socket()? };
Inseob Kim090b70b2022-11-16 20:01:14 +0900228
Jiyong Park202856e2022-08-22 16:04:26 +0900229 load_crashkernel_if_supported().context("Failed to load crashkernel")?;
230
Alice Wangeff58392023-07-04 13:32:09 +0000231 swap::init_swap().context("Failed to initialize swap")?;
Keir Fraser933f0ac2022-10-12 08:23:28 +0000232 info!("swap enabled.");
233
Inseob Kim11f40d02022-06-13 17:16:00 +0900234 let service = get_vms_rpc_binder()
235 .context("cannot connect to VirtualMachineService")
236 .map_err(|e| MicrodroidError::FailedToConnectToVirtualizationService(e.to_string()))?;
Seungjae Yoofd9a0622022-10-14 10:01:29 +0900237
Alice Wangfd222fd2023-05-25 09:37:38 +0000238 match try_run_payload(&service, vm_payload_service_fd) {
Jooyung Han5c6d4172021-12-06 14:17:52 +0900239 Ok(code) => {
Jooyung Han5c6d4172021-12-06 14:17:52 +0900240 if code == 0 {
241 info!("task successfully finished");
242 } else {
243 error!("task exited with exit code: {}", code);
244 }
Shikha Panwardef7ef92023-01-06 08:35:48 +0000245 if let Err(e) = post_payload_work() {
246 error!(
247 "Failed to run post payload work. It is possible that certain tasks
248 like syncing encrypted store might be incomplete. Error: {:?}",
249 e
250 );
251 };
252
253 info!("notifying payload finished");
254 service.notifyPayloadFinished(code)?;
Jooyung Han5c6d4172021-12-06 14:17:52 +0900255 Ok(())
256 }
257 Err(err) => {
Jooyung Han5c6d4172021-12-06 14:17:52 +0900258 let (error_code, message) = translate_error(&err);
259 service.notifyError(error_code, &message)?;
260 Err(err)
261 }
Jooyung Handd0a1732021-11-23 15:26:20 +0900262 }
263}
264
Shikha Panwardef7ef92023-01-06 08:35:48 +0000265fn post_payload_work() -> Result<()> {
266 // Sync the encrypted storage filesystem (flushes the filesystem caches).
267 if Path::new(ENCRYPTEDSTORE_BACKING_DEVICE).exists() {
268 let mountpoint = CString::new(ENCRYPTEDSTORE_MOUNTPOINT).unwrap();
269
Andrew Walbranae3350d2023-07-21 19:01:18 +0100270 // SAFETY: `mountpoint` is a valid C string. `syncfs` and `close` are safe for any parameter
271 // values.
Shikha Panwardef7ef92023-01-06 08:35:48 +0000272 let ret = unsafe {
273 let dirfd = libc::open(
274 mountpoint.as_ptr(),
275 libc::O_DIRECTORY | libc::O_RDONLY | libc::O_CLOEXEC,
276 );
277 ensure!(dirfd >= 0, "Unable to open {:?}", mountpoint);
278 let ret = libc::syncfs(dirfd);
279 libc::close(dirfd);
280 ret
281 };
282 if ret != 0 {
283 error!("failed to sync encrypted storage.");
284 return Err(anyhow!(std::io::Error::last_os_error()));
285 }
286 }
287 Ok(())
288}
Alan Stokes1f417c92022-09-29 15:13:28 +0100289fn dice_derivation(
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000290 dice: DiceDriver,
Alan Stokes1f417c92022-09-29 15:13:28 +0100291 verified_data: &MicrodroidData,
292 payload_metadata: &PayloadMetadata,
Alice Wang62f7e642023-02-10 09:55:13 +0000293) -> Result<OwnedDiceArtifacts> {
Andrew Scullb2f44472022-01-21 14:41:34 +0000294 // Calculate compound digests of code and authorities
Andrew Sculla0d1b1a2022-05-24 19:32:47 +0000295 let mut code_hash_ctx = Sha512::new();
296 let mut authority_hash_ctx = Sha512::new();
Andrew Scullb2f44472022-01-21 14:41:34 +0000297 code_hash_ctx.update(verified_data.apk_data.root_hash.as_ref());
298 authority_hash_ctx.update(verified_data.apk_data.pubkey.as_ref());
Inseob Kimb2519c52022-04-14 02:10:09 +0900299 for extra_apk in &verified_data.extra_apks_data {
Andrew Scullb2f44472022-01-21 14:41:34 +0000300 code_hash_ctx.update(extra_apk.root_hash.as_ref());
301 authority_hash_ctx.update(extra_apk.pubkey.as_ref());
302 }
Inseob Kimb2519c52022-04-14 02:10:09 +0900303 for apex in &verified_data.apex_data {
Andrew Scullb2f44472022-01-21 14:41:34 +0000304 code_hash_ctx.update(apex.root_digest.as_ref());
305 authority_hash_ctx.update(apex.public_key.as_ref());
306 }
Andrew Sculla0d1b1a2022-05-24 19:32:47 +0000307 let code_hash = code_hash_ctx.finish();
308 let authority_hash = authority_hash_ctx.finish();
Andrew Scullb2f44472022-01-21 14:41:34 +0000309
Alice Wang285a3d22023-03-01 11:36:29 +0000310 let config_descriptor = format_payload_config_descriptor(payload_metadata)?;
Andrew Scullb2f44472022-01-21 14:41:34 +0000311
Seungjae Yoofa22bb02022-12-08 16:38:42 +0900312 // Check debuggability, conservatively assuming it is debuggable
313 let debuggable = system_properties::read_bool(DEBUGGABLE_PROP, true)?;
Andrew Scull65ddfc42022-02-14 21:03:58 +0000314
Andrew Scullb2f44472022-01-21 14:41:34 +0000315 // Send the details to diced
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000316 let hidden = verified_data.salt.clone().try_into().unwrap();
Alice Wang285a3d22023-03-01 11:36:29 +0000317 dice.derive(code_hash, &config_descriptor, authority_hash, debuggable, hidden)
Alan Stokes1f417c92022-09-29 15:13:28 +0100318}
319
Andrew Scullab72ec52022-03-14 09:10:52 +0000320fn is_strict_boot() -> bool {
321 Path::new(AVF_STRICT_BOOT).exists()
322}
323
324fn is_new_instance() -> bool {
325 Path::new(AVF_NEW_INSTANCE).exists()
326}
327
Inseob Kime379e7d2022-07-22 18:55:18 +0900328fn is_verified_boot() -> bool {
329 !Path::new(DEBUG_MICRODROID_NO_VERIFIED_BOOT).exists()
330}
331
Inseob Kimab1037d2023-02-08 17:03:31 +0900332fn should_export_tombstones(config: &VmPayloadConfig) -> bool {
333 match config.export_tombstones {
334 Some(b) => b,
335 None => system_properties::read_bool(DEBUGGABLE_PROP, true).unwrap_or(false),
336 }
337}
338
Jaewan Kim3124ef02023-03-23 19:25:20 +0900339/// Get debug policy value in bool. It's true iff the value is explicitly set to <1>.
340fn get_debug_policy_bool(path: &'static str) -> Result<Option<bool>> {
341 let mut file = match File::open(path) {
342 Ok(dp) => dp,
343 Err(e) => {
Jaewan Kim476ecd42023-08-28 05:57:00 +0000344 info!(
345 "Assumes that debug policy is disabled because failed to read debug policy ({e:?})"
346 );
Jaewan Kim3124ef02023-03-23 19:25:20 +0900347 return Ok(Some(false));
348 }
349 };
350 let mut log: [u8; 4] = Default::default();
351 file.read_exact(&mut log).context("Malformed data in {path}")?;
352 // DT spec uses big endian although Android is always little endian.
353 Ok(Some(u32::from_be_bytes(log) == 1))
354}
355
Alice Wangfd222fd2023-05-25 09:37:38 +0000356fn try_run_payload(
357 service: &Strong<dyn IVirtualMachineService>,
358 vm_payload_service_fd: OwnedFd,
359) -> Result<i32> {
Jooyung Han311b1202021-09-14 22:00:16 +0900360 let metadata = load_metadata().context("Failed to load payload metadata")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000361 let dice = DiceDriver::new(Path::new("/dev/open-dice0")).context("Failed to load DICE")?;
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900362
Jooyung Han311b1202021-09-14 22:00:16 +0900363 let mut instance = InstanceDisk::new().context("Failed to load instance.img")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000364 let saved_data =
365 instance.read_microdroid_data(&dice).context("Failed to read identity data")?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900366
Andrew Scullab72ec52022-03-14 09:10:52 +0000367 if is_strict_boot() {
368 // Provisioning must happen on the first boot and never again.
369 if is_new_instance() {
370 ensure!(
371 saved_data.is_none(),
372 MicrodroidError::InvalidConfig("Found instance data on first boot.".to_string())
373 );
374 } else {
375 ensure!(
376 saved_data.is_some(),
377 MicrodroidError::InvalidConfig("Instance data not found.".to_string())
378 );
379 };
380 }
381
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900382 // Verify the payload before using it.
Inseob Kim11f40d02022-06-13 17:16:00 +0900383 let verified_data = verify_payload(&metadata, saved_data.as_ref())
384 .context("Payload verification failed")
385 .map_err(|e| MicrodroidError::PayloadVerificationFailed(e.to_string()))?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900386
387 // In case identity is ignored (by debug policy), we should reuse existing payload data, even
388 // when the payload is changed. This is to keep the derived secret same as before.
389 let verified_data = if let Some(saved_data) = saved_data {
390 if !is_verified_boot() {
391 if saved_data != verified_data {
392 info!("Detected an update of the payload, but continue (regarding debug policy)")
393 }
394 } else {
395 ensure!(
396 saved_data == verified_data,
397 MicrodroidError::PayloadChanged(String::from(
398 "Detected an update of the payload which isn't supported yet."
399 ))
400 );
401 info!("Saved data is verified.");
402 }
403 saved_data
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900404 } else {
Jooyung Han7a343f92021-09-08 22:53:11 +0900405 info!("Saving verified data.");
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000406 instance
407 .write_microdroid_data(&verified_data, &dice)
408 .context("Failed to write identity data")?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900409 verified_data
410 };
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900411
Alan Stokes1f417c92022-09-29 15:13:28 +0100412 let payload_metadata = metadata.payload.ok_or_else(|| {
413 MicrodroidError::InvalidConfig("No payload config in metadata".to_string())
414 })?;
Alan Stokes0d1ef782022-09-27 13:46:35 +0100415
Inseob Kimb2519c52022-04-14 02:10:09 +0900416 // To minimize the exposure to untrusted data, derive dice profile as soon as possible.
417 info!("DICE derivation for payload");
Alice Wang62f7e642023-02-10 09:55:13 +0000418 let dice_artifacts = dice_derivation(dice, &verified_data, &payload_metadata)?;
Shikha Panwar566c9672022-11-15 14:39:58 +0000419
420 // Run encryptedstore binary to prepare the storage
421 let encryptedstore_child = if Path::new(ENCRYPTEDSTORE_BACKING_DEVICE).exists() {
422 info!("Preparing encryptedstore ...");
Alice Wang62f7e642023-02-10 09:55:13 +0000423 Some(prepare_encryptedstore(&dice_artifacts).context("encryptedstore run")?)
Shikha Panwar566c9672022-11-15 14:39:58 +0000424 } else {
425 None
426 };
Inseob Kimb2519c52022-04-14 02:10:09 +0900427
Alan Stokes960c9032022-12-07 16:53:45 +0000428 let mut zipfuse = Zipfuse::default();
429
Jooyung Hana6d11eb2021-09-10 11:48:05 +0900430 // Before reading a file from the APK, start zipfuse
Alan Stokes960c9032022-12-07 16:53:45 +0000431 zipfuse.mount(
Alan Stokes60f82202022-10-07 16:40:07 +0100432 MountForExec::Allowed,
Inseob Kim217038e2021-11-25 11:15:06 +0900433 "fscontext=u:object_r:zipfusefs:s0,context=u:object_r:system_file:s0",
434 Path::new("/dev/block/mapper/microdroid-apk"),
Alice Wang6bbb6da2022-10-26 12:44:06 +0000435 Path::new(VM_APK_CONTENTS_PATH),
Alan Stokes960c9032022-12-07 16:53:45 +0000436 "microdroid_manager.apk.mounted".to_owned(),
437 )?;
Jiyong Park21ce2c52021-08-28 02:32:17 +0900438
Andrew Scull4d262dc2022-10-21 13:14:33 +0000439 // Restricted APIs are only allowed to be used by platform or test components. Infer this from
440 // the use of a VM config file since those can only be used by platform and test components.
441 let allow_restricted_apis = match payload_metadata {
Ludovic Barman93ee3082023-06-20 12:18:43 +0000442 PayloadMetadata::ConfigPath(_) => true,
443 PayloadMetadata::Config(_) => false,
444 _ => false, // default is false for safety
Andrew Scull4d262dc2022-10-21 13:14:33 +0000445 };
446
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100447 let config = load_config(payload_metadata).context("Failed to load payload metadata")?;
Shikha Panwar6f03c942022-04-13 20:26:50 +0000448
Alan Stokes01b3ef02022-09-22 17:43:24 +0100449 let task = config
450 .task
451 .as_ref()
452 .ok_or_else(|| MicrodroidError::InvalidConfig("No task in VM config".to_string()))?;
453
Alice Wang061478b2023-04-11 13:26:17 +0000454 ensure!(
455 config.extra_apks.len() == verified_data.extra_apks_data.len(),
456 "config expects {} extra apks, but found {}",
457 config.extra_apks.len(),
458 verified_data.extra_apks_data.len()
459 );
Alan Stokes960c9032022-12-07 16:53:45 +0000460 mount_extra_apks(&config, &mut zipfuse)?;
Jooyung Han634e2d72021-06-10 16:27:38 +0900461
Jooyung Han5c6d4172021-12-06 14:17:52 +0900462 // Wait until apex config is done. (e.g. linker configuration for apexes)
Jooyung Han5c6d4172021-12-06 14:17:52 +0900463 wait_for_apex_config_done()?;
464
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000465 setup_config_sysprops(&config)?;
466
Shikha Panwar1a6efcd2023-02-03 19:23:43 +0000467 // Set export_tombstones if enabled
Inseob Kimab1037d2023-02-08 17:03:31 +0900468 if should_export_tombstones(&config) {
Shikha Panwar1a6efcd2023-02-03 19:23:43 +0000469 // This property is read by tombstone_handler.
470 system_properties::write("microdroid_manager.export_tombstones.enabled", "1")
471 .context("set microdroid_manager.export_tombstones.enabled")?;
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900472 }
473
Alan Stokes960c9032022-12-07 16:53:45 +0000474 // Wait until zipfuse has mounted the APKs so we can access the payload
475 zipfuse.wait_until_done()?;
Alan Stokes60f82202022-10-07 16:40:07 +0100476
Alice Wangfd222fd2023-05-25 09:37:38 +0000477 register_vm_payload_service(
478 allow_restricted_apis,
479 service.clone(),
480 dice_artifacts,
481 vm_payload_service_fd,
482 )?;
Shikha Panwar566c9672022-11-15 14:39:58 +0000483
Shikha Panwarddc124b2022-11-28 19:17:54 +0000484 // Wait for encryptedstore to finish mounting the storage (if enabled) before setting
485 // microdroid_manager.init_done. Reason is init stops uneventd after that.
486 // Encryptedstore, however requires ueventd
Shikha Panwar566c9672022-11-15 14:39:58 +0000487 if let Some(mut child) = encryptedstore_child {
488 let exitcode = child.wait().context("Wait for encryptedstore child")?;
489 ensure!(exitcode.success(), "Unable to prepare encrypted storage. Exitcode={}", exitcode);
490 }
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100491
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000492 wait_for_property_true("dev.bootcomplete").context("failed waiting for dev.bootcomplete")?;
Shikha Panwar3f6f6a52022-11-29 17:28:36 +0000493 system_properties::write("microdroid_manager.init_done", "1")
494 .context("set microdroid_manager.init_done")?;
Inseob Kimc16b0cc2023-01-26 14:57:24 +0900495
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000496 info!("boot completed, time to run payload");
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100497 exec_task(task, service).context("Failed to run payload")
Alan Stokes01b3ef02022-09-22 17:43:24 +0100498}
499
Inseob Kim217038e2021-11-25 11:15:06 +0900500struct ApkDmverityArgument<'a> {
501 apk: &'a str,
502 idsig: &'a str,
503 name: &'a str,
Inseob Kim197748b2021-12-01 19:49:00 +0900504 saved_root_hash: Option<&'a RootHash>,
Inseob Kim217038e2021-11-25 11:15:06 +0900505}
506
507fn run_apkdmverity(args: &[ApkDmverityArgument]) -> Result<Child> {
508 let mut cmd = Command::new(APKDMVERITY_BIN);
509
Inseob Kim217038e2021-11-25 11:15:06 +0900510 for argument in args {
511 cmd.arg("--apk").arg(argument.apk).arg(argument.idsig).arg(argument.name);
Inseob Kim197748b2021-12-01 19:49:00 +0900512 if let Some(root_hash) = argument.saved_root_hash {
513 cmd.arg(&to_hex_string(root_hash));
514 } else {
515 cmd.arg("none");
516 }
Inseob Kim217038e2021-11-25 11:15:06 +0900517 }
518
519 cmd.spawn().context("Spawn apkdmverity")
520}
521
Alan Stokes60f82202022-10-07 16:40:07 +0100522enum MountForExec {
523 Allowed,
524 Disallowed,
525}
526
Alan Stokes960c9032022-12-07 16:53:45 +0000527#[derive(Default)]
528struct Zipfuse {
529 ready_properties: Vec<String>,
530}
531
532impl Zipfuse {
533 fn mount(
534 &mut self,
535 noexec: MountForExec,
536 option: &str,
537 zip_path: &Path,
538 mount_dir: &Path,
539 ready_prop: String,
540 ) -> Result<Child> {
541 let mut cmd = Command::new(ZIPFUSE_BIN);
542 if let MountForExec::Disallowed = noexec {
543 cmd.arg("--noexec");
544 }
Alan Stokes1294f942023-08-21 14:34:12 +0100545 // Let root own the files in APK, so we can access them, but set the group to
546 // allow all payloads to have access too.
547 let (uid, gid) = (microdroid_uids::ROOT_UID, microdroid_uids::MICRODROID_PAYLOAD_GID);
548
Alan Stokes960c9032022-12-07 16:53:45 +0000549 cmd.args(["-p", &ready_prop, "-o", option]);
Alan Stokes1294f942023-08-21 14:34:12 +0100550 cmd.args(["-u", &uid.to_string()]);
551 cmd.args(["-g", &gid.to_string()]);
Alan Stokes960c9032022-12-07 16:53:45 +0000552 cmd.arg(zip_path).arg(mount_dir);
553 self.ready_properties.push(ready_prop);
554 cmd.spawn().with_context(|| format!("Failed to run zipfuse for {mount_dir:?}"))
Andrew Scullcc339a12022-07-04 12:44:19 +0000555 }
Alan Stokes960c9032022-12-07 16:53:45 +0000556
557 fn wait_until_done(self) -> Result<()> {
558 // We check the last-started check first in the hope that by the time it is done
559 // all or most of the others will also be done, minimising the number of times we
560 // block on a property.
561 for property in self.ready_properties.into_iter().rev() {
562 wait_for_property_true(&property)
563 .with_context(|| format!("Failed waiting for {property}"))?;
564 }
565 Ok(())
Alan Stokes60f82202022-10-07 16:40:07 +0100566 }
Inseob Kim217038e2021-11-25 11:15:06 +0900567}
568
Inseob Kime379e7d2022-07-22 18:55:18 +0900569fn write_apex_payload_data(
570 saved_data: Option<&MicrodroidData>,
571 apex_data_from_payload: &[ApexData],
572) -> Result<()> {
573 if let Some(saved_apex_data) = saved_data.map(|d| &d.apex_data) {
574 // We don't support APEX updates. (assuming that update will change root digest)
575 ensure!(
576 saved_apex_data == apex_data_from_payload,
577 MicrodroidError::PayloadChanged(String::from("APEXes have changed."))
578 );
579 let apex_metadata = to_metadata(apex_data_from_payload);
580 // Pass metadata(with public keys and root digests) to apexd so that it uses the passed
581 // metadata instead of the default one (/dev/block/by-name/payload-metadata)
582 OpenOptions::new()
583 .create_new(true)
584 .write(true)
585 .open("/apex/vm-payload-metadata")
586 .context("Failed to open /apex/vm-payload-metadata")
587 .and_then(|f| write_metadata(&apex_metadata, f))?;
588 }
589 Ok(())
590}
591
Jooyung Han7a343f92021-09-08 22:53:11 +0900592// Verify payload before executing it. For APK payload, Full verification (which is slow) is done
593// when the root_hash values from the idsig file and the instance disk are different. This function
594// returns the verified root hash (for APK payload) and pubkeys (for APEX payloads) that can be
595// saved to the instance disk.
596fn verify_payload(
597 metadata: &Metadata,
598 saved_data: Option<&MicrodroidData>,
599) -> Result<MicrodroidData> {
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900600 let start_time = SystemTime::now();
601
Inseob Kim197748b2021-12-01 19:49:00 +0900602 // Verify main APK
Inseob Kim197748b2021-12-01 19:49:00 +0900603 let root_hash_from_idsig = get_apk_root_hash_from_idsig(MAIN_APK_IDSIG_PATH)?;
Alice Wang061478b2023-04-11 13:26:17 +0000604 let root_hash_trustful =
605 saved_data.map(|d| d.apk_data.root_hash_eq(root_hash_from_idsig.as_ref())).unwrap_or(false);
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900606
Jiyong Parkf7dea252021-09-08 01:42:54 +0900607 // If root_hash can be trusted, pass it to apkdmverity so that it uses the passed root_hash
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900608 // instead of the value read from the idsig file.
Inseob Kim197748b2021-12-01 19:49:00 +0900609 let main_apk_argument = {
610 ApkDmverityArgument {
611 apk: MAIN_APK_PATH,
612 idsig: MAIN_APK_IDSIG_PATH,
613 name: MAIN_APK_DEVICE_NAME,
614 saved_root_hash: if root_hash_trustful {
615 Some(root_hash_from_idsig.as_ref())
616 } else {
617 None
618 },
619 }
620 };
621 let mut apkdmverity_arguments = vec![main_apk_argument];
622
623 // Verify extra APKs
624 // For now, we can't read the payload config, so glob APKs and idsigs.
625 // Later, we'll see if it matches with the payload config.
626
627 // sort globbed paths to match apks (extra-apk-{idx}) and idsigs (extra-idsig-{idx})
628 // e.g. "extra-apk-0" corresponds to "extra-idsig-0"
629 let extra_apks =
630 sorted(glob(EXTRA_APK_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
631 let extra_idsigs =
632 sorted(glob(EXTRA_IDSIG_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
Alice Wang061478b2023-04-11 13:26:17 +0000633 ensure!(
634 extra_apks.len() == extra_idsigs.len(),
635 "Extra apks/idsigs mismatch: {} apks but {} idsigs",
636 extra_apks.len(),
637 extra_idsigs.len()
638 );
Inseob Kim197748b2021-12-01 19:49:00 +0900639
Alice Wang061478b2023-04-11 13:26:17 +0000640 let extra_root_hashes_from_idsig: Vec<_> = extra_idsigs
Inseob Kim197748b2021-12-01 19:49:00 +0900641 .iter()
Alice Wang061478b2023-04-11 13:26:17 +0000642 .map(|idsig| {
643 get_apk_root_hash_from_idsig(idsig).expect("Can't find root hash from extra idsig")
Inseob Kim197748b2021-12-01 19:49:00 +0900644 })
645 .collect();
646
Alice Wang061478b2023-04-11 13:26:17 +0000647 let extra_root_hashes_trustful: Vec<_> = if let Some(data) = saved_data {
648 extra_root_hashes_from_idsig
649 .iter()
650 .enumerate()
651 .map(|(i, root_hash)| data.extra_apk_root_hash_eq(i, root_hash))
652 .collect()
653 } else {
654 vec![false; extra_root_hashes_from_idsig.len()]
655 };
656 let extra_apk_names: Vec<_> =
657 (0..extra_apks.len()).map(|i| format!("extra-apk-{}", i)).collect();
658
659 for (i, extra_apk) in extra_apks.iter().enumerate() {
Inseob Kim197748b2021-12-01 19:49:00 +0900660 apkdmverity_arguments.push({
661 ApkDmverityArgument {
Alice Wang061478b2023-04-11 13:26:17 +0000662 apk: extra_apk.to_str().unwrap(),
Inseob Kim197748b2021-12-01 19:49:00 +0900663 idsig: extra_idsigs[i].to_str().unwrap(),
664 name: &extra_apk_names[i],
665 saved_root_hash: if extra_root_hashes_trustful[i] {
666 Some(&extra_root_hashes_from_idsig[i])
667 } else {
668 None
669 },
670 }
671 });
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900672 }
673
674 // Start apkdmverity and wait for the dm-verify block
Inseob Kim197748b2021-12-01 19:49:00 +0900675 let mut apkdmverity_child = run_apkdmverity(&apkdmverity_arguments)?;
Jooyung Han7a343f92021-09-08 22:53:11 +0900676
Jooyung Hanc8deb472021-09-13 13:48:25 +0900677 // While waiting for apkdmverity to mount APK, gathers public keys and root digests from
678 // APEX payload.
Jooyung Han7a343f92021-09-08 22:53:11 +0900679 let apex_data_from_payload = get_apex_data_from_payload(metadata)?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900680
681 // Writing /apex/vm-payload-metadata is to verify that the payload isn't changed.
682 // Skip writing it if the debug policy ignoring identity is on
683 if is_verified_boot() {
684 write_apex_payload_data(saved_data, &apex_data_from_payload)?;
Jooyung Han4a9b3bf2021-09-10 17:19:00 +0900685 }
Inseob Kime379e7d2022-07-22 18:55:18 +0900686
Jooyung Han4a9b3bf2021-09-10 17:19:00 +0900687 // Start apexd to activate APEXes
688 system_properties::write("ctl.start", "apexd-vm")?;
Jooyung Han7a343f92021-09-08 22:53:11 +0900689
Inseob Kim217038e2021-11-25 11:15:06 +0900690 // TODO(inseob): add timeout
691 apkdmverity_child.wait()?;
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900692
Jiyong Parkf7dea252021-09-08 01:42:54 +0900693 // Do the full verification if the root_hash is un-trustful. This requires the full scanning of
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900694 // the APK file and therefore can be very slow if the APK is large. Note that this step is
Jiyong Parkf7dea252021-09-08 01:42:54 +0900695 // taken only when the root_hash is un-trustful which can be either when this is the first boot
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900696 // of the VM or APK was updated in the host.
697 // TODO(jooyung): consider multithreading to make this faster
Inseob Kim197748b2021-12-01 19:49:00 +0900698 let main_apk_pubkey = get_public_key_from_apk(DM_MOUNTED_APK_PATH, root_hash_trustful)?;
699 let extra_apks_data = extra_root_hashes_from_idsig
700 .into_iter()
701 .enumerate()
702 .map(|(i, extra_root_hash)| {
703 let mount_path = format!("/dev/block/mapper/{}", &extra_apk_names[i]);
704 let apk_pubkey = get_public_key_from_apk(&mount_path, extra_root_hashes_trustful[i])?;
705 Ok(ApkData { root_hash: extra_root_hash, pubkey: apk_pubkey })
706 })
707 .collect::<Result<Vec<_>>>()?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900708
709 info!("payload verification successful. took {:#?}", start_time.elapsed().unwrap());
710
Andrew Scull34916a72022-01-30 21:34:24 +0000711 // Use the salt from a verified instance, or generate a salt for a new instance.
712 let salt = if let Some(saved_data) = saved_data {
713 saved_data.salt.clone()
Pierre-Clément Tosicecb0aa2023-02-08 16:57:54 +0000714 } else if is_strict_boot() {
715 // No need to add more entropy as a previous stage must have used a new, random salt.
716 vec![0u8; 64]
Andrew Scull34916a72022-01-30 21:34:24 +0000717 } else {
718 let mut salt = vec![0u8; 64];
719 salt.as_mut_slice().try_fill(&mut rand::thread_rng())?;
720 salt
721 };
722
Jiyong Parkf7dea252021-09-08 01:42:54 +0900723 // At this point, we can ensure that the root_hash from the idsig file is trusted, either by
724 // fully verifying the APK or by comparing it with the saved root_hash.
Jooyung Han7a343f92021-09-08 22:53:11 +0900725 Ok(MicrodroidData {
Andrew Scull34916a72022-01-30 21:34:24 +0000726 salt,
Inseob Kim197748b2021-12-01 19:49:00 +0900727 apk_data: ApkData { root_hash: root_hash_from_idsig, pubkey: main_apk_pubkey },
728 extra_apks_data,
Jooyung Han7a343f92021-09-08 22:53:11 +0900729 apex_data: apex_data_from_payload,
730 })
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900731}
732
Alan Stokes960c9032022-12-07 16:53:45 +0000733fn mount_extra_apks(config: &VmPayloadConfig, zipfuse: &mut Zipfuse) -> Result<()> {
Inseob Kim197748b2021-12-01 19:49:00 +0900734 // For now, only the number of apks is important, as the mount point and dm-verity name is fixed
735 for i in 0..config.extra_apks.len() {
Alan Stokes960c9032022-12-07 16:53:45 +0000736 let mount_dir = format!("/mnt/extra-apk/{i}");
Inseob Kim197748b2021-12-01 19:49:00 +0900737 create_dir(Path::new(&mount_dir)).context("Failed to create mount dir for extra apks")?;
738
739 // don't wait, just detach
Alan Stokes960c9032022-12-07 16:53:45 +0000740 zipfuse.mount(
Alan Stokes60f82202022-10-07 16:40:07 +0100741 MountForExec::Disallowed,
Inseob Kim197748b2021-12-01 19:49:00 +0900742 "fscontext=u:object_r:zipfusefs:s0,context=u:object_r:extra_apk_file:s0",
Alan Stokes960c9032022-12-07 16:53:45 +0000743 Path::new(&format!("/dev/block/mapper/extra-apk-{i}")),
Inseob Kim197748b2021-12-01 19:49:00 +0900744 Path::new(&mount_dir),
Alan Stokes960c9032022-12-07 16:53:45 +0000745 format!("microdroid_manager.extra_apk.mounted.{i}"),
746 )?;
Inseob Kim197748b2021-12-01 19:49:00 +0900747 }
748
749 Ok(())
750}
751
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000752fn setup_config_sysprops(config: &VmPayloadConfig) -> Result<()> {
753 if config.enable_authfs {
754 system_properties::write("microdroid_manager.authfs.enabled", "1")
755 .context("failed to write microdroid_manager.authfs.enabled")?;
756 }
757 system_properties::write("microdroid_manager.config_done", "1")
758 .context("failed to write microdroid_manager.config_done")?;
759 Ok(())
760}
761
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900762// Waits until linker config is generated
763fn wait_for_apex_config_done() -> Result<()> {
Alan Stokes60f82202022-10-07 16:40:07 +0100764 wait_for_property_true(APEX_CONFIG_DONE_PROP).context("Failed waiting for apex config done")
765}
766
767fn wait_for_property_true(property_name: &str) -> Result<()> {
768 let mut prop = PropertyWatcher::new(property_name)?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900769 loop {
Andrew Walbrand9c766e2023-05-10 15:15:39 +0000770 prop.wait(None)?;
Alan Stokes60f82202022-10-07 16:40:07 +0100771 if system_properties::read_bool(property_name, false)? {
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900772 break;
773 }
774 }
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900775 Ok(())
776}
777
Alice Wang89cff012022-09-26 10:05:16 +0000778fn get_apk_root_hash_from_idsig<P: AsRef<Path>>(idsig_path: P) -> Result<Box<RootHash>> {
779 Ok(V4Signature::from_idsig_path(idsig_path)?.hashing_info.raw_root_hash)
Jiyong Park21ce2c52021-08-28 02:32:17 +0900780}
781
Inseob Kim197748b2021-12-01 19:49:00 +0900782fn get_public_key_from_apk(apk: &str, root_hash_trustful: bool) -> Result<Box<[u8]>> {
Alan Stokes25f69362023-03-06 16:51:54 +0000783 let current_sdk = get_current_sdk()?;
Inseob Kim197748b2021-12-01 19:49:00 +0900784 if !root_hash_trustful {
Alan Stokes25f69362023-03-06 16:51:54 +0000785 verify(apk, current_sdk).context(MicrodroidError::PayloadVerificationFailed(format!(
Inseob Kim197748b2021-12-01 19:49:00 +0900786 "failed to verify {}",
787 apk
788 )))
789 } else {
Alan Stokes25f69362023-03-06 16:51:54 +0000790 get_public_key_der(apk, current_sdk)
Inseob Kim197748b2021-12-01 19:49:00 +0900791 }
792}
793
Alan Stokes25f69362023-03-06 16:51:54 +0000794fn get_current_sdk() -> Result<u32> {
795 let current_sdk = system_properties::read("ro.build.version.sdk")?;
796 let current_sdk = current_sdk.ok_or_else(|| anyhow!("SDK version missing"))?;
797 current_sdk.parse().context("Malformed SDK version")
798}
799
Alan Stokes1f417c92022-09-29 15:13:28 +0100800fn load_config(payload_metadata: PayloadMetadata) -> Result<VmPayloadConfig> {
801 match payload_metadata {
Ludovic Barman93ee3082023-06-20 12:18:43 +0000802 PayloadMetadata::ConfigPath(path) => {
Alan Stokes1f417c92022-09-29 15:13:28 +0100803 let path = Path::new(&path);
804 info!("loading config from {:?}...", path);
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100805 let file = ioutil::wait_for_file(path, WAIT_TIMEOUT)
806 .with_context(|| format!("Failed to read {:?}", path))?;
Alan Stokes1f417c92022-09-29 15:13:28 +0100807 Ok(serde_json::from_reader(file)?)
808 }
Ludovic Barman93ee3082023-06-20 12:18:43 +0000809 PayloadMetadata::Config(payload_config) => {
Alan Stokes1f417c92022-09-29 15:13:28 +0100810 let task = Task {
811 type_: TaskType::MicrodroidLauncher,
Alan Stokes8f12f2b2023-01-09 09:19:20 +0000812 command: payload_config.payload_binary_name,
Alan Stokes1f417c92022-09-29 15:13:28 +0100813 };
814 Ok(VmPayloadConfig {
815 os: OsConfig { name: "microdroid".to_owned() },
816 task: Some(task),
817 apexes: vec![],
818 extra_apks: vec![],
819 prefer_staged: false,
Inseob Kimab1037d2023-02-08 17:03:31 +0900820 export_tombstones: None,
Alan Stokes1f417c92022-09-29 15:13:28 +0100821 enable_authfs: false,
822 })
823 }
Ludovic Barman93ee3082023-06-20 12:18:43 +0000824 _ => bail!("Failed to match config against a config type."),
Alan Stokes1f417c92022-09-29 15:13:28 +0100825 }
Jooyung Han634e2d72021-06-10 16:27:38 +0900826}
827
Jaewan Kim3124ef02023-03-23 19:25:20 +0900828/// Loads the crashkernel into memory using kexec if debuggable or debug policy says so.
829/// The VM should be loaded with `crashkernel=' parameter in the cmdline to allocate memory
830/// for crashkernel.
Jiyong Park202856e2022-08-22 16:04:26 +0900831fn load_crashkernel_if_supported() -> Result<()> {
832 let supported = std::fs::read_to_string("/proc/cmdline")?.contains(" crashkernel=");
833 info!("ramdump supported: {}", supported);
Jaewan Kim3124ef02023-03-23 19:25:20 +0900834
835 if !supported {
836 return Ok(());
837 }
838
839 let debuggable = system_properties::read_bool(DEBUGGABLE_PROP, true)?;
840 let ramdump = get_debug_policy_bool(AVF_DEBUG_POLICY_RAMDUMP)?.unwrap_or_default();
841 let requested = debuggable | ramdump;
842
843 if requested {
Jiyong Park202856e2022-08-22 16:04:26 +0900844 let status = Command::new("/system/bin/kexec_load").status()?;
845 if !status.success() {
846 return Err(anyhow!("Failed to load crashkernel: {:?}", status));
847 }
Jaewan Kim3124ef02023-03-23 19:25:20 +0900848 info!("ramdump is loaded: debuggable={debuggable}, ramdump={ramdump}");
Jiyong Park202856e2022-08-22 16:04:26 +0900849 }
850 Ok(())
851}
852
Inseob Kim090b70b2022-11-16 20:01:14 +0900853/// Executes the given task.
Jooyung Han5c6d4172021-12-06 14:17:52 +0900854fn exec_task(task: &Task, service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
Jiyong Park8611a6c2021-07-09 18:17:44 +0900855 info!("executing main task {:?}...", task);
David Brazdil451cc962022-10-14 14:08:12 +0100856 let mut command = match task.type_ {
Alan Stokes1294f942023-08-21 14:34:12 +0100857 TaskType::Executable => {
Alan Stokes679ddf32023-09-01 11:14:48 +0100858 // TODO(b/297501338): Figure out how to handle non-root for system payloads.
Alan Stokes1294f942023-08-21 14:34:12 +0100859 Command::new(&task.command)
860 }
David Brazdil451cc962022-10-14 14:08:12 +0100861 TaskType::MicrodroidLauncher => {
862 let mut command = Command::new("/system/bin/microdroid_launcher");
863 command.arg(find_library_path(&task.command)?);
Alan Stokes1294f942023-08-21 14:34:12 +0100864 command.uid(microdroid_uids::MICRODROID_PAYLOAD_UID);
865 command.gid(microdroid_uids::MICRODROID_PAYLOAD_GID);
David Brazdil451cc962022-10-14 14:08:12 +0100866 command
867 }
868 };
Nikita Ioffe3452ee22022-12-15 00:31:56 +0000869
Andrew Walbranaac68302023-07-21 19:05:34 +0100870 // SAFETY: We are not accessing any resource of the parent process. This means we can't make any
871 // log calls inside the closure.
Nikita Ioffe3452ee22022-12-15 00:31:56 +0000872 unsafe {
Nikita Ioffe3452ee22022-12-15 00:31:56 +0000873 command.pre_exec(|| {
Nikita Ioffe3452ee22022-12-15 00:31:56 +0000874 // It is OK to continue with payload execution even if the calls below fail, since
875 // whether process can use a capability is controlled by the SELinux. Dropping the
876 // capabilities here is just another defense-in-depth layer.
Andrew Walbranaac68302023-07-21 19:05:34 +0100877 let _ = cap::drop_inheritable_caps();
878 let _ = cap::drop_bounding_set();
Nikita Ioffe3452ee22022-12-15 00:31:56 +0000879 Ok(())
880 });
881 }
882
Inseob Kim090b70b2022-11-16 20:01:14 +0900883 command.stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null());
Inseob Kim7f61fe72021-08-20 20:50:47 +0900884
885 info!("notifying payload started");
Inseob Kimc7d28c72021-10-25 14:28:10 +0000886 service.notifyPayloadStarted()?;
Inseob Kim7f61fe72021-08-20 20:50:47 +0900887
Inseob Kim86ca0162021-10-20 02:21:02 +0000888 let exit_status = command.spawn()?.wait()?;
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -0800889 match exit_status.code() {
890 Some(exit_code) => Ok(exit_code),
891 None => Err(match exit_status.signal() {
892 Some(signal) => anyhow!(
893 "Payload exited due to signal: {} ({})",
894 signal,
895 Signal::try_from(signal).map_or("unknown", |s| s.as_str())
896 ),
897 None => anyhow!("Payload has neither exit code nor signal"),
898 }),
899 }
Jooyung Han347d9f22021-05-28 00:05:14 +0900900}
Jooyung Han634e2d72021-06-10 16:27:38 +0900901
Jooyung Han634e2d72021-06-10 16:27:38 +0900902fn find_library_path(name: &str) -> Result<String> {
903 let mut watcher = PropertyWatcher::new("ro.product.cpu.abilist")?;
904 let value = watcher.read(|_name, value| Ok(value.trim().to_string()))?;
905 let abi = value.split(',').next().ok_or_else(|| anyhow!("no abilist"))?;
Alice Wang6bbb6da2022-10-26 12:44:06 +0000906 let path = format!("{}/lib/{}/{}", VM_APK_CONTENTS_PATH, abi, name);
Jooyung Han634e2d72021-06-10 16:27:38 +0900907
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100908 let metadata = fs::metadata(&path).with_context(|| format!("Unable to access {}", path))?;
Jooyung Han634e2d72021-06-10 16:27:38 +0900909 if !metadata.is_file() {
910 bail!("{} is not a file", &path);
911 }
912
913 Ok(path)
914}
Jiyong Park21ce2c52021-08-28 02:32:17 +0900915
916fn to_hex_string(buf: &[u8]) -> String {
917 buf.iter().map(|b| format!("{:02X}", b)).collect()
918}
Shikha Panwar566c9672022-11-15 14:39:58 +0000919
Alice Wang62f7e642023-02-10 09:55:13 +0000920fn prepare_encryptedstore(dice_artifacts: &OwnedDiceArtifacts) -> Result<Child> {
Shikha Panwar566c9672022-11-15 14:39:58 +0000921 // Use a fixed salt to scope the derivation to this API.
922 // Generated using hexdump -vn32 -e'14/1 "0x%02X, " 1 "\n"' /dev/urandom
923 // TODO(b/241541860) : Move this (& other salts) to a salt container, i.e. a global enum
924 let salt = [
925 0xFC, 0x1D, 0x35, 0x7B, 0x96, 0xF3, 0xEF, 0x17, 0x78, 0x7D, 0x70, 0xED, 0xEA, 0xFE, 0x1D,
926 0x6F, 0xB3, 0xF9, 0x40, 0xCE, 0xDD, 0x99, 0x40, 0xAA, 0xA7, 0x0E, 0x92, 0x73, 0x90, 0x86,
927 0x4A, 0x75,
928 ];
Alice Wang7e6c9352023-02-15 15:44:13 +0000929 let mut key = ZVec::new(ENCRYPTEDSTORE_KEYSIZE)?;
930 derive_sealing_key(dice_artifacts, &salt, ENCRYPTEDSTORE_KEY_IDENTIFIER.as_bytes(), &mut key)?;
Shikha Panwar566c9672022-11-15 14:39:58 +0000931
932 let mut cmd = Command::new(ENCRYPTEDSTORE_BIN);
933 cmd.arg("--blkdevice")
934 .arg(ENCRYPTEDSTORE_BACKING_DEVICE)
935 .arg("--key")
936 .arg(hex::encode(&*key))
Shikha Panwar9fd198f2022-11-18 17:43:43 +0000937 .args(["--mountpoint", ENCRYPTEDSTORE_MOUNTPOINT])
Shikha Panwar566c9672022-11-15 14:39:58 +0000938 .spawn()
939 .context("encryptedstore failed")
940}