blob: 1148c31836c2c36bbe13dc353332dff2f9633a94 [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 Wang62f7e642023-02-10 09:55:13 +000024use crate::dice::{DiceDriver, derive_sealing_key};
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;
Alan Stokes1f417c92022-09-29 15:13:28 +010038use diced_utils::cbor::{encode_header, encode_number};
Inseob Kim197748b2021-12-01 19:49:00 +090039use glob::glob;
Inseob Kim197748b2021-12-01 19:49:00 +090040use itertools::sorted;
David Brazdila07a1792022-10-25 13:37:57 +010041use libc::VMADDR_CID_HOST;
Inseob Kim090b70b2022-11-16 20:01:14 +090042use log::{error, info, warn};
Alice Wang7e6c9352023-02-15 15:44:13 +000043use keystore2_crypto::ZVec;
Alan Stokes0d1ef782022-09-27 13:46:35 +010044use microdroid_metadata::{write_metadata, Metadata, PayloadMetadata};
Seungjae Yoofd9a0622022-10-14 10:01:29 +090045use microdroid_payload_config::{OsConfig, Task, TaskType, VmPayloadConfig};
Inseob Kim090b70b2022-11-16 20:01:14 +090046use nix::fcntl::{fcntl, F_SETFD, FdFlag};
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -080047use nix::sys::signal::Signal;
Andrew Sculla0d1b1a2022-05-24 19:32:47 +000048use openssl::sha::Sha512;
Jooyung Han4a9b3bf2021-09-10 17:19:00 +090049use payload::{get_apex_data_from_payload, load_metadata, to_metadata};
Andrew Scull34916a72022-01-30 21:34:24 +000050use rand::Fill;
David Brazdila2125dd2022-12-14 16:37:44 +000051use rpcbinder::RpcSession;
Inseob Kim090b70b2022-11-16 20:01:14 +090052use rustutils::sockets::android_get_control_socket;
Jiyong Parkbb4a9872021-09-06 15:59:21 +090053use rustutils::system_properties;
Joel Galenson482704c2021-07-29 15:53:53 -070054use rustutils::system_properties::PropertyWatcher;
Alan Stokes3ba10fd2022-10-06 15:46:51 +010055use std::borrow::Cow::{Borrowed, Owned};
Andrew Scullb2f44472022-01-21 14:41:34 +000056use std::convert::TryInto;
Inseob Kim7ff121c2022-11-14 18:13:23 +090057use std::env;
Shikha Panwardef7ef92023-01-06 08:35:48 +000058use std::ffi::CString;
David Brazdil451cc962022-10-14 14:08:12 +010059use std::fs::{self, create_dir, OpenOptions};
Inseob Kim11f40d02022-06-13 17:16:00 +090060use std::io::Write;
Nikita Ioffe3452ee22022-12-15 00:31:56 +000061use std::os::unix::process::CommandExt;
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -080062use std::os::unix::process::ExitStatusExt;
Jooyung Hanf48ceb42021-06-01 18:00:04 +090063use std::path::Path;
Inseob Kim217038e2021-11-25 11:15:06 +090064use std::process::{Child, Command, Stdio};
Jiyong Park8611a6c2021-07-09 18:17:44 +090065use std::str;
Jiyong Parkbb4a9872021-09-06 15:59:21 +090066use std::time::{Duration, SystemTime};
Jooyung Han634e2d72021-06-10 16:27:38 +090067
68const WAIT_TIMEOUT: Duration = Duration::from_secs(10);
Inseob Kim197748b2021-12-01 19:49:00 +090069const MAIN_APK_PATH: &str = "/dev/block/by-name/microdroid-apk";
70const MAIN_APK_IDSIG_PATH: &str = "/dev/block/by-name/microdroid-apk-idsig";
71const MAIN_APK_DEVICE_NAME: &str = "microdroid-apk";
72const EXTRA_APK_PATH_PATTERN: &str = "/dev/block/by-name/extra-apk-*";
73const EXTRA_IDSIG_PATH_PATTERN: &str = "/dev/block/by-name/extra-idsig-*";
Jooyung Han19c1d6c2021-08-06 14:08:16 +090074const DM_MOUNTED_APK_PATH: &str = "/dev/block/mapper/microdroid-apk";
Andrew Scullab72ec52022-03-14 09:10:52 +000075const AVF_STRICT_BOOT: &str = "/sys/firmware/devicetree/base/chosen/avf,strict-boot";
76const AVF_NEW_INSTANCE: &str = "/sys/firmware/devicetree/base/chosen/avf,new-instance";
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";
Inseob Kimf44917c2023-01-20 17:31:37 +090085const TOMBSTONE_TRANSMIT_DONE_PROP: &str = "tombstone_transmit.init_done";
Seungjae Yoofa22bb02022-12-08 16:38:42 +090086const DEBUGGABLE_PROP: &str = "ro.boot.microdroid.debuggable";
Jiyong Parkbb4a9872021-09-06 15:59:21 +090087
Inseob Kim11f40d02022-06-13 17:16:00 +090088// SYNC WITH virtualizationservice/src/crosvm.rs
89const FAILURE_SERIAL_DEVICE: &str = "/dev/ttyS1";
90
Shikha Panwar566c9672022-11-15 14:39:58 +000091const ENCRYPTEDSTORE_BACKING_DEVICE: &str = "/dev/block/by-name/encryptedstore";
Shikha Panwar566c9672022-11-15 14:39:58 +000092const ENCRYPTEDSTORE_KEY_IDENTIFIER: &str = "encryptedstore_key";
Alice Wang62f7e642023-02-10 09:55:13 +000093const ENCRYPTEDSTORE_KEYSIZE: usize = 32;
Shikha Panwar566c9672022-11-15 14:39:58 +000094
Jooyung Handd0a1732021-11-23 15:26:20 +090095#[derive(thiserror::Error, Debug)]
96enum MicrodroidError {
Inseob Kim11f40d02022-06-13 17:16:00 +090097 #[error("Cannot connect to virtualization service: {0}")]
98 FailedToConnectToVirtualizationService(String),
Jooyung Handd0a1732021-11-23 15:26:20 +090099 #[error("Payload has changed: {0}")]
100 PayloadChanged(String),
101 #[error("Payload verification has failed: {0}")]
102 PayloadVerificationFailed(String),
Jooyung Han5c6d4172021-12-06 14:17:52 +0900103 #[error("Payload config is invalid: {0}")]
104 InvalidConfig(String),
Jooyung Handd0a1732021-11-23 15:26:20 +0900105}
106
Alan Stokes2bead0d2022-09-05 16:58:34 +0100107fn translate_error(err: &Error) -> (ErrorCode, String) {
Jooyung Handd0a1732021-11-23 15:26:20 +0900108 if let Some(e) = err.downcast_ref::<MicrodroidError>() {
109 match e {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100110 MicrodroidError::PayloadChanged(msg) => (ErrorCode::PAYLOAD_CHANGED, msg.to_string()),
Jooyung Handd0a1732021-11-23 15:26:20 +0900111 MicrodroidError::PayloadVerificationFailed(msg) => {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100112 (ErrorCode::PAYLOAD_VERIFICATION_FAILED, msg.to_string())
Jooyung Handd0a1732021-11-23 15:26:20 +0900113 }
Alan Stokes2bead0d2022-09-05 16:58:34 +0100114 MicrodroidError::InvalidConfig(msg) => {
115 (ErrorCode::PAYLOAD_CONFIG_INVALID, msg.to_string())
116 }
Inseob Kim11f40d02022-06-13 17:16:00 +0900117
118 // Connection failure won't be reported to VS; return the default value
119 MicrodroidError::FailedToConnectToVirtualizationService(msg) => {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100120 (ErrorCode::UNKNOWN, msg.to_string())
Inseob Kim11f40d02022-06-13 17:16:00 +0900121 }
Jooyung Handd0a1732021-11-23 15:26:20 +0900122 }
123 } else {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100124 (ErrorCode::UNKNOWN, err.to_string())
Jooyung Handd0a1732021-11-23 15:26:20 +0900125 }
126}
127
Inseob Kim11f40d02022-06-13 17:16:00 +0900128fn write_death_reason_to_serial(err: &Error) -> Result<()> {
129 let death_reason = if let Some(e) = err.downcast_ref::<MicrodroidError>() {
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100130 Borrowed(match e {
Inseob Kim11f40d02022-06-13 17:16:00 +0900131 MicrodroidError::FailedToConnectToVirtualizationService(_) => {
132 "MICRODROID_FAILED_TO_CONNECT_TO_VIRTUALIZATION_SERVICE"
133 }
134 MicrodroidError::PayloadChanged(_) => "MICRODROID_PAYLOAD_HAS_CHANGED",
135 MicrodroidError::PayloadVerificationFailed(_) => {
136 "MICRODROID_PAYLOAD_VERIFICATION_FAILED"
137 }
138 MicrodroidError::InvalidConfig(_) => "MICRODROID_INVALID_PAYLOAD_CONFIG",
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100139 })
Inseob Kim11f40d02022-06-13 17:16:00 +0900140 } else {
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100141 // Send context information back after a separator, to ease diagnosis.
142 // These errors occur before the payload runs, so this should not leak sensitive
143 // information.
144 Owned(format!("MICRODROID_UNKNOWN_RUNTIME_ERROR|{:?}", err))
Inseob Kim11f40d02022-06-13 17:16:00 +0900145 };
146
147 let death_reason_bytes = death_reason.as_bytes();
148 let mut sent_total = 0;
149 while sent_total < death_reason_bytes.len() {
150 // TODO(b/220071963): Sometimes, sending more than 16 bytes at once makes MM hang.
151 let begin = sent_total;
152 let end = std::cmp::min(begin.saturating_add(16), death_reason_bytes.len());
153 OpenOptions::new()
154 .read(false)
155 .write(true)
156 .open(FAILURE_SERIAL_DEVICE)?
157 .write_all(&death_reason_bytes[begin..end])?;
158 sent_total = end;
159 }
160
161 Ok(())
162}
163
Inseob Kim1b95f2e2021-08-19 13:17:40 +0900164fn get_vms_rpc_binder() -> Result<Strong<dyn IVirtualMachineService>> {
David Brazdil73988ea2022-11-11 15:10:32 +0000165 // The host is running a VirtualMachineService for this VM on a port equal
166 // to the CID of this VM.
167 let port = vsock::get_local_cid().context("Could not determine local CID")?;
David Brazdila2125dd2022-12-14 16:37:44 +0000168 RpcSession::new()
169 .setup_vsock_client(VMADDR_CID_HOST, port)
David Brazdil73988ea2022-11-11 15:10:32 +0000170 .context("Could not connect to IVirtualMachineService")
Inseob Kim1b95f2e2021-08-19 13:17:40 +0900171}
172
Inseob Kim437f1052022-06-21 11:30:22 +0900173fn main() -> Result<()> {
Inseob Kim7ff121c2022-11-14 18:13:23 +0900174 // If debuggable, print full backtrace to console log with stdio_to_kmsg
Seungjae Yoofa22bb02022-12-08 16:38:42 +0900175 if system_properties::read_bool(DEBUGGABLE_PROP, true)? {
Inseob Kim7ff121c2022-11-14 18:13:23 +0900176 env::set_var("RUST_BACKTRACE", "full");
177 }
178
Inseob Kim437f1052022-06-21 11:30:22 +0900179 scopeguard::defer! {
180 info!("Shutting down...");
Jooyung Hanbfe086f2021-10-28 10:15:45 +0900181 if let Err(e) = system_properties::write("sys.powerctl", "shutdown") {
182 error!("failed to shutdown {:?}", e);
183 }
Jooyung Han311b1202021-09-14 22:00:16 +0900184 }
Inseob Kim437f1052022-06-21 11:30:22 +0900185
186 try_main().map_err(|e| {
187 error!("Failed with {:?}.", e);
188 if let Err(e) = write_death_reason_to_serial(&e) {
189 error!("Failed to write death reason {:?}", e);
190 }
191 e
192 })
Jooyung Han311b1202021-09-14 22:00:16 +0900193}
194
Inseob Kim090b70b2022-11-16 20:01:14 +0900195fn set_cloexec_on_vm_payload_service_socket() -> Result<()> {
196 let fd = android_get_control_socket(VM_PAYLOAD_SERVICE_SOCKET_NAME)?;
197
198 fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC))?;
199
200 Ok(())
201}
202
Jooyung Han311b1202021-09-14 22:00:16 +0900203fn try_main() -> Result<()> {
Andrew Sculle127cff2022-02-15 15:34:04 +0000204 let _ = kernlog::init();
Jooyung Han347d9f22021-05-28 00:05:14 +0900205 info!("started.");
206
Inseob Kim090b70b2022-11-16 20:01:14 +0900207 if let Err(e) = set_cloexec_on_vm_payload_service_socket() {
208 warn!("Failed to set cloexec on vm payload socket: {:?}", e);
209 }
210
Jiyong Park202856e2022-08-22 16:04:26 +0900211 load_crashkernel_if_supported().context("Failed to load crashkernel")?;
212
Keir Fraser933f0ac2022-10-12 08:23:28 +0000213 swap::init_swap().context("Failed to initialise swap")?;
214 info!("swap enabled.");
215
Inseob Kim11f40d02022-06-13 17:16:00 +0900216 let service = get_vms_rpc_binder()
217 .context("cannot connect to VirtualMachineService")
218 .map_err(|e| MicrodroidError::FailedToConnectToVirtualizationService(e.to_string()))?;
Seungjae Yoofd9a0622022-10-14 10:01:29 +0900219
Jooyung Han5c6d4172021-12-06 14:17:52 +0900220 match try_run_payload(&service) {
221 Ok(code) => {
Jooyung Han5c6d4172021-12-06 14:17:52 +0900222 if code == 0 {
223 info!("task successfully finished");
224 } else {
225 error!("task exited with exit code: {}", code);
226 }
Shikha Panwardef7ef92023-01-06 08:35:48 +0000227 if let Err(e) = post_payload_work() {
228 error!(
229 "Failed to run post payload work. It is possible that certain tasks
230 like syncing encrypted store might be incomplete. Error: {:?}",
231 e
232 );
233 };
234
235 info!("notifying payload finished");
236 service.notifyPayloadFinished(code)?;
Jooyung Han5c6d4172021-12-06 14:17:52 +0900237 Ok(())
238 }
239 Err(err) => {
Jooyung Han5c6d4172021-12-06 14:17:52 +0900240 let (error_code, message) = translate_error(&err);
241 service.notifyError(error_code, &message)?;
242 Err(err)
243 }
Jooyung Handd0a1732021-11-23 15:26:20 +0900244 }
245}
246
Shikha Panwardef7ef92023-01-06 08:35:48 +0000247fn post_payload_work() -> Result<()> {
248 // Sync the encrypted storage filesystem (flushes the filesystem caches).
249 if Path::new(ENCRYPTEDSTORE_BACKING_DEVICE).exists() {
250 let mountpoint = CString::new(ENCRYPTEDSTORE_MOUNTPOINT).unwrap();
251
252 let ret = unsafe {
253 let dirfd = libc::open(
254 mountpoint.as_ptr(),
255 libc::O_DIRECTORY | libc::O_RDONLY | libc::O_CLOEXEC,
256 );
257 ensure!(dirfd >= 0, "Unable to open {:?}", mountpoint);
258 let ret = libc::syncfs(dirfd);
259 libc::close(dirfd);
260 ret
261 };
262 if ret != 0 {
263 error!("failed to sync encrypted storage.");
264 return Err(anyhow!(std::io::Error::last_os_error()));
265 }
266 }
267 Ok(())
268}
Alan Stokes1f417c92022-09-29 15:13:28 +0100269fn dice_derivation(
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000270 dice: DiceDriver,
Alan Stokes1f417c92022-09-29 15:13:28 +0100271 verified_data: &MicrodroidData,
272 payload_metadata: &PayloadMetadata,
Alice Wang62f7e642023-02-10 09:55:13 +0000273) -> Result<OwnedDiceArtifacts> {
Andrew Scullb2f44472022-01-21 14:41:34 +0000274 // Calculate compound digests of code and authorities
Andrew Sculla0d1b1a2022-05-24 19:32:47 +0000275 let mut code_hash_ctx = Sha512::new();
276 let mut authority_hash_ctx = Sha512::new();
Andrew Scullb2f44472022-01-21 14:41:34 +0000277 code_hash_ctx.update(verified_data.apk_data.root_hash.as_ref());
278 authority_hash_ctx.update(verified_data.apk_data.pubkey.as_ref());
Inseob Kimb2519c52022-04-14 02:10:09 +0900279 for extra_apk in &verified_data.extra_apks_data {
Andrew Scullb2f44472022-01-21 14:41:34 +0000280 code_hash_ctx.update(extra_apk.root_hash.as_ref());
281 authority_hash_ctx.update(extra_apk.pubkey.as_ref());
282 }
Inseob Kimb2519c52022-04-14 02:10:09 +0900283 for apex in &verified_data.apex_data {
Andrew Scullb2f44472022-01-21 14:41:34 +0000284 code_hash_ctx.update(apex.root_digest.as_ref());
285 authority_hash_ctx.update(apex.public_key.as_ref());
286 }
Andrew Sculla0d1b1a2022-05-24 19:32:47 +0000287 let code_hash = code_hash_ctx.finish();
288 let authority_hash = authority_hash_ctx.finish();
Andrew Scullb2f44472022-01-21 14:41:34 +0000289
290 // {
291 // -70002: "Microdroid payload",
Alan Stokes1f417c92022-09-29 15:13:28 +0100292 // ? -71000: tstr // payload_config_path
293 // ? -71001: PayloadConfig
Andrew Scullb2f44472022-01-21 14:41:34 +0000294 // }
Alan Stokes1f417c92022-09-29 15:13:28 +0100295 // PayloadConfig = {
Alan Stokes8f12f2b2023-01-09 09:19:20 +0000296 // 1: tstr // payload_binary_name
Alan Stokes1f417c92022-09-29 15:13:28 +0100297 // }
298
Andrew Scullb2f44472022-01-21 14:41:34 +0000299 let mut config_desc = vec![
Alan Stokes1f417c92022-09-29 15:13:28 +0100300 0xa2, // map(2)
301 0x3a, 0x00, 0x01, 0x11, 0x71, // -70002
302 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79,
303 0x6c, 0x6f, 0x61, 0x64, // "Microdroid payload"
Andrew Scullb2f44472022-01-21 14:41:34 +0000304 ];
Alan Stokes1f417c92022-09-29 15:13:28 +0100305
306 match payload_metadata {
307 PayloadMetadata::config_path(payload_config_path) => {
308 encode_negative_number(-71000, &mut config_desc)?;
309 encode_tstr(payload_config_path, &mut config_desc)?;
310 }
311 PayloadMetadata::config(payload_config) => {
312 encode_negative_number(-71001, &mut config_desc)?;
313 encode_header(5, 1, &mut config_desc)?; // map(1)
314 encode_number(1, &mut config_desc)?;
Alan Stokes8f12f2b2023-01-09 09:19:20 +0000315 encode_tstr(&payload_config.payload_binary_name, &mut config_desc)?;
Alan Stokes1f417c92022-09-29 15:13:28 +0100316 }
317 }
Andrew Scullb2f44472022-01-21 14:41:34 +0000318
Seungjae Yoofa22bb02022-12-08 16:38:42 +0900319 // Check debuggability, conservatively assuming it is debuggable
320 let debuggable = system_properties::read_bool(DEBUGGABLE_PROP, true)?;
Andrew Scull65ddfc42022-02-14 21:03:58 +0000321
Andrew Scullb2f44472022-01-21 14:41:34 +0000322 // Send the details to diced
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000323 let hidden = verified_data.salt.clone().try_into().unwrap();
Seungjae Yoofa22bb02022-12-08 16:38:42 +0900324 dice.derive(code_hash, &config_desc, authority_hash, debuggable, hidden)
Andrew Scullb2f44472022-01-21 14:41:34 +0000325}
326
Alan Stokes1f417c92022-09-29 15:13:28 +0100327fn encode_tstr(tstr: &str, buffer: &mut Vec<u8>) -> Result<()> {
328 let bytes = tstr.as_bytes();
329 encode_header(3, bytes.len().try_into().unwrap(), buffer)?;
330 buffer.extend_from_slice(bytes);
331 Ok(())
332}
333
334fn encode_negative_number(n: i64, buffer: &mut dyn Write) -> Result<()> {
335 ensure!(n < 0);
336 let n = -1 - n;
337 encode_header(1, n.try_into().unwrap(), buffer)
338}
339
Andrew Scullab72ec52022-03-14 09:10:52 +0000340fn is_strict_boot() -> bool {
341 Path::new(AVF_STRICT_BOOT).exists()
342}
343
344fn is_new_instance() -> bool {
345 Path::new(AVF_NEW_INSTANCE).exists()
346}
347
Inseob Kime379e7d2022-07-22 18:55:18 +0900348fn is_verified_boot() -> bool {
349 !Path::new(DEBUG_MICRODROID_NO_VERIFIED_BOOT).exists()
350}
351
Inseob Kimab1037d2023-02-08 17:03:31 +0900352fn should_export_tombstones(config: &VmPayloadConfig) -> bool {
353 match config.export_tombstones {
354 Some(b) => b,
355 None => system_properties::read_bool(DEBUGGABLE_PROP, true).unwrap_or(false),
356 }
357}
358
Jooyung Han5c6d4172021-12-06 14:17:52 +0900359fn try_run_payload(service: &Strong<dyn IVirtualMachineService>) -> 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 {
442 PayloadMetadata::config_path(_) => true,
443 PayloadMetadata::config(_) => false,
444 };
445
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100446 let config = load_config(payload_metadata).context("Failed to load payload metadata")?;
Shikha Panwar6f03c942022-04-13 20:26:50 +0000447
Alan Stokes01b3ef02022-09-22 17:43:24 +0100448 let task = config
449 .task
450 .as_ref()
451 .ok_or_else(|| MicrodroidError::InvalidConfig("No task in VM config".to_string()))?;
452
Inseob Kim197748b2021-12-01 19:49:00 +0900453 if config.extra_apks.len() != verified_data.extra_apks_data.len() {
454 return Err(anyhow!(
Alan Stokes1f417c92022-09-29 15:13:28 +0100455 "config expects {} extra apks, but found {}",
Inseob Kim197748b2021-12-01 19:49:00 +0900456 config.extra_apks.len(),
457 verified_data.extra_apks_data.len()
458 ));
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
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900467 // Start tombstone_transmit if enabled
Inseob Kimab1037d2023-02-08 17:03:31 +0900468 if should_export_tombstones(&config) {
Inseob Kimc16b0cc2023-01-26 14:57:24 +0900469 system_properties::write("tombstone_transmit.start", "1")
470 .context("set tombstone_transmit.start")?;
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900471 } else {
Alan Stokes01b3ef02022-09-22 17:43:24 +0100472 control_service("stop", "tombstoned")?;
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900473 }
474
Alan Stokes960c9032022-12-07 16:53:45 +0000475 // Wait until zipfuse has mounted the APKs so we can access the payload
476 zipfuse.wait_until_done()?;
Alan Stokes60f82202022-10-07 16:40:07 +0100477
Alice Wang62f7e642023-02-10 09:55:13 +0000478 register_vm_payload_service(allow_restricted_apis, service.clone(), dice_artifacts)?;
Shikha Panwar566c9672022-11-15 14:39:58 +0000479
Shikha Panwarddc124b2022-11-28 19:17:54 +0000480 // Wait for encryptedstore to finish mounting the storage (if enabled) before setting
481 // microdroid_manager.init_done. Reason is init stops uneventd after that.
482 // Encryptedstore, however requires ueventd
Shikha Panwar566c9672022-11-15 14:39:58 +0000483 if let Some(mut child) = encryptedstore_child {
484 let exitcode = child.wait().context("Wait for encryptedstore child")?;
485 ensure!(exitcode.success(), "Unable to prepare encrypted storage. Exitcode={}", exitcode);
486 }
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100487
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000488 wait_for_property_true("dev.bootcomplete").context("failed waiting for dev.bootcomplete")?;
Shikha Panwar3f6f6a52022-11-29 17:28:36 +0000489 system_properties::write("microdroid_manager.init_done", "1")
490 .context("set microdroid_manager.init_done")?;
Inseob Kimc16b0cc2023-01-26 14:57:24 +0900491
492 // Wait for tombstone_transmit to init
Inseob Kimab1037d2023-02-08 17:03:31 +0900493 if should_export_tombstones(&config) {
Inseob Kimc16b0cc2023-01-26 14:57:24 +0900494 wait_for_tombstone_transmit_done()?;
495 }
496
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000497 info!("boot completed, time to run payload");
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100498 exec_task(task, service).context("Failed to run payload")
Alan Stokes01b3ef02022-09-22 17:43:24 +0100499}
500
501fn control_service(action: &str, service: &str) -> Result<()> {
502 system_properties::write(&format!("ctl.{}", action), service)
503 .with_context(|| format!("Failed to {} {}", action, service))
Jooyung Han347d9f22021-05-28 00:05:14 +0900504}
505
Inseob Kim217038e2021-11-25 11:15:06 +0900506struct ApkDmverityArgument<'a> {
507 apk: &'a str,
508 idsig: &'a str,
509 name: &'a str,
Inseob Kim197748b2021-12-01 19:49:00 +0900510 saved_root_hash: Option<&'a RootHash>,
Inseob Kim217038e2021-11-25 11:15:06 +0900511}
512
513fn run_apkdmverity(args: &[ApkDmverityArgument]) -> Result<Child> {
514 let mut cmd = Command::new(APKDMVERITY_BIN);
515
Inseob Kim217038e2021-11-25 11:15:06 +0900516 for argument in args {
517 cmd.arg("--apk").arg(argument.apk).arg(argument.idsig).arg(argument.name);
Inseob Kim197748b2021-12-01 19:49:00 +0900518 if let Some(root_hash) = argument.saved_root_hash {
519 cmd.arg(&to_hex_string(root_hash));
520 } else {
521 cmd.arg("none");
522 }
Inseob Kim217038e2021-11-25 11:15:06 +0900523 }
524
525 cmd.spawn().context("Spawn apkdmverity")
526}
527
Alan Stokes60f82202022-10-07 16:40:07 +0100528enum MountForExec {
529 Allowed,
530 Disallowed,
531}
532
Alan Stokes960c9032022-12-07 16:53:45 +0000533#[derive(Default)]
534struct Zipfuse {
535 ready_properties: Vec<String>,
536}
537
538impl Zipfuse {
Jiyong Park231f9692023-01-09 19:36:21 +0900539 const MICRODROID_PAYLOAD_UID: u32 = 0; // TODO(b/264861173) should be non-root
540 const MICRODROID_PAYLOAD_GID: u32 = 0; // TODO(b/264861173) should be non-root
Alan Stokes960c9032022-12-07 16:53:45 +0000541 fn mount(
542 &mut self,
543 noexec: MountForExec,
544 option: &str,
545 zip_path: &Path,
546 mount_dir: &Path,
547 ready_prop: String,
548 ) -> Result<Child> {
549 let mut cmd = Command::new(ZIPFUSE_BIN);
550 if let MountForExec::Disallowed = noexec {
551 cmd.arg("--noexec");
552 }
553 cmd.args(["-p", &ready_prop, "-o", option]);
Jiyong Park231f9692023-01-09 19:36:21 +0900554 cmd.args(["-u", &Self::MICRODROID_PAYLOAD_UID.to_string()]);
555 cmd.args(["-g", &Self::MICRODROID_PAYLOAD_GID.to_string()]);
Alan Stokes960c9032022-12-07 16:53:45 +0000556 cmd.arg(zip_path).arg(mount_dir);
557 self.ready_properties.push(ready_prop);
558 cmd.spawn().with_context(|| format!("Failed to run zipfuse for {mount_dir:?}"))
Andrew Scullcc339a12022-07-04 12:44:19 +0000559 }
Alan Stokes960c9032022-12-07 16:53:45 +0000560
561 fn wait_until_done(self) -> Result<()> {
562 // We check the last-started check first in the hope that by the time it is done
563 // all or most of the others will also be done, minimising the number of times we
564 // block on a property.
565 for property in self.ready_properties.into_iter().rev() {
566 wait_for_property_true(&property)
567 .with_context(|| format!("Failed waiting for {property}"))?;
568 }
569 Ok(())
Alan Stokes60f82202022-10-07 16:40:07 +0100570 }
Inseob Kim217038e2021-11-25 11:15:06 +0900571}
572
Inseob Kime379e7d2022-07-22 18:55:18 +0900573fn write_apex_payload_data(
574 saved_data: Option<&MicrodroidData>,
575 apex_data_from_payload: &[ApexData],
576) -> Result<()> {
577 if let Some(saved_apex_data) = saved_data.map(|d| &d.apex_data) {
578 // We don't support APEX updates. (assuming that update will change root digest)
579 ensure!(
580 saved_apex_data == apex_data_from_payload,
581 MicrodroidError::PayloadChanged(String::from("APEXes have changed."))
582 );
583 let apex_metadata = to_metadata(apex_data_from_payload);
584 // Pass metadata(with public keys and root digests) to apexd so that it uses the passed
585 // metadata instead of the default one (/dev/block/by-name/payload-metadata)
586 OpenOptions::new()
587 .create_new(true)
588 .write(true)
589 .open("/apex/vm-payload-metadata")
590 .context("Failed to open /apex/vm-payload-metadata")
591 .and_then(|f| write_metadata(&apex_metadata, f))?;
592 }
593 Ok(())
594}
595
Jooyung Han7a343f92021-09-08 22:53:11 +0900596// Verify payload before executing it. For APK payload, Full verification (which is slow) is done
597// when the root_hash values from the idsig file and the instance disk are different. This function
598// returns the verified root hash (for APK payload) and pubkeys (for APEX payloads) that can be
599// saved to the instance disk.
600fn verify_payload(
601 metadata: &Metadata,
602 saved_data: Option<&MicrodroidData>,
603) -> Result<MicrodroidData> {
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900604 let start_time = SystemTime::now();
605
Inseob Kim197748b2021-12-01 19:49:00 +0900606 // Verify main APK
Jooyung Han7a343f92021-09-08 22:53:11 +0900607 let root_hash = saved_data.map(|d| &d.apk_data.root_hash);
Inseob Kim197748b2021-12-01 19:49:00 +0900608 let root_hash_from_idsig = get_apk_root_hash_from_idsig(MAIN_APK_IDSIG_PATH)?;
Jiyong Parkf7dea252021-09-08 01:42:54 +0900609 let root_hash_trustful = root_hash == Some(&root_hash_from_idsig);
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900610
Jiyong Parkf7dea252021-09-08 01:42:54 +0900611 // 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 +0900612 // instead of the value read from the idsig file.
Inseob Kim197748b2021-12-01 19:49:00 +0900613 let main_apk_argument = {
614 ApkDmverityArgument {
615 apk: MAIN_APK_PATH,
616 idsig: MAIN_APK_IDSIG_PATH,
617 name: MAIN_APK_DEVICE_NAME,
618 saved_root_hash: if root_hash_trustful {
619 Some(root_hash_from_idsig.as_ref())
620 } else {
621 None
622 },
623 }
624 };
625 let mut apkdmverity_arguments = vec![main_apk_argument];
626
627 // Verify extra APKs
628 // For now, we can't read the payload config, so glob APKs and idsigs.
629 // Later, we'll see if it matches with the payload config.
630
631 // sort globbed paths to match apks (extra-apk-{idx}) and idsigs (extra-idsig-{idx})
632 // e.g. "extra-apk-0" corresponds to "extra-idsig-0"
633 let extra_apks =
634 sorted(glob(EXTRA_APK_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
635 let extra_idsigs =
636 sorted(glob(EXTRA_IDSIG_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
637 if extra_apks.len() != extra_idsigs.len() {
638 return Err(anyhow!(
639 "Extra apks/idsigs mismatch: {} apks but {} idsigs",
640 extra_apks.len(),
641 extra_idsigs.len()
642 ));
643 }
644 let extra_apks_count = extra_apks.len();
645
646 let (extra_apk_names, extra_root_hashes_from_idsig): (Vec<_>, Vec<_>) = extra_idsigs
647 .iter()
648 .enumerate()
649 .map(|(i, extra_idsig)| {
650 (
651 format!("extra-apk-{}", i),
Alice Wang89cff012022-09-26 10:05:16 +0000652 get_apk_root_hash_from_idsig(extra_idsig)
Inseob Kim197748b2021-12-01 19:49:00 +0900653 .expect("Can't find root hash from extra idsig"),
654 )
655 })
656 .unzip();
657
658 let saved_extra_root_hashes: Vec<_> = saved_data
659 .map(|d| d.extra_apks_data.iter().map(|apk_data| &apk_data.root_hash).collect())
660 .unwrap_or_else(Vec::new);
661 let extra_root_hashes_trustful: Vec<_> = extra_root_hashes_from_idsig
662 .iter()
663 .enumerate()
664 .map(|(i, root_hash_from_idsig)| {
665 saved_extra_root_hashes.get(i).copied() == Some(root_hash_from_idsig)
666 })
667 .collect();
668
669 for i in 0..extra_apks_count {
670 apkdmverity_arguments.push({
671 ApkDmverityArgument {
672 apk: extra_apks[i].to_str().unwrap(),
673 idsig: extra_idsigs[i].to_str().unwrap(),
674 name: &extra_apk_names[i],
675 saved_root_hash: if extra_root_hashes_trustful[i] {
676 Some(&extra_root_hashes_from_idsig[i])
677 } else {
678 None
679 },
680 }
681 });
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900682 }
683
684 // Start apkdmverity and wait for the dm-verify block
Inseob Kim197748b2021-12-01 19:49:00 +0900685 let mut apkdmverity_child = run_apkdmverity(&apkdmverity_arguments)?;
Jooyung Han7a343f92021-09-08 22:53:11 +0900686
Jooyung Hanc8deb472021-09-13 13:48:25 +0900687 // While waiting for apkdmverity to mount APK, gathers public keys and root digests from
688 // APEX payload.
Jooyung Han7a343f92021-09-08 22:53:11 +0900689 let apex_data_from_payload = get_apex_data_from_payload(metadata)?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900690
691 // Writing /apex/vm-payload-metadata is to verify that the payload isn't changed.
692 // Skip writing it if the debug policy ignoring identity is on
693 if is_verified_boot() {
694 write_apex_payload_data(saved_data, &apex_data_from_payload)?;
Jooyung Han4a9b3bf2021-09-10 17:19:00 +0900695 }
Inseob Kime379e7d2022-07-22 18:55:18 +0900696
Jooyung Han4a9b3bf2021-09-10 17:19:00 +0900697 // Start apexd to activate APEXes
698 system_properties::write("ctl.start", "apexd-vm")?;
Jooyung Han7a343f92021-09-08 22:53:11 +0900699
Inseob Kim217038e2021-11-25 11:15:06 +0900700 // TODO(inseob): add timeout
701 apkdmverity_child.wait()?;
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900702
Jiyong Parkf7dea252021-09-08 01:42:54 +0900703 // Do the full verification if the root_hash is un-trustful. This requires the full scanning of
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900704 // 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 +0900705 // 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 +0900706 // of the VM or APK was updated in the host.
707 // TODO(jooyung): consider multithreading to make this faster
Inseob Kim197748b2021-12-01 19:49:00 +0900708 let main_apk_pubkey = get_public_key_from_apk(DM_MOUNTED_APK_PATH, root_hash_trustful)?;
709 let extra_apks_data = extra_root_hashes_from_idsig
710 .into_iter()
711 .enumerate()
712 .map(|(i, extra_root_hash)| {
713 let mount_path = format!("/dev/block/mapper/{}", &extra_apk_names[i]);
714 let apk_pubkey = get_public_key_from_apk(&mount_path, extra_root_hashes_trustful[i])?;
715 Ok(ApkData { root_hash: extra_root_hash, pubkey: apk_pubkey })
716 })
717 .collect::<Result<Vec<_>>>()?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900718
719 info!("payload verification successful. took {:#?}", start_time.elapsed().unwrap());
720
Andrew Scull34916a72022-01-30 21:34:24 +0000721 // Use the salt from a verified instance, or generate a salt for a new instance.
722 let salt = if let Some(saved_data) = saved_data {
723 saved_data.salt.clone()
724 } else {
725 let mut salt = vec![0u8; 64];
726 salt.as_mut_slice().try_fill(&mut rand::thread_rng())?;
727 salt
728 };
729
Jiyong Parkf7dea252021-09-08 01:42:54 +0900730 // At this point, we can ensure that the root_hash from the idsig file is trusted, either by
731 // fully verifying the APK or by comparing it with the saved root_hash.
Jooyung Han7a343f92021-09-08 22:53:11 +0900732 Ok(MicrodroidData {
Andrew Scull34916a72022-01-30 21:34:24 +0000733 salt,
Inseob Kim197748b2021-12-01 19:49:00 +0900734 apk_data: ApkData { root_hash: root_hash_from_idsig, pubkey: main_apk_pubkey },
735 extra_apks_data,
Jooyung Han7a343f92021-09-08 22:53:11 +0900736 apex_data: apex_data_from_payload,
737 })
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900738}
739
Alan Stokes960c9032022-12-07 16:53:45 +0000740fn mount_extra_apks(config: &VmPayloadConfig, zipfuse: &mut Zipfuse) -> Result<()> {
Inseob Kim197748b2021-12-01 19:49:00 +0900741 // For now, only the number of apks is important, as the mount point and dm-verity name is fixed
742 for i in 0..config.extra_apks.len() {
Alan Stokes960c9032022-12-07 16:53:45 +0000743 let mount_dir = format!("/mnt/extra-apk/{i}");
Inseob Kim197748b2021-12-01 19:49:00 +0900744 create_dir(Path::new(&mount_dir)).context("Failed to create mount dir for extra apks")?;
745
746 // don't wait, just detach
Alan Stokes960c9032022-12-07 16:53:45 +0000747 zipfuse.mount(
Alan Stokes60f82202022-10-07 16:40:07 +0100748 MountForExec::Disallowed,
Inseob Kim197748b2021-12-01 19:49:00 +0900749 "fscontext=u:object_r:zipfusefs:s0,context=u:object_r:extra_apk_file:s0",
Alan Stokes960c9032022-12-07 16:53:45 +0000750 Path::new(&format!("/dev/block/mapper/extra-apk-{i}")),
Inseob Kim197748b2021-12-01 19:49:00 +0900751 Path::new(&mount_dir),
Alan Stokes960c9032022-12-07 16:53:45 +0000752 format!("microdroid_manager.extra_apk.mounted.{i}"),
753 )?;
Inseob Kim197748b2021-12-01 19:49:00 +0900754 }
755
756 Ok(())
757}
758
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000759fn setup_config_sysprops(config: &VmPayloadConfig) -> Result<()> {
760 if config.enable_authfs {
761 system_properties::write("microdroid_manager.authfs.enabled", "1")
762 .context("failed to write microdroid_manager.authfs.enabled")?;
763 }
764 system_properties::write("microdroid_manager.config_done", "1")
765 .context("failed to write microdroid_manager.config_done")?;
766 Ok(())
767}
768
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900769// Waits until linker config is generated
770fn wait_for_apex_config_done() -> Result<()> {
Alan Stokes60f82202022-10-07 16:40:07 +0100771 wait_for_property_true(APEX_CONFIG_DONE_PROP).context("Failed waiting for apex config done")
772}
773
Inseob Kimf44917c2023-01-20 17:31:37 +0900774fn wait_for_tombstone_transmit_done() -> Result<()> {
775 wait_for_property_true(TOMBSTONE_TRANSMIT_DONE_PROP)
776 .context("Failed waiting for tombstone transmit done")
777}
778
Alan Stokes60f82202022-10-07 16:40:07 +0100779fn wait_for_property_true(property_name: &str) -> Result<()> {
780 let mut prop = PropertyWatcher::new(property_name)?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900781 loop {
782 prop.wait()?;
Alan Stokes60f82202022-10-07 16:40:07 +0100783 if system_properties::read_bool(property_name, false)? {
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900784 break;
785 }
786 }
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900787 Ok(())
788}
789
Alice Wang89cff012022-09-26 10:05:16 +0000790fn get_apk_root_hash_from_idsig<P: AsRef<Path>>(idsig_path: P) -> Result<Box<RootHash>> {
791 Ok(V4Signature::from_idsig_path(idsig_path)?.hashing_info.raw_root_hash)
Jiyong Park21ce2c52021-08-28 02:32:17 +0900792}
793
Inseob Kim197748b2021-12-01 19:49:00 +0900794fn get_public_key_from_apk(apk: &str, root_hash_trustful: bool) -> Result<Box<[u8]>> {
795 if !root_hash_trustful {
796 verify(apk).context(MicrodroidError::PayloadVerificationFailed(format!(
797 "failed to verify {}",
798 apk
799 )))
800 } else {
801 get_public_key_der(apk)
802 }
803}
804
Alan Stokes1f417c92022-09-29 15:13:28 +0100805fn load_config(payload_metadata: PayloadMetadata) -> Result<VmPayloadConfig> {
806 match payload_metadata {
807 PayloadMetadata::config_path(path) => {
808 let path = Path::new(&path);
809 info!("loading config from {:?}...", path);
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100810 let file = ioutil::wait_for_file(path, WAIT_TIMEOUT)
811 .with_context(|| format!("Failed to read {:?}", path))?;
Alan Stokes1f417c92022-09-29 15:13:28 +0100812 Ok(serde_json::from_reader(file)?)
813 }
814 PayloadMetadata::config(payload_config) => {
815 let task = Task {
816 type_: TaskType::MicrodroidLauncher,
Alan Stokes8f12f2b2023-01-09 09:19:20 +0000817 command: payload_config.payload_binary_name,
Alan Stokes1f417c92022-09-29 15:13:28 +0100818 };
819 Ok(VmPayloadConfig {
820 os: OsConfig { name: "microdroid".to_owned() },
821 task: Some(task),
822 apexes: vec![],
823 extra_apks: vec![],
824 prefer_staged: false,
Inseob Kimab1037d2023-02-08 17:03:31 +0900825 export_tombstones: None,
Alan Stokes1f417c92022-09-29 15:13:28 +0100826 enable_authfs: false,
827 })
828 }
829 }
Jooyung Han634e2d72021-06-10 16:27:38 +0900830}
831
Jiyong Park202856e2022-08-22 16:04:26 +0900832/// Loads the crashkernel into memory using kexec if the VM is loaded with `crashkernel=' parameter
833/// in the cmdline.
834fn load_crashkernel_if_supported() -> Result<()> {
835 let supported = std::fs::read_to_string("/proc/cmdline")?.contains(" crashkernel=");
836 info!("ramdump supported: {}", supported);
837 if supported {
838 let status = Command::new("/system/bin/kexec_load").status()?;
839 if !status.success() {
840 return Err(anyhow!("Failed to load crashkernel: {:?}", status));
841 }
842 }
843 Ok(())
844}
845
Inseob Kim090b70b2022-11-16 20:01:14 +0900846/// Executes the given task.
Jooyung Han5c6d4172021-12-06 14:17:52 +0900847fn exec_task(task: &Task, service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
Jiyong Park8611a6c2021-07-09 18:17:44 +0900848 info!("executing main task {:?}...", task);
David Brazdil451cc962022-10-14 14:08:12 +0100849 let mut command = match task.type_ {
850 TaskType::Executable => Command::new(&task.command),
851 TaskType::MicrodroidLauncher => {
852 let mut command = Command::new("/system/bin/microdroid_launcher");
853 command.arg(find_library_path(&task.command)?);
854 command
855 }
856 };
Nikita Ioffe3452ee22022-12-15 00:31:56 +0000857
858 unsafe {
859 // SAFETY: we are not accessing any resource of the parent process.
860 command.pre_exec(|| {
861 info!("dropping capabilities before executing payload");
862 // It is OK to continue with payload execution even if the calls below fail, since
863 // whether process can use a capability is controlled by the SELinux. Dropping the
864 // capabilities here is just another defense-in-depth layer.
865 if let Err(e) = cap::drop_inheritable_caps() {
866 error!("failed to drop inheritable capabilities: {:?}", e);
867 }
868 if let Err(e) = cap::drop_bounding_set() {
869 error!("failed to drop bounding set: {:?}", e);
870 }
871 Ok(())
872 });
873 }
874
Inseob Kim090b70b2022-11-16 20:01:14 +0900875 command.stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null());
Inseob Kim7f61fe72021-08-20 20:50:47 +0900876
877 info!("notifying payload started");
Inseob Kimc7d28c72021-10-25 14:28:10 +0000878 service.notifyPayloadStarted()?;
Inseob Kim7f61fe72021-08-20 20:50:47 +0900879
Inseob Kim86ca0162021-10-20 02:21:02 +0000880 let exit_status = command.spawn()?.wait()?;
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -0800881 match exit_status.code() {
882 Some(exit_code) => Ok(exit_code),
883 None => Err(match exit_status.signal() {
884 Some(signal) => anyhow!(
885 "Payload exited due to signal: {} ({})",
886 signal,
887 Signal::try_from(signal).map_or("unknown", |s| s.as_str())
888 ),
889 None => anyhow!("Payload has neither exit code nor signal"),
890 }),
891 }
Jooyung Han347d9f22021-05-28 00:05:14 +0900892}
Jooyung Han634e2d72021-06-10 16:27:38 +0900893
Jooyung Han634e2d72021-06-10 16:27:38 +0900894fn find_library_path(name: &str) -> Result<String> {
895 let mut watcher = PropertyWatcher::new("ro.product.cpu.abilist")?;
896 let value = watcher.read(|_name, value| Ok(value.trim().to_string()))?;
897 let abi = value.split(',').next().ok_or_else(|| anyhow!("no abilist"))?;
Alice Wang6bbb6da2022-10-26 12:44:06 +0000898 let path = format!("{}/lib/{}/{}", VM_APK_CONTENTS_PATH, abi, name);
Jooyung Han634e2d72021-06-10 16:27:38 +0900899
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100900 let metadata = fs::metadata(&path).with_context(|| format!("Unable to access {}", path))?;
Jooyung Han634e2d72021-06-10 16:27:38 +0900901 if !metadata.is_file() {
902 bail!("{} is not a file", &path);
903 }
904
905 Ok(path)
906}
Jiyong Park21ce2c52021-08-28 02:32:17 +0900907
908fn to_hex_string(buf: &[u8]) -> String {
909 buf.iter().map(|b| format!("{:02X}", b)).collect()
910}
Shikha Panwar566c9672022-11-15 14:39:58 +0000911
Alice Wang62f7e642023-02-10 09:55:13 +0000912fn prepare_encryptedstore(dice_artifacts: &OwnedDiceArtifacts) -> Result<Child> {
Shikha Panwar566c9672022-11-15 14:39:58 +0000913 // Use a fixed salt to scope the derivation to this API.
914 // Generated using hexdump -vn32 -e'14/1 "0x%02X, " 1 "\n"' /dev/urandom
915 // TODO(b/241541860) : Move this (& other salts) to a salt container, i.e. a global enum
916 let salt = [
917 0xFC, 0x1D, 0x35, 0x7B, 0x96, 0xF3, 0xEF, 0x17, 0x78, 0x7D, 0x70, 0xED, 0xEA, 0xFE, 0x1D,
918 0x6F, 0xB3, 0xF9, 0x40, 0xCE, 0xDD, 0x99, 0x40, 0xAA, 0xA7, 0x0E, 0x92, 0x73, 0x90, 0x86,
919 0x4A, 0x75,
920 ];
Alice Wang7e6c9352023-02-15 15:44:13 +0000921 let mut key = ZVec::new(ENCRYPTEDSTORE_KEYSIZE)?;
922 derive_sealing_key(dice_artifacts, &salt, ENCRYPTEDSTORE_KEY_IDENTIFIER.as_bytes(), &mut key)?;
Shikha Panwar566c9672022-11-15 14:39:58 +0000923
924 let mut cmd = Command::new(ENCRYPTEDSTORE_BIN);
925 cmd.arg("--blkdevice")
926 .arg(ENCRYPTEDSTORE_BACKING_DEVICE)
927 .arg("--key")
928 .arg(hex::encode(&*key))
Shikha Panwar9fd198f2022-11-18 17:43:43 +0000929 .args(["--mountpoint", ENCRYPTEDSTORE_MOUNTPOINT])
Shikha Panwar566c9672022-11-15 14:39:58 +0000930 .spawn()
931 .context("encryptedstore failed")
932}