blob: 7ca0d3c1f580a839e68a175224ac4a52eb280955 [file] [log] [blame]
Jooyung Han347d9f22021-05-28 00:05:14 +09001// Copyright 2021, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Microdroid Manager
16
Andrew Sculld64ae7d2022-10-05 17:41:43 +000017mod dice;
Jiyong Park21ce2c52021-08-28 02:32:17 +090018mod instance;
Jooyung Hanf48ceb42021-06-01 18:00:04 +090019mod ioutil;
Jooyung Han7a343f92021-09-08 22:53:11 +090020mod payload;
Keir Fraser933f0ac2022-10-12 08:23:28 +000021mod swap;
Alice Wang59a9e562022-10-04 15:24:10 +000022mod vm_payload_service;
Jooyung Han347d9f22021-05-28 00:05:14 +090023
Alice Wang62f7e642023-02-10 09:55:13 +000024use crate::dice::{DiceDriver, derive_sealing_key};
Inseob Kime379e7d2022-07-22 18:55:18 +090025use crate::instance::{ApexData, ApkData, InstanceDisk, MicrodroidData, RootHash};
Alice Wang59a9e562022-10-04 15:24:10 +000026use crate::vm_payload_service::register_vm_payload_service;
Alan Stokes2bead0d2022-09-05 16:58:34 +010027use android_system_virtualizationcommon::aidl::android::system::virtualizationcommon::ErrorCode::ErrorCode;
David Brazdil73988ea2022-11-11 15:10:32 +000028use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::IVirtualMachineService;
Inseob Kim090b70b2022-11-16 20:01:14 +090029use android_system_virtualization_payload::aidl::android::system::virtualization::payload::IVmPayloadService::{
30 VM_APK_CONTENTS_PATH,
31 VM_PAYLOAD_SERVICE_SOCKET_NAME,
Shikha Panwarddc124b2022-11-28 19:17:54 +000032 ENCRYPTEDSTORE_MOUNTPOINT,
Inseob Kim090b70b2022-11-16 20:01:14 +090033};
Jooyung Handd0a1732021-11-23 15:26:20 +090034use anyhow::{anyhow, bail, ensure, Context, Error, Result};
Alice Wang1bf3d782022-09-28 07:56:36 +000035use apkverify::{get_public_key_der, verify, V4Signature};
Alice Wang43c884b2022-10-24 09:42:40 +000036use binder::Strong;
Alice Wang62f7e642023-02-10 09:55:13 +000037use diced_open_dice::OwnedDiceArtifacts;
Alan Stokes1f417c92022-09-29 15:13:28 +010038use diced_utils::cbor::{encode_header, encode_number};
Inseob Kim197748b2021-12-01 19:49:00 +090039use glob::glob;
Inseob Kim197748b2021-12-01 19:49:00 +090040use itertools::sorted;
David Brazdila07a1792022-10-25 13:37:57 +010041use libc::VMADDR_CID_HOST;
Inseob Kim090b70b2022-11-16 20:01:14 +090042use log::{error, info, warn};
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};
Inseob Kim090b70b2022-11-16 20:01:14 +090045use nix::fcntl::{fcntl, F_SETFD, FdFlag};
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -080046use nix::sys::signal::Signal;
Andrew Sculla0d1b1a2022-05-24 19:32:47 +000047use openssl::sha::Sha512;
Jooyung Han4a9b3bf2021-09-10 17:19:00 +090048use payload::{get_apex_data_from_payload, load_metadata, to_metadata};
Andrew Scull34916a72022-01-30 21:34:24 +000049use rand::Fill;
David Brazdila2125dd2022-12-14 16:37:44 +000050use rpcbinder::RpcSession;
Inseob Kim090b70b2022-11-16 20:01:14 +090051use rustutils::sockets::android_get_control_socket;
Jiyong Parkbb4a9872021-09-06 15:59:21 +090052use rustutils::system_properties;
Joel Galenson482704c2021-07-29 15:53:53 -070053use rustutils::system_properties::PropertyWatcher;
Alan Stokes3ba10fd2022-10-06 15:46:51 +010054use std::borrow::Cow::{Borrowed, Owned};
Andrew Scullb2f44472022-01-21 14:41:34 +000055use std::convert::TryInto;
Inseob Kim7ff121c2022-11-14 18:13:23 +090056use std::env;
Shikha Panwardef7ef92023-01-06 08:35:48 +000057use std::ffi::CString;
David Brazdil451cc962022-10-14 14:08:12 +010058use std::fs::{self, create_dir, OpenOptions};
Inseob Kim11f40d02022-06-13 17:16:00 +090059use std::io::Write;
Nikita Ioffe3452ee22022-12-15 00:31:56 +000060use std::os::unix::process::CommandExt;
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -080061use std::os::unix::process::ExitStatusExt;
Jooyung Hanf48ceb42021-06-01 18:00:04 +090062use std::path::Path;
Inseob Kim217038e2021-11-25 11:15:06 +090063use std::process::{Child, Command, Stdio};
Jiyong Park8611a6c2021-07-09 18:17:44 +090064use std::str;
Jiyong Parkbb4a9872021-09-06 15:59:21 +090065use std::time::{Duration, SystemTime};
Jooyung Han634e2d72021-06-10 16:27:38 +090066
67const WAIT_TIMEOUT: Duration = Duration::from_secs(10);
Inseob Kim197748b2021-12-01 19:49:00 +090068const MAIN_APK_PATH: &str = "/dev/block/by-name/microdroid-apk";
69const MAIN_APK_IDSIG_PATH: &str = "/dev/block/by-name/microdroid-apk-idsig";
70const MAIN_APK_DEVICE_NAME: &str = "microdroid-apk";
71const EXTRA_APK_PATH_PATTERN: &str = "/dev/block/by-name/extra-apk-*";
72const EXTRA_IDSIG_PATH_PATTERN: &str = "/dev/block/by-name/extra-idsig-*";
Jooyung Han19c1d6c2021-08-06 14:08:16 +090073const DM_MOUNTED_APK_PATH: &str = "/dev/block/mapper/microdroid-apk";
Andrew Scullab72ec52022-03-14 09:10:52 +000074const AVF_STRICT_BOOT: &str = "/sys/firmware/devicetree/base/chosen/avf,strict-boot";
75const AVF_NEW_INSTANCE: &str = "/sys/firmware/devicetree/base/chosen/avf,new-instance";
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";
Inseob Kimf44917c2023-01-20 17:31:37 +090084const TOMBSTONE_TRANSMIT_DONE_PROP: &str = "tombstone_transmit.init_done";
Seungjae Yoofa22bb02022-12-08 16:38:42 +090085const DEBUGGABLE_PROP: &str = "ro.boot.microdroid.debuggable";
Jiyong Parkbb4a9872021-09-06 15:59:21 +090086
Inseob Kim11f40d02022-06-13 17:16:00 +090087// SYNC WITH virtualizationservice/src/crosvm.rs
88const FAILURE_SERIAL_DEVICE: &str = "/dev/ttyS1";
89
Shikha Panwar566c9672022-11-15 14:39:58 +000090const ENCRYPTEDSTORE_BACKING_DEVICE: &str = "/dev/block/by-name/encryptedstore";
Shikha Panwar566c9672022-11-15 14:39:58 +000091const ENCRYPTEDSTORE_KEY_IDENTIFIER: &str = "encryptedstore_key";
Alice Wang62f7e642023-02-10 09:55:13 +000092const ENCRYPTEDSTORE_KEYSIZE: usize = 32;
Shikha Panwar566c9672022-11-15 14:39:58 +000093
Jooyung Handd0a1732021-11-23 15:26:20 +090094#[derive(thiserror::Error, Debug)]
95enum MicrodroidError {
Inseob Kim11f40d02022-06-13 17:16:00 +090096 #[error("Cannot connect to virtualization service: {0}")]
97 FailedToConnectToVirtualizationService(String),
Jooyung Handd0a1732021-11-23 15:26:20 +090098 #[error("Payload has changed: {0}")]
99 PayloadChanged(String),
100 #[error("Payload verification has failed: {0}")]
101 PayloadVerificationFailed(String),
Jooyung Han5c6d4172021-12-06 14:17:52 +0900102 #[error("Payload config is invalid: {0}")]
103 InvalidConfig(String),
Jooyung Handd0a1732021-11-23 15:26:20 +0900104}
105
Alan Stokes2bead0d2022-09-05 16:58:34 +0100106fn translate_error(err: &Error) -> (ErrorCode, String) {
Jooyung Handd0a1732021-11-23 15:26:20 +0900107 if let Some(e) = err.downcast_ref::<MicrodroidError>() {
108 match e {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100109 MicrodroidError::PayloadChanged(msg) => (ErrorCode::PAYLOAD_CHANGED, msg.to_string()),
Jooyung Handd0a1732021-11-23 15:26:20 +0900110 MicrodroidError::PayloadVerificationFailed(msg) => {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100111 (ErrorCode::PAYLOAD_VERIFICATION_FAILED, msg.to_string())
Jooyung Handd0a1732021-11-23 15:26:20 +0900112 }
Alan Stokes2bead0d2022-09-05 16:58:34 +0100113 MicrodroidError::InvalidConfig(msg) => {
114 (ErrorCode::PAYLOAD_CONFIG_INVALID, msg.to_string())
115 }
Inseob Kim11f40d02022-06-13 17:16:00 +0900116
117 // Connection failure won't be reported to VS; return the default value
118 MicrodroidError::FailedToConnectToVirtualizationService(msg) => {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100119 (ErrorCode::UNKNOWN, msg.to_string())
Inseob Kim11f40d02022-06-13 17:16:00 +0900120 }
Jooyung Handd0a1732021-11-23 15:26:20 +0900121 }
122 } else {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100123 (ErrorCode::UNKNOWN, err.to_string())
Jooyung Handd0a1732021-11-23 15:26:20 +0900124 }
125}
126
Inseob Kim11f40d02022-06-13 17:16:00 +0900127fn write_death_reason_to_serial(err: &Error) -> Result<()> {
128 let death_reason = if let Some(e) = err.downcast_ref::<MicrodroidError>() {
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100129 Borrowed(match e {
Inseob Kim11f40d02022-06-13 17:16:00 +0900130 MicrodroidError::FailedToConnectToVirtualizationService(_) => {
131 "MICRODROID_FAILED_TO_CONNECT_TO_VIRTUALIZATION_SERVICE"
132 }
133 MicrodroidError::PayloadChanged(_) => "MICRODROID_PAYLOAD_HAS_CHANGED",
134 MicrodroidError::PayloadVerificationFailed(_) => {
135 "MICRODROID_PAYLOAD_VERIFICATION_FAILED"
136 }
137 MicrodroidError::InvalidConfig(_) => "MICRODROID_INVALID_PAYLOAD_CONFIG",
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100138 })
Inseob Kim11f40d02022-06-13 17:16:00 +0900139 } else {
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100140 // Send context information back after a separator, to ease diagnosis.
141 // These errors occur before the payload runs, so this should not leak sensitive
142 // information.
143 Owned(format!("MICRODROID_UNKNOWN_RUNTIME_ERROR|{:?}", err))
Inseob Kim11f40d02022-06-13 17:16:00 +0900144 };
145
146 let death_reason_bytes = death_reason.as_bytes();
147 let mut sent_total = 0;
148 while sent_total < death_reason_bytes.len() {
149 // TODO(b/220071963): Sometimes, sending more than 16 bytes at once makes MM hang.
150 let begin = sent_total;
151 let end = std::cmp::min(begin.saturating_add(16), death_reason_bytes.len());
152 OpenOptions::new()
153 .read(false)
154 .write(true)
155 .open(FAILURE_SERIAL_DEVICE)?
156 .write_all(&death_reason_bytes[begin..end])?;
157 sent_total = end;
158 }
159
160 Ok(())
161}
162
Inseob Kim1b95f2e2021-08-19 13:17:40 +0900163fn get_vms_rpc_binder() -> Result<Strong<dyn IVirtualMachineService>> {
David Brazdil73988ea2022-11-11 15:10:32 +0000164 // The host is running a VirtualMachineService for this VM on a port equal
165 // to the CID of this VM.
166 let port = vsock::get_local_cid().context("Could not determine local CID")?;
David Brazdila2125dd2022-12-14 16:37:44 +0000167 RpcSession::new()
168 .setup_vsock_client(VMADDR_CID_HOST, port)
David Brazdil73988ea2022-11-11 15:10:32 +0000169 .context("Could not connect to IVirtualMachineService")
Inseob Kim1b95f2e2021-08-19 13:17:40 +0900170}
171
Inseob Kim437f1052022-06-21 11:30:22 +0900172fn main() -> Result<()> {
Inseob Kim7ff121c2022-11-14 18:13:23 +0900173 // If debuggable, print full backtrace to console log with stdio_to_kmsg
Seungjae Yoofa22bb02022-12-08 16:38:42 +0900174 if system_properties::read_bool(DEBUGGABLE_PROP, true)? {
Inseob Kim7ff121c2022-11-14 18:13:23 +0900175 env::set_var("RUST_BACKTRACE", "full");
176 }
177
Inseob Kim437f1052022-06-21 11:30:22 +0900178 scopeguard::defer! {
179 info!("Shutting down...");
Jooyung Hanbfe086f2021-10-28 10:15:45 +0900180 if let Err(e) = system_properties::write("sys.powerctl", "shutdown") {
181 error!("failed to shutdown {:?}", e);
182 }
Jooyung Han311b1202021-09-14 22:00:16 +0900183 }
Inseob Kim437f1052022-06-21 11:30:22 +0900184
185 try_main().map_err(|e| {
186 error!("Failed with {:?}.", e);
187 if let Err(e) = write_death_reason_to_serial(&e) {
188 error!("Failed to write death reason {:?}", e);
189 }
190 e
191 })
Jooyung Han311b1202021-09-14 22:00:16 +0900192}
193
Inseob Kim090b70b2022-11-16 20:01:14 +0900194fn set_cloexec_on_vm_payload_service_socket() -> Result<()> {
195 let fd = android_get_control_socket(VM_PAYLOAD_SERVICE_SOCKET_NAME)?;
196
197 fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC))?;
198
199 Ok(())
200}
201
Jooyung Han311b1202021-09-14 22:00:16 +0900202fn try_main() -> Result<()> {
Andrew Sculle127cff2022-02-15 15:34:04 +0000203 let _ = kernlog::init();
Jooyung Han347d9f22021-05-28 00:05:14 +0900204 info!("started.");
205
Inseob Kim090b70b2022-11-16 20:01:14 +0900206 if let Err(e) = set_cloexec_on_vm_payload_service_socket() {
207 warn!("Failed to set cloexec on vm payload socket: {:?}", e);
208 }
209
Jiyong Park202856e2022-08-22 16:04:26 +0900210 load_crashkernel_if_supported().context("Failed to load crashkernel")?;
211
Keir Fraser933f0ac2022-10-12 08:23:28 +0000212 swap::init_swap().context("Failed to initialise swap")?;
213 info!("swap enabled.");
214
Inseob Kim11f40d02022-06-13 17:16:00 +0900215 let service = get_vms_rpc_binder()
216 .context("cannot connect to VirtualMachineService")
217 .map_err(|e| MicrodroidError::FailedToConnectToVirtualizationService(e.to_string()))?;
Seungjae Yoofd9a0622022-10-14 10:01:29 +0900218
Jooyung Han5c6d4172021-12-06 14:17:52 +0900219 match try_run_payload(&service) {
220 Ok(code) => {
Jooyung Han5c6d4172021-12-06 14:17:52 +0900221 if code == 0 {
222 info!("task successfully finished");
223 } else {
224 error!("task exited with exit code: {}", code);
225 }
Shikha Panwardef7ef92023-01-06 08:35:48 +0000226 if let Err(e) = post_payload_work() {
227 error!(
228 "Failed to run post payload work. It is possible that certain tasks
229 like syncing encrypted store might be incomplete. Error: {:?}",
230 e
231 );
232 };
233
234 info!("notifying payload finished");
235 service.notifyPayloadFinished(code)?;
Jooyung Han5c6d4172021-12-06 14:17:52 +0900236 Ok(())
237 }
238 Err(err) => {
Jooyung Han5c6d4172021-12-06 14:17:52 +0900239 let (error_code, message) = translate_error(&err);
240 service.notifyError(error_code, &message)?;
241 Err(err)
242 }
Jooyung Handd0a1732021-11-23 15:26:20 +0900243 }
244}
245
Shikha Panwardef7ef92023-01-06 08:35:48 +0000246fn post_payload_work() -> Result<()> {
247 // Sync the encrypted storage filesystem (flushes the filesystem caches).
248 if Path::new(ENCRYPTEDSTORE_BACKING_DEVICE).exists() {
249 let mountpoint = CString::new(ENCRYPTEDSTORE_MOUNTPOINT).unwrap();
250
251 let ret = unsafe {
252 let dirfd = libc::open(
253 mountpoint.as_ptr(),
254 libc::O_DIRECTORY | libc::O_RDONLY | libc::O_CLOEXEC,
255 );
256 ensure!(dirfd >= 0, "Unable to open {:?}", mountpoint);
257 let ret = libc::syncfs(dirfd);
258 libc::close(dirfd);
259 ret
260 };
261 if ret != 0 {
262 error!("failed to sync encrypted storage.");
263 return Err(anyhow!(std::io::Error::last_os_error()));
264 }
265 }
266 Ok(())
267}
Alan Stokes1f417c92022-09-29 15:13:28 +0100268fn dice_derivation(
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000269 dice: DiceDriver,
Alan Stokes1f417c92022-09-29 15:13:28 +0100270 verified_data: &MicrodroidData,
271 payload_metadata: &PayloadMetadata,
Alice Wang62f7e642023-02-10 09:55:13 +0000272) -> Result<OwnedDiceArtifacts> {
Andrew Scullb2f44472022-01-21 14:41:34 +0000273 // Calculate compound digests of code and authorities
Andrew Sculla0d1b1a2022-05-24 19:32:47 +0000274 let mut code_hash_ctx = Sha512::new();
275 let mut authority_hash_ctx = Sha512::new();
Andrew Scullb2f44472022-01-21 14:41:34 +0000276 code_hash_ctx.update(verified_data.apk_data.root_hash.as_ref());
277 authority_hash_ctx.update(verified_data.apk_data.pubkey.as_ref());
Inseob Kimb2519c52022-04-14 02:10:09 +0900278 for extra_apk in &verified_data.extra_apks_data {
Andrew Scullb2f44472022-01-21 14:41:34 +0000279 code_hash_ctx.update(extra_apk.root_hash.as_ref());
280 authority_hash_ctx.update(extra_apk.pubkey.as_ref());
281 }
Inseob Kimb2519c52022-04-14 02:10:09 +0900282 for apex in &verified_data.apex_data {
Andrew Scullb2f44472022-01-21 14:41:34 +0000283 code_hash_ctx.update(apex.root_digest.as_ref());
284 authority_hash_ctx.update(apex.public_key.as_ref());
285 }
Andrew Sculla0d1b1a2022-05-24 19:32:47 +0000286 let code_hash = code_hash_ctx.finish();
287 let authority_hash = authority_hash_ctx.finish();
Andrew Scullb2f44472022-01-21 14:41:34 +0000288
289 // {
290 // -70002: "Microdroid payload",
Alan Stokes1f417c92022-09-29 15:13:28 +0100291 // ? -71000: tstr // payload_config_path
292 // ? -71001: PayloadConfig
Andrew Scullb2f44472022-01-21 14:41:34 +0000293 // }
Alan Stokes1f417c92022-09-29 15:13:28 +0100294 // PayloadConfig = {
Alan Stokes8f12f2b2023-01-09 09:19:20 +0000295 // 1: tstr // payload_binary_name
Alan Stokes1f417c92022-09-29 15:13:28 +0100296 // }
297
Andrew Scullb2f44472022-01-21 14:41:34 +0000298 let mut config_desc = vec![
Alan Stokes1f417c92022-09-29 15:13:28 +0100299 0xa2, // map(2)
300 0x3a, 0x00, 0x01, 0x11, 0x71, // -70002
301 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79,
302 0x6c, 0x6f, 0x61, 0x64, // "Microdroid payload"
Andrew Scullb2f44472022-01-21 14:41:34 +0000303 ];
Alan Stokes1f417c92022-09-29 15:13:28 +0100304
305 match payload_metadata {
306 PayloadMetadata::config_path(payload_config_path) => {
307 encode_negative_number(-71000, &mut config_desc)?;
308 encode_tstr(payload_config_path, &mut config_desc)?;
309 }
310 PayloadMetadata::config(payload_config) => {
311 encode_negative_number(-71001, &mut config_desc)?;
312 encode_header(5, 1, &mut config_desc)?; // map(1)
313 encode_number(1, &mut config_desc)?;
Alan Stokes8f12f2b2023-01-09 09:19:20 +0000314 encode_tstr(&payload_config.payload_binary_name, &mut config_desc)?;
Alan Stokes1f417c92022-09-29 15:13:28 +0100315 }
316 }
Andrew Scullb2f44472022-01-21 14:41:34 +0000317
Seungjae Yoofa22bb02022-12-08 16:38:42 +0900318 // Check debuggability, conservatively assuming it is debuggable
319 let debuggable = system_properties::read_bool(DEBUGGABLE_PROP, true)?;
Andrew Scull65ddfc42022-02-14 21:03:58 +0000320
Andrew Scullb2f44472022-01-21 14:41:34 +0000321 // Send the details to diced
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000322 let hidden = verified_data.salt.clone().try_into().unwrap();
Seungjae Yoofa22bb02022-12-08 16:38:42 +0900323 dice.derive(code_hash, &config_desc, authority_hash, debuggable, hidden)
Andrew Scullb2f44472022-01-21 14:41:34 +0000324}
325
Alan Stokes1f417c92022-09-29 15:13:28 +0100326fn encode_tstr(tstr: &str, buffer: &mut Vec<u8>) -> Result<()> {
327 let bytes = tstr.as_bytes();
328 encode_header(3, bytes.len().try_into().unwrap(), buffer)?;
329 buffer.extend_from_slice(bytes);
330 Ok(())
331}
332
333fn encode_negative_number(n: i64, buffer: &mut dyn Write) -> Result<()> {
334 ensure!(n < 0);
335 let n = -1 - n;
336 encode_header(1, n.try_into().unwrap(), buffer)
337}
338
Andrew Scullab72ec52022-03-14 09:10:52 +0000339fn is_strict_boot() -> bool {
340 Path::new(AVF_STRICT_BOOT).exists()
341}
342
343fn is_new_instance() -> bool {
344 Path::new(AVF_NEW_INSTANCE).exists()
345}
346
Inseob Kime379e7d2022-07-22 18:55:18 +0900347fn is_verified_boot() -> bool {
348 !Path::new(DEBUG_MICRODROID_NO_VERIFIED_BOOT).exists()
349}
350
Inseob Kimab1037d2023-02-08 17:03:31 +0900351fn should_export_tombstones(config: &VmPayloadConfig) -> bool {
352 match config.export_tombstones {
353 Some(b) => b,
354 None => system_properties::read_bool(DEBUGGABLE_PROP, true).unwrap_or(false),
355 }
356}
357
Jooyung Han5c6d4172021-12-06 14:17:52 +0900358fn try_run_payload(service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
Jooyung Han311b1202021-09-14 22:00:16 +0900359 let metadata = load_metadata().context("Failed to load payload metadata")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000360 let dice = DiceDriver::new(Path::new("/dev/open-dice0")).context("Failed to load DICE")?;
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900361
Jooyung Han311b1202021-09-14 22:00:16 +0900362 let mut instance = InstanceDisk::new().context("Failed to load instance.img")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000363 let saved_data =
364 instance.read_microdroid_data(&dice).context("Failed to read identity data")?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900365
Andrew Scullab72ec52022-03-14 09:10:52 +0000366 if is_strict_boot() {
367 // Provisioning must happen on the first boot and never again.
368 if is_new_instance() {
369 ensure!(
370 saved_data.is_none(),
371 MicrodroidError::InvalidConfig("Found instance data on first boot.".to_string())
372 );
373 } else {
374 ensure!(
375 saved_data.is_some(),
376 MicrodroidError::InvalidConfig("Instance data not found.".to_string())
377 );
378 };
379 }
380
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900381 // Verify the payload before using it.
Inseob Kim11f40d02022-06-13 17:16:00 +0900382 let verified_data = verify_payload(&metadata, saved_data.as_ref())
383 .context("Payload verification failed")
384 .map_err(|e| MicrodroidError::PayloadVerificationFailed(e.to_string()))?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900385
386 // In case identity is ignored (by debug policy), we should reuse existing payload data, even
387 // when the payload is changed. This is to keep the derived secret same as before.
388 let verified_data = if let Some(saved_data) = saved_data {
389 if !is_verified_boot() {
390 if saved_data != verified_data {
391 info!("Detected an update of the payload, but continue (regarding debug policy)")
392 }
393 } else {
394 ensure!(
395 saved_data == verified_data,
396 MicrodroidError::PayloadChanged(String::from(
397 "Detected an update of the payload which isn't supported yet."
398 ))
399 );
400 info!("Saved data is verified.");
401 }
402 saved_data
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900403 } else {
Jooyung Han7a343f92021-09-08 22:53:11 +0900404 info!("Saving verified data.");
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000405 instance
406 .write_microdroid_data(&verified_data, &dice)
407 .context("Failed to write identity data")?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900408 verified_data
409 };
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900410
Alan Stokes1f417c92022-09-29 15:13:28 +0100411 let payload_metadata = metadata.payload.ok_or_else(|| {
412 MicrodroidError::InvalidConfig("No payload config in metadata".to_string())
413 })?;
Alan Stokes0d1ef782022-09-27 13:46:35 +0100414
Inseob Kimb2519c52022-04-14 02:10:09 +0900415 // To minimize the exposure to untrusted data, derive dice profile as soon as possible.
416 info!("DICE derivation for payload");
Alice Wang62f7e642023-02-10 09:55:13 +0000417 let dice_artifacts = dice_derivation(dice, &verified_data, &payload_metadata)?;
Shikha Panwar566c9672022-11-15 14:39:58 +0000418
419 // Run encryptedstore binary to prepare the storage
420 let encryptedstore_child = if Path::new(ENCRYPTEDSTORE_BACKING_DEVICE).exists() {
421 info!("Preparing encryptedstore ...");
Alice Wang62f7e642023-02-10 09:55:13 +0000422 Some(prepare_encryptedstore(&dice_artifacts).context("encryptedstore run")?)
Shikha Panwar566c9672022-11-15 14:39:58 +0000423 } else {
424 None
425 };
Inseob Kimb2519c52022-04-14 02:10:09 +0900426
Alan Stokes960c9032022-12-07 16:53:45 +0000427 let mut zipfuse = Zipfuse::default();
428
Jooyung Hana6d11eb2021-09-10 11:48:05 +0900429 // Before reading a file from the APK, start zipfuse
Alan Stokes960c9032022-12-07 16:53:45 +0000430 zipfuse.mount(
Alan Stokes60f82202022-10-07 16:40:07 +0100431 MountForExec::Allowed,
Inseob Kim217038e2021-11-25 11:15:06 +0900432 "fscontext=u:object_r:zipfusefs:s0,context=u:object_r:system_file:s0",
433 Path::new("/dev/block/mapper/microdroid-apk"),
Alice Wang6bbb6da2022-10-26 12:44:06 +0000434 Path::new(VM_APK_CONTENTS_PATH),
Alan Stokes960c9032022-12-07 16:53:45 +0000435 "microdroid_manager.apk.mounted".to_owned(),
436 )?;
Jiyong Park21ce2c52021-08-28 02:32:17 +0900437
Andrew Scull4d262dc2022-10-21 13:14:33 +0000438 // Restricted APIs are only allowed to be used by platform or test components. Infer this from
439 // the use of a VM config file since those can only be used by platform and test components.
440 let allow_restricted_apis = match payload_metadata {
441 PayloadMetadata::config_path(_) => true,
442 PayloadMetadata::config(_) => false,
443 };
444
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100445 let config = load_config(payload_metadata).context("Failed to load payload metadata")?;
Shikha Panwar6f03c942022-04-13 20:26:50 +0000446
Alan Stokes01b3ef02022-09-22 17:43:24 +0100447 let task = config
448 .task
449 .as_ref()
450 .ok_or_else(|| MicrodroidError::InvalidConfig("No task in VM config".to_string()))?;
451
Inseob Kim197748b2021-12-01 19:49:00 +0900452 if config.extra_apks.len() != verified_data.extra_apks_data.len() {
453 return Err(anyhow!(
Alan Stokes1f417c92022-09-29 15:13:28 +0100454 "config expects {} extra apks, but found {}",
Inseob Kim197748b2021-12-01 19:49:00 +0900455 config.extra_apks.len(),
456 verified_data.extra_apks_data.len()
457 ));
458 }
Alan Stokes960c9032022-12-07 16:53:45 +0000459 mount_extra_apks(&config, &mut zipfuse)?;
Jooyung Han634e2d72021-06-10 16:27:38 +0900460
Jooyung Han5c6d4172021-12-06 14:17:52 +0900461 // Wait until apex config is done. (e.g. linker configuration for apexes)
Jooyung Han5c6d4172021-12-06 14:17:52 +0900462 wait_for_apex_config_done()?;
463
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000464 setup_config_sysprops(&config)?;
465
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900466 // Start tombstone_transmit if enabled
Inseob Kimab1037d2023-02-08 17:03:31 +0900467 if should_export_tombstones(&config) {
Inseob Kimc16b0cc2023-01-26 14:57:24 +0900468 system_properties::write("tombstone_transmit.start", "1")
469 .context("set tombstone_transmit.start")?;
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900470 } else {
Alan Stokes01b3ef02022-09-22 17:43:24 +0100471 control_service("stop", "tombstoned")?;
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900472 }
473
Alan Stokes960c9032022-12-07 16:53:45 +0000474 // Wait until zipfuse has mounted the APKs so we can access the payload
475 zipfuse.wait_until_done()?;
Alan Stokes60f82202022-10-07 16:40:07 +0100476
Alice Wang62f7e642023-02-10 09:55:13 +0000477 register_vm_payload_service(allow_restricted_apis, service.clone(), dice_artifacts)?;
Shikha Panwar566c9672022-11-15 14:39:58 +0000478
Shikha Panwarddc124b2022-11-28 19:17:54 +0000479 // Wait for encryptedstore to finish mounting the storage (if enabled) before setting
480 // microdroid_manager.init_done. Reason is init stops uneventd after that.
481 // Encryptedstore, however requires ueventd
Shikha Panwar566c9672022-11-15 14:39:58 +0000482 if let Some(mut child) = encryptedstore_child {
483 let exitcode = child.wait().context("Wait for encryptedstore child")?;
484 ensure!(exitcode.success(), "Unable to prepare encrypted storage. Exitcode={}", exitcode);
485 }
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100486
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000487 wait_for_property_true("dev.bootcomplete").context("failed waiting for dev.bootcomplete")?;
Shikha Panwar3f6f6a52022-11-29 17:28:36 +0000488 system_properties::write("microdroid_manager.init_done", "1")
489 .context("set microdroid_manager.init_done")?;
Inseob Kimc16b0cc2023-01-26 14:57:24 +0900490
491 // Wait for tombstone_transmit to init
Inseob Kimab1037d2023-02-08 17:03:31 +0900492 if should_export_tombstones(&config) {
Inseob Kimc16b0cc2023-01-26 14:57:24 +0900493 wait_for_tombstone_transmit_done()?;
494 }
495
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000496 info!("boot completed, time to run payload");
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100497 exec_task(task, service).context("Failed to run payload")
Alan Stokes01b3ef02022-09-22 17:43:24 +0100498}
499
500fn control_service(action: &str, service: &str) -> Result<()> {
501 system_properties::write(&format!("ctl.{}", action), service)
502 .with_context(|| format!("Failed to {} {}", action, service))
Jooyung Han347d9f22021-05-28 00:05:14 +0900503}
504
Inseob Kim217038e2021-11-25 11:15:06 +0900505struct ApkDmverityArgument<'a> {
506 apk: &'a str,
507 idsig: &'a str,
508 name: &'a str,
Inseob Kim197748b2021-12-01 19:49:00 +0900509 saved_root_hash: Option<&'a RootHash>,
Inseob Kim217038e2021-11-25 11:15:06 +0900510}
511
512fn run_apkdmverity(args: &[ApkDmverityArgument]) -> Result<Child> {
513 let mut cmd = Command::new(APKDMVERITY_BIN);
514
Inseob Kim217038e2021-11-25 11:15:06 +0900515 for argument in args {
516 cmd.arg("--apk").arg(argument.apk).arg(argument.idsig).arg(argument.name);
Inseob Kim197748b2021-12-01 19:49:00 +0900517 if let Some(root_hash) = argument.saved_root_hash {
518 cmd.arg(&to_hex_string(root_hash));
519 } else {
520 cmd.arg("none");
521 }
Inseob Kim217038e2021-11-25 11:15:06 +0900522 }
523
524 cmd.spawn().context("Spawn apkdmverity")
525}
526
Alan Stokes60f82202022-10-07 16:40:07 +0100527enum MountForExec {
528 Allowed,
529 Disallowed,
530}
531
Alan Stokes960c9032022-12-07 16:53:45 +0000532#[derive(Default)]
533struct Zipfuse {
534 ready_properties: Vec<String>,
535}
536
537impl Zipfuse {
Jiyong Park231f9692023-01-09 19:36:21 +0900538 const MICRODROID_PAYLOAD_UID: u32 = 0; // TODO(b/264861173) should be non-root
539 const MICRODROID_PAYLOAD_GID: u32 = 0; // TODO(b/264861173) should be non-root
Alan Stokes960c9032022-12-07 16:53:45 +0000540 fn mount(
541 &mut self,
542 noexec: MountForExec,
543 option: &str,
544 zip_path: &Path,
545 mount_dir: &Path,
546 ready_prop: String,
547 ) -> Result<Child> {
548 let mut cmd = Command::new(ZIPFUSE_BIN);
549 if let MountForExec::Disallowed = noexec {
550 cmd.arg("--noexec");
551 }
552 cmd.args(["-p", &ready_prop, "-o", option]);
Jiyong Park231f9692023-01-09 19:36:21 +0900553 cmd.args(["-u", &Self::MICRODROID_PAYLOAD_UID.to_string()]);
554 cmd.args(["-g", &Self::MICRODROID_PAYLOAD_GID.to_string()]);
Alan Stokes960c9032022-12-07 16:53:45 +0000555 cmd.arg(zip_path).arg(mount_dir);
556 self.ready_properties.push(ready_prop);
557 cmd.spawn().with_context(|| format!("Failed to run zipfuse for {mount_dir:?}"))
Andrew Scullcc339a12022-07-04 12:44:19 +0000558 }
Alan Stokes960c9032022-12-07 16:53:45 +0000559
560 fn wait_until_done(self) -> Result<()> {
561 // We check the last-started check first in the hope that by the time it is done
562 // all or most of the others will also be done, minimising the number of times we
563 // block on a property.
564 for property in self.ready_properties.into_iter().rev() {
565 wait_for_property_true(&property)
566 .with_context(|| format!("Failed waiting for {property}"))?;
567 }
568 Ok(())
Alan Stokes60f82202022-10-07 16:40:07 +0100569 }
Inseob Kim217038e2021-11-25 11:15:06 +0900570}
571
Inseob Kime379e7d2022-07-22 18:55:18 +0900572fn write_apex_payload_data(
573 saved_data: Option<&MicrodroidData>,
574 apex_data_from_payload: &[ApexData],
575) -> Result<()> {
576 if let Some(saved_apex_data) = saved_data.map(|d| &d.apex_data) {
577 // We don't support APEX updates. (assuming that update will change root digest)
578 ensure!(
579 saved_apex_data == apex_data_from_payload,
580 MicrodroidError::PayloadChanged(String::from("APEXes have changed."))
581 );
582 let apex_metadata = to_metadata(apex_data_from_payload);
583 // Pass metadata(with public keys and root digests) to apexd so that it uses the passed
584 // metadata instead of the default one (/dev/block/by-name/payload-metadata)
585 OpenOptions::new()
586 .create_new(true)
587 .write(true)
588 .open("/apex/vm-payload-metadata")
589 .context("Failed to open /apex/vm-payload-metadata")
590 .and_then(|f| write_metadata(&apex_metadata, f))?;
591 }
592 Ok(())
593}
594
Jooyung Han7a343f92021-09-08 22:53:11 +0900595// Verify payload before executing it. For APK payload, Full verification (which is slow) is done
596// when the root_hash values from the idsig file and the instance disk are different. This function
597// returns the verified root hash (for APK payload) and pubkeys (for APEX payloads) that can be
598// saved to the instance disk.
599fn verify_payload(
600 metadata: &Metadata,
601 saved_data: Option<&MicrodroidData>,
602) -> Result<MicrodroidData> {
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900603 let start_time = SystemTime::now();
604
Inseob Kim197748b2021-12-01 19:49:00 +0900605 // Verify main APK
Jooyung Han7a343f92021-09-08 22:53:11 +0900606 let root_hash = saved_data.map(|d| &d.apk_data.root_hash);
Inseob Kim197748b2021-12-01 19:49:00 +0900607 let root_hash_from_idsig = get_apk_root_hash_from_idsig(MAIN_APK_IDSIG_PATH)?;
Jiyong Parkf7dea252021-09-08 01:42:54 +0900608 let root_hash_trustful = root_hash == Some(&root_hash_from_idsig);
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900609
Jiyong Parkf7dea252021-09-08 01:42:54 +0900610 // 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 +0900611 // instead of the value read from the idsig file.
Inseob Kim197748b2021-12-01 19:49:00 +0900612 let main_apk_argument = {
613 ApkDmverityArgument {
614 apk: MAIN_APK_PATH,
615 idsig: MAIN_APK_IDSIG_PATH,
616 name: MAIN_APK_DEVICE_NAME,
617 saved_root_hash: if root_hash_trustful {
618 Some(root_hash_from_idsig.as_ref())
619 } else {
620 None
621 },
622 }
623 };
624 let mut apkdmverity_arguments = vec![main_apk_argument];
625
626 // Verify extra APKs
627 // For now, we can't read the payload config, so glob APKs and idsigs.
628 // Later, we'll see if it matches with the payload config.
629
630 // sort globbed paths to match apks (extra-apk-{idx}) and idsigs (extra-idsig-{idx})
631 // e.g. "extra-apk-0" corresponds to "extra-idsig-0"
632 let extra_apks =
633 sorted(glob(EXTRA_APK_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
634 let extra_idsigs =
635 sorted(glob(EXTRA_IDSIG_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
636 if extra_apks.len() != extra_idsigs.len() {
637 return Err(anyhow!(
638 "Extra apks/idsigs mismatch: {} apks but {} idsigs",
639 extra_apks.len(),
640 extra_idsigs.len()
641 ));
642 }
643 let extra_apks_count = extra_apks.len();
644
645 let (extra_apk_names, extra_root_hashes_from_idsig): (Vec<_>, Vec<_>) = extra_idsigs
646 .iter()
647 .enumerate()
648 .map(|(i, extra_idsig)| {
649 (
650 format!("extra-apk-{}", i),
Alice Wang89cff012022-09-26 10:05:16 +0000651 get_apk_root_hash_from_idsig(extra_idsig)
Inseob Kim197748b2021-12-01 19:49:00 +0900652 .expect("Can't find root hash from extra idsig"),
653 )
654 })
655 .unzip();
656
657 let saved_extra_root_hashes: Vec<_> = saved_data
658 .map(|d| d.extra_apks_data.iter().map(|apk_data| &apk_data.root_hash).collect())
659 .unwrap_or_else(Vec::new);
660 let extra_root_hashes_trustful: Vec<_> = extra_root_hashes_from_idsig
661 .iter()
662 .enumerate()
663 .map(|(i, root_hash_from_idsig)| {
664 saved_extra_root_hashes.get(i).copied() == Some(root_hash_from_idsig)
665 })
666 .collect();
667
668 for i in 0..extra_apks_count {
669 apkdmverity_arguments.push({
670 ApkDmverityArgument {
671 apk: extra_apks[i].to_str().unwrap(),
672 idsig: extra_idsigs[i].to_str().unwrap(),
673 name: &extra_apk_names[i],
674 saved_root_hash: if extra_root_hashes_trustful[i] {
675 Some(&extra_root_hashes_from_idsig[i])
676 } else {
677 None
678 },
679 }
680 });
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900681 }
682
683 // Start apkdmverity and wait for the dm-verify block
Inseob Kim197748b2021-12-01 19:49:00 +0900684 let mut apkdmverity_child = run_apkdmverity(&apkdmverity_arguments)?;
Jooyung Han7a343f92021-09-08 22:53:11 +0900685
Jooyung Hanc8deb472021-09-13 13:48:25 +0900686 // While waiting for apkdmverity to mount APK, gathers public keys and root digests from
687 // APEX payload.
Jooyung Han7a343f92021-09-08 22:53:11 +0900688 let apex_data_from_payload = get_apex_data_from_payload(metadata)?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900689
690 // Writing /apex/vm-payload-metadata is to verify that the payload isn't changed.
691 // Skip writing it if the debug policy ignoring identity is on
692 if is_verified_boot() {
693 write_apex_payload_data(saved_data, &apex_data_from_payload)?;
Jooyung Han4a9b3bf2021-09-10 17:19:00 +0900694 }
Inseob Kime379e7d2022-07-22 18:55:18 +0900695
Jooyung Han4a9b3bf2021-09-10 17:19:00 +0900696 // Start apexd to activate APEXes
697 system_properties::write("ctl.start", "apexd-vm")?;
Jooyung Han7a343f92021-09-08 22:53:11 +0900698
Inseob Kim217038e2021-11-25 11:15:06 +0900699 // TODO(inseob): add timeout
700 apkdmverity_child.wait()?;
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900701
Jiyong Parkf7dea252021-09-08 01:42:54 +0900702 // Do the full verification if the root_hash is un-trustful. This requires the full scanning of
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900703 // 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 +0900704 // 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 +0900705 // of the VM or APK was updated in the host.
706 // TODO(jooyung): consider multithreading to make this faster
Inseob Kim197748b2021-12-01 19:49:00 +0900707 let main_apk_pubkey = get_public_key_from_apk(DM_MOUNTED_APK_PATH, root_hash_trustful)?;
708 let extra_apks_data = extra_root_hashes_from_idsig
709 .into_iter()
710 .enumerate()
711 .map(|(i, extra_root_hash)| {
712 let mount_path = format!("/dev/block/mapper/{}", &extra_apk_names[i]);
713 let apk_pubkey = get_public_key_from_apk(&mount_path, extra_root_hashes_trustful[i])?;
714 Ok(ApkData { root_hash: extra_root_hash, pubkey: apk_pubkey })
715 })
716 .collect::<Result<Vec<_>>>()?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900717
718 info!("payload verification successful. took {:#?}", start_time.elapsed().unwrap());
719
Andrew Scull34916a72022-01-30 21:34:24 +0000720 // Use the salt from a verified instance, or generate a salt for a new instance.
721 let salt = if let Some(saved_data) = saved_data {
722 saved_data.salt.clone()
723 } else {
724 let mut salt = vec![0u8; 64];
725 salt.as_mut_slice().try_fill(&mut rand::thread_rng())?;
726 salt
727 };
728
Jiyong Parkf7dea252021-09-08 01:42:54 +0900729 // At this point, we can ensure that the root_hash from the idsig file is trusted, either by
730 // fully verifying the APK or by comparing it with the saved root_hash.
Jooyung Han7a343f92021-09-08 22:53:11 +0900731 Ok(MicrodroidData {
Andrew Scull34916a72022-01-30 21:34:24 +0000732 salt,
Inseob Kim197748b2021-12-01 19:49:00 +0900733 apk_data: ApkData { root_hash: root_hash_from_idsig, pubkey: main_apk_pubkey },
734 extra_apks_data,
Jooyung Han7a343f92021-09-08 22:53:11 +0900735 apex_data: apex_data_from_payload,
736 })
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900737}
738
Alan Stokes960c9032022-12-07 16:53:45 +0000739fn mount_extra_apks(config: &VmPayloadConfig, zipfuse: &mut Zipfuse) -> Result<()> {
Inseob Kim197748b2021-12-01 19:49:00 +0900740 // For now, only the number of apks is important, as the mount point and dm-verity name is fixed
741 for i in 0..config.extra_apks.len() {
Alan Stokes960c9032022-12-07 16:53:45 +0000742 let mount_dir = format!("/mnt/extra-apk/{i}");
Inseob Kim197748b2021-12-01 19:49:00 +0900743 create_dir(Path::new(&mount_dir)).context("Failed to create mount dir for extra apks")?;
744
745 // don't wait, just detach
Alan Stokes960c9032022-12-07 16:53:45 +0000746 zipfuse.mount(
Alan Stokes60f82202022-10-07 16:40:07 +0100747 MountForExec::Disallowed,
Inseob Kim197748b2021-12-01 19:49:00 +0900748 "fscontext=u:object_r:zipfusefs:s0,context=u:object_r:extra_apk_file:s0",
Alan Stokes960c9032022-12-07 16:53:45 +0000749 Path::new(&format!("/dev/block/mapper/extra-apk-{i}")),
Inseob Kim197748b2021-12-01 19:49:00 +0900750 Path::new(&mount_dir),
Alan Stokes960c9032022-12-07 16:53:45 +0000751 format!("microdroid_manager.extra_apk.mounted.{i}"),
752 )?;
Inseob Kim197748b2021-12-01 19:49:00 +0900753 }
754
755 Ok(())
756}
757
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000758fn setup_config_sysprops(config: &VmPayloadConfig) -> Result<()> {
759 if config.enable_authfs {
760 system_properties::write("microdroid_manager.authfs.enabled", "1")
761 .context("failed to write microdroid_manager.authfs.enabled")?;
762 }
763 system_properties::write("microdroid_manager.config_done", "1")
764 .context("failed to write microdroid_manager.config_done")?;
765 Ok(())
766}
767
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900768// Waits until linker config is generated
769fn wait_for_apex_config_done() -> Result<()> {
Alan Stokes60f82202022-10-07 16:40:07 +0100770 wait_for_property_true(APEX_CONFIG_DONE_PROP).context("Failed waiting for apex config done")
771}
772
Inseob Kimf44917c2023-01-20 17:31:37 +0900773fn wait_for_tombstone_transmit_done() -> Result<()> {
774 wait_for_property_true(TOMBSTONE_TRANSMIT_DONE_PROP)
775 .context("Failed waiting for tombstone transmit done")
776}
777
Alan Stokes60f82202022-10-07 16:40:07 +0100778fn wait_for_property_true(property_name: &str) -> Result<()> {
779 let mut prop = PropertyWatcher::new(property_name)?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900780 loop {
781 prop.wait()?;
Alan Stokes60f82202022-10-07 16:40:07 +0100782 if system_properties::read_bool(property_name, false)? {
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900783 break;
784 }
785 }
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900786 Ok(())
787}
788
Alice Wang89cff012022-09-26 10:05:16 +0000789fn get_apk_root_hash_from_idsig<P: AsRef<Path>>(idsig_path: P) -> Result<Box<RootHash>> {
790 Ok(V4Signature::from_idsig_path(idsig_path)?.hashing_info.raw_root_hash)
Jiyong Park21ce2c52021-08-28 02:32:17 +0900791}
792
Inseob Kim197748b2021-12-01 19:49:00 +0900793fn get_public_key_from_apk(apk: &str, root_hash_trustful: bool) -> Result<Box<[u8]>> {
794 if !root_hash_trustful {
795 verify(apk).context(MicrodroidError::PayloadVerificationFailed(format!(
796 "failed to verify {}",
797 apk
798 )))
799 } else {
800 get_public_key_der(apk)
801 }
802}
803
Alan Stokes1f417c92022-09-29 15:13:28 +0100804fn load_config(payload_metadata: PayloadMetadata) -> Result<VmPayloadConfig> {
805 match payload_metadata {
806 PayloadMetadata::config_path(path) => {
807 let path = Path::new(&path);
808 info!("loading config from {:?}...", path);
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100809 let file = ioutil::wait_for_file(path, WAIT_TIMEOUT)
810 .with_context(|| format!("Failed to read {:?}", path))?;
Alan Stokes1f417c92022-09-29 15:13:28 +0100811 Ok(serde_json::from_reader(file)?)
812 }
813 PayloadMetadata::config(payload_config) => {
814 let task = Task {
815 type_: TaskType::MicrodroidLauncher,
Alan Stokes8f12f2b2023-01-09 09:19:20 +0000816 command: payload_config.payload_binary_name,
Alan Stokes1f417c92022-09-29 15:13:28 +0100817 };
818 Ok(VmPayloadConfig {
819 os: OsConfig { name: "microdroid".to_owned() },
820 task: Some(task),
821 apexes: vec![],
822 extra_apks: vec![],
823 prefer_staged: false,
Inseob Kimab1037d2023-02-08 17:03:31 +0900824 export_tombstones: None,
Alan Stokes1f417c92022-09-29 15:13:28 +0100825 enable_authfs: false,
826 })
827 }
828 }
Jooyung Han634e2d72021-06-10 16:27:38 +0900829}
830
Jiyong Park202856e2022-08-22 16:04:26 +0900831/// Loads the crashkernel into memory using kexec if the VM is loaded with `crashkernel=' parameter
832/// in the cmdline.
833fn load_crashkernel_if_supported() -> Result<()> {
834 let supported = std::fs::read_to_string("/proc/cmdline")?.contains(" crashkernel=");
835 info!("ramdump supported: {}", supported);
836 if supported {
837 let status = Command::new("/system/bin/kexec_load").status()?;
838 if !status.success() {
839 return Err(anyhow!("Failed to load crashkernel: {:?}", status));
840 }
841 }
842 Ok(())
843}
844
Inseob Kim090b70b2022-11-16 20:01:14 +0900845/// Executes the given task.
Jooyung Han5c6d4172021-12-06 14:17:52 +0900846fn exec_task(task: &Task, service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
Jiyong Park8611a6c2021-07-09 18:17:44 +0900847 info!("executing main task {:?}...", task);
David Brazdil451cc962022-10-14 14:08:12 +0100848 let mut command = match task.type_ {
849 TaskType::Executable => Command::new(&task.command),
850 TaskType::MicrodroidLauncher => {
851 let mut command = Command::new("/system/bin/microdroid_launcher");
852 command.arg(find_library_path(&task.command)?);
853 command
854 }
855 };
Nikita Ioffe3452ee22022-12-15 00:31:56 +0000856
857 unsafe {
858 // SAFETY: we are not accessing any resource of the parent process.
859 command.pre_exec(|| {
860 info!("dropping capabilities before executing payload");
861 // It is OK to continue with payload execution even if the calls below fail, since
862 // whether process can use a capability is controlled by the SELinux. Dropping the
863 // capabilities here is just another defense-in-depth layer.
864 if let Err(e) = cap::drop_inheritable_caps() {
865 error!("failed to drop inheritable capabilities: {:?}", e);
866 }
867 if let Err(e) = cap::drop_bounding_set() {
868 error!("failed to drop bounding set: {:?}", e);
869 }
870 Ok(())
871 });
872 }
873
Inseob Kim090b70b2022-11-16 20:01:14 +0900874 command.stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null());
Inseob Kim7f61fe72021-08-20 20:50:47 +0900875
876 info!("notifying payload started");
Inseob Kimc7d28c72021-10-25 14:28:10 +0000877 service.notifyPayloadStarted()?;
Inseob Kim7f61fe72021-08-20 20:50:47 +0900878
Inseob Kim86ca0162021-10-20 02:21:02 +0000879 let exit_status = command.spawn()?.wait()?;
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -0800880 match exit_status.code() {
881 Some(exit_code) => Ok(exit_code),
882 None => Err(match exit_status.signal() {
883 Some(signal) => anyhow!(
884 "Payload exited due to signal: {} ({})",
885 signal,
886 Signal::try_from(signal).map_or("unknown", |s| s.as_str())
887 ),
888 None => anyhow!("Payload has neither exit code nor signal"),
889 }),
890 }
Jooyung Han347d9f22021-05-28 00:05:14 +0900891}
Jooyung Han634e2d72021-06-10 16:27:38 +0900892
Jooyung Han634e2d72021-06-10 16:27:38 +0900893fn find_library_path(name: &str) -> Result<String> {
894 let mut watcher = PropertyWatcher::new("ro.product.cpu.abilist")?;
895 let value = watcher.read(|_name, value| Ok(value.trim().to_string()))?;
896 let abi = value.split(',').next().ok_or_else(|| anyhow!("no abilist"))?;
Alice Wang6bbb6da2022-10-26 12:44:06 +0000897 let path = format!("{}/lib/{}/{}", VM_APK_CONTENTS_PATH, abi, name);
Jooyung Han634e2d72021-06-10 16:27:38 +0900898
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100899 let metadata = fs::metadata(&path).with_context(|| format!("Unable to access {}", path))?;
Jooyung Han634e2d72021-06-10 16:27:38 +0900900 if !metadata.is_file() {
901 bail!("{} is not a file", &path);
902 }
903
904 Ok(path)
905}
Jiyong Park21ce2c52021-08-28 02:32:17 +0900906
907fn to_hex_string(buf: &[u8]) -> String {
908 buf.iter().map(|b| format!("{:02X}", b)).collect()
909}
Shikha Panwar566c9672022-11-15 14:39:58 +0000910
Alice Wang62f7e642023-02-10 09:55:13 +0000911fn prepare_encryptedstore(dice_artifacts: &OwnedDiceArtifacts) -> Result<Child> {
Shikha Panwar566c9672022-11-15 14:39:58 +0000912 // Use a fixed salt to scope the derivation to this API.
913 // Generated using hexdump -vn32 -e'14/1 "0x%02X, " 1 "\n"' /dev/urandom
914 // TODO(b/241541860) : Move this (& other salts) to a salt container, i.e. a global enum
915 let salt = [
916 0xFC, 0x1D, 0x35, 0x7B, 0x96, 0xF3, 0xEF, 0x17, 0x78, 0x7D, 0x70, 0xED, 0xEA, 0xFE, 0x1D,
917 0x6F, 0xB3, 0xF9, 0x40, 0xCE, 0xDD, 0x99, 0x40, 0xAA, 0xA7, 0x0E, 0x92, 0x73, 0x90, 0x86,
918 0x4A, 0x75,
919 ];
Alice Wang62f7e642023-02-10 09:55:13 +0000920 let key = derive_sealing_key(
921 &dice_artifacts.cdi_values.cdi_seal,
Shikha Panwar566c9672022-11-15 14:39:58 +0000922 &salt,
923 ENCRYPTEDSTORE_KEY_IDENTIFIER.as_bytes(),
924 ENCRYPTEDSTORE_KEYSIZE,
925 )?;
926
927 let mut cmd = Command::new(ENCRYPTEDSTORE_BIN);
928 cmd.arg("--blkdevice")
929 .arg(ENCRYPTEDSTORE_BACKING_DEVICE)
930 .arg("--key")
931 .arg(hex::encode(&*key))
Shikha Panwar9fd198f2022-11-18 17:43:43 +0000932 .args(["--mountpoint", ENCRYPTEDSTORE_MOUNTPOINT])
Shikha Panwar566c9672022-11-15 14:39:58 +0000933 .spawn()
934 .context("encryptedstore failed")
935}