blob: 4f6b4a782b177b65162b3e03bdb00d6363004f15 [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;
Shikha Panwardef7ef92023-01-06 08:35:48 +000056use std::ffi::CString;
David Brazdil451cc962022-10-14 14:08:12 +010057use std::fs::{self, create_dir, OpenOptions};
Inseob Kim11f40d02022-06-13 17:16:00 +090058use std::io::Write;
Nikita Ioffe3452ee22022-12-15 00:31:56 +000059use std::os::unix::process::CommandExt;
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -080060use std::os::unix::process::ExitStatusExt;
Jooyung Hanf48ceb42021-06-01 18:00:04 +090061use std::path::Path;
Inseob Kim217038e2021-11-25 11:15:06 +090062use std::process::{Child, Command, Stdio};
Jiyong Park8611a6c2021-07-09 18:17:44 +090063use std::str;
Jiyong Parkbb4a9872021-09-06 15:59:21 +090064use std::time::{Duration, SystemTime};
Jooyung Han634e2d72021-06-10 16:27:38 +090065
66const WAIT_TIMEOUT: Duration = Duration::from_secs(10);
Inseob Kim197748b2021-12-01 19:49:00 +090067const MAIN_APK_PATH: &str = "/dev/block/by-name/microdroid-apk";
68const MAIN_APK_IDSIG_PATH: &str = "/dev/block/by-name/microdroid-apk-idsig";
69const MAIN_APK_DEVICE_NAME: &str = "microdroid-apk";
70const EXTRA_APK_PATH_PATTERN: &str = "/dev/block/by-name/extra-apk-*";
71const EXTRA_IDSIG_PATH_PATTERN: &str = "/dev/block/by-name/extra-idsig-*";
Jooyung Han19c1d6c2021-08-06 14:08:16 +090072const DM_MOUNTED_APK_PATH: &str = "/dev/block/mapper/microdroid-apk";
Inseob Kim217038e2021-11-25 11:15:06 +090073const APKDMVERITY_BIN: &str = "/system/bin/apkdmverity";
74const ZIPFUSE_BIN: &str = "/system/bin/zipfuse";
Andrew Scullab72ec52022-03-14 09:10:52 +000075const AVF_STRICT_BOOT: &str = "/sys/firmware/devicetree/base/chosen/avf,strict-boot";
76const AVF_NEW_INSTANCE: &str = "/sys/firmware/devicetree/base/chosen/avf,new-instance";
Inseob Kime379e7d2022-07-22 18:55:18 +090077const DEBUG_MICRODROID_NO_VERIFIED_BOOT: &str =
78 "/sys/firmware/devicetree/base/virtualization/guest/debug-microdroid,no-verified-boot";
Jooyung Han347d9f22021-05-28 00:05:14 +090079
Jiyong Parkbb4a9872021-09-06 15:59:21 +090080const APEX_CONFIG_DONE_PROP: &str = "apex_config.done";
Inseob Kimf44917c2023-01-20 17:31:37 +090081const TOMBSTONE_TRANSMIT_DONE_PROP: &str = "tombstone_transmit.init_done";
Seungjae Yoofa22bb02022-12-08 16:38:42 +090082const DEBUGGABLE_PROP: &str = "ro.boot.microdroid.debuggable";
Jiyong Parkbb4a9872021-09-06 15:59:21 +090083
Inseob Kim11f40d02022-06-13 17:16:00 +090084// SYNC WITH virtualizationservice/src/crosvm.rs
85const FAILURE_SERIAL_DEVICE: &str = "/dev/ttyS1";
86
Shikha Panwar566c9672022-11-15 14:39:58 +000087/// Identifier for the key used for encrypted store.
88const ENCRYPTEDSTORE_BACKING_DEVICE: &str = "/dev/block/by-name/encryptedstore";
89const ENCRYPTEDSTORE_BIN: &str = "/system/bin/encryptedstore";
90const ENCRYPTEDSTORE_KEY_IDENTIFIER: &str = "encryptedstore_key";
Shikha Panwar195f89c2022-11-23 16:20:34 +000091const ENCRYPTEDSTORE_KEYSIZE: u32 = 32;
Shikha Panwar566c9672022-11-15 14:39:58 +000092
Jooyung Handd0a1732021-11-23 15:26:20 +090093#[derive(thiserror::Error, Debug)]
94enum MicrodroidError {
Inseob Kim11f40d02022-06-13 17:16:00 +090095 #[error("Cannot connect to virtualization service: {0}")]
96 FailedToConnectToVirtualizationService(String),
Jooyung Handd0a1732021-11-23 15:26:20 +090097 #[error("Payload has changed: {0}")]
98 PayloadChanged(String),
99 #[error("Payload verification has failed: {0}")]
100 PayloadVerificationFailed(String),
Jooyung Han5c6d4172021-12-06 14:17:52 +0900101 #[error("Payload config is invalid: {0}")]
102 InvalidConfig(String),
Jooyung Handd0a1732021-11-23 15:26:20 +0900103}
104
Alan Stokes2bead0d2022-09-05 16:58:34 +0100105fn translate_error(err: &Error) -> (ErrorCode, String) {
Jooyung Handd0a1732021-11-23 15:26:20 +0900106 if let Some(e) = err.downcast_ref::<MicrodroidError>() {
107 match e {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100108 MicrodroidError::PayloadChanged(msg) => (ErrorCode::PAYLOAD_CHANGED, msg.to_string()),
Jooyung Handd0a1732021-11-23 15:26:20 +0900109 MicrodroidError::PayloadVerificationFailed(msg) => {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100110 (ErrorCode::PAYLOAD_VERIFICATION_FAILED, msg.to_string())
Jooyung Handd0a1732021-11-23 15:26:20 +0900111 }
Alan Stokes2bead0d2022-09-05 16:58:34 +0100112 MicrodroidError::InvalidConfig(msg) => {
113 (ErrorCode::PAYLOAD_CONFIG_INVALID, msg.to_string())
114 }
Inseob Kim11f40d02022-06-13 17:16:00 +0900115
116 // Connection failure won't be reported to VS; return the default value
117 MicrodroidError::FailedToConnectToVirtualizationService(msg) => {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100118 (ErrorCode::UNKNOWN, msg.to_string())
Inseob Kim11f40d02022-06-13 17:16:00 +0900119 }
Jooyung Handd0a1732021-11-23 15:26:20 +0900120 }
121 } else {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100122 (ErrorCode::UNKNOWN, err.to_string())
Jooyung Handd0a1732021-11-23 15:26:20 +0900123 }
124}
125
Inseob Kim11f40d02022-06-13 17:16:00 +0900126fn write_death_reason_to_serial(err: &Error) -> Result<()> {
127 let death_reason = if let Some(e) = err.downcast_ref::<MicrodroidError>() {
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100128 Borrowed(match e {
Inseob Kim11f40d02022-06-13 17:16:00 +0900129 MicrodroidError::FailedToConnectToVirtualizationService(_) => {
130 "MICRODROID_FAILED_TO_CONNECT_TO_VIRTUALIZATION_SERVICE"
131 }
132 MicrodroidError::PayloadChanged(_) => "MICRODROID_PAYLOAD_HAS_CHANGED",
133 MicrodroidError::PayloadVerificationFailed(_) => {
134 "MICRODROID_PAYLOAD_VERIFICATION_FAILED"
135 }
136 MicrodroidError::InvalidConfig(_) => "MICRODROID_INVALID_PAYLOAD_CONFIG",
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100137 })
Inseob Kim11f40d02022-06-13 17:16:00 +0900138 } else {
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100139 // Send context information back after a separator, to ease diagnosis.
140 // These errors occur before the payload runs, so this should not leak sensitive
141 // information.
142 Owned(format!("MICRODROID_UNKNOWN_RUNTIME_ERROR|{:?}", err))
Inseob Kim11f40d02022-06-13 17:16:00 +0900143 };
144
145 let death_reason_bytes = death_reason.as_bytes();
146 let mut sent_total = 0;
147 while sent_total < death_reason_bytes.len() {
148 // TODO(b/220071963): Sometimes, sending more than 16 bytes at once makes MM hang.
149 let begin = sent_total;
150 let end = std::cmp::min(begin.saturating_add(16), death_reason_bytes.len());
151 OpenOptions::new()
152 .read(false)
153 .write(true)
154 .open(FAILURE_SERIAL_DEVICE)?
155 .write_all(&death_reason_bytes[begin..end])?;
156 sent_total = end;
157 }
158
159 Ok(())
160}
161
Inseob Kim1b95f2e2021-08-19 13:17:40 +0900162fn get_vms_rpc_binder() -> Result<Strong<dyn IVirtualMachineService>> {
David Brazdil73988ea2022-11-11 15:10:32 +0000163 // The host is running a VirtualMachineService for this VM on a port equal
164 // to the CID of this VM.
165 let port = vsock::get_local_cid().context("Could not determine local CID")?;
David Brazdila2125dd2022-12-14 16:37:44 +0000166 RpcSession::new()
167 .setup_vsock_client(VMADDR_CID_HOST, port)
David Brazdil73988ea2022-11-11 15:10:32 +0000168 .context("Could not connect to IVirtualMachineService")
Inseob Kim1b95f2e2021-08-19 13:17:40 +0900169}
170
Inseob Kim437f1052022-06-21 11:30:22 +0900171fn main() -> Result<()> {
Inseob Kim7ff121c2022-11-14 18:13:23 +0900172 // If debuggable, print full backtrace to console log with stdio_to_kmsg
Seungjae Yoofa22bb02022-12-08 16:38:42 +0900173 if system_properties::read_bool(DEBUGGABLE_PROP, true)? {
Inseob Kim7ff121c2022-11-14 18:13:23 +0900174 env::set_var("RUST_BACKTRACE", "full");
175 }
176
Inseob Kim437f1052022-06-21 11:30:22 +0900177 scopeguard::defer! {
178 info!("Shutting down...");
Jooyung Hanbfe086f2021-10-28 10:15:45 +0900179 if let Err(e) = system_properties::write("sys.powerctl", "shutdown") {
180 error!("failed to shutdown {:?}", e);
181 }
Jooyung Han311b1202021-09-14 22:00:16 +0900182 }
Inseob Kim437f1052022-06-21 11:30:22 +0900183
184 try_main().map_err(|e| {
185 error!("Failed with {:?}.", e);
186 if let Err(e) = write_death_reason_to_serial(&e) {
187 error!("Failed to write death reason {:?}", e);
188 }
189 e
190 })
Jooyung Han311b1202021-09-14 22:00:16 +0900191}
192
Inseob Kim090b70b2022-11-16 20:01:14 +0900193fn set_cloexec_on_vm_payload_service_socket() -> Result<()> {
194 let fd = android_get_control_socket(VM_PAYLOAD_SERVICE_SOCKET_NAME)?;
195
196 fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC))?;
197
198 Ok(())
199}
200
Jooyung Han311b1202021-09-14 22:00:16 +0900201fn try_main() -> Result<()> {
Andrew Sculle127cff2022-02-15 15:34:04 +0000202 let _ = kernlog::init();
Jooyung Han347d9f22021-05-28 00:05:14 +0900203 info!("started.");
204
Inseob Kim090b70b2022-11-16 20:01:14 +0900205 if let Err(e) = set_cloexec_on_vm_payload_service_socket() {
206 warn!("Failed to set cloexec on vm payload socket: {:?}", e);
207 }
208
Jiyong Park202856e2022-08-22 16:04:26 +0900209 load_crashkernel_if_supported().context("Failed to load crashkernel")?;
210
Keir Fraser933f0ac2022-10-12 08:23:28 +0000211 swap::init_swap().context("Failed to initialise swap")?;
212 info!("swap enabled.");
213
Inseob Kim11f40d02022-06-13 17:16:00 +0900214 let service = get_vms_rpc_binder()
215 .context("cannot connect to VirtualMachineService")
216 .map_err(|e| MicrodroidError::FailedToConnectToVirtualizationService(e.to_string()))?;
Seungjae Yoofd9a0622022-10-14 10:01:29 +0900217
Jooyung Han5c6d4172021-12-06 14:17:52 +0900218 match try_run_payload(&service) {
219 Ok(code) => {
Jooyung Han5c6d4172021-12-06 14:17:52 +0900220 if code == 0 {
221 info!("task successfully finished");
222 } else {
223 error!("task exited with exit code: {}", code);
224 }
Shikha Panwardef7ef92023-01-06 08:35:48 +0000225 if let Err(e) = post_payload_work() {
226 error!(
227 "Failed to run post payload work. It is possible that certain tasks
228 like syncing encrypted store might be incomplete. Error: {:?}",
229 e
230 );
231 };
232
233 info!("notifying payload finished");
234 service.notifyPayloadFinished(code)?;
Jooyung Han5c6d4172021-12-06 14:17:52 +0900235 Ok(())
236 }
237 Err(err) => {
Jooyung Han5c6d4172021-12-06 14:17:52 +0900238 let (error_code, message) = translate_error(&err);
239 service.notifyError(error_code, &message)?;
240 Err(err)
241 }
Jooyung Handd0a1732021-11-23 15:26:20 +0900242 }
243}
244
Shikha Panwardef7ef92023-01-06 08:35:48 +0000245fn post_payload_work() -> Result<()> {
246 // Sync the encrypted storage filesystem (flushes the filesystem caches).
247 if Path::new(ENCRYPTEDSTORE_BACKING_DEVICE).exists() {
248 let mountpoint = CString::new(ENCRYPTEDSTORE_MOUNTPOINT).unwrap();
249
250 let ret = unsafe {
251 let dirfd = libc::open(
252 mountpoint.as_ptr(),
253 libc::O_DIRECTORY | libc::O_RDONLY | libc::O_CLOEXEC,
254 );
255 ensure!(dirfd >= 0, "Unable to open {:?}", mountpoint);
256 let ret = libc::syncfs(dirfd);
257 libc::close(dirfd);
258 ret
259 };
260 if ret != 0 {
261 error!("failed to sync encrypted storage.");
262 return Err(anyhow!(std::io::Error::last_os_error()));
263 }
264 }
265 Ok(())
266}
Alan Stokes1f417c92022-09-29 15:13:28 +0100267fn dice_derivation(
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000268 dice: DiceDriver,
Alan Stokes1f417c92022-09-29 15:13:28 +0100269 verified_data: &MicrodroidData,
270 payload_metadata: &PayloadMetadata,
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000271) -> Result<DiceContext> {
Andrew Scullb2f44472022-01-21 14:41:34 +0000272 // Calculate compound digests of code and authorities
Andrew Sculla0d1b1a2022-05-24 19:32:47 +0000273 let mut code_hash_ctx = Sha512::new();
274 let mut authority_hash_ctx = Sha512::new();
Andrew Scullb2f44472022-01-21 14:41:34 +0000275 code_hash_ctx.update(verified_data.apk_data.root_hash.as_ref());
276 authority_hash_ctx.update(verified_data.apk_data.pubkey.as_ref());
Inseob Kimb2519c52022-04-14 02:10:09 +0900277 for extra_apk in &verified_data.extra_apks_data {
Andrew Scullb2f44472022-01-21 14:41:34 +0000278 code_hash_ctx.update(extra_apk.root_hash.as_ref());
279 authority_hash_ctx.update(extra_apk.pubkey.as_ref());
280 }
Inseob Kimb2519c52022-04-14 02:10:09 +0900281 for apex in &verified_data.apex_data {
Andrew Scullb2f44472022-01-21 14:41:34 +0000282 code_hash_ctx.update(apex.root_digest.as_ref());
283 authority_hash_ctx.update(apex.public_key.as_ref());
284 }
Andrew Sculla0d1b1a2022-05-24 19:32:47 +0000285 let code_hash = code_hash_ctx.finish();
286 let authority_hash = authority_hash_ctx.finish();
Andrew Scullb2f44472022-01-21 14:41:34 +0000287
288 // {
289 // -70002: "Microdroid payload",
Alan Stokes1f417c92022-09-29 15:13:28 +0100290 // ? -71000: tstr // payload_config_path
291 // ? -71001: PayloadConfig
Andrew Scullb2f44472022-01-21 14:41:34 +0000292 // }
Alan Stokes1f417c92022-09-29 15:13:28 +0100293 // PayloadConfig = {
Alan Stokes8f12f2b2023-01-09 09:19:20 +0000294 // 1: tstr // payload_binary_name
Alan Stokes1f417c92022-09-29 15:13:28 +0100295 // }
296
Andrew Scullb2f44472022-01-21 14:41:34 +0000297 let mut config_desc = vec![
Alan Stokes1f417c92022-09-29 15:13:28 +0100298 0xa2, // map(2)
299 0x3a, 0x00, 0x01, 0x11, 0x71, // -70002
300 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79,
301 0x6c, 0x6f, 0x61, 0x64, // "Microdroid payload"
Andrew Scullb2f44472022-01-21 14:41:34 +0000302 ];
Alan Stokes1f417c92022-09-29 15:13:28 +0100303
304 match payload_metadata {
305 PayloadMetadata::config_path(payload_config_path) => {
306 encode_negative_number(-71000, &mut config_desc)?;
307 encode_tstr(payload_config_path, &mut config_desc)?;
308 }
309 PayloadMetadata::config(payload_config) => {
310 encode_negative_number(-71001, &mut config_desc)?;
311 encode_header(5, 1, &mut config_desc)?; // map(1)
312 encode_number(1, &mut config_desc)?;
Alan Stokes8f12f2b2023-01-09 09:19:20 +0000313 encode_tstr(&payload_config.payload_binary_name, &mut config_desc)?;
Alan Stokes1f417c92022-09-29 15:13:28 +0100314 }
315 }
Andrew Scullb2f44472022-01-21 14:41:34 +0000316
Seungjae Yoofa22bb02022-12-08 16:38:42 +0900317 // Check debuggability, conservatively assuming it is debuggable
318 let debuggable = system_properties::read_bool(DEBUGGABLE_PROP, true)?;
Andrew Scull65ddfc42022-02-14 21:03:58 +0000319
Andrew Scullb2f44472022-01-21 14:41:34 +0000320 // Send the details to diced
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000321 let hidden = verified_data.salt.clone().try_into().unwrap();
Seungjae Yoofa22bb02022-12-08 16:38:42 +0900322 dice.derive(code_hash, &config_desc, authority_hash, debuggable, hidden)
Andrew Scullb2f44472022-01-21 14:41:34 +0000323}
324
Alan Stokes1f417c92022-09-29 15:13:28 +0100325fn encode_tstr(tstr: &str, buffer: &mut Vec<u8>) -> Result<()> {
326 let bytes = tstr.as_bytes();
327 encode_header(3, bytes.len().try_into().unwrap(), buffer)?;
328 buffer.extend_from_slice(bytes);
329 Ok(())
330}
331
332fn encode_negative_number(n: i64, buffer: &mut dyn Write) -> Result<()> {
333 ensure!(n < 0);
334 let n = -1 - n;
335 encode_header(1, n.try_into().unwrap(), buffer)
336}
337
Andrew Scullab72ec52022-03-14 09:10:52 +0000338fn is_strict_boot() -> bool {
339 Path::new(AVF_STRICT_BOOT).exists()
340}
341
342fn is_new_instance() -> bool {
343 Path::new(AVF_NEW_INSTANCE).exists()
344}
345
Inseob Kime379e7d2022-07-22 18:55:18 +0900346fn is_verified_boot() -> bool {
347 !Path::new(DEBUG_MICRODROID_NO_VERIFIED_BOOT).exists()
348}
349
Inseob Kimab1037d2023-02-08 17:03:31 +0900350fn should_export_tombstones(config: &VmPayloadConfig) -> bool {
351 match config.export_tombstones {
352 Some(b) => b,
353 None => system_properties::read_bool(DEBUGGABLE_PROP, true).unwrap_or(false),
354 }
355}
356
Jooyung Han5c6d4172021-12-06 14:17:52 +0900357fn try_run_payload(service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
Jooyung Han311b1202021-09-14 22:00:16 +0900358 let metadata = load_metadata().context("Failed to load payload metadata")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000359 let dice = DiceDriver::new(Path::new("/dev/open-dice0")).context("Failed to load DICE")?;
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900360
Jooyung Han311b1202021-09-14 22:00:16 +0900361 let mut instance = InstanceDisk::new().context("Failed to load instance.img")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000362 let saved_data =
363 instance.read_microdroid_data(&dice).context("Failed to read identity data")?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900364
Andrew Scullab72ec52022-03-14 09:10:52 +0000365 if is_strict_boot() {
366 // Provisioning must happen on the first boot and never again.
367 if is_new_instance() {
368 ensure!(
369 saved_data.is_none(),
370 MicrodroidError::InvalidConfig("Found instance data on first boot.".to_string())
371 );
372 } else {
373 ensure!(
374 saved_data.is_some(),
375 MicrodroidError::InvalidConfig("Instance data not found.".to_string())
376 );
377 };
378 }
379
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900380 // Verify the payload before using it.
Inseob Kim11f40d02022-06-13 17:16:00 +0900381 let verified_data = verify_payload(&metadata, saved_data.as_ref())
382 .context("Payload verification failed")
383 .map_err(|e| MicrodroidError::PayloadVerificationFailed(e.to_string()))?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900384
385 // In case identity is ignored (by debug policy), we should reuse existing payload data, even
386 // when the payload is changed. This is to keep the derived secret same as before.
387 let verified_data = if let Some(saved_data) = saved_data {
388 if !is_verified_boot() {
389 if saved_data != verified_data {
390 info!("Detected an update of the payload, but continue (regarding debug policy)")
391 }
392 } else {
393 ensure!(
394 saved_data == verified_data,
395 MicrodroidError::PayloadChanged(String::from(
396 "Detected an update of the payload which isn't supported yet."
397 ))
398 );
399 info!("Saved data is verified.");
400 }
401 saved_data
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900402 } else {
Jooyung Han7a343f92021-09-08 22:53:11 +0900403 info!("Saving verified data.");
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000404 instance
405 .write_microdroid_data(&verified_data, &dice)
406 .context("Failed to write identity data")?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900407 verified_data
408 };
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900409
Alan Stokes1f417c92022-09-29 15:13:28 +0100410 let payload_metadata = metadata.payload.ok_or_else(|| {
411 MicrodroidError::InvalidConfig("No payload config in metadata".to_string())
412 })?;
Alan Stokes0d1ef782022-09-27 13:46:35 +0100413
Inseob Kimb2519c52022-04-14 02:10:09 +0900414 // To minimize the exposure to untrusted data, derive dice profile as soon as possible.
415 info!("DICE derivation for payload");
Shikha Panwar566c9672022-11-15 14:39:58 +0000416 let dice_context = dice_derivation(dice, &verified_data, &payload_metadata)?;
417
418 // Run encryptedstore binary to prepare the storage
419 let encryptedstore_child = if Path::new(ENCRYPTEDSTORE_BACKING_DEVICE).exists() {
420 info!("Preparing encryptedstore ...");
421 Some(prepare_encryptedstore(&dice_context).context("encryptedstore run")?)
422 } else {
423 None
424 };
Inseob Kimb2519c52022-04-14 02:10:09 +0900425
Alan Stokes960c9032022-12-07 16:53:45 +0000426 let mut zipfuse = Zipfuse::default();
427
Jooyung Hana6d11eb2021-09-10 11:48:05 +0900428 // Before reading a file from the APK, start zipfuse
Alan Stokes960c9032022-12-07 16:53:45 +0000429 zipfuse.mount(
Alan Stokes60f82202022-10-07 16:40:07 +0100430 MountForExec::Allowed,
Inseob Kim217038e2021-11-25 11:15:06 +0900431 "fscontext=u:object_r:zipfusefs:s0,context=u:object_r:system_file:s0",
432 Path::new("/dev/block/mapper/microdroid-apk"),
Alice Wang6bbb6da2022-10-26 12:44:06 +0000433 Path::new(VM_APK_CONTENTS_PATH),
Alan Stokes960c9032022-12-07 16:53:45 +0000434 "microdroid_manager.apk.mounted".to_owned(),
435 )?;
Jiyong Park21ce2c52021-08-28 02:32:17 +0900436
Andrew Scull4d262dc2022-10-21 13:14:33 +0000437 // Restricted APIs are only allowed to be used by platform or test components. Infer this from
438 // the use of a VM config file since those can only be used by platform and test components.
439 let allow_restricted_apis = match payload_metadata {
440 PayloadMetadata::config_path(_) => true,
441 PayloadMetadata::config(_) => false,
442 };
443
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100444 let config = load_config(payload_metadata).context("Failed to load payload metadata")?;
Shikha Panwar6f03c942022-04-13 20:26:50 +0000445
Alan Stokes01b3ef02022-09-22 17:43:24 +0100446 let task = config
447 .task
448 .as_ref()
449 .ok_or_else(|| MicrodroidError::InvalidConfig("No task in VM config".to_string()))?;
450
Inseob Kim197748b2021-12-01 19:49:00 +0900451 if config.extra_apks.len() != verified_data.extra_apks_data.len() {
452 return Err(anyhow!(
Alan Stokes1f417c92022-09-29 15:13:28 +0100453 "config expects {} extra apks, but found {}",
Inseob Kim197748b2021-12-01 19:49:00 +0900454 config.extra_apks.len(),
455 verified_data.extra_apks_data.len()
456 ));
457 }
Alan Stokes960c9032022-12-07 16:53:45 +0000458 mount_extra_apks(&config, &mut zipfuse)?;
Jooyung Han634e2d72021-06-10 16:27:38 +0900459
Jooyung Han5c6d4172021-12-06 14:17:52 +0900460 // Wait until apex config is done. (e.g. linker configuration for apexes)
Jooyung Han5c6d4172021-12-06 14:17:52 +0900461 wait_for_apex_config_done()?;
462
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000463 setup_config_sysprops(&config)?;
464
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900465 // Start tombstone_transmit if enabled
Inseob Kimab1037d2023-02-08 17:03:31 +0900466 if should_export_tombstones(&config) {
Inseob Kimc16b0cc2023-01-26 14:57:24 +0900467 system_properties::write("tombstone_transmit.start", "1")
468 .context("set tombstone_transmit.start")?;
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900469 } else {
Alan Stokes01b3ef02022-09-22 17:43:24 +0100470 control_service("stop", "tombstoned")?;
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900471 }
472
Alan Stokes960c9032022-12-07 16:53:45 +0000473 // Wait until zipfuse has mounted the APKs so we can access the payload
474 zipfuse.wait_until_done()?;
Alan Stokes60f82202022-10-07 16:40:07 +0100475
Shikha Panwar566c9672022-11-15 14:39:58 +0000476 register_vm_payload_service(allow_restricted_apis, service.clone(), dice_context)?;
477
Shikha Panwarddc124b2022-11-28 19:17:54 +0000478 // Wait for encryptedstore to finish mounting the storage (if enabled) before setting
479 // microdroid_manager.init_done. Reason is init stops uneventd after that.
480 // Encryptedstore, however requires ueventd
Shikha Panwar566c9672022-11-15 14:39:58 +0000481 if let Some(mut child) = encryptedstore_child {
482 let exitcode = child.wait().context("Wait for encryptedstore child")?;
483 ensure!(exitcode.success(), "Unable to prepare encrypted storage. Exitcode={}", exitcode);
484 }
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100485
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000486 wait_for_property_true("dev.bootcomplete").context("failed waiting for dev.bootcomplete")?;
Shikha Panwar3f6f6a52022-11-29 17:28:36 +0000487 system_properties::write("microdroid_manager.init_done", "1")
488 .context("set microdroid_manager.init_done")?;
Inseob Kimc16b0cc2023-01-26 14:57:24 +0900489
490 // Wait for tombstone_transmit to init
Inseob Kimab1037d2023-02-08 17:03:31 +0900491 if should_export_tombstones(&config) {
Inseob Kimc16b0cc2023-01-26 14:57:24 +0900492 wait_for_tombstone_transmit_done()?;
493 }
494
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000495 info!("boot completed, time to run payload");
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100496 exec_task(task, service).context("Failed to run payload")
Alan Stokes01b3ef02022-09-22 17:43:24 +0100497}
498
499fn control_service(action: &str, service: &str) -> Result<()> {
500 system_properties::write(&format!("ctl.{}", action), service)
501 .with_context(|| format!("Failed to {} {}", action, service))
Jooyung Han347d9f22021-05-28 00:05:14 +0900502}
503
Inseob Kim217038e2021-11-25 11:15:06 +0900504struct ApkDmverityArgument<'a> {
505 apk: &'a str,
506 idsig: &'a str,
507 name: &'a str,
Inseob Kim197748b2021-12-01 19:49:00 +0900508 saved_root_hash: Option<&'a RootHash>,
Inseob Kim217038e2021-11-25 11:15:06 +0900509}
510
511fn run_apkdmverity(args: &[ApkDmverityArgument]) -> Result<Child> {
512 let mut cmd = Command::new(APKDMVERITY_BIN);
513
Inseob Kim217038e2021-11-25 11:15:06 +0900514 for argument in args {
515 cmd.arg("--apk").arg(argument.apk).arg(argument.idsig).arg(argument.name);
Inseob Kim197748b2021-12-01 19:49:00 +0900516 if let Some(root_hash) = argument.saved_root_hash {
517 cmd.arg(&to_hex_string(root_hash));
518 } else {
519 cmd.arg("none");
520 }
Inseob Kim217038e2021-11-25 11:15:06 +0900521 }
522
523 cmd.spawn().context("Spawn apkdmverity")
524}
525
Alan Stokes60f82202022-10-07 16:40:07 +0100526enum MountForExec {
527 Allowed,
528 Disallowed,
529}
530
Alan Stokes960c9032022-12-07 16:53:45 +0000531#[derive(Default)]
532struct Zipfuse {
533 ready_properties: Vec<String>,
534}
535
536impl Zipfuse {
Jiyong Park231f9692023-01-09 19:36:21 +0900537 const MICRODROID_PAYLOAD_UID: u32 = 0; // TODO(b/264861173) should be non-root
538 const MICRODROID_PAYLOAD_GID: u32 = 0; // TODO(b/264861173) should be non-root
Alan Stokes960c9032022-12-07 16:53:45 +0000539 fn mount(
540 &mut self,
541 noexec: MountForExec,
542 option: &str,
543 zip_path: &Path,
544 mount_dir: &Path,
545 ready_prop: String,
546 ) -> Result<Child> {
547 let mut cmd = Command::new(ZIPFUSE_BIN);
548 if let MountForExec::Disallowed = noexec {
549 cmd.arg("--noexec");
550 }
551 cmd.args(["-p", &ready_prop, "-o", option]);
Jiyong Park231f9692023-01-09 19:36:21 +0900552 cmd.args(["-u", &Self::MICRODROID_PAYLOAD_UID.to_string()]);
553 cmd.args(["-g", &Self::MICRODROID_PAYLOAD_GID.to_string()]);
Alan Stokes960c9032022-12-07 16:53:45 +0000554 cmd.arg(zip_path).arg(mount_dir);
555 self.ready_properties.push(ready_prop);
556 cmd.spawn().with_context(|| format!("Failed to run zipfuse for {mount_dir:?}"))
Andrew Scullcc339a12022-07-04 12:44:19 +0000557 }
Alan Stokes960c9032022-12-07 16:53:45 +0000558
559 fn wait_until_done(self) -> Result<()> {
560 // We check the last-started check first in the hope that by the time it is done
561 // all or most of the others will also be done, minimising the number of times we
562 // block on a property.
563 for property in self.ready_properties.into_iter().rev() {
564 wait_for_property_true(&property)
565 .with_context(|| format!("Failed waiting for {property}"))?;
566 }
567 Ok(())
Alan Stokes60f82202022-10-07 16:40:07 +0100568 }
Inseob Kim217038e2021-11-25 11:15:06 +0900569}
570
Inseob Kime379e7d2022-07-22 18:55:18 +0900571fn write_apex_payload_data(
572 saved_data: Option<&MicrodroidData>,
573 apex_data_from_payload: &[ApexData],
574) -> Result<()> {
575 if let Some(saved_apex_data) = saved_data.map(|d| &d.apex_data) {
576 // We don't support APEX updates. (assuming that update will change root digest)
577 ensure!(
578 saved_apex_data == apex_data_from_payload,
579 MicrodroidError::PayloadChanged(String::from("APEXes have changed."))
580 );
581 let apex_metadata = to_metadata(apex_data_from_payload);
582 // Pass metadata(with public keys and root digests) to apexd so that it uses the passed
583 // metadata instead of the default one (/dev/block/by-name/payload-metadata)
584 OpenOptions::new()
585 .create_new(true)
586 .write(true)
587 .open("/apex/vm-payload-metadata")
588 .context("Failed to open /apex/vm-payload-metadata")
589 .and_then(|f| write_metadata(&apex_metadata, f))?;
590 }
591 Ok(())
592}
593
Jooyung Han7a343f92021-09-08 22:53:11 +0900594// Verify payload before executing it. For APK payload, Full verification (which is slow) is done
595// when the root_hash values from the idsig file and the instance disk are different. This function
596// returns the verified root hash (for APK payload) and pubkeys (for APEX payloads) that can be
597// saved to the instance disk.
598fn verify_payload(
599 metadata: &Metadata,
600 saved_data: Option<&MicrodroidData>,
601) -> Result<MicrodroidData> {
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900602 let start_time = SystemTime::now();
603
Inseob Kim197748b2021-12-01 19:49:00 +0900604 // Verify main APK
Jooyung Han7a343f92021-09-08 22:53:11 +0900605 let root_hash = saved_data.map(|d| &d.apk_data.root_hash);
Inseob Kim197748b2021-12-01 19:49:00 +0900606 let root_hash_from_idsig = get_apk_root_hash_from_idsig(MAIN_APK_IDSIG_PATH)?;
Jiyong Parkf7dea252021-09-08 01:42:54 +0900607 let root_hash_trustful = root_hash == Some(&root_hash_from_idsig);
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900608
Jiyong Parkf7dea252021-09-08 01:42:54 +0900609 // 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 +0900610 // instead of the value read from the idsig file.
Inseob Kim197748b2021-12-01 19:49:00 +0900611 let main_apk_argument = {
612 ApkDmverityArgument {
613 apk: MAIN_APK_PATH,
614 idsig: MAIN_APK_IDSIG_PATH,
615 name: MAIN_APK_DEVICE_NAME,
616 saved_root_hash: if root_hash_trustful {
617 Some(root_hash_from_idsig.as_ref())
618 } else {
619 None
620 },
621 }
622 };
623 let mut apkdmverity_arguments = vec![main_apk_argument];
624
625 // Verify extra APKs
626 // For now, we can't read the payload config, so glob APKs and idsigs.
627 // Later, we'll see if it matches with the payload config.
628
629 // sort globbed paths to match apks (extra-apk-{idx}) and idsigs (extra-idsig-{idx})
630 // e.g. "extra-apk-0" corresponds to "extra-idsig-0"
631 let extra_apks =
632 sorted(glob(EXTRA_APK_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
633 let extra_idsigs =
634 sorted(glob(EXTRA_IDSIG_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
635 if extra_apks.len() != extra_idsigs.len() {
636 return Err(anyhow!(
637 "Extra apks/idsigs mismatch: {} apks but {} idsigs",
638 extra_apks.len(),
639 extra_idsigs.len()
640 ));
641 }
642 let extra_apks_count = extra_apks.len();
643
644 let (extra_apk_names, extra_root_hashes_from_idsig): (Vec<_>, Vec<_>) = extra_idsigs
645 .iter()
646 .enumerate()
647 .map(|(i, extra_idsig)| {
648 (
649 format!("extra-apk-{}", i),
Alice Wang89cff012022-09-26 10:05:16 +0000650 get_apk_root_hash_from_idsig(extra_idsig)
Inseob Kim197748b2021-12-01 19:49:00 +0900651 .expect("Can't find root hash from extra idsig"),
652 )
653 })
654 .unzip();
655
656 let saved_extra_root_hashes: Vec<_> = saved_data
657 .map(|d| d.extra_apks_data.iter().map(|apk_data| &apk_data.root_hash).collect())
658 .unwrap_or_else(Vec::new);
659 let extra_root_hashes_trustful: Vec<_> = extra_root_hashes_from_idsig
660 .iter()
661 .enumerate()
662 .map(|(i, root_hash_from_idsig)| {
663 saved_extra_root_hashes.get(i).copied() == Some(root_hash_from_idsig)
664 })
665 .collect();
666
667 for i in 0..extra_apks_count {
668 apkdmverity_arguments.push({
669 ApkDmverityArgument {
670 apk: extra_apks[i].to_str().unwrap(),
671 idsig: extra_idsigs[i].to_str().unwrap(),
672 name: &extra_apk_names[i],
673 saved_root_hash: if extra_root_hashes_trustful[i] {
674 Some(&extra_root_hashes_from_idsig[i])
675 } else {
676 None
677 },
678 }
679 });
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900680 }
681
682 // Start apkdmverity and wait for the dm-verify block
Inseob Kim197748b2021-12-01 19:49:00 +0900683 let mut apkdmverity_child = run_apkdmverity(&apkdmverity_arguments)?;
Jooyung Han7a343f92021-09-08 22:53:11 +0900684
Jooyung Hanc8deb472021-09-13 13:48:25 +0900685 // While waiting for apkdmverity to mount APK, gathers public keys and root digests from
686 // APEX payload.
Jooyung Han7a343f92021-09-08 22:53:11 +0900687 let apex_data_from_payload = get_apex_data_from_payload(metadata)?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900688
689 // Writing /apex/vm-payload-metadata is to verify that the payload isn't changed.
690 // Skip writing it if the debug policy ignoring identity is on
691 if is_verified_boot() {
692 write_apex_payload_data(saved_data, &apex_data_from_payload)?;
Jooyung Han4a9b3bf2021-09-10 17:19:00 +0900693 }
Inseob Kime379e7d2022-07-22 18:55:18 +0900694
Jooyung Han4a9b3bf2021-09-10 17:19:00 +0900695 // Start apexd to activate APEXes
696 system_properties::write("ctl.start", "apexd-vm")?;
Jooyung Han7a343f92021-09-08 22:53:11 +0900697
Inseob Kim217038e2021-11-25 11:15:06 +0900698 // TODO(inseob): add timeout
699 apkdmverity_child.wait()?;
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900700
Jiyong Parkf7dea252021-09-08 01:42:54 +0900701 // Do the full verification if the root_hash is un-trustful. This requires the full scanning of
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900702 // 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 +0900703 // 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 +0900704 // of the VM or APK was updated in the host.
705 // TODO(jooyung): consider multithreading to make this faster
Inseob Kim197748b2021-12-01 19:49:00 +0900706 let main_apk_pubkey = get_public_key_from_apk(DM_MOUNTED_APK_PATH, root_hash_trustful)?;
707 let extra_apks_data = extra_root_hashes_from_idsig
708 .into_iter()
709 .enumerate()
710 .map(|(i, extra_root_hash)| {
711 let mount_path = format!("/dev/block/mapper/{}", &extra_apk_names[i]);
712 let apk_pubkey = get_public_key_from_apk(&mount_path, extra_root_hashes_trustful[i])?;
713 Ok(ApkData { root_hash: extra_root_hash, pubkey: apk_pubkey })
714 })
715 .collect::<Result<Vec<_>>>()?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900716
717 info!("payload verification successful. took {:#?}", start_time.elapsed().unwrap());
718
Andrew Scull34916a72022-01-30 21:34:24 +0000719 // Use the salt from a verified instance, or generate a salt for a new instance.
720 let salt = if let Some(saved_data) = saved_data {
721 saved_data.salt.clone()
722 } else {
723 let mut salt = vec![0u8; 64];
724 salt.as_mut_slice().try_fill(&mut rand::thread_rng())?;
725 salt
726 };
727
Jiyong Parkf7dea252021-09-08 01:42:54 +0900728 // At this point, we can ensure that the root_hash from the idsig file is trusted, either by
729 // fully verifying the APK or by comparing it with the saved root_hash.
Jooyung Han7a343f92021-09-08 22:53:11 +0900730 Ok(MicrodroidData {
Andrew Scull34916a72022-01-30 21:34:24 +0000731 salt,
Inseob Kim197748b2021-12-01 19:49:00 +0900732 apk_data: ApkData { root_hash: root_hash_from_idsig, pubkey: main_apk_pubkey },
733 extra_apks_data,
Jooyung Han7a343f92021-09-08 22:53:11 +0900734 apex_data: apex_data_from_payload,
735 })
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900736}
737
Alan Stokes960c9032022-12-07 16:53:45 +0000738fn mount_extra_apks(config: &VmPayloadConfig, zipfuse: &mut Zipfuse) -> Result<()> {
Inseob Kim197748b2021-12-01 19:49:00 +0900739 // For now, only the number of apks is important, as the mount point and dm-verity name is fixed
740 for i in 0..config.extra_apks.len() {
Alan Stokes960c9032022-12-07 16:53:45 +0000741 let mount_dir = format!("/mnt/extra-apk/{i}");
Inseob Kim197748b2021-12-01 19:49:00 +0900742 create_dir(Path::new(&mount_dir)).context("Failed to create mount dir for extra apks")?;
743
744 // don't wait, just detach
Alan Stokes960c9032022-12-07 16:53:45 +0000745 zipfuse.mount(
Alan Stokes60f82202022-10-07 16:40:07 +0100746 MountForExec::Disallowed,
Inseob Kim197748b2021-12-01 19:49:00 +0900747 "fscontext=u:object_r:zipfusefs:s0,context=u:object_r:extra_apk_file:s0",
Alan Stokes960c9032022-12-07 16:53:45 +0000748 Path::new(&format!("/dev/block/mapper/extra-apk-{i}")),
Inseob Kim197748b2021-12-01 19:49:00 +0900749 Path::new(&mount_dir),
Alan Stokes960c9032022-12-07 16:53:45 +0000750 format!("microdroid_manager.extra_apk.mounted.{i}"),
751 )?;
Inseob Kim197748b2021-12-01 19:49:00 +0900752 }
753
754 Ok(())
755}
756
Nikita Ioffe57bc8d72022-11-27 00:50:50 +0000757fn setup_config_sysprops(config: &VmPayloadConfig) -> Result<()> {
758 if config.enable_authfs {
759 system_properties::write("microdroid_manager.authfs.enabled", "1")
760 .context("failed to write microdroid_manager.authfs.enabled")?;
761 }
762 system_properties::write("microdroid_manager.config_done", "1")
763 .context("failed to write microdroid_manager.config_done")?;
764 Ok(())
765}
766
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900767// Waits until linker config is generated
768fn wait_for_apex_config_done() -> Result<()> {
Alan Stokes60f82202022-10-07 16:40:07 +0100769 wait_for_property_true(APEX_CONFIG_DONE_PROP).context("Failed waiting for apex config done")
770}
771
Inseob Kimf44917c2023-01-20 17:31:37 +0900772fn wait_for_tombstone_transmit_done() -> Result<()> {
773 wait_for_property_true(TOMBSTONE_TRANSMIT_DONE_PROP)
774 .context("Failed waiting for tombstone transmit done")
775}
776
Alan Stokes60f82202022-10-07 16:40:07 +0100777fn wait_for_property_true(property_name: &str) -> Result<()> {
778 let mut prop = PropertyWatcher::new(property_name)?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900779 loop {
780 prop.wait()?;
Alan Stokes60f82202022-10-07 16:40:07 +0100781 if system_properties::read_bool(property_name, false)? {
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900782 break;
783 }
784 }
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900785 Ok(())
786}
787
Alice Wang89cff012022-09-26 10:05:16 +0000788fn get_apk_root_hash_from_idsig<P: AsRef<Path>>(idsig_path: P) -> Result<Box<RootHash>> {
789 Ok(V4Signature::from_idsig_path(idsig_path)?.hashing_info.raw_root_hash)
Jiyong Park21ce2c52021-08-28 02:32:17 +0900790}
791
Inseob Kim197748b2021-12-01 19:49:00 +0900792fn get_public_key_from_apk(apk: &str, root_hash_trustful: bool) -> Result<Box<[u8]>> {
793 if !root_hash_trustful {
794 verify(apk).context(MicrodroidError::PayloadVerificationFailed(format!(
795 "failed to verify {}",
796 apk
797 )))
798 } else {
799 get_public_key_der(apk)
800 }
801}
802
Alan Stokes1f417c92022-09-29 15:13:28 +0100803fn load_config(payload_metadata: PayloadMetadata) -> Result<VmPayloadConfig> {
804 match payload_metadata {
805 PayloadMetadata::config_path(path) => {
806 let path = Path::new(&path);
807 info!("loading config from {:?}...", path);
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100808 let file = ioutil::wait_for_file(path, WAIT_TIMEOUT)
809 .with_context(|| format!("Failed to read {:?}", path))?;
Alan Stokes1f417c92022-09-29 15:13:28 +0100810 Ok(serde_json::from_reader(file)?)
811 }
812 PayloadMetadata::config(payload_config) => {
813 let task = Task {
814 type_: TaskType::MicrodroidLauncher,
Alan Stokes8f12f2b2023-01-09 09:19:20 +0000815 command: payload_config.payload_binary_name,
Alan Stokes1f417c92022-09-29 15:13:28 +0100816 };
817 Ok(VmPayloadConfig {
818 os: OsConfig { name: "microdroid".to_owned() },
819 task: Some(task),
820 apexes: vec![],
821 extra_apks: vec![],
822 prefer_staged: false,
Inseob Kimab1037d2023-02-08 17:03:31 +0900823 export_tombstones: None,
Alan Stokes1f417c92022-09-29 15:13:28 +0100824 enable_authfs: false,
825 })
826 }
827 }
Jooyung Han634e2d72021-06-10 16:27:38 +0900828}
829
Jiyong Park202856e2022-08-22 16:04:26 +0900830/// Loads the crashkernel into memory using kexec if the VM is loaded with `crashkernel=' parameter
831/// in the cmdline.
832fn load_crashkernel_if_supported() -> Result<()> {
833 let supported = std::fs::read_to_string("/proc/cmdline")?.contains(" crashkernel=");
834 info!("ramdump supported: {}", supported);
835 if supported {
836 let status = Command::new("/system/bin/kexec_load").status()?;
837 if !status.success() {
838 return Err(anyhow!("Failed to load crashkernel: {:?}", status));
839 }
840 }
841 Ok(())
842}
843
Inseob Kim090b70b2022-11-16 20:01:14 +0900844/// Executes the given task.
Jooyung Han5c6d4172021-12-06 14:17:52 +0900845fn exec_task(task: &Task, service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
Jiyong Park8611a6c2021-07-09 18:17:44 +0900846 info!("executing main task {:?}...", task);
David Brazdil451cc962022-10-14 14:08:12 +0100847 let mut command = match task.type_ {
848 TaskType::Executable => Command::new(&task.command),
849 TaskType::MicrodroidLauncher => {
850 let mut command = Command::new("/system/bin/microdroid_launcher");
851 command.arg(find_library_path(&task.command)?);
852 command
853 }
854 };
Nikita Ioffe3452ee22022-12-15 00:31:56 +0000855
856 unsafe {
857 // SAFETY: we are not accessing any resource of the parent process.
858 command.pre_exec(|| {
859 info!("dropping capabilities before executing payload");
860 // It is OK to continue with payload execution even if the calls below fail, since
861 // whether process can use a capability is controlled by the SELinux. Dropping the
862 // capabilities here is just another defense-in-depth layer.
863 if let Err(e) = cap::drop_inheritable_caps() {
864 error!("failed to drop inheritable capabilities: {:?}", e);
865 }
866 if let Err(e) = cap::drop_bounding_set() {
867 error!("failed to drop bounding set: {:?}", e);
868 }
869 Ok(())
870 });
871 }
872
Inseob Kim090b70b2022-11-16 20:01:14 +0900873 command.stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null());
Inseob Kim7f61fe72021-08-20 20:50:47 +0900874
875 info!("notifying payload started");
Inseob Kimc7d28c72021-10-25 14:28:10 +0000876 service.notifyPayloadStarted()?;
Inseob Kim7f61fe72021-08-20 20:50:47 +0900877
Inseob Kim86ca0162021-10-20 02:21:02 +0000878 let exit_status = command.spawn()?.wait()?;
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -0800879 match exit_status.code() {
880 Some(exit_code) => Ok(exit_code),
881 None => Err(match exit_status.signal() {
882 Some(signal) => anyhow!(
883 "Payload exited due to signal: {} ({})",
884 signal,
885 Signal::try_from(signal).map_or("unknown", |s| s.as_str())
886 ),
887 None => anyhow!("Payload has neither exit code nor signal"),
888 }),
889 }
Jooyung Han347d9f22021-05-28 00:05:14 +0900890}
Jooyung Han634e2d72021-06-10 16:27:38 +0900891
Jooyung Han634e2d72021-06-10 16:27:38 +0900892fn find_library_path(name: &str) -> Result<String> {
893 let mut watcher = PropertyWatcher::new("ro.product.cpu.abilist")?;
894 let value = watcher.read(|_name, value| Ok(value.trim().to_string()))?;
895 let abi = value.split(',').next().ok_or_else(|| anyhow!("no abilist"))?;
Alice Wang6bbb6da2022-10-26 12:44:06 +0000896 let path = format!("{}/lib/{}/{}", VM_APK_CONTENTS_PATH, abi, name);
Jooyung Han634e2d72021-06-10 16:27:38 +0900897
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100898 let metadata = fs::metadata(&path).with_context(|| format!("Unable to access {}", path))?;
Jooyung Han634e2d72021-06-10 16:27:38 +0900899 if !metadata.is_file() {
900 bail!("{} is not a file", &path);
901 }
902
903 Ok(path)
904}
Jiyong Park21ce2c52021-08-28 02:32:17 +0900905
906fn to_hex_string(buf: &[u8]) -> String {
907 buf.iter().map(|b| format!("{:02X}", b)).collect()
908}
Shikha Panwar566c9672022-11-15 14:39:58 +0000909
910fn prepare_encryptedstore(dice: &DiceContext) -> Result<Child> {
911 // Use a fixed salt to scope the derivation to this API.
912 // Generated using hexdump -vn32 -e'14/1 "0x%02X, " 1 "\n"' /dev/urandom
913 // TODO(b/241541860) : Move this (& other salts) to a salt container, i.e. a global enum
914 let salt = [
915 0xFC, 0x1D, 0x35, 0x7B, 0x96, 0xF3, 0xEF, 0x17, 0x78, 0x7D, 0x70, 0xED, 0xEA, 0xFE, 0x1D,
916 0x6F, 0xB3, 0xF9, 0x40, 0xCE, 0xDD, 0x99, 0x40, 0xAA, 0xA7, 0x0E, 0x92, 0x73, 0x90, 0x86,
917 0x4A, 0x75,
918 ];
919 let key = dice.get_sealing_key(
920 &salt,
921 ENCRYPTEDSTORE_KEY_IDENTIFIER.as_bytes(),
922 ENCRYPTEDSTORE_KEYSIZE,
923 )?;
924
925 let mut cmd = Command::new(ENCRYPTEDSTORE_BIN);
926 cmd.arg("--blkdevice")
927 .arg(ENCRYPTEDSTORE_BACKING_DEVICE)
928 .arg("--key")
929 .arg(hex::encode(&*key))
Shikha Panwar9fd198f2022-11-18 17:43:43 +0000930 .args(["--mountpoint", ENCRYPTEDSTORE_MOUNTPOINT])
Shikha Panwar566c9672022-11-15 14:39:58 +0000931 .spawn()
932 .context("encryptedstore failed")
933}