blob: f48611b2a0ed7439ccf1da417f9d7b6f9a403ce1 [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";
Seungjae Yoofa22bb02022-12-08 16:38:42 +090080const DEBUGGABLE_PROP: &str = "ro.boot.microdroid.debuggable";
Jiyong Parkbb4a9872021-09-06 15:59:21 +090081
Inseob Kim11f40d02022-06-13 17:16:00 +090082// SYNC WITH virtualizationservice/src/crosvm.rs
83const FAILURE_SERIAL_DEVICE: &str = "/dev/ttyS1";
84
Shikha Panwar566c9672022-11-15 14:39:58 +000085/// Identifier for the key used for encrypted store.
86const ENCRYPTEDSTORE_BACKING_DEVICE: &str = "/dev/block/by-name/encryptedstore";
87const ENCRYPTEDSTORE_BIN: &str = "/system/bin/encryptedstore";
88const ENCRYPTEDSTORE_KEY_IDENTIFIER: &str = "encryptedstore_key";
Shikha Panwar195f89c2022-11-23 16:20:34 +000089const ENCRYPTEDSTORE_KEYSIZE: u32 = 32;
Shikha Panwar566c9672022-11-15 14:39:58 +000090
Jooyung Handd0a1732021-11-23 15:26:20 +090091#[derive(thiserror::Error, Debug)]
92enum MicrodroidError {
Inseob Kim11f40d02022-06-13 17:16:00 +090093 #[error("Cannot connect to virtualization service: {0}")]
94 FailedToConnectToVirtualizationService(String),
Jooyung Handd0a1732021-11-23 15:26:20 +090095 #[error("Payload has changed: {0}")]
96 PayloadChanged(String),
97 #[error("Payload verification has failed: {0}")]
98 PayloadVerificationFailed(String),
Jooyung Han5c6d4172021-12-06 14:17:52 +090099 #[error("Payload config is invalid: {0}")]
100 InvalidConfig(String),
Jooyung Handd0a1732021-11-23 15:26:20 +0900101}
102
Alan Stokes2bead0d2022-09-05 16:58:34 +0100103fn translate_error(err: &Error) -> (ErrorCode, String) {
Jooyung Handd0a1732021-11-23 15:26:20 +0900104 if let Some(e) = err.downcast_ref::<MicrodroidError>() {
105 match e {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100106 MicrodroidError::PayloadChanged(msg) => (ErrorCode::PAYLOAD_CHANGED, msg.to_string()),
Jooyung Handd0a1732021-11-23 15:26:20 +0900107 MicrodroidError::PayloadVerificationFailed(msg) => {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100108 (ErrorCode::PAYLOAD_VERIFICATION_FAILED, msg.to_string())
Jooyung Handd0a1732021-11-23 15:26:20 +0900109 }
Alan Stokes2bead0d2022-09-05 16:58:34 +0100110 MicrodroidError::InvalidConfig(msg) => {
111 (ErrorCode::PAYLOAD_CONFIG_INVALID, msg.to_string())
112 }
Inseob Kim11f40d02022-06-13 17:16:00 +0900113
114 // Connection failure won't be reported to VS; return the default value
115 MicrodroidError::FailedToConnectToVirtualizationService(msg) => {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100116 (ErrorCode::UNKNOWN, msg.to_string())
Inseob Kim11f40d02022-06-13 17:16:00 +0900117 }
Jooyung Handd0a1732021-11-23 15:26:20 +0900118 }
119 } else {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100120 (ErrorCode::UNKNOWN, err.to_string())
Jooyung Handd0a1732021-11-23 15:26:20 +0900121 }
122}
123
Inseob Kim11f40d02022-06-13 17:16:00 +0900124fn write_death_reason_to_serial(err: &Error) -> Result<()> {
125 let death_reason = if let Some(e) = err.downcast_ref::<MicrodroidError>() {
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100126 Borrowed(match e {
Inseob Kim11f40d02022-06-13 17:16:00 +0900127 MicrodroidError::FailedToConnectToVirtualizationService(_) => {
128 "MICRODROID_FAILED_TO_CONNECT_TO_VIRTUALIZATION_SERVICE"
129 }
130 MicrodroidError::PayloadChanged(_) => "MICRODROID_PAYLOAD_HAS_CHANGED",
131 MicrodroidError::PayloadVerificationFailed(_) => {
132 "MICRODROID_PAYLOAD_VERIFICATION_FAILED"
133 }
134 MicrodroidError::InvalidConfig(_) => "MICRODROID_INVALID_PAYLOAD_CONFIG",
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100135 })
Inseob Kim11f40d02022-06-13 17:16:00 +0900136 } else {
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100137 // Send context information back after a separator, to ease diagnosis.
138 // These errors occur before the payload runs, so this should not leak sensitive
139 // information.
140 Owned(format!("MICRODROID_UNKNOWN_RUNTIME_ERROR|{:?}", err))
Inseob Kim11f40d02022-06-13 17:16:00 +0900141 };
142
143 let death_reason_bytes = death_reason.as_bytes();
144 let mut sent_total = 0;
145 while sent_total < death_reason_bytes.len() {
146 // TODO(b/220071963): Sometimes, sending more than 16 bytes at once makes MM hang.
147 let begin = sent_total;
148 let end = std::cmp::min(begin.saturating_add(16), death_reason_bytes.len());
149 OpenOptions::new()
150 .read(false)
151 .write(true)
152 .open(FAILURE_SERIAL_DEVICE)?
153 .write_all(&death_reason_bytes[begin..end])?;
154 sent_total = end;
155 }
156
157 Ok(())
158}
159
Inseob Kim1b95f2e2021-08-19 13:17:40 +0900160fn get_vms_rpc_binder() -> Result<Strong<dyn IVirtualMachineService>> {
David Brazdil73988ea2022-11-11 15:10:32 +0000161 // The host is running a VirtualMachineService for this VM on a port equal
162 // to the CID of this VM.
163 let port = vsock::get_local_cid().context("Could not determine local CID")?;
David Brazdila2125dd2022-12-14 16:37:44 +0000164 RpcSession::new()
165 .setup_vsock_client(VMADDR_CID_HOST, port)
David Brazdil73988ea2022-11-11 15:10:32 +0000166 .context("Could not connect to IVirtualMachineService")
Inseob Kim1b95f2e2021-08-19 13:17:40 +0900167}
168
Inseob Kim437f1052022-06-21 11:30:22 +0900169fn main() -> Result<()> {
Inseob Kim7ff121c2022-11-14 18:13:23 +0900170 // If debuggable, print full backtrace to console log with stdio_to_kmsg
Seungjae Yoofa22bb02022-12-08 16:38:42 +0900171 if system_properties::read_bool(DEBUGGABLE_PROP, true)? {
Inseob Kim7ff121c2022-11-14 18:13:23 +0900172 env::set_var("RUST_BACKTRACE", "full");
173 }
174
Inseob Kim437f1052022-06-21 11:30:22 +0900175 scopeguard::defer! {
176 info!("Shutting down...");
Jooyung Hanbfe086f2021-10-28 10:15:45 +0900177 if let Err(e) = system_properties::write("sys.powerctl", "shutdown") {
178 error!("failed to shutdown {:?}", e);
179 }
Jooyung Han311b1202021-09-14 22:00:16 +0900180 }
Inseob Kim437f1052022-06-21 11:30:22 +0900181
182 try_main().map_err(|e| {
183 error!("Failed with {:?}.", e);
184 if let Err(e) = write_death_reason_to_serial(&e) {
185 error!("Failed to write death reason {:?}", e);
186 }
187 e
188 })
Jooyung Han311b1202021-09-14 22:00:16 +0900189}
190
Inseob Kim090b70b2022-11-16 20:01:14 +0900191fn set_cloexec_on_vm_payload_service_socket() -> Result<()> {
192 let fd = android_get_control_socket(VM_PAYLOAD_SERVICE_SOCKET_NAME)?;
193
194 fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC))?;
195
196 Ok(())
197}
198
Jooyung Han311b1202021-09-14 22:00:16 +0900199fn try_main() -> Result<()> {
Andrew Sculle127cff2022-02-15 15:34:04 +0000200 let _ = kernlog::init();
Jooyung Han347d9f22021-05-28 00:05:14 +0900201 info!("started.");
202
Inseob Kim090b70b2022-11-16 20:01:14 +0900203 if let Err(e) = set_cloexec_on_vm_payload_service_socket() {
204 warn!("Failed to set cloexec on vm payload socket: {:?}", e);
205 }
206
Jiyong Park202856e2022-08-22 16:04:26 +0900207 load_crashkernel_if_supported().context("Failed to load crashkernel")?;
208
Keir Fraser933f0ac2022-10-12 08:23:28 +0000209 swap::init_swap().context("Failed to initialise swap")?;
210 info!("swap enabled.");
211
Inseob Kim11f40d02022-06-13 17:16:00 +0900212 let service = get_vms_rpc_binder()
213 .context("cannot connect to VirtualMachineService")
214 .map_err(|e| MicrodroidError::FailedToConnectToVirtualizationService(e.to_string()))?;
Seungjae Yoofd9a0622022-10-14 10:01:29 +0900215
Jooyung Han5c6d4172021-12-06 14:17:52 +0900216 match try_run_payload(&service) {
217 Ok(code) => {
218 info!("notifying payload finished");
219 service.notifyPayloadFinished(code)?;
220 if code == 0 {
221 info!("task successfully finished");
222 } else {
223 error!("task exited with exit code: {}", code);
224 }
225 Ok(())
226 }
227 Err(err) => {
Jooyung Han5c6d4172021-12-06 14:17:52 +0900228 let (error_code, message) = translate_error(&err);
229 service.notifyError(error_code, &message)?;
230 Err(err)
231 }
Jooyung Handd0a1732021-11-23 15:26:20 +0900232 }
233}
234
Alan Stokes1f417c92022-09-29 15:13:28 +0100235fn dice_derivation(
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000236 dice: DiceDriver,
Alan Stokes1f417c92022-09-29 15:13:28 +0100237 verified_data: &MicrodroidData,
238 payload_metadata: &PayloadMetadata,
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000239) -> Result<DiceContext> {
Andrew Scullb2f44472022-01-21 14:41:34 +0000240 // Calculate compound digests of code and authorities
Andrew Sculla0d1b1a2022-05-24 19:32:47 +0000241 let mut code_hash_ctx = Sha512::new();
242 let mut authority_hash_ctx = Sha512::new();
Andrew Scullb2f44472022-01-21 14:41:34 +0000243 code_hash_ctx.update(verified_data.apk_data.root_hash.as_ref());
244 authority_hash_ctx.update(verified_data.apk_data.pubkey.as_ref());
Inseob Kimb2519c52022-04-14 02:10:09 +0900245 for extra_apk in &verified_data.extra_apks_data {
Andrew Scullb2f44472022-01-21 14:41:34 +0000246 code_hash_ctx.update(extra_apk.root_hash.as_ref());
247 authority_hash_ctx.update(extra_apk.pubkey.as_ref());
248 }
Inseob Kimb2519c52022-04-14 02:10:09 +0900249 for apex in &verified_data.apex_data {
Andrew Scullb2f44472022-01-21 14:41:34 +0000250 code_hash_ctx.update(apex.root_digest.as_ref());
251 authority_hash_ctx.update(apex.public_key.as_ref());
252 }
Andrew Sculla0d1b1a2022-05-24 19:32:47 +0000253 let code_hash = code_hash_ctx.finish();
254 let authority_hash = authority_hash_ctx.finish();
Andrew Scullb2f44472022-01-21 14:41:34 +0000255
256 // {
257 // -70002: "Microdroid payload",
Alan Stokes1f417c92022-09-29 15:13:28 +0100258 // ? -71000: tstr // payload_config_path
259 // ? -71001: PayloadConfig
Andrew Scullb2f44472022-01-21 14:41:34 +0000260 // }
Alan Stokes1f417c92022-09-29 15:13:28 +0100261 // PayloadConfig = {
Alan Stokes8f12f2b2023-01-09 09:19:20 +0000262 // 1: tstr // payload_binary_name
Alan Stokes1f417c92022-09-29 15:13:28 +0100263 // }
264
Andrew Scullb2f44472022-01-21 14:41:34 +0000265 let mut config_desc = vec![
Alan Stokes1f417c92022-09-29 15:13:28 +0100266 0xa2, // map(2)
267 0x3a, 0x00, 0x01, 0x11, 0x71, // -70002
268 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79,
269 0x6c, 0x6f, 0x61, 0x64, // "Microdroid payload"
Andrew Scullb2f44472022-01-21 14:41:34 +0000270 ];
Alan Stokes1f417c92022-09-29 15:13:28 +0100271
272 match payload_metadata {
273 PayloadMetadata::config_path(payload_config_path) => {
274 encode_negative_number(-71000, &mut config_desc)?;
275 encode_tstr(payload_config_path, &mut config_desc)?;
276 }
277 PayloadMetadata::config(payload_config) => {
278 encode_negative_number(-71001, &mut config_desc)?;
279 encode_header(5, 1, &mut config_desc)?; // map(1)
280 encode_number(1, &mut config_desc)?;
Alan Stokes8f12f2b2023-01-09 09:19:20 +0000281 encode_tstr(&payload_config.payload_binary_name, &mut config_desc)?;
Alan Stokes1f417c92022-09-29 15:13:28 +0100282 }
283 }
Andrew Scullb2f44472022-01-21 14:41:34 +0000284
Seungjae Yoofa22bb02022-12-08 16:38:42 +0900285 // Check debuggability, conservatively assuming it is debuggable
286 let debuggable = system_properties::read_bool(DEBUGGABLE_PROP, true)?;
Andrew Scull65ddfc42022-02-14 21:03:58 +0000287
Andrew Scullb2f44472022-01-21 14:41:34 +0000288 // Send the details to diced
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000289 let hidden = verified_data.salt.clone().try_into().unwrap();
Seungjae Yoofa22bb02022-12-08 16:38:42 +0900290 dice.derive(code_hash, &config_desc, authority_hash, debuggable, hidden)
Andrew Scullb2f44472022-01-21 14:41:34 +0000291}
292
Alan Stokes1f417c92022-09-29 15:13:28 +0100293fn encode_tstr(tstr: &str, buffer: &mut Vec<u8>) -> Result<()> {
294 let bytes = tstr.as_bytes();
295 encode_header(3, bytes.len().try_into().unwrap(), buffer)?;
296 buffer.extend_from_slice(bytes);
297 Ok(())
298}
299
300fn encode_negative_number(n: i64, buffer: &mut dyn Write) -> Result<()> {
301 ensure!(n < 0);
302 let n = -1 - n;
303 encode_header(1, n.try_into().unwrap(), buffer)
304}
305
Andrew Scullab72ec52022-03-14 09:10:52 +0000306fn is_strict_boot() -> bool {
307 Path::new(AVF_STRICT_BOOT).exists()
308}
309
310fn is_new_instance() -> bool {
311 Path::new(AVF_NEW_INSTANCE).exists()
312}
313
Inseob Kime379e7d2022-07-22 18:55:18 +0900314fn is_verified_boot() -> bool {
315 !Path::new(DEBUG_MICRODROID_NO_VERIFIED_BOOT).exists()
316}
317
Jooyung Han5c6d4172021-12-06 14:17:52 +0900318fn try_run_payload(service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
Jooyung Han311b1202021-09-14 22:00:16 +0900319 let metadata = load_metadata().context("Failed to load payload metadata")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000320 let dice = DiceDriver::new(Path::new("/dev/open-dice0")).context("Failed to load DICE")?;
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900321
Jooyung Han311b1202021-09-14 22:00:16 +0900322 let mut instance = InstanceDisk::new().context("Failed to load instance.img")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000323 let saved_data =
324 instance.read_microdroid_data(&dice).context("Failed to read identity data")?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900325
Andrew Scullab72ec52022-03-14 09:10:52 +0000326 if is_strict_boot() {
327 // Provisioning must happen on the first boot and never again.
328 if is_new_instance() {
329 ensure!(
330 saved_data.is_none(),
331 MicrodroidError::InvalidConfig("Found instance data on first boot.".to_string())
332 );
333 } else {
334 ensure!(
335 saved_data.is_some(),
336 MicrodroidError::InvalidConfig("Instance data not found.".to_string())
337 );
338 };
339 }
340
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900341 // Verify the payload before using it.
Inseob Kim11f40d02022-06-13 17:16:00 +0900342 let verified_data = verify_payload(&metadata, saved_data.as_ref())
343 .context("Payload verification failed")
344 .map_err(|e| MicrodroidError::PayloadVerificationFailed(e.to_string()))?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900345
346 // In case identity is ignored (by debug policy), we should reuse existing payload data, even
347 // when the payload is changed. This is to keep the derived secret same as before.
348 let verified_data = if let Some(saved_data) = saved_data {
349 if !is_verified_boot() {
350 if saved_data != verified_data {
351 info!("Detected an update of the payload, but continue (regarding debug policy)")
352 }
353 } else {
354 ensure!(
355 saved_data == verified_data,
356 MicrodroidError::PayloadChanged(String::from(
357 "Detected an update of the payload which isn't supported yet."
358 ))
359 );
360 info!("Saved data is verified.");
361 }
362 saved_data
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900363 } else {
Jooyung Han7a343f92021-09-08 22:53:11 +0900364 info!("Saving verified data.");
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000365 instance
366 .write_microdroid_data(&verified_data, &dice)
367 .context("Failed to write identity data")?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900368 verified_data
369 };
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900370
Alan Stokes1f417c92022-09-29 15:13:28 +0100371 let payload_metadata = metadata.payload.ok_or_else(|| {
372 MicrodroidError::InvalidConfig("No payload config in metadata".to_string())
373 })?;
Alan Stokes0d1ef782022-09-27 13:46:35 +0100374
Inseob Kimb2519c52022-04-14 02:10:09 +0900375 // To minimize the exposure to untrusted data, derive dice profile as soon as possible.
376 info!("DICE derivation for payload");
Shikha Panwar566c9672022-11-15 14:39:58 +0000377 let dice_context = dice_derivation(dice, &verified_data, &payload_metadata)?;
378
379 // Run encryptedstore binary to prepare the storage
380 let encryptedstore_child = if Path::new(ENCRYPTEDSTORE_BACKING_DEVICE).exists() {
381 info!("Preparing encryptedstore ...");
382 Some(prepare_encryptedstore(&dice_context).context("encryptedstore run")?)
383 } else {
384 None
385 };
Inseob Kimb2519c52022-04-14 02:10:09 +0900386
Alan Stokes960c9032022-12-07 16:53:45 +0000387 let mut zipfuse = Zipfuse::default();
388
Jooyung Hana6d11eb2021-09-10 11:48:05 +0900389 // Before reading a file from the APK, start zipfuse
Alan Stokes960c9032022-12-07 16:53:45 +0000390 zipfuse.mount(
Alan Stokes60f82202022-10-07 16:40:07 +0100391 MountForExec::Allowed,
Inseob Kim217038e2021-11-25 11:15:06 +0900392 "fscontext=u:object_r:zipfusefs:s0,context=u:object_r:system_file:s0",
393 Path::new("/dev/block/mapper/microdroid-apk"),
Alice Wang6bbb6da2022-10-26 12:44:06 +0000394 Path::new(VM_APK_CONTENTS_PATH),
Alan Stokes960c9032022-12-07 16:53:45 +0000395 "microdroid_manager.apk.mounted".to_owned(),
396 )?;
Jiyong Park21ce2c52021-08-28 02:32:17 +0900397
Andrew Scull4d262dc2022-10-21 13:14:33 +0000398 // Restricted APIs are only allowed to be used by platform or test components. Infer this from
399 // the use of a VM config file since those can only be used by platform and test components.
400 let allow_restricted_apis = match payload_metadata {
401 PayloadMetadata::config_path(_) => true,
402 PayloadMetadata::config(_) => false,
403 };
404
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100405 let config = load_config(payload_metadata).context("Failed to load payload metadata")?;
Shikha Panwar6f03c942022-04-13 20:26:50 +0000406
Alan Stokes01b3ef02022-09-22 17:43:24 +0100407 let task = config
408 .task
409 .as_ref()
410 .ok_or_else(|| MicrodroidError::InvalidConfig("No task in VM config".to_string()))?;
411
Inseob Kim197748b2021-12-01 19:49:00 +0900412 if config.extra_apks.len() != verified_data.extra_apks_data.len() {
413 return Err(anyhow!(
Alan Stokes1f417c92022-09-29 15:13:28 +0100414 "config expects {} extra apks, but found {}",
Inseob Kim197748b2021-12-01 19:49:00 +0900415 config.extra_apks.len(),
416 verified_data.extra_apks_data.len()
417 ));
418 }
Alan Stokes960c9032022-12-07 16:53:45 +0000419 mount_extra_apks(&config, &mut zipfuse)?;
Jooyung Han634e2d72021-06-10 16:27:38 +0900420
Jooyung Han5c6d4172021-12-06 14:17:52 +0900421 // Wait until apex config is done. (e.g. linker configuration for apexes)
Jooyung Han5c6d4172021-12-06 14:17:52 +0900422 wait_for_apex_config_done()?;
423
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000424 setup_config_sysprops(&config)?;
425
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900426 // Start tombstone_transmit if enabled
427 if config.export_tombstones {
Alan Stokes01b3ef02022-09-22 17:43:24 +0100428 control_service("start", "tombstone_transmit")?;
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900429 } else {
Alan Stokes01b3ef02022-09-22 17:43:24 +0100430 control_service("stop", "tombstoned")?;
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900431 }
432
Alan Stokes960c9032022-12-07 16:53:45 +0000433 // Wait until zipfuse has mounted the APKs so we can access the payload
434 zipfuse.wait_until_done()?;
Alan Stokes60f82202022-10-07 16:40:07 +0100435
Shikha Panwar566c9672022-11-15 14:39:58 +0000436 register_vm_payload_service(allow_restricted_apis, service.clone(), dice_context)?;
437
Shikha Panwarddc124b2022-11-28 19:17:54 +0000438 // Wait for encryptedstore to finish mounting the storage (if enabled) before setting
439 // microdroid_manager.init_done. Reason is init stops uneventd after that.
440 // Encryptedstore, however requires ueventd
Shikha Panwar566c9672022-11-15 14:39:58 +0000441 if let Some(mut child) = encryptedstore_child {
442 let exitcode = child.wait().context("Wait for encryptedstore child")?;
443 ensure!(exitcode.success(), "Unable to prepare encrypted storage. Exitcode={}", exitcode);
444 }
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100445
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000446 wait_for_property_true("dev.bootcomplete").context("failed waiting for dev.bootcomplete")?;
Shikha Panwar3f6f6a52022-11-29 17:28:36 +0000447 system_properties::write("microdroid_manager.init_done", "1")
448 .context("set microdroid_manager.init_done")?;
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000449 info!("boot completed, time to run payload");
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100450 exec_task(task, service).context("Failed to run payload")
Alan Stokes01b3ef02022-09-22 17:43:24 +0100451}
452
453fn control_service(action: &str, service: &str) -> Result<()> {
454 system_properties::write(&format!("ctl.{}", action), service)
455 .with_context(|| format!("Failed to {} {}", action, service))
Jooyung Han347d9f22021-05-28 00:05:14 +0900456}
457
Inseob Kim217038e2021-11-25 11:15:06 +0900458struct ApkDmverityArgument<'a> {
459 apk: &'a str,
460 idsig: &'a str,
461 name: &'a str,
Inseob Kim197748b2021-12-01 19:49:00 +0900462 saved_root_hash: Option<&'a RootHash>,
Inseob Kim217038e2021-11-25 11:15:06 +0900463}
464
465fn run_apkdmverity(args: &[ApkDmverityArgument]) -> Result<Child> {
466 let mut cmd = Command::new(APKDMVERITY_BIN);
467
Inseob Kim217038e2021-11-25 11:15:06 +0900468 for argument in args {
469 cmd.arg("--apk").arg(argument.apk).arg(argument.idsig).arg(argument.name);
Inseob Kim197748b2021-12-01 19:49:00 +0900470 if let Some(root_hash) = argument.saved_root_hash {
471 cmd.arg(&to_hex_string(root_hash));
472 } else {
473 cmd.arg("none");
474 }
Inseob Kim217038e2021-11-25 11:15:06 +0900475 }
476
477 cmd.spawn().context("Spawn apkdmverity")
478}
479
Alan Stokes60f82202022-10-07 16:40:07 +0100480enum MountForExec {
481 Allowed,
482 Disallowed,
483}
484
Alan Stokes960c9032022-12-07 16:53:45 +0000485#[derive(Default)]
486struct Zipfuse {
487 ready_properties: Vec<String>,
488}
489
490impl Zipfuse {
Jiyong Park231f9692023-01-09 19:36:21 +0900491 const MICRODROID_PAYLOAD_UID: u32 = 0; // TODO(b/264861173) should be non-root
492 const MICRODROID_PAYLOAD_GID: u32 = 0; // TODO(b/264861173) should be non-root
Alan Stokes960c9032022-12-07 16:53:45 +0000493 fn mount(
494 &mut self,
495 noexec: MountForExec,
496 option: &str,
497 zip_path: &Path,
498 mount_dir: &Path,
499 ready_prop: String,
500 ) -> Result<Child> {
501 let mut cmd = Command::new(ZIPFUSE_BIN);
502 if let MountForExec::Disallowed = noexec {
503 cmd.arg("--noexec");
504 }
505 cmd.args(["-p", &ready_prop, "-o", option]);
Jiyong Park231f9692023-01-09 19:36:21 +0900506 cmd.args(["-u", &Self::MICRODROID_PAYLOAD_UID.to_string()]);
507 cmd.args(["-g", &Self::MICRODROID_PAYLOAD_GID.to_string()]);
Alan Stokes960c9032022-12-07 16:53:45 +0000508 cmd.arg(zip_path).arg(mount_dir);
509 self.ready_properties.push(ready_prop);
510 cmd.spawn().with_context(|| format!("Failed to run zipfuse for {mount_dir:?}"))
Andrew Scullcc339a12022-07-04 12:44:19 +0000511 }
Alan Stokes960c9032022-12-07 16:53:45 +0000512
513 fn wait_until_done(self) -> Result<()> {
514 // We check the last-started check first in the hope that by the time it is done
515 // all or most of the others will also be done, minimising the number of times we
516 // block on a property.
517 for property in self.ready_properties.into_iter().rev() {
518 wait_for_property_true(&property)
519 .with_context(|| format!("Failed waiting for {property}"))?;
520 }
521 Ok(())
Alan Stokes60f82202022-10-07 16:40:07 +0100522 }
Inseob Kim217038e2021-11-25 11:15:06 +0900523}
524
Inseob Kime379e7d2022-07-22 18:55:18 +0900525fn write_apex_payload_data(
526 saved_data: Option<&MicrodroidData>,
527 apex_data_from_payload: &[ApexData],
528) -> Result<()> {
529 if let Some(saved_apex_data) = saved_data.map(|d| &d.apex_data) {
530 // We don't support APEX updates. (assuming that update will change root digest)
531 ensure!(
532 saved_apex_data == apex_data_from_payload,
533 MicrodroidError::PayloadChanged(String::from("APEXes have changed."))
534 );
535 let apex_metadata = to_metadata(apex_data_from_payload);
536 // Pass metadata(with public keys and root digests) to apexd so that it uses the passed
537 // metadata instead of the default one (/dev/block/by-name/payload-metadata)
538 OpenOptions::new()
539 .create_new(true)
540 .write(true)
541 .open("/apex/vm-payload-metadata")
542 .context("Failed to open /apex/vm-payload-metadata")
543 .and_then(|f| write_metadata(&apex_metadata, f))?;
544 }
545 Ok(())
546}
547
Jooyung Han7a343f92021-09-08 22:53:11 +0900548// Verify payload before executing it. For APK payload, Full verification (which is slow) is done
549// when the root_hash values from the idsig file and the instance disk are different. This function
550// returns the verified root hash (for APK payload) and pubkeys (for APEX payloads) that can be
551// saved to the instance disk.
552fn verify_payload(
553 metadata: &Metadata,
554 saved_data: Option<&MicrodroidData>,
555) -> Result<MicrodroidData> {
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900556 let start_time = SystemTime::now();
557
Inseob Kim197748b2021-12-01 19:49:00 +0900558 // Verify main APK
Jooyung Han7a343f92021-09-08 22:53:11 +0900559 let root_hash = saved_data.map(|d| &d.apk_data.root_hash);
Inseob Kim197748b2021-12-01 19:49:00 +0900560 let root_hash_from_idsig = get_apk_root_hash_from_idsig(MAIN_APK_IDSIG_PATH)?;
Jiyong Parkf7dea252021-09-08 01:42:54 +0900561 let root_hash_trustful = root_hash == Some(&root_hash_from_idsig);
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900562
Jiyong Parkf7dea252021-09-08 01:42:54 +0900563 // 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 +0900564 // instead of the value read from the idsig file.
Inseob Kim197748b2021-12-01 19:49:00 +0900565 let main_apk_argument = {
566 ApkDmverityArgument {
567 apk: MAIN_APK_PATH,
568 idsig: MAIN_APK_IDSIG_PATH,
569 name: MAIN_APK_DEVICE_NAME,
570 saved_root_hash: if root_hash_trustful {
571 Some(root_hash_from_idsig.as_ref())
572 } else {
573 None
574 },
575 }
576 };
577 let mut apkdmverity_arguments = vec![main_apk_argument];
578
579 // Verify extra APKs
580 // For now, we can't read the payload config, so glob APKs and idsigs.
581 // Later, we'll see if it matches with the payload config.
582
583 // sort globbed paths to match apks (extra-apk-{idx}) and idsigs (extra-idsig-{idx})
584 // e.g. "extra-apk-0" corresponds to "extra-idsig-0"
585 let extra_apks =
586 sorted(glob(EXTRA_APK_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
587 let extra_idsigs =
588 sorted(glob(EXTRA_IDSIG_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
589 if extra_apks.len() != extra_idsigs.len() {
590 return Err(anyhow!(
591 "Extra apks/idsigs mismatch: {} apks but {} idsigs",
592 extra_apks.len(),
593 extra_idsigs.len()
594 ));
595 }
596 let extra_apks_count = extra_apks.len();
597
598 let (extra_apk_names, extra_root_hashes_from_idsig): (Vec<_>, Vec<_>) = extra_idsigs
599 .iter()
600 .enumerate()
601 .map(|(i, extra_idsig)| {
602 (
603 format!("extra-apk-{}", i),
Alice Wang89cff012022-09-26 10:05:16 +0000604 get_apk_root_hash_from_idsig(extra_idsig)
Inseob Kim197748b2021-12-01 19:49:00 +0900605 .expect("Can't find root hash from extra idsig"),
606 )
607 })
608 .unzip();
609
610 let saved_extra_root_hashes: Vec<_> = saved_data
611 .map(|d| d.extra_apks_data.iter().map(|apk_data| &apk_data.root_hash).collect())
612 .unwrap_or_else(Vec::new);
613 let extra_root_hashes_trustful: Vec<_> = extra_root_hashes_from_idsig
614 .iter()
615 .enumerate()
616 .map(|(i, root_hash_from_idsig)| {
617 saved_extra_root_hashes.get(i).copied() == Some(root_hash_from_idsig)
618 })
619 .collect();
620
621 for i in 0..extra_apks_count {
622 apkdmverity_arguments.push({
623 ApkDmverityArgument {
624 apk: extra_apks[i].to_str().unwrap(),
625 idsig: extra_idsigs[i].to_str().unwrap(),
626 name: &extra_apk_names[i],
627 saved_root_hash: if extra_root_hashes_trustful[i] {
628 Some(&extra_root_hashes_from_idsig[i])
629 } else {
630 None
631 },
632 }
633 });
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900634 }
635
636 // Start apkdmverity and wait for the dm-verify block
Inseob Kim197748b2021-12-01 19:49:00 +0900637 let mut apkdmverity_child = run_apkdmverity(&apkdmverity_arguments)?;
Jooyung Han7a343f92021-09-08 22:53:11 +0900638
Jooyung Hanc8deb472021-09-13 13:48:25 +0900639 // While waiting for apkdmverity to mount APK, gathers public keys and root digests from
640 // APEX payload.
Jooyung Han7a343f92021-09-08 22:53:11 +0900641 let apex_data_from_payload = get_apex_data_from_payload(metadata)?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900642
643 // Writing /apex/vm-payload-metadata is to verify that the payload isn't changed.
644 // Skip writing it if the debug policy ignoring identity is on
645 if is_verified_boot() {
646 write_apex_payload_data(saved_data, &apex_data_from_payload)?;
Jooyung Han4a9b3bf2021-09-10 17:19:00 +0900647 }
Inseob Kime379e7d2022-07-22 18:55:18 +0900648
Jooyung Han4a9b3bf2021-09-10 17:19:00 +0900649 // Start apexd to activate APEXes
650 system_properties::write("ctl.start", "apexd-vm")?;
Jooyung Han7a343f92021-09-08 22:53:11 +0900651
Inseob Kim217038e2021-11-25 11:15:06 +0900652 // TODO(inseob): add timeout
653 apkdmverity_child.wait()?;
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900654
Jiyong Parkf7dea252021-09-08 01:42:54 +0900655 // Do the full verification if the root_hash is un-trustful. This requires the full scanning of
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900656 // 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 +0900657 // 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 +0900658 // of the VM or APK was updated in the host.
659 // TODO(jooyung): consider multithreading to make this faster
Inseob Kim197748b2021-12-01 19:49:00 +0900660 let main_apk_pubkey = get_public_key_from_apk(DM_MOUNTED_APK_PATH, root_hash_trustful)?;
661 let extra_apks_data = extra_root_hashes_from_idsig
662 .into_iter()
663 .enumerate()
664 .map(|(i, extra_root_hash)| {
665 let mount_path = format!("/dev/block/mapper/{}", &extra_apk_names[i]);
666 let apk_pubkey = get_public_key_from_apk(&mount_path, extra_root_hashes_trustful[i])?;
667 Ok(ApkData { root_hash: extra_root_hash, pubkey: apk_pubkey })
668 })
669 .collect::<Result<Vec<_>>>()?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900670
671 info!("payload verification successful. took {:#?}", start_time.elapsed().unwrap());
672
Andrew Scull34916a72022-01-30 21:34:24 +0000673 // Use the salt from a verified instance, or generate a salt for a new instance.
674 let salt = if let Some(saved_data) = saved_data {
675 saved_data.salt.clone()
676 } else {
677 let mut salt = vec![0u8; 64];
678 salt.as_mut_slice().try_fill(&mut rand::thread_rng())?;
679 salt
680 };
681
Jiyong Parkf7dea252021-09-08 01:42:54 +0900682 // At this point, we can ensure that the root_hash from the idsig file is trusted, either by
683 // fully verifying the APK or by comparing it with the saved root_hash.
Jooyung Han7a343f92021-09-08 22:53:11 +0900684 Ok(MicrodroidData {
Andrew Scull34916a72022-01-30 21:34:24 +0000685 salt,
Inseob Kim197748b2021-12-01 19:49:00 +0900686 apk_data: ApkData { root_hash: root_hash_from_idsig, pubkey: main_apk_pubkey },
687 extra_apks_data,
Jooyung Han7a343f92021-09-08 22:53:11 +0900688 apex_data: apex_data_from_payload,
689 })
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900690}
691
Alan Stokes960c9032022-12-07 16:53:45 +0000692fn mount_extra_apks(config: &VmPayloadConfig, zipfuse: &mut Zipfuse) -> Result<()> {
Inseob Kim197748b2021-12-01 19:49:00 +0900693 // For now, only the number of apks is important, as the mount point and dm-verity name is fixed
694 for i in 0..config.extra_apks.len() {
Alan Stokes960c9032022-12-07 16:53:45 +0000695 let mount_dir = format!("/mnt/extra-apk/{i}");
Inseob Kim197748b2021-12-01 19:49:00 +0900696 create_dir(Path::new(&mount_dir)).context("Failed to create mount dir for extra apks")?;
697
698 // don't wait, just detach
Alan Stokes960c9032022-12-07 16:53:45 +0000699 zipfuse.mount(
Alan Stokes60f82202022-10-07 16:40:07 +0100700 MountForExec::Disallowed,
Inseob Kim197748b2021-12-01 19:49:00 +0900701 "fscontext=u:object_r:zipfusefs:s0,context=u:object_r:extra_apk_file:s0",
Alan Stokes960c9032022-12-07 16:53:45 +0000702 Path::new(&format!("/dev/block/mapper/extra-apk-{i}")),
Inseob Kim197748b2021-12-01 19:49:00 +0900703 Path::new(&mount_dir),
Alan Stokes960c9032022-12-07 16:53:45 +0000704 format!("microdroid_manager.extra_apk.mounted.{i}"),
705 )?;
Inseob Kim197748b2021-12-01 19:49:00 +0900706 }
707
708 Ok(())
709}
710
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000711fn setup_config_sysprops(config: &VmPayloadConfig) -> Result<()> {
712 if config.enable_authfs {
713 system_properties::write("microdroid_manager.authfs.enabled", "1")
714 .context("failed to write microdroid_manager.authfs.enabled")?;
715 }
716 system_properties::write("microdroid_manager.config_done", "1")
717 .context("failed to write microdroid_manager.config_done")?;
718 Ok(())
719}
720
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900721// Waits until linker config is generated
722fn wait_for_apex_config_done() -> Result<()> {
Alan Stokes60f82202022-10-07 16:40:07 +0100723 wait_for_property_true(APEX_CONFIG_DONE_PROP).context("Failed waiting for apex config done")
724}
725
726fn wait_for_property_true(property_name: &str) -> Result<()> {
727 let mut prop = PropertyWatcher::new(property_name)?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900728 loop {
729 prop.wait()?;
Alan Stokes60f82202022-10-07 16:40:07 +0100730 if system_properties::read_bool(property_name, false)? {
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900731 break;
732 }
733 }
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900734 Ok(())
735}
736
Alice Wang89cff012022-09-26 10:05:16 +0000737fn get_apk_root_hash_from_idsig<P: AsRef<Path>>(idsig_path: P) -> Result<Box<RootHash>> {
738 Ok(V4Signature::from_idsig_path(idsig_path)?.hashing_info.raw_root_hash)
Jiyong Park21ce2c52021-08-28 02:32:17 +0900739}
740
Inseob Kim197748b2021-12-01 19:49:00 +0900741fn get_public_key_from_apk(apk: &str, root_hash_trustful: bool) -> Result<Box<[u8]>> {
742 if !root_hash_trustful {
743 verify(apk).context(MicrodroidError::PayloadVerificationFailed(format!(
744 "failed to verify {}",
745 apk
746 )))
747 } else {
748 get_public_key_der(apk)
749 }
750}
751
Alan Stokes1f417c92022-09-29 15:13:28 +0100752fn load_config(payload_metadata: PayloadMetadata) -> Result<VmPayloadConfig> {
753 match payload_metadata {
754 PayloadMetadata::config_path(path) => {
755 let path = Path::new(&path);
756 info!("loading config from {:?}...", path);
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100757 let file = ioutil::wait_for_file(path, WAIT_TIMEOUT)
758 .with_context(|| format!("Failed to read {:?}", path))?;
Alan Stokes1f417c92022-09-29 15:13:28 +0100759 Ok(serde_json::from_reader(file)?)
760 }
761 PayloadMetadata::config(payload_config) => {
762 let task = Task {
763 type_: TaskType::MicrodroidLauncher,
Alan Stokes8f12f2b2023-01-09 09:19:20 +0000764 command: payload_config.payload_binary_name,
Alan Stokes1f417c92022-09-29 15:13:28 +0100765 };
766 Ok(VmPayloadConfig {
767 os: OsConfig { name: "microdroid".to_owned() },
768 task: Some(task),
769 apexes: vec![],
770 extra_apks: vec![],
771 prefer_staged: false,
772 export_tombstones: false,
773 enable_authfs: false,
774 })
775 }
776 }
Jooyung Han634e2d72021-06-10 16:27:38 +0900777}
778
Jiyong Park202856e2022-08-22 16:04:26 +0900779/// Loads the crashkernel into memory using kexec if the VM is loaded with `crashkernel=' parameter
780/// in the cmdline.
781fn load_crashkernel_if_supported() -> Result<()> {
782 let supported = std::fs::read_to_string("/proc/cmdline")?.contains(" crashkernel=");
783 info!("ramdump supported: {}", supported);
784 if supported {
785 let status = Command::new("/system/bin/kexec_load").status()?;
786 if !status.success() {
787 return Err(anyhow!("Failed to load crashkernel: {:?}", status));
788 }
789 }
790 Ok(())
791}
792
Inseob Kim090b70b2022-11-16 20:01:14 +0900793/// Executes the given task.
Jooyung Han5c6d4172021-12-06 14:17:52 +0900794fn exec_task(task: &Task, service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
Jiyong Park8611a6c2021-07-09 18:17:44 +0900795 info!("executing main task {:?}...", task);
David Brazdil451cc962022-10-14 14:08:12 +0100796 let mut command = match task.type_ {
797 TaskType::Executable => Command::new(&task.command),
798 TaskType::MicrodroidLauncher => {
799 let mut command = Command::new("/system/bin/microdroid_launcher");
800 command.arg(find_library_path(&task.command)?);
801 command
802 }
803 };
Nikita Ioffe3452ee22022-12-15 00:31:56 +0000804
805 unsafe {
806 // SAFETY: we are not accessing any resource of the parent process.
807 command.pre_exec(|| {
808 info!("dropping capabilities before executing payload");
809 // It is OK to continue with payload execution even if the calls below fail, since
810 // whether process can use a capability is controlled by the SELinux. Dropping the
811 // capabilities here is just another defense-in-depth layer.
812 if let Err(e) = cap::drop_inheritable_caps() {
813 error!("failed to drop inheritable capabilities: {:?}", e);
814 }
815 if let Err(e) = cap::drop_bounding_set() {
816 error!("failed to drop bounding set: {:?}", e);
817 }
818 Ok(())
819 });
820 }
821
Inseob Kim090b70b2022-11-16 20:01:14 +0900822 command.stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null());
Inseob Kim7f61fe72021-08-20 20:50:47 +0900823
824 info!("notifying payload started");
Inseob Kimc7d28c72021-10-25 14:28:10 +0000825 service.notifyPayloadStarted()?;
Inseob Kim7f61fe72021-08-20 20:50:47 +0900826
Inseob Kim86ca0162021-10-20 02:21:02 +0000827 let exit_status = command.spawn()?.wait()?;
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -0800828 match exit_status.code() {
829 Some(exit_code) => Ok(exit_code),
830 None => Err(match exit_status.signal() {
831 Some(signal) => anyhow!(
832 "Payload exited due to signal: {} ({})",
833 signal,
834 Signal::try_from(signal).map_or("unknown", |s| s.as_str())
835 ),
836 None => anyhow!("Payload has neither exit code nor signal"),
837 }),
838 }
Jooyung Han347d9f22021-05-28 00:05:14 +0900839}
Jooyung Han634e2d72021-06-10 16:27:38 +0900840
Jooyung Han634e2d72021-06-10 16:27:38 +0900841fn find_library_path(name: &str) -> Result<String> {
842 let mut watcher = PropertyWatcher::new("ro.product.cpu.abilist")?;
843 let value = watcher.read(|_name, value| Ok(value.trim().to_string()))?;
844 let abi = value.split(',').next().ok_or_else(|| anyhow!("no abilist"))?;
Alice Wang6bbb6da2022-10-26 12:44:06 +0000845 let path = format!("{}/lib/{}/{}", VM_APK_CONTENTS_PATH, abi, name);
Jooyung Han634e2d72021-06-10 16:27:38 +0900846
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100847 let metadata = fs::metadata(&path).with_context(|| format!("Unable to access {}", path))?;
Jooyung Han634e2d72021-06-10 16:27:38 +0900848 if !metadata.is_file() {
849 bail!("{} is not a file", &path);
850 }
851
852 Ok(path)
853}
Jiyong Park21ce2c52021-08-28 02:32:17 +0900854
855fn to_hex_string(buf: &[u8]) -> String {
856 buf.iter().map(|b| format!("{:02X}", b)).collect()
857}
Shikha Panwar566c9672022-11-15 14:39:58 +0000858
859fn prepare_encryptedstore(dice: &DiceContext) -> Result<Child> {
860 // Use a fixed salt to scope the derivation to this API.
861 // Generated using hexdump -vn32 -e'14/1 "0x%02X, " 1 "\n"' /dev/urandom
862 // TODO(b/241541860) : Move this (& other salts) to a salt container, i.e. a global enum
863 let salt = [
864 0xFC, 0x1D, 0x35, 0x7B, 0x96, 0xF3, 0xEF, 0x17, 0x78, 0x7D, 0x70, 0xED, 0xEA, 0xFE, 0x1D,
865 0x6F, 0xB3, 0xF9, 0x40, 0xCE, 0xDD, 0x99, 0x40, 0xAA, 0xA7, 0x0E, 0x92, 0x73, 0x90, 0x86,
866 0x4A, 0x75,
867 ];
868 let key = dice.get_sealing_key(
869 &salt,
870 ENCRYPTEDSTORE_KEY_IDENTIFIER.as_bytes(),
871 ENCRYPTEDSTORE_KEYSIZE,
872 )?;
873
874 let mut cmd = Command::new(ENCRYPTEDSTORE_BIN);
875 cmd.arg("--blkdevice")
876 .arg(ENCRYPTEDSTORE_BACKING_DEVICE)
877 .arg("--key")
878 .arg(hex::encode(&*key))
Shikha Panwar9fd198f2022-11-18 17:43:43 +0000879 .args(["--mountpoint", ENCRYPTEDSTORE_MOUNTPOINT])
Shikha Panwar566c9672022-11-15 14:39:58 +0000880 .spawn()
881 .context("encryptedstore failed")
882}