blob: a53b4018df67d2b8e489529e25db55fe2ef50464 [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;
Seungjae Yoodd91f0f2022-11-09 15:25:21 +090028use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::{
David Brazdil451cc962022-10-14 14:08:12 +010029 IVirtualMachineService, VM_BINDER_SERVICE_PORT,
Alan Stokes2bead0d2022-09-05 16:58:34 +010030};
Inseob Kim090b70b2022-11-16 20:01:14 +090031use android_system_virtualization_payload::aidl::android::system::virtualization::payload::IVmPayloadService::{
32 VM_APK_CONTENTS_PATH,
33 VM_PAYLOAD_SERVICE_SOCKET_NAME,
34};
Jooyung Handd0a1732021-11-23 15:26:20 +090035use anyhow::{anyhow, bail, ensure, Context, Error, Result};
Alice Wang1bf3d782022-09-28 07:56:36 +000036use apkverify::{get_public_key_der, verify, V4Signature};
Alice Wang43c884b2022-10-24 09:42:40 +000037use binder::Strong;
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;
Andrew Walbran7eb5ca42022-08-08 15:33:34 +000050use rpcbinder::get_vsock_rpc_interface;
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;
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;
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -080059use std::os::unix::process::ExitStatusExt;
Jooyung Hanf48ceb42021-06-01 18:00:04 +090060use std::path::Path;
Inseob Kim217038e2021-11-25 11:15:06 +090061use std::process::{Child, Command, Stdio};
Jiyong Park8611a6c2021-07-09 18:17:44 +090062use std::str;
Jiyong Parkbb4a9872021-09-06 15:59:21 +090063use std::time::{Duration, SystemTime};
Jooyung Han634e2d72021-06-10 16:27:38 +090064
65const WAIT_TIMEOUT: Duration = Duration::from_secs(10);
Inseob Kim197748b2021-12-01 19:49:00 +090066const MAIN_APK_PATH: &str = "/dev/block/by-name/microdroid-apk";
67const MAIN_APK_IDSIG_PATH: &str = "/dev/block/by-name/microdroid-apk-idsig";
68const MAIN_APK_DEVICE_NAME: &str = "microdroid-apk";
69const EXTRA_APK_PATH_PATTERN: &str = "/dev/block/by-name/extra-apk-*";
70const EXTRA_IDSIG_PATH_PATTERN: &str = "/dev/block/by-name/extra-idsig-*";
Jooyung Han19c1d6c2021-08-06 14:08:16 +090071const DM_MOUNTED_APK_PATH: &str = "/dev/block/mapper/microdroid-apk";
Inseob Kim217038e2021-11-25 11:15:06 +090072const APKDMVERITY_BIN: &str = "/system/bin/apkdmverity";
73const ZIPFUSE_BIN: &str = "/system/bin/zipfuse";
Andrew Scullab72ec52022-03-14 09:10:52 +000074const AVF_STRICT_BOOT: &str = "/sys/firmware/devicetree/base/chosen/avf,strict-boot";
75const AVF_NEW_INSTANCE: &str = "/sys/firmware/devicetree/base/chosen/avf,new-instance";
Inseob Kime379e7d2022-07-22 18:55:18 +090076const DEBUG_MICRODROID_NO_VERIFIED_BOOT: &str =
77 "/sys/firmware/devicetree/base/virtualization/guest/debug-microdroid,no-verified-boot";
Jooyung Han347d9f22021-05-28 00:05:14 +090078
Jiyong Parkbb4a9872021-09-06 15:59:21 +090079const APEX_CONFIG_DONE_PROP: &str = "apex_config.done";
Andrew Scull65ddfc42022-02-14 21:03:58 +000080const APP_DEBUGGABLE_PROP: &str = "ro.boot.microdroid.app_debuggable";
Alan Stokes60f82202022-10-07 16:40:07 +010081const APK_MOUNT_DONE_PROP: &str = "microdroid_manager.apk.mounted";
Jiyong Parkbb4a9872021-09-06 15:59:21 +090082
Inseob Kim11f40d02022-06-13 17:16:00 +090083// SYNC WITH virtualizationservice/src/crosvm.rs
84const FAILURE_SERIAL_DEVICE: &str = "/dev/ttyS1";
85
Shikha Panwar566c9672022-11-15 14:39:58 +000086/// Identifier for the key used for encrypted store.
87const ENCRYPTEDSTORE_BACKING_DEVICE: &str = "/dev/block/by-name/encryptedstore";
88const ENCRYPTEDSTORE_BIN: &str = "/system/bin/encryptedstore";
89const ENCRYPTEDSTORE_KEY_IDENTIFIER: &str = "encryptedstore_key";
90const ENCRYPTEDSTORE_KEYSIZE: u32 = 64;
Shikha Panwar9fd198f2022-11-18 17:43:43 +000091const ENCRYPTEDSTORE_MOUNTPOINT: &str = "/mnt/encryptedstore";
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>> {
Andrew Walbran7eb5ca42022-08-08 15:33:34 +0000163 get_vsock_rpc_interface(VMADDR_CID_HOST, VM_BINDER_SERVICE_PORT as u32)
Andrew Walbranc4ce7872022-07-29 11:26:41 +0000164 .context("Cannot connect to RPC service")
Inseob Kim1b95f2e2021-08-19 13:17:40 +0900165}
166
Inseob Kim437f1052022-06-21 11:30:22 +0900167fn main() -> Result<()> {
Inseob Kim7ff121c2022-11-14 18:13:23 +0900168 // If debuggable, print full backtrace to console log with stdio_to_kmsg
169 if system_properties::read_bool(APP_DEBUGGABLE_PROP, true)? {
170 env::set_var("RUST_BACKTRACE", "full");
171 }
172
Inseob Kim437f1052022-06-21 11:30:22 +0900173 scopeguard::defer! {
174 info!("Shutting down...");
Jooyung Hanbfe086f2021-10-28 10:15:45 +0900175 if let Err(e) = system_properties::write("sys.powerctl", "shutdown") {
176 error!("failed to shutdown {:?}", e);
177 }
Jooyung Han311b1202021-09-14 22:00:16 +0900178 }
Inseob Kim437f1052022-06-21 11:30:22 +0900179
180 try_main().map_err(|e| {
181 error!("Failed with {:?}.", e);
182 if let Err(e) = write_death_reason_to_serial(&e) {
183 error!("Failed to write death reason {:?}", e);
184 }
185 e
186 })
Jooyung Han311b1202021-09-14 22:00:16 +0900187}
188
Inseob Kim090b70b2022-11-16 20:01:14 +0900189fn set_cloexec_on_vm_payload_service_socket() -> Result<()> {
190 let fd = android_get_control_socket(VM_PAYLOAD_SERVICE_SOCKET_NAME)?;
191
192 fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC))?;
193
194 Ok(())
195}
196
Jooyung Han311b1202021-09-14 22:00:16 +0900197fn try_main() -> Result<()> {
Andrew Sculle127cff2022-02-15 15:34:04 +0000198 let _ = kernlog::init();
Jooyung Han347d9f22021-05-28 00:05:14 +0900199 info!("started.");
200
Inseob Kim090b70b2022-11-16 20:01:14 +0900201 if let Err(e) = set_cloexec_on_vm_payload_service_socket() {
202 warn!("Failed to set cloexec on vm payload socket: {:?}", e);
203 }
204
Jiyong Park202856e2022-08-22 16:04:26 +0900205 load_crashkernel_if_supported().context("Failed to load crashkernel")?;
206
Keir Fraser933f0ac2022-10-12 08:23:28 +0000207 swap::init_swap().context("Failed to initialise swap")?;
208 info!("swap enabled.");
209
Inseob Kim11f40d02022-06-13 17:16:00 +0900210 let service = get_vms_rpc_binder()
211 .context("cannot connect to VirtualMachineService")
212 .map_err(|e| MicrodroidError::FailedToConnectToVirtualizationService(e.to_string()))?;
Seungjae Yoofd9a0622022-10-14 10:01:29 +0900213
Jooyung Han5c6d4172021-12-06 14:17:52 +0900214 match try_run_payload(&service) {
215 Ok(code) => {
216 info!("notifying payload finished");
217 service.notifyPayloadFinished(code)?;
218 if code == 0 {
219 info!("task successfully finished");
220 } else {
221 error!("task exited with exit code: {}", code);
222 }
223 Ok(())
224 }
225 Err(err) => {
Jooyung Han5c6d4172021-12-06 14:17:52 +0900226 let (error_code, message) = translate_error(&err);
227 service.notifyError(error_code, &message)?;
228 Err(err)
229 }
Jooyung Handd0a1732021-11-23 15:26:20 +0900230 }
231}
232
Alan Stokes1f417c92022-09-29 15:13:28 +0100233fn dice_derivation(
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000234 dice: DiceDriver,
Alan Stokes1f417c92022-09-29 15:13:28 +0100235 verified_data: &MicrodroidData,
236 payload_metadata: &PayloadMetadata,
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000237) -> Result<DiceContext> {
Andrew Scullb2f44472022-01-21 14:41:34 +0000238 // Calculate compound digests of code and authorities
Andrew Sculla0d1b1a2022-05-24 19:32:47 +0000239 let mut code_hash_ctx = Sha512::new();
240 let mut authority_hash_ctx = Sha512::new();
Andrew Scullb2f44472022-01-21 14:41:34 +0000241 code_hash_ctx.update(verified_data.apk_data.root_hash.as_ref());
242 authority_hash_ctx.update(verified_data.apk_data.pubkey.as_ref());
Inseob Kimb2519c52022-04-14 02:10:09 +0900243 for extra_apk in &verified_data.extra_apks_data {
Andrew Scullb2f44472022-01-21 14:41:34 +0000244 code_hash_ctx.update(extra_apk.root_hash.as_ref());
245 authority_hash_ctx.update(extra_apk.pubkey.as_ref());
246 }
Inseob Kimb2519c52022-04-14 02:10:09 +0900247 for apex in &verified_data.apex_data {
Andrew Scullb2f44472022-01-21 14:41:34 +0000248 code_hash_ctx.update(apex.root_digest.as_ref());
249 authority_hash_ctx.update(apex.public_key.as_ref());
250 }
Andrew Sculla0d1b1a2022-05-24 19:32:47 +0000251 let code_hash = code_hash_ctx.finish();
252 let authority_hash = authority_hash_ctx.finish();
Andrew Scullb2f44472022-01-21 14:41:34 +0000253
254 // {
255 // -70002: "Microdroid payload",
Alan Stokes1f417c92022-09-29 15:13:28 +0100256 // ? -71000: tstr // payload_config_path
257 // ? -71001: PayloadConfig
Andrew Scullb2f44472022-01-21 14:41:34 +0000258 // }
Alan Stokes1f417c92022-09-29 15:13:28 +0100259 // PayloadConfig = {
260 // 1: tstr // payload_binary_path
Alan Stokes1f417c92022-09-29 15:13:28 +0100261 // }
262
Andrew Scullb2f44472022-01-21 14:41:34 +0000263 let mut config_desc = vec![
Alan Stokes1f417c92022-09-29 15:13:28 +0100264 0xa2, // map(2)
265 0x3a, 0x00, 0x01, 0x11, 0x71, // -70002
266 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79,
267 0x6c, 0x6f, 0x61, 0x64, // "Microdroid payload"
Andrew Scullb2f44472022-01-21 14:41:34 +0000268 ];
Alan Stokes1f417c92022-09-29 15:13:28 +0100269
270 match payload_metadata {
271 PayloadMetadata::config_path(payload_config_path) => {
272 encode_negative_number(-71000, &mut config_desc)?;
273 encode_tstr(payload_config_path, &mut config_desc)?;
274 }
275 PayloadMetadata::config(payload_config) => {
276 encode_negative_number(-71001, &mut config_desc)?;
277 encode_header(5, 1, &mut config_desc)?; // map(1)
278 encode_number(1, &mut config_desc)?;
279 encode_tstr(&payload_config.payload_binary_path, &mut config_desc)?;
280 }
281 }
Andrew Scullb2f44472022-01-21 14:41:34 +0000282
Andrew Scull65ddfc42022-02-14 21:03:58 +0000283 // Check app debuggability, conervatively assuming it is debuggable
284 let app_debuggable = system_properties::read_bool(APP_DEBUGGABLE_PROP, true)?;
285
Andrew Scullb2f44472022-01-21 14:41:34 +0000286 // Send the details to diced
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000287 let hidden = verified_data.salt.clone().try_into().unwrap();
288 dice.derive(code_hash, &config_desc, authority_hash, app_debuggable, hidden)
Andrew Scullb2f44472022-01-21 14:41:34 +0000289}
290
Alan Stokes1f417c92022-09-29 15:13:28 +0100291fn encode_tstr(tstr: &str, buffer: &mut Vec<u8>) -> Result<()> {
292 let bytes = tstr.as_bytes();
293 encode_header(3, bytes.len().try_into().unwrap(), buffer)?;
294 buffer.extend_from_slice(bytes);
295 Ok(())
296}
297
298fn encode_negative_number(n: i64, buffer: &mut dyn Write) -> Result<()> {
299 ensure!(n < 0);
300 let n = -1 - n;
301 encode_header(1, n.try_into().unwrap(), buffer)
302}
303
Andrew Scullab72ec52022-03-14 09:10:52 +0000304fn is_strict_boot() -> bool {
305 Path::new(AVF_STRICT_BOOT).exists()
306}
307
308fn is_new_instance() -> bool {
309 Path::new(AVF_NEW_INSTANCE).exists()
310}
311
Inseob Kime379e7d2022-07-22 18:55:18 +0900312fn is_verified_boot() -> bool {
313 !Path::new(DEBUG_MICRODROID_NO_VERIFIED_BOOT).exists()
314}
315
Jooyung Han5c6d4172021-12-06 14:17:52 +0900316fn try_run_payload(service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
Jooyung Han311b1202021-09-14 22:00:16 +0900317 let metadata = load_metadata().context("Failed to load payload metadata")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000318 let dice = DiceDriver::new(Path::new("/dev/open-dice0")).context("Failed to load DICE")?;
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900319
Jooyung Han311b1202021-09-14 22:00:16 +0900320 let mut instance = InstanceDisk::new().context("Failed to load instance.img")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000321 let saved_data =
322 instance.read_microdroid_data(&dice).context("Failed to read identity data")?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900323
Andrew Scullab72ec52022-03-14 09:10:52 +0000324 if is_strict_boot() {
325 // Provisioning must happen on the first boot and never again.
326 if is_new_instance() {
327 ensure!(
328 saved_data.is_none(),
329 MicrodroidError::InvalidConfig("Found instance data on first boot.".to_string())
330 );
331 } else {
332 ensure!(
333 saved_data.is_some(),
334 MicrodroidError::InvalidConfig("Instance data not found.".to_string())
335 );
336 };
337 }
338
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900339 // Verify the payload before using it.
Inseob Kim11f40d02022-06-13 17:16:00 +0900340 let verified_data = verify_payload(&metadata, saved_data.as_ref())
341 .context("Payload verification failed")
342 .map_err(|e| MicrodroidError::PayloadVerificationFailed(e.to_string()))?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900343
344 // In case identity is ignored (by debug policy), we should reuse existing payload data, even
345 // when the payload is changed. This is to keep the derived secret same as before.
346 let verified_data = if let Some(saved_data) = saved_data {
347 if !is_verified_boot() {
348 if saved_data != verified_data {
349 info!("Detected an update of the payload, but continue (regarding debug policy)")
350 }
351 } else {
352 ensure!(
353 saved_data == verified_data,
354 MicrodroidError::PayloadChanged(String::from(
355 "Detected an update of the payload which isn't supported yet."
356 ))
357 );
358 info!("Saved data is verified.");
359 }
360 saved_data
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900361 } else {
Jooyung Han7a343f92021-09-08 22:53:11 +0900362 info!("Saving verified data.");
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000363 instance
364 .write_microdroid_data(&verified_data, &dice)
365 .context("Failed to write identity data")?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900366 verified_data
367 };
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900368
Alan Stokes1f417c92022-09-29 15:13:28 +0100369 let payload_metadata = metadata.payload.ok_or_else(|| {
370 MicrodroidError::InvalidConfig("No payload config in metadata".to_string())
371 })?;
Alan Stokes0d1ef782022-09-27 13:46:35 +0100372
Inseob Kimb2519c52022-04-14 02:10:09 +0900373 // To minimize the exposure to untrusted data, derive dice profile as soon as possible.
374 info!("DICE derivation for payload");
Shikha Panwar566c9672022-11-15 14:39:58 +0000375 let dice_context = dice_derivation(dice, &verified_data, &payload_metadata)?;
376
377 // Run encryptedstore binary to prepare the storage
378 let encryptedstore_child = if Path::new(ENCRYPTEDSTORE_BACKING_DEVICE).exists() {
379 info!("Preparing encryptedstore ...");
380 Some(prepare_encryptedstore(&dice_context).context("encryptedstore run")?)
381 } else {
382 None
383 };
Inseob Kimb2519c52022-04-14 02:10:09 +0900384
Jooyung Hana6d11eb2021-09-10 11:48:05 +0900385 // Before reading a file from the APK, start zipfuse
Inseob Kim217038e2021-11-25 11:15:06 +0900386 run_zipfuse(
Alan Stokes60f82202022-10-07 16:40:07 +0100387 MountForExec::Allowed,
Inseob Kim217038e2021-11-25 11:15:06 +0900388 "fscontext=u:object_r:zipfusefs:s0,context=u:object_r:system_file:s0",
389 Path::new("/dev/block/mapper/microdroid-apk"),
Alice Wang6bbb6da2022-10-26 12:44:06 +0000390 Path::new(VM_APK_CONTENTS_PATH),
Alan Stokes60f82202022-10-07 16:40:07 +0100391 Some(APK_MOUNT_DONE_PROP),
Inseob Kim217038e2021-11-25 11:15:06 +0900392 )
393 .context("Failed to run zipfuse")?;
Jiyong Park21ce2c52021-08-28 02:32:17 +0900394
Andrew Scull4d262dc2022-10-21 13:14:33 +0000395 // Restricted APIs are only allowed to be used by platform or test components. Infer this from
396 // the use of a VM config file since those can only be used by platform and test components.
397 let allow_restricted_apis = match payload_metadata {
398 PayloadMetadata::config_path(_) => true,
399 PayloadMetadata::config(_) => false,
400 };
401
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100402 let config = load_config(payload_metadata).context("Failed to load payload metadata")?;
Shikha Panwar6f03c942022-04-13 20:26:50 +0000403
Alan Stokes01b3ef02022-09-22 17:43:24 +0100404 let task = config
405 .task
406 .as_ref()
407 .ok_or_else(|| MicrodroidError::InvalidConfig("No task in VM config".to_string()))?;
408
Inseob Kim197748b2021-12-01 19:49:00 +0900409 if config.extra_apks.len() != verified_data.extra_apks_data.len() {
410 return Err(anyhow!(
Alan Stokes1f417c92022-09-29 15:13:28 +0100411 "config expects {} extra apks, but found {}",
Inseob Kim197748b2021-12-01 19:49:00 +0900412 config.extra_apks.len(),
413 verified_data.extra_apks_data.len()
414 ));
415 }
416 mount_extra_apks(&config)?;
Jooyung Han634e2d72021-06-10 16:27:38 +0900417
Jooyung Han5c6d4172021-12-06 14:17:52 +0900418 // Wait until apex config is done. (e.g. linker configuration for apexes)
419 // TODO(jooyung): wait until sys.boot_completed?
420 wait_for_apex_config_done()?;
421
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900422 // Start tombstone_transmit if enabled
423 if config.export_tombstones {
Alan Stokes01b3ef02022-09-22 17:43:24 +0100424 control_service("start", "tombstone_transmit")?;
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900425 } else {
Alan Stokes01b3ef02022-09-22 17:43:24 +0100426 control_service("stop", "tombstoned")?;
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900427 }
428
Alan Stokes01b3ef02022-09-22 17:43:24 +0100429 // Start authfs if enabled
430 if config.enable_authfs {
431 control_service("start", "authfs_service")?;
432 }
433
Alan Stokes60f82202022-10-07 16:40:07 +0100434 // Wait until zipfuse has mounted the APK so we can access the payload
435 wait_for_property_true(APK_MOUNT_DONE_PROP).context("Failed waiting for APK mount done")?;
436
Shikha Panwar566c9672022-11-15 14:39:58 +0000437 register_vm_payload_service(allow_restricted_apis, service.clone(), dice_context)?;
438
439 if let Some(mut child) = encryptedstore_child {
440 let exitcode = child.wait().context("Wait for encryptedstore child")?;
441 ensure!(exitcode.success(), "Unable to prepare encrypted storage. Exitcode={}", exitcode);
442 }
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100443
444 system_properties::write("dev.bootcomplete", "1").context("set dev.bootcomplete")?;
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100445 exec_task(task, service).context("Failed to run payload")
Alan Stokes01b3ef02022-09-22 17:43:24 +0100446}
447
448fn control_service(action: &str, service: &str) -> Result<()> {
449 system_properties::write(&format!("ctl.{}", action), service)
450 .with_context(|| format!("Failed to {} {}", action, service))
Jooyung Han347d9f22021-05-28 00:05:14 +0900451}
452
Inseob Kim217038e2021-11-25 11:15:06 +0900453struct ApkDmverityArgument<'a> {
454 apk: &'a str,
455 idsig: &'a str,
456 name: &'a str,
Inseob Kim197748b2021-12-01 19:49:00 +0900457 saved_root_hash: Option<&'a RootHash>,
Inseob Kim217038e2021-11-25 11:15:06 +0900458}
459
460fn run_apkdmverity(args: &[ApkDmverityArgument]) -> Result<Child> {
461 let mut cmd = Command::new(APKDMVERITY_BIN);
462
Inseob Kim217038e2021-11-25 11:15:06 +0900463 for argument in args {
464 cmd.arg("--apk").arg(argument.apk).arg(argument.idsig).arg(argument.name);
Inseob Kim197748b2021-12-01 19:49:00 +0900465 if let Some(root_hash) = argument.saved_root_hash {
466 cmd.arg(&to_hex_string(root_hash));
467 } else {
468 cmd.arg("none");
469 }
Inseob Kim217038e2021-11-25 11:15:06 +0900470 }
471
472 cmd.spawn().context("Spawn apkdmverity")
473}
474
Alan Stokes60f82202022-10-07 16:40:07 +0100475enum MountForExec {
476 Allowed,
477 Disallowed,
478}
479
480fn run_zipfuse(
481 noexec: MountForExec,
482 option: &str,
483 zip_path: &Path,
484 mount_dir: &Path,
485 ready_prop: Option<&str>,
486) -> Result<Child> {
Andrew Scullcc339a12022-07-04 12:44:19 +0000487 let mut cmd = Command::new(ZIPFUSE_BIN);
Alan Stokes60f82202022-10-07 16:40:07 +0100488 if let MountForExec::Disallowed = noexec {
Andrew Scullcc339a12022-07-04 12:44:19 +0000489 cmd.arg("--noexec");
490 }
Alan Stokes60f82202022-10-07 16:40:07 +0100491 if let Some(property_name) = ready_prop {
492 cmd.args(["-p", property_name]);
493 }
Inseob Kimadd7b7f2022-11-21 15:06:05 +0900494 cmd.arg("-o").arg(option).arg(zip_path).arg(mount_dir).spawn().context("Spawn zipfuse")
Inseob Kim217038e2021-11-25 11:15:06 +0900495}
496
Inseob Kime379e7d2022-07-22 18:55:18 +0900497fn write_apex_payload_data(
498 saved_data: Option<&MicrodroidData>,
499 apex_data_from_payload: &[ApexData],
500) -> Result<()> {
501 if let Some(saved_apex_data) = saved_data.map(|d| &d.apex_data) {
502 // We don't support APEX updates. (assuming that update will change root digest)
503 ensure!(
504 saved_apex_data == apex_data_from_payload,
505 MicrodroidError::PayloadChanged(String::from("APEXes have changed."))
506 );
507 let apex_metadata = to_metadata(apex_data_from_payload);
508 // Pass metadata(with public keys and root digests) to apexd so that it uses the passed
509 // metadata instead of the default one (/dev/block/by-name/payload-metadata)
510 OpenOptions::new()
511 .create_new(true)
512 .write(true)
513 .open("/apex/vm-payload-metadata")
514 .context("Failed to open /apex/vm-payload-metadata")
515 .and_then(|f| write_metadata(&apex_metadata, f))?;
516 }
517 Ok(())
518}
519
Jooyung Han7a343f92021-09-08 22:53:11 +0900520// Verify payload before executing it. For APK payload, Full verification (which is slow) is done
521// when the root_hash values from the idsig file and the instance disk are different. This function
522// returns the verified root hash (for APK payload) and pubkeys (for APEX payloads) that can be
523// saved to the instance disk.
524fn verify_payload(
525 metadata: &Metadata,
526 saved_data: Option<&MicrodroidData>,
527) -> Result<MicrodroidData> {
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900528 let start_time = SystemTime::now();
529
Inseob Kim197748b2021-12-01 19:49:00 +0900530 // Verify main APK
Jooyung Han7a343f92021-09-08 22:53:11 +0900531 let root_hash = saved_data.map(|d| &d.apk_data.root_hash);
Inseob Kim197748b2021-12-01 19:49:00 +0900532 let root_hash_from_idsig = get_apk_root_hash_from_idsig(MAIN_APK_IDSIG_PATH)?;
Jiyong Parkf7dea252021-09-08 01:42:54 +0900533 let root_hash_trustful = root_hash == Some(&root_hash_from_idsig);
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900534
Jiyong Parkf7dea252021-09-08 01:42:54 +0900535 // 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 +0900536 // instead of the value read from the idsig file.
Inseob Kim197748b2021-12-01 19:49:00 +0900537 let main_apk_argument = {
538 ApkDmverityArgument {
539 apk: MAIN_APK_PATH,
540 idsig: MAIN_APK_IDSIG_PATH,
541 name: MAIN_APK_DEVICE_NAME,
542 saved_root_hash: if root_hash_trustful {
543 Some(root_hash_from_idsig.as_ref())
544 } else {
545 None
546 },
547 }
548 };
549 let mut apkdmverity_arguments = vec![main_apk_argument];
550
551 // Verify extra APKs
552 // For now, we can't read the payload config, so glob APKs and idsigs.
553 // Later, we'll see if it matches with the payload config.
554
555 // sort globbed paths to match apks (extra-apk-{idx}) and idsigs (extra-idsig-{idx})
556 // e.g. "extra-apk-0" corresponds to "extra-idsig-0"
557 let extra_apks =
558 sorted(glob(EXTRA_APK_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
559 let extra_idsigs =
560 sorted(glob(EXTRA_IDSIG_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
561 if extra_apks.len() != extra_idsigs.len() {
562 return Err(anyhow!(
563 "Extra apks/idsigs mismatch: {} apks but {} idsigs",
564 extra_apks.len(),
565 extra_idsigs.len()
566 ));
567 }
568 let extra_apks_count = extra_apks.len();
569
570 let (extra_apk_names, extra_root_hashes_from_idsig): (Vec<_>, Vec<_>) = extra_idsigs
571 .iter()
572 .enumerate()
573 .map(|(i, extra_idsig)| {
574 (
575 format!("extra-apk-{}", i),
Alice Wang89cff012022-09-26 10:05:16 +0000576 get_apk_root_hash_from_idsig(extra_idsig)
Inseob Kim197748b2021-12-01 19:49:00 +0900577 .expect("Can't find root hash from extra idsig"),
578 )
579 })
580 .unzip();
581
582 let saved_extra_root_hashes: Vec<_> = saved_data
583 .map(|d| d.extra_apks_data.iter().map(|apk_data| &apk_data.root_hash).collect())
584 .unwrap_or_else(Vec::new);
585 let extra_root_hashes_trustful: Vec<_> = extra_root_hashes_from_idsig
586 .iter()
587 .enumerate()
588 .map(|(i, root_hash_from_idsig)| {
589 saved_extra_root_hashes.get(i).copied() == Some(root_hash_from_idsig)
590 })
591 .collect();
592
593 for i in 0..extra_apks_count {
594 apkdmverity_arguments.push({
595 ApkDmverityArgument {
596 apk: extra_apks[i].to_str().unwrap(),
597 idsig: extra_idsigs[i].to_str().unwrap(),
598 name: &extra_apk_names[i],
599 saved_root_hash: if extra_root_hashes_trustful[i] {
600 Some(&extra_root_hashes_from_idsig[i])
601 } else {
602 None
603 },
604 }
605 });
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900606 }
607
608 // Start apkdmverity and wait for the dm-verify block
Inseob Kim197748b2021-12-01 19:49:00 +0900609 let mut apkdmverity_child = run_apkdmverity(&apkdmverity_arguments)?;
Jooyung Han7a343f92021-09-08 22:53:11 +0900610
Jooyung Hanc8deb472021-09-13 13:48:25 +0900611 // While waiting for apkdmverity to mount APK, gathers public keys and root digests from
612 // APEX payload.
Jooyung Han7a343f92021-09-08 22:53:11 +0900613 let apex_data_from_payload = get_apex_data_from_payload(metadata)?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900614
615 // Writing /apex/vm-payload-metadata is to verify that the payload isn't changed.
616 // Skip writing it if the debug policy ignoring identity is on
617 if is_verified_boot() {
618 write_apex_payload_data(saved_data, &apex_data_from_payload)?;
Jooyung Han4a9b3bf2021-09-10 17:19:00 +0900619 }
Inseob Kime379e7d2022-07-22 18:55:18 +0900620
Jooyung Han4a9b3bf2021-09-10 17:19:00 +0900621 // Start apexd to activate APEXes
622 system_properties::write("ctl.start", "apexd-vm")?;
Jooyung Han7a343f92021-09-08 22:53:11 +0900623
Inseob Kim217038e2021-11-25 11:15:06 +0900624 // TODO(inseob): add timeout
625 apkdmverity_child.wait()?;
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900626
Jiyong Parkf7dea252021-09-08 01:42:54 +0900627 // Do the full verification if the root_hash is un-trustful. This requires the full scanning of
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900628 // 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 +0900629 // 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 +0900630 // of the VM or APK was updated in the host.
631 // TODO(jooyung): consider multithreading to make this faster
Inseob Kim197748b2021-12-01 19:49:00 +0900632 let main_apk_pubkey = get_public_key_from_apk(DM_MOUNTED_APK_PATH, root_hash_trustful)?;
633 let extra_apks_data = extra_root_hashes_from_idsig
634 .into_iter()
635 .enumerate()
636 .map(|(i, extra_root_hash)| {
637 let mount_path = format!("/dev/block/mapper/{}", &extra_apk_names[i]);
638 let apk_pubkey = get_public_key_from_apk(&mount_path, extra_root_hashes_trustful[i])?;
639 Ok(ApkData { root_hash: extra_root_hash, pubkey: apk_pubkey })
640 })
641 .collect::<Result<Vec<_>>>()?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900642
643 info!("payload verification successful. took {:#?}", start_time.elapsed().unwrap());
644
Andrew Scull34916a72022-01-30 21:34:24 +0000645 // Use the salt from a verified instance, or generate a salt for a new instance.
646 let salt = if let Some(saved_data) = saved_data {
647 saved_data.salt.clone()
648 } else {
649 let mut salt = vec![0u8; 64];
650 salt.as_mut_slice().try_fill(&mut rand::thread_rng())?;
651 salt
652 };
653
Jiyong Parkf7dea252021-09-08 01:42:54 +0900654 // At this point, we can ensure that the root_hash from the idsig file is trusted, either by
655 // fully verifying the APK or by comparing it with the saved root_hash.
Jooyung Han7a343f92021-09-08 22:53:11 +0900656 Ok(MicrodroidData {
Andrew Scull34916a72022-01-30 21:34:24 +0000657 salt,
Inseob Kim197748b2021-12-01 19:49:00 +0900658 apk_data: ApkData { root_hash: root_hash_from_idsig, pubkey: main_apk_pubkey },
659 extra_apks_data,
Jooyung Han7a343f92021-09-08 22:53:11 +0900660 apex_data: apex_data_from_payload,
661 })
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900662}
663
Inseob Kim197748b2021-12-01 19:49:00 +0900664fn mount_extra_apks(config: &VmPayloadConfig) -> Result<()> {
665 // For now, only the number of apks is important, as the mount point and dm-verity name is fixed
666 for i in 0..config.extra_apks.len() {
667 let mount_dir = format!("/mnt/extra-apk/{}", i);
668 create_dir(Path::new(&mount_dir)).context("Failed to create mount dir for extra apks")?;
669
670 // don't wait, just detach
671 run_zipfuse(
Alan Stokes60f82202022-10-07 16:40:07 +0100672 MountForExec::Disallowed,
Inseob Kim197748b2021-12-01 19:49:00 +0900673 "fscontext=u:object_r:zipfusefs:s0,context=u:object_r:extra_apk_file:s0",
674 Path::new(&format!("/dev/block/mapper/extra-apk-{}", i)),
675 Path::new(&mount_dir),
Alan Stokes60f82202022-10-07 16:40:07 +0100676 None,
Inseob Kim197748b2021-12-01 19:49:00 +0900677 )
678 .context("Failed to zipfuse extra apks")?;
679 }
680
681 Ok(())
682}
683
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900684// Waits until linker config is generated
685fn wait_for_apex_config_done() -> Result<()> {
Alan Stokes60f82202022-10-07 16:40:07 +0100686 wait_for_property_true(APEX_CONFIG_DONE_PROP).context("Failed waiting for apex config done")
687}
688
689fn wait_for_property_true(property_name: &str) -> Result<()> {
690 let mut prop = PropertyWatcher::new(property_name)?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900691 loop {
692 prop.wait()?;
Alan Stokes60f82202022-10-07 16:40:07 +0100693 if system_properties::read_bool(property_name, false)? {
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900694 break;
695 }
696 }
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900697 Ok(())
698}
699
Alice Wang89cff012022-09-26 10:05:16 +0000700fn get_apk_root_hash_from_idsig<P: AsRef<Path>>(idsig_path: P) -> Result<Box<RootHash>> {
701 Ok(V4Signature::from_idsig_path(idsig_path)?.hashing_info.raw_root_hash)
Jiyong Park21ce2c52021-08-28 02:32:17 +0900702}
703
Inseob Kim197748b2021-12-01 19:49:00 +0900704fn get_public_key_from_apk(apk: &str, root_hash_trustful: bool) -> Result<Box<[u8]>> {
705 if !root_hash_trustful {
706 verify(apk).context(MicrodroidError::PayloadVerificationFailed(format!(
707 "failed to verify {}",
708 apk
709 )))
710 } else {
711 get_public_key_der(apk)
712 }
713}
714
Alan Stokes1f417c92022-09-29 15:13:28 +0100715fn load_config(payload_metadata: PayloadMetadata) -> Result<VmPayloadConfig> {
716 match payload_metadata {
717 PayloadMetadata::config_path(path) => {
718 let path = Path::new(&path);
719 info!("loading config from {:?}...", path);
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100720 let file = ioutil::wait_for_file(path, WAIT_TIMEOUT)
721 .with_context(|| format!("Failed to read {:?}", path))?;
Alan Stokes1f417c92022-09-29 15:13:28 +0100722 Ok(serde_json::from_reader(file)?)
723 }
724 PayloadMetadata::config(payload_config) => {
725 let task = Task {
726 type_: TaskType::MicrodroidLauncher,
727 command: payload_config.payload_binary_path,
Alan Stokes1f417c92022-09-29 15:13:28 +0100728 };
729 Ok(VmPayloadConfig {
730 os: OsConfig { name: "microdroid".to_owned() },
731 task: Some(task),
732 apexes: vec![],
733 extra_apks: vec![],
734 prefer_staged: false,
735 export_tombstones: false,
736 enable_authfs: false,
737 })
738 }
739 }
Jooyung Han634e2d72021-06-10 16:27:38 +0900740}
741
Jiyong Park202856e2022-08-22 16:04:26 +0900742/// Loads the crashkernel into memory using kexec if the VM is loaded with `crashkernel=' parameter
743/// in the cmdline.
744fn load_crashkernel_if_supported() -> Result<()> {
745 let supported = std::fs::read_to_string("/proc/cmdline")?.contains(" crashkernel=");
746 info!("ramdump supported: {}", supported);
747 if supported {
748 let status = Command::new("/system/bin/kexec_load").status()?;
749 if !status.success() {
750 return Err(anyhow!("Failed to load crashkernel: {:?}", status));
751 }
752 }
753 Ok(())
754}
755
Inseob Kim090b70b2022-11-16 20:01:14 +0900756/// Executes the given task.
Jooyung Han5c6d4172021-12-06 14:17:52 +0900757fn exec_task(task: &Task, service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
Jiyong Park8611a6c2021-07-09 18:17:44 +0900758 info!("executing main task {:?}...", task);
David Brazdil451cc962022-10-14 14:08:12 +0100759 let mut command = match task.type_ {
760 TaskType::Executable => Command::new(&task.command),
761 TaskType::MicrodroidLauncher => {
762 let mut command = Command::new("/system/bin/microdroid_launcher");
763 command.arg(find_library_path(&task.command)?);
764 command
765 }
766 };
Inseob Kim090b70b2022-11-16 20:01:14 +0900767 command.stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null());
Inseob Kim7f61fe72021-08-20 20:50:47 +0900768
769 info!("notifying payload started");
Inseob Kimc7d28c72021-10-25 14:28:10 +0000770 service.notifyPayloadStarted()?;
Inseob Kim7f61fe72021-08-20 20:50:47 +0900771
Inseob Kim86ca0162021-10-20 02:21:02 +0000772 let exit_status = command.spawn()?.wait()?;
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -0800773 match exit_status.code() {
774 Some(exit_code) => Ok(exit_code),
775 None => Err(match exit_status.signal() {
776 Some(signal) => anyhow!(
777 "Payload exited due to signal: {} ({})",
778 signal,
779 Signal::try_from(signal).map_or("unknown", |s| s.as_str())
780 ),
781 None => anyhow!("Payload has neither exit code nor signal"),
782 }),
783 }
Jooyung Han347d9f22021-05-28 00:05:14 +0900784}
Jooyung Han634e2d72021-06-10 16:27:38 +0900785
Jooyung Han634e2d72021-06-10 16:27:38 +0900786fn find_library_path(name: &str) -> Result<String> {
787 let mut watcher = PropertyWatcher::new("ro.product.cpu.abilist")?;
788 let value = watcher.read(|_name, value| Ok(value.trim().to_string()))?;
789 let abi = value.split(',').next().ok_or_else(|| anyhow!("no abilist"))?;
Alice Wang6bbb6da2022-10-26 12:44:06 +0000790 let path = format!("{}/lib/{}/{}", VM_APK_CONTENTS_PATH, abi, name);
Jooyung Han634e2d72021-06-10 16:27:38 +0900791
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100792 let metadata = fs::metadata(&path).with_context(|| format!("Unable to access {}", path))?;
Jooyung Han634e2d72021-06-10 16:27:38 +0900793 if !metadata.is_file() {
794 bail!("{} is not a file", &path);
795 }
796
797 Ok(path)
798}
Jiyong Park21ce2c52021-08-28 02:32:17 +0900799
800fn to_hex_string(buf: &[u8]) -> String {
801 buf.iter().map(|b| format!("{:02X}", b)).collect()
802}
Shikha Panwar566c9672022-11-15 14:39:58 +0000803
804fn prepare_encryptedstore(dice: &DiceContext) -> Result<Child> {
805 // Use a fixed salt to scope the derivation to this API.
806 // Generated using hexdump -vn32 -e'14/1 "0x%02X, " 1 "\n"' /dev/urandom
807 // TODO(b/241541860) : Move this (& other salts) to a salt container, i.e. a global enum
808 let salt = [
809 0xFC, 0x1D, 0x35, 0x7B, 0x96, 0xF3, 0xEF, 0x17, 0x78, 0x7D, 0x70, 0xED, 0xEA, 0xFE, 0x1D,
810 0x6F, 0xB3, 0xF9, 0x40, 0xCE, 0xDD, 0x99, 0x40, 0xAA, 0xA7, 0x0E, 0x92, 0x73, 0x90, 0x86,
811 0x4A, 0x75,
812 ];
813 let key = dice.get_sealing_key(
814 &salt,
815 ENCRYPTEDSTORE_KEY_IDENTIFIER.as_bytes(),
816 ENCRYPTEDSTORE_KEYSIZE,
817 )?;
818
819 let mut cmd = Command::new(ENCRYPTEDSTORE_BIN);
820 cmd.arg("--blkdevice")
821 .arg(ENCRYPTEDSTORE_BACKING_DEVICE)
822 .arg("--key")
823 .arg(hex::encode(&*key))
Shikha Panwar9fd198f2022-11-18 17:43:43 +0000824 .args(["--mountpoint", ENCRYPTEDSTORE_MOUNTPOINT])
Shikha Panwar566c9672022-11-15 14:39:58 +0000825 .spawn()
826 .context("encryptedstore failed")
827}