blob: be862472cad94160b19d2b7c217582bbdd702ed9 [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;
Jooyung Hanf48ceb42021-06-01 18:00:04 +090061use std::path::Path;
Inseob Kim217038e2021-11-25 11:15:06 +090062use std::process::{Child, Command, Stdio};
Jiyong Park8611a6c2021-07-09 18:17:44 +090063use std::str;
Jiyong Parkbb4a9872021-09-06 15:59:21 +090064use std::time::{Duration, SystemTime};
Jooyung Han634e2d72021-06-10 16:27:38 +090065
66const WAIT_TIMEOUT: Duration = Duration::from_secs(10);
Inseob Kim197748b2021-12-01 19:49:00 +090067const MAIN_APK_PATH: &str = "/dev/block/by-name/microdroid-apk";
68const MAIN_APK_IDSIG_PATH: &str = "/dev/block/by-name/microdroid-apk-idsig";
69const MAIN_APK_DEVICE_NAME: &str = "microdroid-apk";
70const EXTRA_APK_PATH_PATTERN: &str = "/dev/block/by-name/extra-apk-*";
71const EXTRA_IDSIG_PATH_PATTERN: &str = "/dev/block/by-name/extra-idsig-*";
Jooyung Han19c1d6c2021-08-06 14:08:16 +090072const DM_MOUNTED_APK_PATH: &str = "/dev/block/mapper/microdroid-apk";
Andrew Scullab72ec52022-03-14 09:10:52 +000073const AVF_STRICT_BOOT: &str = "/sys/firmware/devicetree/base/chosen/avf,strict-boot";
74const AVF_NEW_INSTANCE: &str = "/sys/firmware/devicetree/base/chosen/avf,new-instance";
Jaewan Kim3124ef02023-03-23 19:25:20 +090075const AVF_DEBUG_POLICY_RAMDUMP: &str = "/sys/firmware/devicetree/base/avf/guest/common/ramdump";
Inseob Kime379e7d2022-07-22 18:55:18 +090076const DEBUG_MICRODROID_NO_VERIFIED_BOOT: &str =
77 "/sys/firmware/devicetree/base/virtualization/guest/debug-microdroid,no-verified-boot";
Jooyung Han347d9f22021-05-28 00:05:14 +090078
Alan Stokes4fb201c2023-02-08 17:39:05 +000079const APKDMVERITY_BIN: &str = "/system/bin/apkdmverity";
80const ENCRYPTEDSTORE_BIN: &str = "/system/bin/encryptedstore";
81const ZIPFUSE_BIN: &str = "/system/bin/zipfuse";
82
Jiyong Parkbb4a9872021-09-06 15:59:21 +090083const APEX_CONFIG_DONE_PROP: &str = "apex_config.done";
Seungjae Yoofa22bb02022-12-08 16:38:42 +090084const DEBUGGABLE_PROP: &str = "ro.boot.microdroid.debuggable";
Jiyong Parkbb4a9872021-09-06 15:59:21 +090085
Inseob Kim11f40d02022-06-13 17:16:00 +090086// SYNC WITH virtualizationservice/src/crosvm.rs
87const FAILURE_SERIAL_DEVICE: &str = "/dev/ttyS1";
88
Shikha Panwar566c9672022-11-15 14:39:58 +000089const ENCRYPTEDSTORE_BACKING_DEVICE: &str = "/dev/block/by-name/encryptedstore";
Shikha Panwar566c9672022-11-15 14:39:58 +000090const ENCRYPTEDSTORE_KEY_IDENTIFIER: &str = "encryptedstore_key";
Alice Wang62f7e642023-02-10 09:55:13 +000091const ENCRYPTEDSTORE_KEYSIZE: usize = 32;
Shikha Panwar566c9672022-11-15 14:39:58 +000092
Jooyung Handd0a1732021-11-23 15:26:20 +090093#[derive(thiserror::Error, Debug)]
94enum MicrodroidError {
Inseob Kim11f40d02022-06-13 17:16:00 +090095 #[error("Cannot connect to virtualization service: {0}")]
96 FailedToConnectToVirtualizationService(String),
Jooyung Handd0a1732021-11-23 15:26:20 +090097 #[error("Payload has changed: {0}")]
98 PayloadChanged(String),
99 #[error("Payload verification has failed: {0}")]
100 PayloadVerificationFailed(String),
Jooyung Han5c6d4172021-12-06 14:17:52 +0900101 #[error("Payload config is invalid: {0}")]
102 InvalidConfig(String),
Jooyung Handd0a1732021-11-23 15:26:20 +0900103}
104
Alan Stokes2bead0d2022-09-05 16:58:34 +0100105fn translate_error(err: &Error) -> (ErrorCode, String) {
Jooyung Handd0a1732021-11-23 15:26:20 +0900106 if let Some(e) = err.downcast_ref::<MicrodroidError>() {
107 match e {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100108 MicrodroidError::PayloadChanged(msg) => (ErrorCode::PAYLOAD_CHANGED, msg.to_string()),
Jooyung Handd0a1732021-11-23 15:26:20 +0900109 MicrodroidError::PayloadVerificationFailed(msg) => {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100110 (ErrorCode::PAYLOAD_VERIFICATION_FAILED, msg.to_string())
Jooyung Handd0a1732021-11-23 15:26:20 +0900111 }
Alan Stokes2bead0d2022-09-05 16:58:34 +0100112 MicrodroidError::InvalidConfig(msg) => {
113 (ErrorCode::PAYLOAD_CONFIG_INVALID, msg.to_string())
114 }
Inseob Kim11f40d02022-06-13 17:16:00 +0900115
116 // Connection failure won't be reported to VS; return the default value
117 MicrodroidError::FailedToConnectToVirtualizationService(msg) => {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100118 (ErrorCode::UNKNOWN, msg.to_string())
Inseob Kim11f40d02022-06-13 17:16:00 +0900119 }
Jooyung Handd0a1732021-11-23 15:26:20 +0900120 }
121 } else {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100122 (ErrorCode::UNKNOWN, err.to_string())
Jooyung Handd0a1732021-11-23 15:26:20 +0900123 }
124}
125
Inseob Kim11f40d02022-06-13 17:16:00 +0900126fn write_death_reason_to_serial(err: &Error) -> Result<()> {
127 let death_reason = if let Some(e) = err.downcast_ref::<MicrodroidError>() {
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100128 Borrowed(match e {
Inseob Kim11f40d02022-06-13 17:16:00 +0900129 MicrodroidError::FailedToConnectToVirtualizationService(_) => {
130 "MICRODROID_FAILED_TO_CONNECT_TO_VIRTUALIZATION_SERVICE"
131 }
132 MicrodroidError::PayloadChanged(_) => "MICRODROID_PAYLOAD_HAS_CHANGED",
133 MicrodroidError::PayloadVerificationFailed(_) => {
134 "MICRODROID_PAYLOAD_VERIFICATION_FAILED"
135 }
136 MicrodroidError::InvalidConfig(_) => "MICRODROID_INVALID_PAYLOAD_CONFIG",
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100137 })
Inseob Kim11f40d02022-06-13 17:16:00 +0900138 } else {
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100139 // Send context information back after a separator, to ease diagnosis.
140 // These errors occur before the payload runs, so this should not leak sensitive
141 // information.
142 Owned(format!("MICRODROID_UNKNOWN_RUNTIME_ERROR|{:?}", err))
Inseob Kim11f40d02022-06-13 17:16:00 +0900143 };
144
145 let death_reason_bytes = death_reason.as_bytes();
146 let mut sent_total = 0;
147 while sent_total < death_reason_bytes.len() {
148 // TODO(b/220071963): Sometimes, sending more than 16 bytes at once makes MM hang.
149 let begin = sent_total;
150 let end = std::cmp::min(begin.saturating_add(16), death_reason_bytes.len());
151 OpenOptions::new()
152 .read(false)
153 .write(true)
154 .open(FAILURE_SERIAL_DEVICE)?
155 .write_all(&death_reason_bytes[begin..end])?;
156 sent_total = end;
157 }
158
159 Ok(())
160}
161
Inseob Kim1b95f2e2021-08-19 13:17:40 +0900162fn get_vms_rpc_binder() -> Result<Strong<dyn IVirtualMachineService>> {
David Brazdil73988ea2022-11-11 15:10:32 +0000163 // The host is running a VirtualMachineService for this VM on a port equal
164 // to the CID of this VM.
165 let port = vsock::get_local_cid().context("Could not determine local CID")?;
David Brazdila2125dd2022-12-14 16:37:44 +0000166 RpcSession::new()
167 .setup_vsock_client(VMADDR_CID_HOST, port)
David Brazdil73988ea2022-11-11 15:10:32 +0000168 .context("Could not connect to IVirtualMachineService")
Inseob Kim1b95f2e2021-08-19 13:17:40 +0900169}
170
Inseob Kim437f1052022-06-21 11:30:22 +0900171fn main() -> Result<()> {
Inseob Kim7ff121c2022-11-14 18:13:23 +0900172 // If debuggable, print full backtrace to console log with stdio_to_kmsg
Seungjae Yoofa22bb02022-12-08 16:38:42 +0900173 if system_properties::read_bool(DEBUGGABLE_PROP, true)? {
Inseob Kim7ff121c2022-11-14 18:13:23 +0900174 env::set_var("RUST_BACKTRACE", "full");
175 }
176
Inseob Kim437f1052022-06-21 11:30:22 +0900177 scopeguard::defer! {
178 info!("Shutting down...");
Jooyung Hanbfe086f2021-10-28 10:15:45 +0900179 if let Err(e) = system_properties::write("sys.powerctl", "shutdown") {
180 error!("failed to shutdown {:?}", e);
181 }
Jooyung Han311b1202021-09-14 22:00:16 +0900182 }
Inseob Kim437f1052022-06-21 11:30:22 +0900183
184 try_main().map_err(|e| {
185 error!("Failed with {:?}.", e);
186 if let Err(e) = write_death_reason_to_serial(&e) {
187 error!("Failed to write death reason {:?}", e);
188 }
189 e
190 })
Jooyung Han311b1202021-09-14 22:00:16 +0900191}
192
Alice Wang2a5306e2023-06-05 09:18:32 +0000193fn prepare_vm_payload_service_socket() -> Result<()> {
194 android_get_control_socket(VM_PAYLOAD_SERVICE_SOCKET_NAME)?;
Inseob Kim090b70b2022-11-16 20:01:14 +0900195
Alice Wang2a5306e2023-06-05 09:18:32 +0000196 // TODO(b/275729094): Convert the obtained file descriptor to `OwnedFd`
197 // and use it to set the `RpcServer`.
Inseob Kim090b70b2022-11-16 20:01:14 +0900198 Ok(())
199}
200
Jooyung Han311b1202021-09-14 22:00:16 +0900201fn try_main() -> Result<()> {
Dan Albert04e5dbd2023-05-08 22:49:40 +0000202 let _ignored = kernlog::init();
Jooyung Han347d9f22021-05-28 00:05:14 +0900203 info!("started.");
204
Alice Wang2a5306e2023-06-05 09:18:32 +0000205 // To ensure that the CLOEXEC flag is set on the file descriptor as early as possible,
206 // it is necessary to fetch the socket corresponding to vm_payload_service at the
207 // very beginning, as android_get_control_socket() sets the CLOEXEC flag on the file
208 // descriptor.
209 prepare_vm_payload_service_socket()?;
Inseob Kim090b70b2022-11-16 20:01:14 +0900210
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
Alice Wang285a3d22023-03-01 11:36:29 +0000290 let config_descriptor = format_payload_config_descriptor(payload_metadata)?;
Andrew Scullb2f44472022-01-21 14:41:34 +0000291
Seungjae Yoofa22bb02022-12-08 16:38:42 +0900292 // Check debuggability, conservatively assuming it is debuggable
293 let debuggable = system_properties::read_bool(DEBUGGABLE_PROP, true)?;
Andrew Scull65ddfc42022-02-14 21:03:58 +0000294
Andrew Scullb2f44472022-01-21 14:41:34 +0000295 // Send the details to diced
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000296 let hidden = verified_data.salt.clone().try_into().unwrap();
Alice Wang285a3d22023-03-01 11:36:29 +0000297 dice.derive(code_hash, &config_descriptor, authority_hash, debuggable, hidden)
Alan Stokes1f417c92022-09-29 15:13:28 +0100298}
299
Andrew Scullab72ec52022-03-14 09:10:52 +0000300fn is_strict_boot() -> bool {
301 Path::new(AVF_STRICT_BOOT).exists()
302}
303
304fn is_new_instance() -> bool {
305 Path::new(AVF_NEW_INSTANCE).exists()
306}
307
Inseob Kime379e7d2022-07-22 18:55:18 +0900308fn is_verified_boot() -> bool {
309 !Path::new(DEBUG_MICRODROID_NO_VERIFIED_BOOT).exists()
310}
311
Inseob Kimab1037d2023-02-08 17:03:31 +0900312fn should_export_tombstones(config: &VmPayloadConfig) -> bool {
313 match config.export_tombstones {
314 Some(b) => b,
315 None => system_properties::read_bool(DEBUGGABLE_PROP, true).unwrap_or(false),
316 }
317}
318
Jaewan Kim3124ef02023-03-23 19:25:20 +0900319/// Get debug policy value in bool. It's true iff the value is explicitly set to <1>.
320fn get_debug_policy_bool(path: &'static str) -> Result<Option<bool>> {
321 let mut file = match File::open(path) {
322 Ok(dp) => dp,
323 Err(e) => {
324 info!("{e:?}. Assumes <0>");
325 return Ok(Some(false));
326 }
327 };
328 let mut log: [u8; 4] = Default::default();
329 file.read_exact(&mut log).context("Malformed data in {path}")?;
330 // DT spec uses big endian although Android is always little endian.
331 Ok(Some(u32::from_be_bytes(log) == 1))
332}
333
Jooyung Han5c6d4172021-12-06 14:17:52 +0900334fn try_run_payload(service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
Jooyung Han311b1202021-09-14 22:00:16 +0900335 let metadata = load_metadata().context("Failed to load payload metadata")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000336 let dice = DiceDriver::new(Path::new("/dev/open-dice0")).context("Failed to load DICE")?;
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900337
Jooyung Han311b1202021-09-14 22:00:16 +0900338 let mut instance = InstanceDisk::new().context("Failed to load instance.img")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000339 let saved_data =
340 instance.read_microdroid_data(&dice).context("Failed to read identity data")?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900341
Andrew Scullab72ec52022-03-14 09:10:52 +0000342 if is_strict_boot() {
343 // Provisioning must happen on the first boot and never again.
344 if is_new_instance() {
345 ensure!(
346 saved_data.is_none(),
347 MicrodroidError::InvalidConfig("Found instance data on first boot.".to_string())
348 );
349 } else {
350 ensure!(
351 saved_data.is_some(),
352 MicrodroidError::InvalidConfig("Instance data not found.".to_string())
353 );
354 };
355 }
356
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900357 // Verify the payload before using it.
Inseob Kim11f40d02022-06-13 17:16:00 +0900358 let verified_data = verify_payload(&metadata, saved_data.as_ref())
359 .context("Payload verification failed")
360 .map_err(|e| MicrodroidError::PayloadVerificationFailed(e.to_string()))?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900361
362 // In case identity is ignored (by debug policy), we should reuse existing payload data, even
363 // when the payload is changed. This is to keep the derived secret same as before.
364 let verified_data = if let Some(saved_data) = saved_data {
365 if !is_verified_boot() {
366 if saved_data != verified_data {
367 info!("Detected an update of the payload, but continue (regarding debug policy)")
368 }
369 } else {
370 ensure!(
371 saved_data == verified_data,
372 MicrodroidError::PayloadChanged(String::from(
373 "Detected an update of the payload which isn't supported yet."
374 ))
375 );
376 info!("Saved data is verified.");
377 }
378 saved_data
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900379 } else {
Jooyung Han7a343f92021-09-08 22:53:11 +0900380 info!("Saving verified data.");
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000381 instance
382 .write_microdroid_data(&verified_data, &dice)
383 .context("Failed to write identity data")?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900384 verified_data
385 };
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900386
Alan Stokes1f417c92022-09-29 15:13:28 +0100387 let payload_metadata = metadata.payload.ok_or_else(|| {
388 MicrodroidError::InvalidConfig("No payload config in metadata".to_string())
389 })?;
Alan Stokes0d1ef782022-09-27 13:46:35 +0100390
Inseob Kimb2519c52022-04-14 02:10:09 +0900391 // To minimize the exposure to untrusted data, derive dice profile as soon as possible.
392 info!("DICE derivation for payload");
Alice Wang62f7e642023-02-10 09:55:13 +0000393 let dice_artifacts = dice_derivation(dice, &verified_data, &payload_metadata)?;
Shikha Panwar566c9672022-11-15 14:39:58 +0000394
395 // Run encryptedstore binary to prepare the storage
396 let encryptedstore_child = if Path::new(ENCRYPTEDSTORE_BACKING_DEVICE).exists() {
397 info!("Preparing encryptedstore ...");
Alice Wang62f7e642023-02-10 09:55:13 +0000398 Some(prepare_encryptedstore(&dice_artifacts).context("encryptedstore run")?)
Shikha Panwar566c9672022-11-15 14:39:58 +0000399 } else {
400 None
401 };
Inseob Kimb2519c52022-04-14 02:10:09 +0900402
Alan Stokes960c9032022-12-07 16:53:45 +0000403 let mut zipfuse = Zipfuse::default();
404
Jooyung Hana6d11eb2021-09-10 11:48:05 +0900405 // Before reading a file from the APK, start zipfuse
Alan Stokes960c9032022-12-07 16:53:45 +0000406 zipfuse.mount(
Alan Stokes60f82202022-10-07 16:40:07 +0100407 MountForExec::Allowed,
Inseob Kim217038e2021-11-25 11:15:06 +0900408 "fscontext=u:object_r:zipfusefs:s0,context=u:object_r:system_file:s0",
409 Path::new("/dev/block/mapper/microdroid-apk"),
Alice Wang6bbb6da2022-10-26 12:44:06 +0000410 Path::new(VM_APK_CONTENTS_PATH),
Alan Stokes960c9032022-12-07 16:53:45 +0000411 "microdroid_manager.apk.mounted".to_owned(),
412 )?;
Jiyong Park21ce2c52021-08-28 02:32:17 +0900413
Andrew Scull4d262dc2022-10-21 13:14:33 +0000414 // Restricted APIs are only allowed to be used by platform or test components. Infer this from
415 // the use of a VM config file since those can only be used by platform and test components.
416 let allow_restricted_apis = match payload_metadata {
417 PayloadMetadata::config_path(_) => true,
418 PayloadMetadata::config(_) => false,
419 };
420
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100421 let config = load_config(payload_metadata).context("Failed to load payload metadata")?;
Shikha Panwar6f03c942022-04-13 20:26:50 +0000422
Alan Stokes01b3ef02022-09-22 17:43:24 +0100423 let task = config
424 .task
425 .as_ref()
426 .ok_or_else(|| MicrodroidError::InvalidConfig("No task in VM config".to_string()))?;
427
Alice Wang061478b2023-04-11 13:26:17 +0000428 ensure!(
429 config.extra_apks.len() == verified_data.extra_apks_data.len(),
430 "config expects {} extra apks, but found {}",
431 config.extra_apks.len(),
432 verified_data.extra_apks_data.len()
433 );
Alan Stokes960c9032022-12-07 16:53:45 +0000434 mount_extra_apks(&config, &mut zipfuse)?;
Jooyung Han634e2d72021-06-10 16:27:38 +0900435
Jooyung Han5c6d4172021-12-06 14:17:52 +0900436 // Wait until apex config is done. (e.g. linker configuration for apexes)
Jooyung Han5c6d4172021-12-06 14:17:52 +0900437 wait_for_apex_config_done()?;
438
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000439 setup_config_sysprops(&config)?;
440
Shikha Panwar1a6efcd2023-02-03 19:23:43 +0000441 // Set export_tombstones if enabled
Inseob Kimab1037d2023-02-08 17:03:31 +0900442 if should_export_tombstones(&config) {
Shikha Panwar1a6efcd2023-02-03 19:23:43 +0000443 // This property is read by tombstone_handler.
444 system_properties::write("microdroid_manager.export_tombstones.enabled", "1")
445 .context("set microdroid_manager.export_tombstones.enabled")?;
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900446 }
447
Alan Stokes960c9032022-12-07 16:53:45 +0000448 // Wait until zipfuse has mounted the APKs so we can access the payload
449 zipfuse.wait_until_done()?;
Alan Stokes60f82202022-10-07 16:40:07 +0100450
Alice Wang62f7e642023-02-10 09:55:13 +0000451 register_vm_payload_service(allow_restricted_apis, service.clone(), dice_artifacts)?;
Shikha Panwar566c9672022-11-15 14:39:58 +0000452
Shikha Panwarddc124b2022-11-28 19:17:54 +0000453 // Wait for encryptedstore to finish mounting the storage (if enabled) before setting
454 // microdroid_manager.init_done. Reason is init stops uneventd after that.
455 // Encryptedstore, however requires ueventd
Shikha Panwar566c9672022-11-15 14:39:58 +0000456 if let Some(mut child) = encryptedstore_child {
457 let exitcode = child.wait().context("Wait for encryptedstore child")?;
458 ensure!(exitcode.success(), "Unable to prepare encrypted storage. Exitcode={}", exitcode);
459 }
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100460
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000461 wait_for_property_true("dev.bootcomplete").context("failed waiting for dev.bootcomplete")?;
Shikha Panwar3f6f6a52022-11-29 17:28:36 +0000462 system_properties::write("microdroid_manager.init_done", "1")
463 .context("set microdroid_manager.init_done")?;
Inseob Kimc16b0cc2023-01-26 14:57:24 +0900464
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000465 info!("boot completed, time to run payload");
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100466 exec_task(task, service).context("Failed to run payload")
Alan Stokes01b3ef02022-09-22 17:43:24 +0100467}
468
Inseob Kim217038e2021-11-25 11:15:06 +0900469struct ApkDmverityArgument<'a> {
470 apk: &'a str,
471 idsig: &'a str,
472 name: &'a str,
Inseob Kim197748b2021-12-01 19:49:00 +0900473 saved_root_hash: Option<&'a RootHash>,
Inseob Kim217038e2021-11-25 11:15:06 +0900474}
475
476fn run_apkdmverity(args: &[ApkDmverityArgument]) -> Result<Child> {
477 let mut cmd = Command::new(APKDMVERITY_BIN);
478
Inseob Kim217038e2021-11-25 11:15:06 +0900479 for argument in args {
480 cmd.arg("--apk").arg(argument.apk).arg(argument.idsig).arg(argument.name);
Inseob Kim197748b2021-12-01 19:49:00 +0900481 if let Some(root_hash) = argument.saved_root_hash {
482 cmd.arg(&to_hex_string(root_hash));
483 } else {
484 cmd.arg("none");
485 }
Inseob Kim217038e2021-11-25 11:15:06 +0900486 }
487
488 cmd.spawn().context("Spawn apkdmverity")
489}
490
Alan Stokes60f82202022-10-07 16:40:07 +0100491enum MountForExec {
492 Allowed,
493 Disallowed,
494}
495
Alan Stokes960c9032022-12-07 16:53:45 +0000496#[derive(Default)]
497struct Zipfuse {
498 ready_properties: Vec<String>,
499}
500
501impl Zipfuse {
Jiyong Park231f9692023-01-09 19:36:21 +0900502 const MICRODROID_PAYLOAD_UID: u32 = 0; // TODO(b/264861173) should be non-root
503 const MICRODROID_PAYLOAD_GID: u32 = 0; // TODO(b/264861173) should be non-root
Alan Stokes960c9032022-12-07 16:53:45 +0000504 fn mount(
505 &mut self,
506 noexec: MountForExec,
507 option: &str,
508 zip_path: &Path,
509 mount_dir: &Path,
510 ready_prop: String,
511 ) -> Result<Child> {
512 let mut cmd = Command::new(ZIPFUSE_BIN);
513 if let MountForExec::Disallowed = noexec {
514 cmd.arg("--noexec");
515 }
516 cmd.args(["-p", &ready_prop, "-o", option]);
Jiyong Park231f9692023-01-09 19:36:21 +0900517 cmd.args(["-u", &Self::MICRODROID_PAYLOAD_UID.to_string()]);
518 cmd.args(["-g", &Self::MICRODROID_PAYLOAD_GID.to_string()]);
Alan Stokes960c9032022-12-07 16:53:45 +0000519 cmd.arg(zip_path).arg(mount_dir);
520 self.ready_properties.push(ready_prop);
521 cmd.spawn().with_context(|| format!("Failed to run zipfuse for {mount_dir:?}"))
Andrew Scullcc339a12022-07-04 12:44:19 +0000522 }
Alan Stokes960c9032022-12-07 16:53:45 +0000523
524 fn wait_until_done(self) -> Result<()> {
525 // We check the last-started check first in the hope that by the time it is done
526 // all or most of the others will also be done, minimising the number of times we
527 // block on a property.
528 for property in self.ready_properties.into_iter().rev() {
529 wait_for_property_true(&property)
530 .with_context(|| format!("Failed waiting for {property}"))?;
531 }
532 Ok(())
Alan Stokes60f82202022-10-07 16:40:07 +0100533 }
Inseob Kim217038e2021-11-25 11:15:06 +0900534}
535
Inseob Kime379e7d2022-07-22 18:55:18 +0900536fn write_apex_payload_data(
537 saved_data: Option<&MicrodroidData>,
538 apex_data_from_payload: &[ApexData],
539) -> Result<()> {
540 if let Some(saved_apex_data) = saved_data.map(|d| &d.apex_data) {
541 // We don't support APEX updates. (assuming that update will change root digest)
542 ensure!(
543 saved_apex_data == apex_data_from_payload,
544 MicrodroidError::PayloadChanged(String::from("APEXes have changed."))
545 );
546 let apex_metadata = to_metadata(apex_data_from_payload);
547 // Pass metadata(with public keys and root digests) to apexd so that it uses the passed
548 // metadata instead of the default one (/dev/block/by-name/payload-metadata)
549 OpenOptions::new()
550 .create_new(true)
551 .write(true)
552 .open("/apex/vm-payload-metadata")
553 .context("Failed to open /apex/vm-payload-metadata")
554 .and_then(|f| write_metadata(&apex_metadata, f))?;
555 }
556 Ok(())
557}
558
Jooyung Han7a343f92021-09-08 22:53:11 +0900559// Verify payload before executing it. For APK payload, Full verification (which is slow) is done
560// when the root_hash values from the idsig file and the instance disk are different. This function
561// returns the verified root hash (for APK payload) and pubkeys (for APEX payloads) that can be
562// saved to the instance disk.
563fn verify_payload(
564 metadata: &Metadata,
565 saved_data: Option<&MicrodroidData>,
566) -> Result<MicrodroidData> {
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900567 let start_time = SystemTime::now();
568
Inseob Kim197748b2021-12-01 19:49:00 +0900569 // Verify main APK
Inseob Kim197748b2021-12-01 19:49:00 +0900570 let root_hash_from_idsig = get_apk_root_hash_from_idsig(MAIN_APK_IDSIG_PATH)?;
Alice Wang061478b2023-04-11 13:26:17 +0000571 let root_hash_trustful =
572 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 +0900573
Jiyong Parkf7dea252021-09-08 01:42:54 +0900574 // 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 +0900575 // instead of the value read from the idsig file.
Inseob Kim197748b2021-12-01 19:49:00 +0900576 let main_apk_argument = {
577 ApkDmverityArgument {
578 apk: MAIN_APK_PATH,
579 idsig: MAIN_APK_IDSIG_PATH,
580 name: MAIN_APK_DEVICE_NAME,
581 saved_root_hash: if root_hash_trustful {
582 Some(root_hash_from_idsig.as_ref())
583 } else {
584 None
585 },
586 }
587 };
588 let mut apkdmverity_arguments = vec![main_apk_argument];
589
590 // Verify extra APKs
591 // For now, we can't read the payload config, so glob APKs and idsigs.
592 // Later, we'll see if it matches with the payload config.
593
594 // sort globbed paths to match apks (extra-apk-{idx}) and idsigs (extra-idsig-{idx})
595 // e.g. "extra-apk-0" corresponds to "extra-idsig-0"
596 let extra_apks =
597 sorted(glob(EXTRA_APK_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
598 let extra_idsigs =
599 sorted(glob(EXTRA_IDSIG_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
Alice Wang061478b2023-04-11 13:26:17 +0000600 ensure!(
601 extra_apks.len() == extra_idsigs.len(),
602 "Extra apks/idsigs mismatch: {} apks but {} idsigs",
603 extra_apks.len(),
604 extra_idsigs.len()
605 );
Inseob Kim197748b2021-12-01 19:49:00 +0900606
Alice Wang061478b2023-04-11 13:26:17 +0000607 let extra_root_hashes_from_idsig: Vec<_> = extra_idsigs
Inseob Kim197748b2021-12-01 19:49:00 +0900608 .iter()
Alice Wang061478b2023-04-11 13:26:17 +0000609 .map(|idsig| {
610 get_apk_root_hash_from_idsig(idsig).expect("Can't find root hash from extra idsig")
Inseob Kim197748b2021-12-01 19:49:00 +0900611 })
612 .collect();
613
Alice Wang061478b2023-04-11 13:26:17 +0000614 let extra_root_hashes_trustful: Vec<_> = if let Some(data) = saved_data {
615 extra_root_hashes_from_idsig
616 .iter()
617 .enumerate()
618 .map(|(i, root_hash)| data.extra_apk_root_hash_eq(i, root_hash))
619 .collect()
620 } else {
621 vec![false; extra_root_hashes_from_idsig.len()]
622 };
623 let extra_apk_names: Vec<_> =
624 (0..extra_apks.len()).map(|i| format!("extra-apk-{}", i)).collect();
625
626 for (i, extra_apk) in extra_apks.iter().enumerate() {
Inseob Kim197748b2021-12-01 19:49:00 +0900627 apkdmverity_arguments.push({
628 ApkDmverityArgument {
Alice Wang061478b2023-04-11 13:26:17 +0000629 apk: extra_apk.to_str().unwrap(),
Inseob Kim197748b2021-12-01 19:49:00 +0900630 idsig: extra_idsigs[i].to_str().unwrap(),
631 name: &extra_apk_names[i],
632 saved_root_hash: if extra_root_hashes_trustful[i] {
633 Some(&extra_root_hashes_from_idsig[i])
634 } else {
635 None
636 },
637 }
638 });
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900639 }
640
641 // Start apkdmverity and wait for the dm-verify block
Inseob Kim197748b2021-12-01 19:49:00 +0900642 let mut apkdmverity_child = run_apkdmverity(&apkdmverity_arguments)?;
Jooyung Han7a343f92021-09-08 22:53:11 +0900643
Jooyung Hanc8deb472021-09-13 13:48:25 +0900644 // While waiting for apkdmverity to mount APK, gathers public keys and root digests from
645 // APEX payload.
Jooyung Han7a343f92021-09-08 22:53:11 +0900646 let apex_data_from_payload = get_apex_data_from_payload(metadata)?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900647
648 // Writing /apex/vm-payload-metadata is to verify that the payload isn't changed.
649 // Skip writing it if the debug policy ignoring identity is on
650 if is_verified_boot() {
651 write_apex_payload_data(saved_data, &apex_data_from_payload)?;
Jooyung Han4a9b3bf2021-09-10 17:19:00 +0900652 }
Inseob Kime379e7d2022-07-22 18:55:18 +0900653
Jooyung Han4a9b3bf2021-09-10 17:19:00 +0900654 // Start apexd to activate APEXes
655 system_properties::write("ctl.start", "apexd-vm")?;
Jooyung Han7a343f92021-09-08 22:53:11 +0900656
Inseob Kim217038e2021-11-25 11:15:06 +0900657 // TODO(inseob): add timeout
658 apkdmverity_child.wait()?;
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900659
Jiyong Parkf7dea252021-09-08 01:42:54 +0900660 // Do the full verification if the root_hash is un-trustful. This requires the full scanning of
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900661 // 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 +0900662 // 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 +0900663 // of the VM or APK was updated in the host.
664 // TODO(jooyung): consider multithreading to make this faster
Inseob Kim197748b2021-12-01 19:49:00 +0900665 let main_apk_pubkey = get_public_key_from_apk(DM_MOUNTED_APK_PATH, root_hash_trustful)?;
666 let extra_apks_data = extra_root_hashes_from_idsig
667 .into_iter()
668 .enumerate()
669 .map(|(i, extra_root_hash)| {
670 let mount_path = format!("/dev/block/mapper/{}", &extra_apk_names[i]);
671 let apk_pubkey = get_public_key_from_apk(&mount_path, extra_root_hashes_trustful[i])?;
672 Ok(ApkData { root_hash: extra_root_hash, pubkey: apk_pubkey })
673 })
674 .collect::<Result<Vec<_>>>()?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900675
676 info!("payload verification successful. took {:#?}", start_time.elapsed().unwrap());
677
Andrew Scull34916a72022-01-30 21:34:24 +0000678 // Use the salt from a verified instance, or generate a salt for a new instance.
679 let salt = if let Some(saved_data) = saved_data {
680 saved_data.salt.clone()
Pierre-Clément Tosicecb0aa2023-02-08 16:57:54 +0000681 } else if is_strict_boot() {
682 // No need to add more entropy as a previous stage must have used a new, random salt.
683 vec![0u8; 64]
Andrew Scull34916a72022-01-30 21:34:24 +0000684 } else {
685 let mut salt = vec![0u8; 64];
686 salt.as_mut_slice().try_fill(&mut rand::thread_rng())?;
687 salt
688 };
689
Jiyong Parkf7dea252021-09-08 01:42:54 +0900690 // At this point, we can ensure that the root_hash from the idsig file is trusted, either by
691 // fully verifying the APK or by comparing it with the saved root_hash.
Jooyung Han7a343f92021-09-08 22:53:11 +0900692 Ok(MicrodroidData {
Andrew Scull34916a72022-01-30 21:34:24 +0000693 salt,
Inseob Kim197748b2021-12-01 19:49:00 +0900694 apk_data: ApkData { root_hash: root_hash_from_idsig, pubkey: main_apk_pubkey },
695 extra_apks_data,
Jooyung Han7a343f92021-09-08 22:53:11 +0900696 apex_data: apex_data_from_payload,
697 })
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900698}
699
Alan Stokes960c9032022-12-07 16:53:45 +0000700fn mount_extra_apks(config: &VmPayloadConfig, zipfuse: &mut Zipfuse) -> Result<()> {
Inseob Kim197748b2021-12-01 19:49:00 +0900701 // For now, only the number of apks is important, as the mount point and dm-verity name is fixed
702 for i in 0..config.extra_apks.len() {
Alan Stokes960c9032022-12-07 16:53:45 +0000703 let mount_dir = format!("/mnt/extra-apk/{i}");
Inseob Kim197748b2021-12-01 19:49:00 +0900704 create_dir(Path::new(&mount_dir)).context("Failed to create mount dir for extra apks")?;
705
706 // don't wait, just detach
Alan Stokes960c9032022-12-07 16:53:45 +0000707 zipfuse.mount(
Alan Stokes60f82202022-10-07 16:40:07 +0100708 MountForExec::Disallowed,
Inseob Kim197748b2021-12-01 19:49:00 +0900709 "fscontext=u:object_r:zipfusefs:s0,context=u:object_r:extra_apk_file:s0",
Alan Stokes960c9032022-12-07 16:53:45 +0000710 Path::new(&format!("/dev/block/mapper/extra-apk-{i}")),
Inseob Kim197748b2021-12-01 19:49:00 +0900711 Path::new(&mount_dir),
Alan Stokes960c9032022-12-07 16:53:45 +0000712 format!("microdroid_manager.extra_apk.mounted.{i}"),
713 )?;
Inseob Kim197748b2021-12-01 19:49:00 +0900714 }
715
716 Ok(())
717}
718
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000719fn setup_config_sysprops(config: &VmPayloadConfig) -> Result<()> {
720 if config.enable_authfs {
721 system_properties::write("microdroid_manager.authfs.enabled", "1")
722 .context("failed to write microdroid_manager.authfs.enabled")?;
723 }
724 system_properties::write("microdroid_manager.config_done", "1")
725 .context("failed to write microdroid_manager.config_done")?;
726 Ok(())
727}
728
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900729// Waits until linker config is generated
730fn wait_for_apex_config_done() -> Result<()> {
Alan Stokes60f82202022-10-07 16:40:07 +0100731 wait_for_property_true(APEX_CONFIG_DONE_PROP).context("Failed waiting for apex config done")
732}
733
734fn wait_for_property_true(property_name: &str) -> Result<()> {
735 let mut prop = PropertyWatcher::new(property_name)?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900736 loop {
Andrew Walbrand9c766e2023-05-10 15:15:39 +0000737 prop.wait(None)?;
Alan Stokes60f82202022-10-07 16:40:07 +0100738 if system_properties::read_bool(property_name, false)? {
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900739 break;
740 }
741 }
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900742 Ok(())
743}
744
Alice Wang89cff012022-09-26 10:05:16 +0000745fn get_apk_root_hash_from_idsig<P: AsRef<Path>>(idsig_path: P) -> Result<Box<RootHash>> {
746 Ok(V4Signature::from_idsig_path(idsig_path)?.hashing_info.raw_root_hash)
Jiyong Park21ce2c52021-08-28 02:32:17 +0900747}
748
Inseob Kim197748b2021-12-01 19:49:00 +0900749fn get_public_key_from_apk(apk: &str, root_hash_trustful: bool) -> Result<Box<[u8]>> {
Alan Stokes25f69362023-03-06 16:51:54 +0000750 let current_sdk = get_current_sdk()?;
Inseob Kim197748b2021-12-01 19:49:00 +0900751 if !root_hash_trustful {
Alan Stokes25f69362023-03-06 16:51:54 +0000752 verify(apk, current_sdk).context(MicrodroidError::PayloadVerificationFailed(format!(
Inseob Kim197748b2021-12-01 19:49:00 +0900753 "failed to verify {}",
754 apk
755 )))
756 } else {
Alan Stokes25f69362023-03-06 16:51:54 +0000757 get_public_key_der(apk, current_sdk)
Inseob Kim197748b2021-12-01 19:49:00 +0900758 }
759}
760
Alan Stokes25f69362023-03-06 16:51:54 +0000761fn get_current_sdk() -> Result<u32> {
762 let current_sdk = system_properties::read("ro.build.version.sdk")?;
763 let current_sdk = current_sdk.ok_or_else(|| anyhow!("SDK version missing"))?;
764 current_sdk.parse().context("Malformed SDK version")
765}
766
Alan Stokes1f417c92022-09-29 15:13:28 +0100767fn load_config(payload_metadata: PayloadMetadata) -> Result<VmPayloadConfig> {
768 match payload_metadata {
769 PayloadMetadata::config_path(path) => {
770 let path = Path::new(&path);
771 info!("loading config from {:?}...", path);
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100772 let file = ioutil::wait_for_file(path, WAIT_TIMEOUT)
773 .with_context(|| format!("Failed to read {:?}", path))?;
Alan Stokes1f417c92022-09-29 15:13:28 +0100774 Ok(serde_json::from_reader(file)?)
775 }
776 PayloadMetadata::config(payload_config) => {
777 let task = Task {
778 type_: TaskType::MicrodroidLauncher,
Alan Stokes8f12f2b2023-01-09 09:19:20 +0000779 command: payload_config.payload_binary_name,
Alan Stokes1f417c92022-09-29 15:13:28 +0100780 };
781 Ok(VmPayloadConfig {
782 os: OsConfig { name: "microdroid".to_owned() },
783 task: Some(task),
784 apexes: vec![],
785 extra_apks: vec![],
786 prefer_staged: false,
Inseob Kimab1037d2023-02-08 17:03:31 +0900787 export_tombstones: None,
Alan Stokes1f417c92022-09-29 15:13:28 +0100788 enable_authfs: false,
789 })
790 }
791 }
Jooyung Han634e2d72021-06-10 16:27:38 +0900792}
793
Jaewan Kim3124ef02023-03-23 19:25:20 +0900794/// Loads the crashkernel into memory using kexec if debuggable or debug policy says so.
795/// The VM should be loaded with `crashkernel=' parameter in the cmdline to allocate memory
796/// for crashkernel.
Jiyong Park202856e2022-08-22 16:04:26 +0900797fn load_crashkernel_if_supported() -> Result<()> {
798 let supported = std::fs::read_to_string("/proc/cmdline")?.contains(" crashkernel=");
799 info!("ramdump supported: {}", supported);
Jaewan Kim3124ef02023-03-23 19:25:20 +0900800
801 if !supported {
802 return Ok(());
803 }
804
805 let debuggable = system_properties::read_bool(DEBUGGABLE_PROP, true)?;
806 let ramdump = get_debug_policy_bool(AVF_DEBUG_POLICY_RAMDUMP)?.unwrap_or_default();
807 let requested = debuggable | ramdump;
808
809 if requested {
Jiyong Park202856e2022-08-22 16:04:26 +0900810 let status = Command::new("/system/bin/kexec_load").status()?;
811 if !status.success() {
812 return Err(anyhow!("Failed to load crashkernel: {:?}", status));
813 }
Jaewan Kim3124ef02023-03-23 19:25:20 +0900814 info!("ramdump is loaded: debuggable={debuggable}, ramdump={ramdump}");
Jiyong Park202856e2022-08-22 16:04:26 +0900815 }
816 Ok(())
817}
818
Inseob Kim090b70b2022-11-16 20:01:14 +0900819/// Executes the given task.
Jooyung Han5c6d4172021-12-06 14:17:52 +0900820fn exec_task(task: &Task, service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
Jiyong Park8611a6c2021-07-09 18:17:44 +0900821 info!("executing main task {:?}...", task);
David Brazdil451cc962022-10-14 14:08:12 +0100822 let mut command = match task.type_ {
823 TaskType::Executable => Command::new(&task.command),
824 TaskType::MicrodroidLauncher => {
825 let mut command = Command::new("/system/bin/microdroid_launcher");
826 command.arg(find_library_path(&task.command)?);
827 command
828 }
829 };
Nikita Ioffe3452ee22022-12-15 00:31:56 +0000830
831 unsafe {
832 // SAFETY: we are not accessing any resource of the parent process.
833 command.pre_exec(|| {
834 info!("dropping capabilities before executing payload");
835 // It is OK to continue with payload execution even if the calls below fail, since
836 // whether process can use a capability is controlled by the SELinux. Dropping the
837 // capabilities here is just another defense-in-depth layer.
838 if let Err(e) = cap::drop_inheritable_caps() {
839 error!("failed to drop inheritable capabilities: {:?}", e);
840 }
841 if let Err(e) = cap::drop_bounding_set() {
842 error!("failed to drop bounding set: {:?}", e);
843 }
844 Ok(())
845 });
846 }
847
Inseob Kim090b70b2022-11-16 20:01:14 +0900848 command.stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null());
Inseob Kim7f61fe72021-08-20 20:50:47 +0900849
850 info!("notifying payload started");
Inseob Kimc7d28c72021-10-25 14:28:10 +0000851 service.notifyPayloadStarted()?;
Inseob Kim7f61fe72021-08-20 20:50:47 +0900852
Inseob Kim86ca0162021-10-20 02:21:02 +0000853 let exit_status = command.spawn()?.wait()?;
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -0800854 match exit_status.code() {
855 Some(exit_code) => Ok(exit_code),
856 None => Err(match exit_status.signal() {
857 Some(signal) => anyhow!(
858 "Payload exited due to signal: {} ({})",
859 signal,
860 Signal::try_from(signal).map_or("unknown", |s| s.as_str())
861 ),
862 None => anyhow!("Payload has neither exit code nor signal"),
863 }),
864 }
Jooyung Han347d9f22021-05-28 00:05:14 +0900865}
Jooyung Han634e2d72021-06-10 16:27:38 +0900866
Jooyung Han634e2d72021-06-10 16:27:38 +0900867fn find_library_path(name: &str) -> Result<String> {
868 let mut watcher = PropertyWatcher::new("ro.product.cpu.abilist")?;
869 let value = watcher.read(|_name, value| Ok(value.trim().to_string()))?;
870 let abi = value.split(',').next().ok_or_else(|| anyhow!("no abilist"))?;
Alice Wang6bbb6da2022-10-26 12:44:06 +0000871 let path = format!("{}/lib/{}/{}", VM_APK_CONTENTS_PATH, abi, name);
Jooyung Han634e2d72021-06-10 16:27:38 +0900872
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100873 let metadata = fs::metadata(&path).with_context(|| format!("Unable to access {}", path))?;
Jooyung Han634e2d72021-06-10 16:27:38 +0900874 if !metadata.is_file() {
875 bail!("{} is not a file", &path);
876 }
877
878 Ok(path)
879}
Jiyong Park21ce2c52021-08-28 02:32:17 +0900880
881fn to_hex_string(buf: &[u8]) -> String {
882 buf.iter().map(|b| format!("{:02X}", b)).collect()
883}
Shikha Panwar566c9672022-11-15 14:39:58 +0000884
Alice Wang62f7e642023-02-10 09:55:13 +0000885fn prepare_encryptedstore(dice_artifacts: &OwnedDiceArtifacts) -> Result<Child> {
Shikha Panwar566c9672022-11-15 14:39:58 +0000886 // Use a fixed salt to scope the derivation to this API.
887 // Generated using hexdump -vn32 -e'14/1 "0x%02X, " 1 "\n"' /dev/urandom
888 // TODO(b/241541860) : Move this (& other salts) to a salt container, i.e. a global enum
889 let salt = [
890 0xFC, 0x1D, 0x35, 0x7B, 0x96, 0xF3, 0xEF, 0x17, 0x78, 0x7D, 0x70, 0xED, 0xEA, 0xFE, 0x1D,
891 0x6F, 0xB3, 0xF9, 0x40, 0xCE, 0xDD, 0x99, 0x40, 0xAA, 0xA7, 0x0E, 0x92, 0x73, 0x90, 0x86,
892 0x4A, 0x75,
893 ];
Alice Wang7e6c9352023-02-15 15:44:13 +0000894 let mut key = ZVec::new(ENCRYPTEDSTORE_KEYSIZE)?;
895 derive_sealing_key(dice_artifacts, &salt, ENCRYPTEDSTORE_KEY_IDENTIFIER.as_bytes(), &mut key)?;
Shikha Panwar566c9672022-11-15 14:39:58 +0000896
897 let mut cmd = Command::new(ENCRYPTEDSTORE_BIN);
898 cmd.arg("--blkdevice")
899 .arg(ENCRYPTEDSTORE_BACKING_DEVICE)
900 .arg("--key")
901 .arg(hex::encode(&*key))
Shikha Panwar9fd198f2022-11-18 17:43:43 +0000902 .args(["--mountpoint", ENCRYPTEDSTORE_MOUNTPOINT])
Shikha Panwar566c9672022-11-15 14:39:58 +0000903 .spawn()
904 .context("encryptedstore failed")
905}