blob: f1c41b9be022207e1363487ce079a0f41fdbb2fe [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
Andrew Sculld64ae7d2022-10-05 17:41:43 +000024use crate::dice::{DiceContext, DiceDriver};
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;
Alan Stokes1f417c92022-09-29 15:13:28 +010037use diced_utils::cbor::{encode_header, encode_number};
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;
Inseob Kim090b70b2022-11-16 20:01:14 +090041use log::{error, info, warn};
Alan Stokes0d1ef782022-09-27 13:46:35 +010042use microdroid_metadata::{write_metadata, Metadata, PayloadMetadata};
Seungjae Yoofd9a0622022-10-14 10:01:29 +090043use microdroid_payload_config::{OsConfig, Task, TaskType, VmPayloadConfig};
Inseob Kim090b70b2022-11-16 20:01:14 +090044use nix::fcntl::{fcntl, F_SETFD, FdFlag};
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;
David Brazdil451cc962022-10-14 14:08:12 +010056use std::fs::{self, create_dir, OpenOptions};
Inseob Kim11f40d02022-06-13 17:16:00 +090057use std::io::Write;
Nikita Ioffe3452ee22022-12-15 00:31:56 +000058use std::os::unix::process::CommandExt;
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -080059use std::os::unix::process::ExitStatusExt;
Jooyung Hanf48ceb42021-06-01 18:00:04 +090060use std::path::Path;
Inseob Kim217038e2021-11-25 11:15:06 +090061use std::process::{Child, Command, Stdio};
Jiyong Park8611a6c2021-07-09 18:17:44 +090062use std::str;
Jiyong Parkbb4a9872021-09-06 15:59:21 +090063use std::time::{Duration, SystemTime};
Jooyung Han634e2d72021-06-10 16:27:38 +090064
65const WAIT_TIMEOUT: Duration = Duration::from_secs(10);
Inseob Kim197748b2021-12-01 19:49:00 +090066const MAIN_APK_PATH: &str = "/dev/block/by-name/microdroid-apk";
67const MAIN_APK_IDSIG_PATH: &str = "/dev/block/by-name/microdroid-apk-idsig";
68const MAIN_APK_DEVICE_NAME: &str = "microdroid-apk";
69const EXTRA_APK_PATH_PATTERN: &str = "/dev/block/by-name/extra-apk-*";
70const EXTRA_IDSIG_PATH_PATTERN: &str = "/dev/block/by-name/extra-idsig-*";
Jooyung Han19c1d6c2021-08-06 14:08:16 +090071const DM_MOUNTED_APK_PATH: &str = "/dev/block/mapper/microdroid-apk";
Inseob Kim217038e2021-11-25 11:15:06 +090072const APKDMVERITY_BIN: &str = "/system/bin/apkdmverity";
73const ZIPFUSE_BIN: &str = "/system/bin/zipfuse";
Andrew Scullab72ec52022-03-14 09:10:52 +000074const AVF_STRICT_BOOT: &str = "/sys/firmware/devicetree/base/chosen/avf,strict-boot";
75const AVF_NEW_INSTANCE: &str = "/sys/firmware/devicetree/base/chosen/avf,new-instance";
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
Jiyong Parkbb4a9872021-09-06 15:59:21 +090079const APEX_CONFIG_DONE_PROP: &str = "apex_config.done";
Inseob Kimf44917c2023-01-20 17:31:37 +090080const TOMBSTONE_TRANSMIT_DONE_PROP: &str = "tombstone_transmit.init_done";
Seungjae Yoofa22bb02022-12-08 16:38:42 +090081const DEBUGGABLE_PROP: &str = "ro.boot.microdroid.debuggable";
Jiyong Parkbb4a9872021-09-06 15:59:21 +090082
Inseob Kim11f40d02022-06-13 17:16:00 +090083// SYNC WITH virtualizationservice/src/crosvm.rs
84const FAILURE_SERIAL_DEVICE: &str = "/dev/ttyS1";
85
Shikha Panwar566c9672022-11-15 14:39:58 +000086/// Identifier for the key used for encrypted store.
87const ENCRYPTEDSTORE_BACKING_DEVICE: &str = "/dev/block/by-name/encryptedstore";
88const ENCRYPTEDSTORE_BIN: &str = "/system/bin/encryptedstore";
89const ENCRYPTEDSTORE_KEY_IDENTIFIER: &str = "encryptedstore_key";
Shikha Panwar195f89c2022-11-23 16:20:34 +000090const ENCRYPTEDSTORE_KEYSIZE: u32 = 32;
Shikha Panwar566c9672022-11-15 14:39:58 +000091
Jooyung Handd0a1732021-11-23 15:26:20 +090092#[derive(thiserror::Error, Debug)]
93enum MicrodroidError {
Inseob Kim11f40d02022-06-13 17:16:00 +090094 #[error("Cannot connect to virtualization service: {0}")]
95 FailedToConnectToVirtualizationService(String),
Jooyung Handd0a1732021-11-23 15:26:20 +090096 #[error("Payload has changed: {0}")]
97 PayloadChanged(String),
98 #[error("Payload verification has failed: {0}")]
99 PayloadVerificationFailed(String),
Jooyung Han5c6d4172021-12-06 14:17:52 +0900100 #[error("Payload config is invalid: {0}")]
101 InvalidConfig(String),
Jooyung Handd0a1732021-11-23 15:26:20 +0900102}
103
Alan Stokes2bead0d2022-09-05 16:58:34 +0100104fn translate_error(err: &Error) -> (ErrorCode, String) {
Jooyung Handd0a1732021-11-23 15:26:20 +0900105 if let Some(e) = err.downcast_ref::<MicrodroidError>() {
106 match e {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100107 MicrodroidError::PayloadChanged(msg) => (ErrorCode::PAYLOAD_CHANGED, msg.to_string()),
Jooyung Handd0a1732021-11-23 15:26:20 +0900108 MicrodroidError::PayloadVerificationFailed(msg) => {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100109 (ErrorCode::PAYLOAD_VERIFICATION_FAILED, msg.to_string())
Jooyung Handd0a1732021-11-23 15:26:20 +0900110 }
Alan Stokes2bead0d2022-09-05 16:58:34 +0100111 MicrodroidError::InvalidConfig(msg) => {
112 (ErrorCode::PAYLOAD_CONFIG_INVALID, msg.to_string())
113 }
Inseob Kim11f40d02022-06-13 17:16:00 +0900114
115 // Connection failure won't be reported to VS; return the default value
116 MicrodroidError::FailedToConnectToVirtualizationService(msg) => {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100117 (ErrorCode::UNKNOWN, msg.to_string())
Inseob Kim11f40d02022-06-13 17:16:00 +0900118 }
Jooyung Handd0a1732021-11-23 15:26:20 +0900119 }
120 } else {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100121 (ErrorCode::UNKNOWN, err.to_string())
Jooyung Handd0a1732021-11-23 15:26:20 +0900122 }
123}
124
Inseob Kim11f40d02022-06-13 17:16:00 +0900125fn write_death_reason_to_serial(err: &Error) -> Result<()> {
126 let death_reason = if let Some(e) = err.downcast_ref::<MicrodroidError>() {
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100127 Borrowed(match e {
Inseob Kim11f40d02022-06-13 17:16:00 +0900128 MicrodroidError::FailedToConnectToVirtualizationService(_) => {
129 "MICRODROID_FAILED_TO_CONNECT_TO_VIRTUALIZATION_SERVICE"
130 }
131 MicrodroidError::PayloadChanged(_) => "MICRODROID_PAYLOAD_HAS_CHANGED",
132 MicrodroidError::PayloadVerificationFailed(_) => {
133 "MICRODROID_PAYLOAD_VERIFICATION_FAILED"
134 }
135 MicrodroidError::InvalidConfig(_) => "MICRODROID_INVALID_PAYLOAD_CONFIG",
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100136 })
Inseob Kim11f40d02022-06-13 17:16:00 +0900137 } else {
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100138 // Send context information back after a separator, to ease diagnosis.
139 // These errors occur before the payload runs, so this should not leak sensitive
140 // information.
141 Owned(format!("MICRODROID_UNKNOWN_RUNTIME_ERROR|{:?}", err))
Inseob Kim11f40d02022-06-13 17:16:00 +0900142 };
143
144 let death_reason_bytes = death_reason.as_bytes();
145 let mut sent_total = 0;
146 while sent_total < death_reason_bytes.len() {
147 // TODO(b/220071963): Sometimes, sending more than 16 bytes at once makes MM hang.
148 let begin = sent_total;
149 let end = std::cmp::min(begin.saturating_add(16), death_reason_bytes.len());
150 OpenOptions::new()
151 .read(false)
152 .write(true)
153 .open(FAILURE_SERIAL_DEVICE)?
154 .write_all(&death_reason_bytes[begin..end])?;
155 sent_total = end;
156 }
157
158 Ok(())
159}
160
Inseob Kim1b95f2e2021-08-19 13:17:40 +0900161fn get_vms_rpc_binder() -> Result<Strong<dyn IVirtualMachineService>> {
David Brazdil73988ea2022-11-11 15:10:32 +0000162 // The host is running a VirtualMachineService for this VM on a port equal
163 // to the CID of this VM.
164 let port = vsock::get_local_cid().context("Could not determine local CID")?;
David Brazdila2125dd2022-12-14 16:37:44 +0000165 RpcSession::new()
166 .setup_vsock_client(VMADDR_CID_HOST, port)
David Brazdil73988ea2022-11-11 15:10:32 +0000167 .context("Could not connect to IVirtualMachineService")
Inseob Kim1b95f2e2021-08-19 13:17:40 +0900168}
169
Inseob Kim437f1052022-06-21 11:30:22 +0900170fn main() -> Result<()> {
Inseob Kim7ff121c2022-11-14 18:13:23 +0900171 // If debuggable, print full backtrace to console log with stdio_to_kmsg
Seungjae Yoofa22bb02022-12-08 16:38:42 +0900172 if system_properties::read_bool(DEBUGGABLE_PROP, true)? {
Inseob Kim7ff121c2022-11-14 18:13:23 +0900173 env::set_var("RUST_BACKTRACE", "full");
174 }
175
Inseob Kim437f1052022-06-21 11:30:22 +0900176 scopeguard::defer! {
177 info!("Shutting down...");
Jooyung Hanbfe086f2021-10-28 10:15:45 +0900178 if let Err(e) = system_properties::write("sys.powerctl", "shutdown") {
179 error!("failed to shutdown {:?}", e);
180 }
Jooyung Han311b1202021-09-14 22:00:16 +0900181 }
Inseob Kim437f1052022-06-21 11:30:22 +0900182
183 try_main().map_err(|e| {
184 error!("Failed with {:?}.", e);
185 if let Err(e) = write_death_reason_to_serial(&e) {
186 error!("Failed to write death reason {:?}", e);
187 }
188 e
189 })
Jooyung Han311b1202021-09-14 22:00:16 +0900190}
191
Inseob Kim090b70b2022-11-16 20:01:14 +0900192fn set_cloexec_on_vm_payload_service_socket() -> Result<()> {
193 let fd = android_get_control_socket(VM_PAYLOAD_SERVICE_SOCKET_NAME)?;
194
195 fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC))?;
196
197 Ok(())
198}
199
Jooyung Han311b1202021-09-14 22:00:16 +0900200fn try_main() -> Result<()> {
Andrew Sculle127cff2022-02-15 15:34:04 +0000201 let _ = kernlog::init();
Jooyung Han347d9f22021-05-28 00:05:14 +0900202 info!("started.");
203
Inseob Kim090b70b2022-11-16 20:01:14 +0900204 if let Err(e) = set_cloexec_on_vm_payload_service_socket() {
205 warn!("Failed to set cloexec on vm payload socket: {:?}", e);
206 }
207
Jiyong Park202856e2022-08-22 16:04:26 +0900208 load_crashkernel_if_supported().context("Failed to load crashkernel")?;
209
Keir Fraser933f0ac2022-10-12 08:23:28 +0000210 swap::init_swap().context("Failed to initialise swap")?;
211 info!("swap enabled.");
212
Inseob Kim11f40d02022-06-13 17:16:00 +0900213 let service = get_vms_rpc_binder()
214 .context("cannot connect to VirtualMachineService")
215 .map_err(|e| MicrodroidError::FailedToConnectToVirtualizationService(e.to_string()))?;
Seungjae Yoofd9a0622022-10-14 10:01:29 +0900216
Jooyung Han5c6d4172021-12-06 14:17:52 +0900217 match try_run_payload(&service) {
218 Ok(code) => {
219 info!("notifying payload finished");
220 service.notifyPayloadFinished(code)?;
221 if code == 0 {
222 info!("task successfully finished");
223 } else {
224 error!("task exited with exit code: {}", code);
225 }
226 Ok(())
227 }
228 Err(err) => {
Jooyung Han5c6d4172021-12-06 14:17:52 +0900229 let (error_code, message) = translate_error(&err);
230 service.notifyError(error_code, &message)?;
231 Err(err)
232 }
Jooyung Handd0a1732021-11-23 15:26:20 +0900233 }
234}
235
Alan Stokes1f417c92022-09-29 15:13:28 +0100236fn dice_derivation(
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000237 dice: DiceDriver,
Alan Stokes1f417c92022-09-29 15:13:28 +0100238 verified_data: &MicrodroidData,
239 payload_metadata: &PayloadMetadata,
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000240) -> Result<DiceContext> {
Andrew Scullb2f44472022-01-21 14:41:34 +0000241 // Calculate compound digests of code and authorities
Andrew Sculla0d1b1a2022-05-24 19:32:47 +0000242 let mut code_hash_ctx = Sha512::new();
243 let mut authority_hash_ctx = Sha512::new();
Andrew Scullb2f44472022-01-21 14:41:34 +0000244 code_hash_ctx.update(verified_data.apk_data.root_hash.as_ref());
245 authority_hash_ctx.update(verified_data.apk_data.pubkey.as_ref());
Inseob Kimb2519c52022-04-14 02:10:09 +0900246 for extra_apk in &verified_data.extra_apks_data {
Andrew Scullb2f44472022-01-21 14:41:34 +0000247 code_hash_ctx.update(extra_apk.root_hash.as_ref());
248 authority_hash_ctx.update(extra_apk.pubkey.as_ref());
249 }
Inseob Kimb2519c52022-04-14 02:10:09 +0900250 for apex in &verified_data.apex_data {
Andrew Scullb2f44472022-01-21 14:41:34 +0000251 code_hash_ctx.update(apex.root_digest.as_ref());
252 authority_hash_ctx.update(apex.public_key.as_ref());
253 }
Andrew Sculla0d1b1a2022-05-24 19:32:47 +0000254 let code_hash = code_hash_ctx.finish();
255 let authority_hash = authority_hash_ctx.finish();
Andrew Scullb2f44472022-01-21 14:41:34 +0000256
257 // {
258 // -70002: "Microdroid payload",
Alan Stokes1f417c92022-09-29 15:13:28 +0100259 // ? -71000: tstr // payload_config_path
260 // ? -71001: PayloadConfig
Andrew Scullb2f44472022-01-21 14:41:34 +0000261 // }
Alan Stokes1f417c92022-09-29 15:13:28 +0100262 // PayloadConfig = {
Alan Stokes8f12f2b2023-01-09 09:19:20 +0000263 // 1: tstr // payload_binary_name
Alan Stokes1f417c92022-09-29 15:13:28 +0100264 // }
265
Andrew Scullb2f44472022-01-21 14:41:34 +0000266 let mut config_desc = vec![
Alan Stokes1f417c92022-09-29 15:13:28 +0100267 0xa2, // map(2)
268 0x3a, 0x00, 0x01, 0x11, 0x71, // -70002
269 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79,
270 0x6c, 0x6f, 0x61, 0x64, // "Microdroid payload"
Andrew Scullb2f44472022-01-21 14:41:34 +0000271 ];
Alan Stokes1f417c92022-09-29 15:13:28 +0100272
273 match payload_metadata {
274 PayloadMetadata::config_path(payload_config_path) => {
275 encode_negative_number(-71000, &mut config_desc)?;
276 encode_tstr(payload_config_path, &mut config_desc)?;
277 }
278 PayloadMetadata::config(payload_config) => {
279 encode_negative_number(-71001, &mut config_desc)?;
280 encode_header(5, 1, &mut config_desc)?; // map(1)
281 encode_number(1, &mut config_desc)?;
Alan Stokes8f12f2b2023-01-09 09:19:20 +0000282 encode_tstr(&payload_config.payload_binary_name, &mut config_desc)?;
Alan Stokes1f417c92022-09-29 15:13:28 +0100283 }
284 }
Andrew Scullb2f44472022-01-21 14:41:34 +0000285
Seungjae Yoofa22bb02022-12-08 16:38:42 +0900286 // Check debuggability, conservatively assuming it is debuggable
287 let debuggable = system_properties::read_bool(DEBUGGABLE_PROP, true)?;
Andrew Scull65ddfc42022-02-14 21:03:58 +0000288
Andrew Scullb2f44472022-01-21 14:41:34 +0000289 // Send the details to diced
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000290 let hidden = verified_data.salt.clone().try_into().unwrap();
Seungjae Yoofa22bb02022-12-08 16:38:42 +0900291 dice.derive(code_hash, &config_desc, authority_hash, debuggable, hidden)
Andrew Scullb2f44472022-01-21 14:41:34 +0000292}
293
Alan Stokes1f417c92022-09-29 15:13:28 +0100294fn encode_tstr(tstr: &str, buffer: &mut Vec<u8>) -> Result<()> {
295 let bytes = tstr.as_bytes();
296 encode_header(3, bytes.len().try_into().unwrap(), buffer)?;
297 buffer.extend_from_slice(bytes);
298 Ok(())
299}
300
301fn encode_negative_number(n: i64, buffer: &mut dyn Write) -> Result<()> {
302 ensure!(n < 0);
303 let n = -1 - n;
304 encode_header(1, n.try_into().unwrap(), buffer)
305}
306
Andrew Scullab72ec52022-03-14 09:10:52 +0000307fn is_strict_boot() -> bool {
308 Path::new(AVF_STRICT_BOOT).exists()
309}
310
311fn is_new_instance() -> bool {
312 Path::new(AVF_NEW_INSTANCE).exists()
313}
314
Inseob Kime379e7d2022-07-22 18:55:18 +0900315fn is_verified_boot() -> bool {
316 !Path::new(DEBUG_MICRODROID_NO_VERIFIED_BOOT).exists()
317}
318
Jooyung Han5c6d4172021-12-06 14:17:52 +0900319fn try_run_payload(service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
Jooyung Han311b1202021-09-14 22:00:16 +0900320 let metadata = load_metadata().context("Failed to load payload metadata")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000321 let dice = DiceDriver::new(Path::new("/dev/open-dice0")).context("Failed to load DICE")?;
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900322
Jooyung Han311b1202021-09-14 22:00:16 +0900323 let mut instance = InstanceDisk::new().context("Failed to load instance.img")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000324 let saved_data =
325 instance.read_microdroid_data(&dice).context("Failed to read identity data")?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900326
Andrew Scullab72ec52022-03-14 09:10:52 +0000327 if is_strict_boot() {
328 // Provisioning must happen on the first boot and never again.
329 if is_new_instance() {
330 ensure!(
331 saved_data.is_none(),
332 MicrodroidError::InvalidConfig("Found instance data on first boot.".to_string())
333 );
334 } else {
335 ensure!(
336 saved_data.is_some(),
337 MicrodroidError::InvalidConfig("Instance data not found.".to_string())
338 );
339 };
340 }
341
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900342 // Verify the payload before using it.
Inseob Kim11f40d02022-06-13 17:16:00 +0900343 let verified_data = verify_payload(&metadata, saved_data.as_ref())
344 .context("Payload verification failed")
345 .map_err(|e| MicrodroidError::PayloadVerificationFailed(e.to_string()))?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900346
347 // In case identity is ignored (by debug policy), we should reuse existing payload data, even
348 // when the payload is changed. This is to keep the derived secret same as before.
349 let verified_data = if let Some(saved_data) = saved_data {
350 if !is_verified_boot() {
351 if saved_data != verified_data {
352 info!("Detected an update of the payload, but continue (regarding debug policy)")
353 }
354 } else {
355 ensure!(
356 saved_data == verified_data,
357 MicrodroidError::PayloadChanged(String::from(
358 "Detected an update of the payload which isn't supported yet."
359 ))
360 );
361 info!("Saved data is verified.");
362 }
363 saved_data
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900364 } else {
Jooyung Han7a343f92021-09-08 22:53:11 +0900365 info!("Saving verified data.");
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000366 instance
367 .write_microdroid_data(&verified_data, &dice)
368 .context("Failed to write identity data")?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900369 verified_data
370 };
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900371
Alan Stokes1f417c92022-09-29 15:13:28 +0100372 let payload_metadata = metadata.payload.ok_or_else(|| {
373 MicrodroidError::InvalidConfig("No payload config in metadata".to_string())
374 })?;
Alan Stokes0d1ef782022-09-27 13:46:35 +0100375
Inseob Kimb2519c52022-04-14 02:10:09 +0900376 // To minimize the exposure to untrusted data, derive dice profile as soon as possible.
377 info!("DICE derivation for payload");
Shikha Panwar566c9672022-11-15 14:39:58 +0000378 let dice_context = dice_derivation(dice, &verified_data, &payload_metadata)?;
379
380 // Run encryptedstore binary to prepare the storage
381 let encryptedstore_child = if Path::new(ENCRYPTEDSTORE_BACKING_DEVICE).exists() {
382 info!("Preparing encryptedstore ...");
383 Some(prepare_encryptedstore(&dice_context).context("encryptedstore run")?)
384 } else {
385 None
386 };
Inseob Kimb2519c52022-04-14 02:10:09 +0900387
Alan Stokes960c9032022-12-07 16:53:45 +0000388 let mut zipfuse = Zipfuse::default();
389
Jooyung Hana6d11eb2021-09-10 11:48:05 +0900390 // Before reading a file from the APK, start zipfuse
Alan Stokes960c9032022-12-07 16:53:45 +0000391 zipfuse.mount(
Alan Stokes60f82202022-10-07 16:40:07 +0100392 MountForExec::Allowed,
Inseob Kim217038e2021-11-25 11:15:06 +0900393 "fscontext=u:object_r:zipfusefs:s0,context=u:object_r:system_file:s0",
394 Path::new("/dev/block/mapper/microdroid-apk"),
Alice Wang6bbb6da2022-10-26 12:44:06 +0000395 Path::new(VM_APK_CONTENTS_PATH),
Alan Stokes960c9032022-12-07 16:53:45 +0000396 "microdroid_manager.apk.mounted".to_owned(),
397 )?;
Jiyong Park21ce2c52021-08-28 02:32:17 +0900398
Andrew Scull4d262dc2022-10-21 13:14:33 +0000399 // Restricted APIs are only allowed to be used by platform or test components. Infer this from
400 // the use of a VM config file since those can only be used by platform and test components.
401 let allow_restricted_apis = match payload_metadata {
402 PayloadMetadata::config_path(_) => true,
403 PayloadMetadata::config(_) => false,
404 };
405
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100406 let config = load_config(payload_metadata).context("Failed to load payload metadata")?;
Shikha Panwar6f03c942022-04-13 20:26:50 +0000407
Alan Stokes01b3ef02022-09-22 17:43:24 +0100408 let task = config
409 .task
410 .as_ref()
411 .ok_or_else(|| MicrodroidError::InvalidConfig("No task in VM config".to_string()))?;
412
Inseob Kim197748b2021-12-01 19:49:00 +0900413 if config.extra_apks.len() != verified_data.extra_apks_data.len() {
414 return Err(anyhow!(
Alan Stokes1f417c92022-09-29 15:13:28 +0100415 "config expects {} extra apks, but found {}",
Inseob Kim197748b2021-12-01 19:49:00 +0900416 config.extra_apks.len(),
417 verified_data.extra_apks_data.len()
418 ));
419 }
Alan Stokes960c9032022-12-07 16:53:45 +0000420 mount_extra_apks(&config, &mut zipfuse)?;
Jooyung Han634e2d72021-06-10 16:27:38 +0900421
Jooyung Han5c6d4172021-12-06 14:17:52 +0900422 // Wait until apex config is done. (e.g. linker configuration for apexes)
Jooyung Han5c6d4172021-12-06 14:17:52 +0900423 wait_for_apex_config_done()?;
424
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000425 setup_config_sysprops(&config)?;
426
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900427 // Start tombstone_transmit if enabled
428 if config.export_tombstones {
Inseob Kimc16b0cc2023-01-26 14:57:24 +0900429 system_properties::write("tombstone_transmit.start", "1")
430 .context("set tombstone_transmit.start")?;
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900431 } else {
Alan Stokes01b3ef02022-09-22 17:43:24 +0100432 control_service("stop", "tombstoned")?;
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900433 }
434
Alan Stokes960c9032022-12-07 16:53:45 +0000435 // Wait until zipfuse has mounted the APKs so we can access the payload
436 zipfuse.wait_until_done()?;
Alan Stokes60f82202022-10-07 16:40:07 +0100437
Shikha Panwar566c9672022-11-15 14:39:58 +0000438 register_vm_payload_service(allow_restricted_apis, service.clone(), dice_context)?;
439
Shikha Panwarddc124b2022-11-28 19:17:54 +0000440 // Wait for encryptedstore to finish mounting the storage (if enabled) before setting
441 // microdroid_manager.init_done. Reason is init stops uneventd after that.
442 // Encryptedstore, however requires ueventd
Shikha Panwar566c9672022-11-15 14:39:58 +0000443 if let Some(mut child) = encryptedstore_child {
444 let exitcode = child.wait().context("Wait for encryptedstore child")?;
445 ensure!(exitcode.success(), "Unable to prepare encrypted storage. Exitcode={}", exitcode);
446 }
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100447
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000448 wait_for_property_true("dev.bootcomplete").context("failed waiting for dev.bootcomplete")?;
Shikha Panwar3f6f6a52022-11-29 17:28:36 +0000449 system_properties::write("microdroid_manager.init_done", "1")
450 .context("set microdroid_manager.init_done")?;
Inseob Kimc16b0cc2023-01-26 14:57:24 +0900451
452 // Wait for tombstone_transmit to init
453 if config.export_tombstones {
454 wait_for_tombstone_transmit_done()?;
455 }
456
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000457 info!("boot completed, time to run payload");
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100458 exec_task(task, service).context("Failed to run payload")
Alan Stokes01b3ef02022-09-22 17:43:24 +0100459}
460
461fn control_service(action: &str, service: &str) -> Result<()> {
462 system_properties::write(&format!("ctl.{}", action), service)
463 .with_context(|| format!("Failed to {} {}", action, service))
Jooyung Han347d9f22021-05-28 00:05:14 +0900464}
465
Inseob Kim217038e2021-11-25 11:15:06 +0900466struct ApkDmverityArgument<'a> {
467 apk: &'a str,
468 idsig: &'a str,
469 name: &'a str,
Inseob Kim197748b2021-12-01 19:49:00 +0900470 saved_root_hash: Option<&'a RootHash>,
Inseob Kim217038e2021-11-25 11:15:06 +0900471}
472
473fn run_apkdmverity(args: &[ApkDmverityArgument]) -> Result<Child> {
474 let mut cmd = Command::new(APKDMVERITY_BIN);
475
Inseob Kim217038e2021-11-25 11:15:06 +0900476 for argument in args {
477 cmd.arg("--apk").arg(argument.apk).arg(argument.idsig).arg(argument.name);
Inseob Kim197748b2021-12-01 19:49:00 +0900478 if let Some(root_hash) = argument.saved_root_hash {
479 cmd.arg(&to_hex_string(root_hash));
480 } else {
481 cmd.arg("none");
482 }
Inseob Kim217038e2021-11-25 11:15:06 +0900483 }
484
485 cmd.spawn().context("Spawn apkdmverity")
486}
487
Alan Stokes60f82202022-10-07 16:40:07 +0100488enum MountForExec {
489 Allowed,
490 Disallowed,
491}
492
Alan Stokes960c9032022-12-07 16:53:45 +0000493#[derive(Default)]
494struct Zipfuse {
495 ready_properties: Vec<String>,
496}
497
498impl Zipfuse {
Jiyong Park231f9692023-01-09 19:36:21 +0900499 const MICRODROID_PAYLOAD_UID: u32 = 0; // TODO(b/264861173) should be non-root
500 const MICRODROID_PAYLOAD_GID: u32 = 0; // TODO(b/264861173) should be non-root
Alan Stokes960c9032022-12-07 16:53:45 +0000501 fn mount(
502 &mut self,
503 noexec: MountForExec,
504 option: &str,
505 zip_path: &Path,
506 mount_dir: &Path,
507 ready_prop: String,
508 ) -> Result<Child> {
509 let mut cmd = Command::new(ZIPFUSE_BIN);
510 if let MountForExec::Disallowed = noexec {
511 cmd.arg("--noexec");
512 }
513 cmd.args(["-p", &ready_prop, "-o", option]);
Jiyong Park231f9692023-01-09 19:36:21 +0900514 cmd.args(["-u", &Self::MICRODROID_PAYLOAD_UID.to_string()]);
515 cmd.args(["-g", &Self::MICRODROID_PAYLOAD_GID.to_string()]);
Alan Stokes960c9032022-12-07 16:53:45 +0000516 cmd.arg(zip_path).arg(mount_dir);
517 self.ready_properties.push(ready_prop);
518 cmd.spawn().with_context(|| format!("Failed to run zipfuse for {mount_dir:?}"))
Andrew Scullcc339a12022-07-04 12:44:19 +0000519 }
Alan Stokes960c9032022-12-07 16:53:45 +0000520
521 fn wait_until_done(self) -> Result<()> {
522 // We check the last-started check first in the hope that by the time it is done
523 // all or most of the others will also be done, minimising the number of times we
524 // block on a property.
525 for property in self.ready_properties.into_iter().rev() {
526 wait_for_property_true(&property)
527 .with_context(|| format!("Failed waiting for {property}"))?;
528 }
529 Ok(())
Alan Stokes60f82202022-10-07 16:40:07 +0100530 }
Inseob Kim217038e2021-11-25 11:15:06 +0900531}
532
Inseob Kime379e7d2022-07-22 18:55:18 +0900533fn write_apex_payload_data(
534 saved_data: Option<&MicrodroidData>,
535 apex_data_from_payload: &[ApexData],
536) -> Result<()> {
537 if let Some(saved_apex_data) = saved_data.map(|d| &d.apex_data) {
538 // We don't support APEX updates. (assuming that update will change root digest)
539 ensure!(
540 saved_apex_data == apex_data_from_payload,
541 MicrodroidError::PayloadChanged(String::from("APEXes have changed."))
542 );
543 let apex_metadata = to_metadata(apex_data_from_payload);
544 // Pass metadata(with public keys and root digests) to apexd so that it uses the passed
545 // metadata instead of the default one (/dev/block/by-name/payload-metadata)
546 OpenOptions::new()
547 .create_new(true)
548 .write(true)
549 .open("/apex/vm-payload-metadata")
550 .context("Failed to open /apex/vm-payload-metadata")
551 .and_then(|f| write_metadata(&apex_metadata, f))?;
552 }
553 Ok(())
554}
555
Jooyung Han7a343f92021-09-08 22:53:11 +0900556// Verify payload before executing it. For APK payload, Full verification (which is slow) is done
557// when the root_hash values from the idsig file and the instance disk are different. This function
558// returns the verified root hash (for APK payload) and pubkeys (for APEX payloads) that can be
559// saved to the instance disk.
560fn verify_payload(
561 metadata: &Metadata,
562 saved_data: Option<&MicrodroidData>,
563) -> Result<MicrodroidData> {
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900564 let start_time = SystemTime::now();
565
Inseob Kim197748b2021-12-01 19:49:00 +0900566 // Verify main APK
Jooyung Han7a343f92021-09-08 22:53:11 +0900567 let root_hash = saved_data.map(|d| &d.apk_data.root_hash);
Inseob Kim197748b2021-12-01 19:49:00 +0900568 let root_hash_from_idsig = get_apk_root_hash_from_idsig(MAIN_APK_IDSIG_PATH)?;
Jiyong Parkf7dea252021-09-08 01:42:54 +0900569 let root_hash_trustful = root_hash == Some(&root_hash_from_idsig);
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900570
Jiyong Parkf7dea252021-09-08 01:42:54 +0900571 // 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 +0900572 // instead of the value read from the idsig file.
Inseob Kim197748b2021-12-01 19:49:00 +0900573 let main_apk_argument = {
574 ApkDmverityArgument {
575 apk: MAIN_APK_PATH,
576 idsig: MAIN_APK_IDSIG_PATH,
577 name: MAIN_APK_DEVICE_NAME,
578 saved_root_hash: if root_hash_trustful {
579 Some(root_hash_from_idsig.as_ref())
580 } else {
581 None
582 },
583 }
584 };
585 let mut apkdmverity_arguments = vec![main_apk_argument];
586
587 // Verify extra APKs
588 // For now, we can't read the payload config, so glob APKs and idsigs.
589 // Later, we'll see if it matches with the payload config.
590
591 // sort globbed paths to match apks (extra-apk-{idx}) and idsigs (extra-idsig-{idx})
592 // e.g. "extra-apk-0" corresponds to "extra-idsig-0"
593 let extra_apks =
594 sorted(glob(EXTRA_APK_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
595 let extra_idsigs =
596 sorted(glob(EXTRA_IDSIG_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
597 if extra_apks.len() != extra_idsigs.len() {
598 return Err(anyhow!(
599 "Extra apks/idsigs mismatch: {} apks but {} idsigs",
600 extra_apks.len(),
601 extra_idsigs.len()
602 ));
603 }
604 let extra_apks_count = extra_apks.len();
605
606 let (extra_apk_names, extra_root_hashes_from_idsig): (Vec<_>, Vec<_>) = extra_idsigs
607 .iter()
608 .enumerate()
609 .map(|(i, extra_idsig)| {
610 (
611 format!("extra-apk-{}", i),
Alice Wang89cff012022-09-26 10:05:16 +0000612 get_apk_root_hash_from_idsig(extra_idsig)
Inseob Kim197748b2021-12-01 19:49:00 +0900613 .expect("Can't find root hash from extra idsig"),
614 )
615 })
616 .unzip();
617
618 let saved_extra_root_hashes: Vec<_> = saved_data
619 .map(|d| d.extra_apks_data.iter().map(|apk_data| &apk_data.root_hash).collect())
620 .unwrap_or_else(Vec::new);
621 let extra_root_hashes_trustful: Vec<_> = extra_root_hashes_from_idsig
622 .iter()
623 .enumerate()
624 .map(|(i, root_hash_from_idsig)| {
625 saved_extra_root_hashes.get(i).copied() == Some(root_hash_from_idsig)
626 })
627 .collect();
628
629 for i in 0..extra_apks_count {
630 apkdmverity_arguments.push({
631 ApkDmverityArgument {
632 apk: extra_apks[i].to_str().unwrap(),
633 idsig: extra_idsigs[i].to_str().unwrap(),
634 name: &extra_apk_names[i],
635 saved_root_hash: if extra_root_hashes_trustful[i] {
636 Some(&extra_root_hashes_from_idsig[i])
637 } else {
638 None
639 },
640 }
641 });
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900642 }
643
644 // Start apkdmverity and wait for the dm-verify block
Inseob Kim197748b2021-12-01 19:49:00 +0900645 let mut apkdmverity_child = run_apkdmverity(&apkdmverity_arguments)?;
Jooyung Han7a343f92021-09-08 22:53:11 +0900646
Jooyung Hanc8deb472021-09-13 13:48:25 +0900647 // While waiting for apkdmverity to mount APK, gathers public keys and root digests from
648 // APEX payload.
Jooyung Han7a343f92021-09-08 22:53:11 +0900649 let apex_data_from_payload = get_apex_data_from_payload(metadata)?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900650
651 // Writing /apex/vm-payload-metadata is to verify that the payload isn't changed.
652 // Skip writing it if the debug policy ignoring identity is on
653 if is_verified_boot() {
654 write_apex_payload_data(saved_data, &apex_data_from_payload)?;
Jooyung Han4a9b3bf2021-09-10 17:19:00 +0900655 }
Inseob Kime379e7d2022-07-22 18:55:18 +0900656
Jooyung Han4a9b3bf2021-09-10 17:19:00 +0900657 // Start apexd to activate APEXes
658 system_properties::write("ctl.start", "apexd-vm")?;
Jooyung Han7a343f92021-09-08 22:53:11 +0900659
Inseob Kim217038e2021-11-25 11:15:06 +0900660 // TODO(inseob): add timeout
661 apkdmverity_child.wait()?;
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900662
Jiyong Parkf7dea252021-09-08 01:42:54 +0900663 // Do the full verification if the root_hash is un-trustful. This requires the full scanning of
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900664 // 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 +0900665 // 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 +0900666 // of the VM or APK was updated in the host.
667 // TODO(jooyung): consider multithreading to make this faster
Inseob Kim197748b2021-12-01 19:49:00 +0900668 let main_apk_pubkey = get_public_key_from_apk(DM_MOUNTED_APK_PATH, root_hash_trustful)?;
669 let extra_apks_data = extra_root_hashes_from_idsig
670 .into_iter()
671 .enumerate()
672 .map(|(i, extra_root_hash)| {
673 let mount_path = format!("/dev/block/mapper/{}", &extra_apk_names[i]);
674 let apk_pubkey = get_public_key_from_apk(&mount_path, extra_root_hashes_trustful[i])?;
675 Ok(ApkData { root_hash: extra_root_hash, pubkey: apk_pubkey })
676 })
677 .collect::<Result<Vec<_>>>()?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900678
679 info!("payload verification successful. took {:#?}", start_time.elapsed().unwrap());
680
Andrew Scull34916a72022-01-30 21:34:24 +0000681 // Use the salt from a verified instance, or generate a salt for a new instance.
682 let salt = if let Some(saved_data) = saved_data {
683 saved_data.salt.clone()
684 } 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
Inseob Kimf44917c2023-01-20 17:31:37 +0900734fn wait_for_tombstone_transmit_done() -> Result<()> {
735 wait_for_property_true(TOMBSTONE_TRANSMIT_DONE_PROP)
736 .context("Failed waiting for tombstone transmit done")
737}
738
Alan Stokes60f82202022-10-07 16:40:07 +0100739fn wait_for_property_true(property_name: &str) -> Result<()> {
740 let mut prop = PropertyWatcher::new(property_name)?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900741 loop {
742 prop.wait()?;
Alan Stokes60f82202022-10-07 16:40:07 +0100743 if system_properties::read_bool(property_name, false)? {
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900744 break;
745 }
746 }
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900747 Ok(())
748}
749
Alice Wang89cff012022-09-26 10:05:16 +0000750fn get_apk_root_hash_from_idsig<P: AsRef<Path>>(idsig_path: P) -> Result<Box<RootHash>> {
751 Ok(V4Signature::from_idsig_path(idsig_path)?.hashing_info.raw_root_hash)
Jiyong Park21ce2c52021-08-28 02:32:17 +0900752}
753
Inseob Kim197748b2021-12-01 19:49:00 +0900754fn get_public_key_from_apk(apk: &str, root_hash_trustful: bool) -> Result<Box<[u8]>> {
755 if !root_hash_trustful {
756 verify(apk).context(MicrodroidError::PayloadVerificationFailed(format!(
757 "failed to verify {}",
758 apk
759 )))
760 } else {
761 get_public_key_der(apk)
762 }
763}
764
Alan Stokes1f417c92022-09-29 15:13:28 +0100765fn load_config(payload_metadata: PayloadMetadata) -> Result<VmPayloadConfig> {
766 match payload_metadata {
767 PayloadMetadata::config_path(path) => {
768 let path = Path::new(&path);
769 info!("loading config from {:?}...", path);
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100770 let file = ioutil::wait_for_file(path, WAIT_TIMEOUT)
771 .with_context(|| format!("Failed to read {:?}", path))?;
Alan Stokes1f417c92022-09-29 15:13:28 +0100772 Ok(serde_json::from_reader(file)?)
773 }
774 PayloadMetadata::config(payload_config) => {
775 let task = Task {
776 type_: TaskType::MicrodroidLauncher,
Alan Stokes8f12f2b2023-01-09 09:19:20 +0000777 command: payload_config.payload_binary_name,
Alan Stokes1f417c92022-09-29 15:13:28 +0100778 };
779 Ok(VmPayloadConfig {
780 os: OsConfig { name: "microdroid".to_owned() },
781 task: Some(task),
782 apexes: vec![],
783 extra_apks: vec![],
784 prefer_staged: false,
785 export_tombstones: false,
786 enable_authfs: false,
787 })
788 }
789 }
Jooyung Han634e2d72021-06-10 16:27:38 +0900790}
791
Jiyong Park202856e2022-08-22 16:04:26 +0900792/// Loads the crashkernel into memory using kexec if the VM is loaded with `crashkernel=' parameter
793/// in the cmdline.
794fn load_crashkernel_if_supported() -> Result<()> {
795 let supported = std::fs::read_to_string("/proc/cmdline")?.contains(" crashkernel=");
796 info!("ramdump supported: {}", supported);
797 if supported {
798 let status = Command::new("/system/bin/kexec_load").status()?;
799 if !status.success() {
800 return Err(anyhow!("Failed to load crashkernel: {:?}", status));
801 }
802 }
803 Ok(())
804}
805
Inseob Kim090b70b2022-11-16 20:01:14 +0900806/// Executes the given task.
Jooyung Han5c6d4172021-12-06 14:17:52 +0900807fn exec_task(task: &Task, service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
Jiyong Park8611a6c2021-07-09 18:17:44 +0900808 info!("executing main task {:?}...", task);
David Brazdil451cc962022-10-14 14:08:12 +0100809 let mut command = match task.type_ {
810 TaskType::Executable => Command::new(&task.command),
811 TaskType::MicrodroidLauncher => {
812 let mut command = Command::new("/system/bin/microdroid_launcher");
813 command.arg(find_library_path(&task.command)?);
814 command
815 }
816 };
Nikita Ioffe3452ee22022-12-15 00:31:56 +0000817
818 unsafe {
819 // SAFETY: we are not accessing any resource of the parent process.
820 command.pre_exec(|| {
821 info!("dropping capabilities before executing payload");
822 // It is OK to continue with payload execution even if the calls below fail, since
823 // whether process can use a capability is controlled by the SELinux. Dropping the
824 // capabilities here is just another defense-in-depth layer.
825 if let Err(e) = cap::drop_inheritable_caps() {
826 error!("failed to drop inheritable capabilities: {:?}", e);
827 }
828 if let Err(e) = cap::drop_bounding_set() {
829 error!("failed to drop bounding set: {:?}", e);
830 }
831 Ok(())
832 });
833 }
834
Inseob Kim090b70b2022-11-16 20:01:14 +0900835 command.stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null());
Inseob Kim7f61fe72021-08-20 20:50:47 +0900836
837 info!("notifying payload started");
Inseob Kimc7d28c72021-10-25 14:28:10 +0000838 service.notifyPayloadStarted()?;
Inseob Kim7f61fe72021-08-20 20:50:47 +0900839
Inseob Kim86ca0162021-10-20 02:21:02 +0000840 let exit_status = command.spawn()?.wait()?;
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -0800841 match exit_status.code() {
842 Some(exit_code) => Ok(exit_code),
843 None => Err(match exit_status.signal() {
844 Some(signal) => anyhow!(
845 "Payload exited due to signal: {} ({})",
846 signal,
847 Signal::try_from(signal).map_or("unknown", |s| s.as_str())
848 ),
849 None => anyhow!("Payload has neither exit code nor signal"),
850 }),
851 }
Jooyung Han347d9f22021-05-28 00:05:14 +0900852}
Jooyung Han634e2d72021-06-10 16:27:38 +0900853
Jooyung Han634e2d72021-06-10 16:27:38 +0900854fn find_library_path(name: &str) -> Result<String> {
855 let mut watcher = PropertyWatcher::new("ro.product.cpu.abilist")?;
856 let value = watcher.read(|_name, value| Ok(value.trim().to_string()))?;
857 let abi = value.split(',').next().ok_or_else(|| anyhow!("no abilist"))?;
Alice Wang6bbb6da2022-10-26 12:44:06 +0000858 let path = format!("{}/lib/{}/{}", VM_APK_CONTENTS_PATH, abi, name);
Jooyung Han634e2d72021-06-10 16:27:38 +0900859
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100860 let metadata = fs::metadata(&path).with_context(|| format!("Unable to access {}", path))?;
Jooyung Han634e2d72021-06-10 16:27:38 +0900861 if !metadata.is_file() {
862 bail!("{} is not a file", &path);
863 }
864
865 Ok(path)
866}
Jiyong Park21ce2c52021-08-28 02:32:17 +0900867
868fn to_hex_string(buf: &[u8]) -> String {
869 buf.iter().map(|b| format!("{:02X}", b)).collect()
870}
Shikha Panwar566c9672022-11-15 14:39:58 +0000871
872fn prepare_encryptedstore(dice: &DiceContext) -> Result<Child> {
873 // Use a fixed salt to scope the derivation to this API.
874 // Generated using hexdump -vn32 -e'14/1 "0x%02X, " 1 "\n"' /dev/urandom
875 // TODO(b/241541860) : Move this (& other salts) to a salt container, i.e. a global enum
876 let salt = [
877 0xFC, 0x1D, 0x35, 0x7B, 0x96, 0xF3, 0xEF, 0x17, 0x78, 0x7D, 0x70, 0xED, 0xEA, 0xFE, 0x1D,
878 0x6F, 0xB3, 0xF9, 0x40, 0xCE, 0xDD, 0x99, 0x40, 0xAA, 0xA7, 0x0E, 0x92, 0x73, 0x90, 0x86,
879 0x4A, 0x75,
880 ];
881 let key = dice.get_sealing_key(
882 &salt,
883 ENCRYPTEDSTORE_KEY_IDENTIFIER.as_bytes(),
884 ENCRYPTEDSTORE_KEYSIZE,
885 )?;
886
887 let mut cmd = Command::new(ENCRYPTEDSTORE_BIN);
888 cmd.arg("--blkdevice")
889 .arg(ENCRYPTEDSTORE_BACKING_DEVICE)
890 .arg("--key")
891 .arg(hex::encode(&*key))
Shikha Panwar9fd198f2022-11-18 17:43:43 +0000892 .args(["--mountpoint", ENCRYPTEDSTORE_MOUNTPOINT])
Shikha Panwar566c9672022-11-15 14:39:58 +0000893 .spawn()
894 .context("encryptedstore failed")
895}