blob: 4ebcc2efb4eb2d1f3fadac453118407023e35ef6 [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;
91
Jooyung Handd0a1732021-11-23 15:26:20 +090092#[derive(thiserror::Error, Debug)]
93enum MicrodroidError {
Inseob Kim11f40d02022-06-13 17:16:00 +090094 #[error("Cannot connect to virtualization service: {0}")]
95 FailedToConnectToVirtualizationService(String),
Jooyung Handd0a1732021-11-23 15:26:20 +090096 #[error("Payload has changed: {0}")]
97 PayloadChanged(String),
98 #[error("Payload verification has failed: {0}")]
99 PayloadVerificationFailed(String),
Jooyung Han5c6d4172021-12-06 14:17:52 +0900100 #[error("Payload config is invalid: {0}")]
101 InvalidConfig(String),
Jooyung Handd0a1732021-11-23 15:26:20 +0900102}
103
Alan Stokes2bead0d2022-09-05 16:58:34 +0100104fn translate_error(err: &Error) -> (ErrorCode, String) {
Jooyung Handd0a1732021-11-23 15:26:20 +0900105 if let Some(e) = err.downcast_ref::<MicrodroidError>() {
106 match e {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100107 MicrodroidError::PayloadChanged(msg) => (ErrorCode::PAYLOAD_CHANGED, msg.to_string()),
Jooyung Handd0a1732021-11-23 15:26:20 +0900108 MicrodroidError::PayloadVerificationFailed(msg) => {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100109 (ErrorCode::PAYLOAD_VERIFICATION_FAILED, msg.to_string())
Jooyung Handd0a1732021-11-23 15:26:20 +0900110 }
Alan Stokes2bead0d2022-09-05 16:58:34 +0100111 MicrodroidError::InvalidConfig(msg) => {
112 (ErrorCode::PAYLOAD_CONFIG_INVALID, msg.to_string())
113 }
Inseob Kim11f40d02022-06-13 17:16:00 +0900114
115 // Connection failure won't be reported to VS; return the default value
116 MicrodroidError::FailedToConnectToVirtualizationService(msg) => {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100117 (ErrorCode::UNKNOWN, msg.to_string())
Inseob Kim11f40d02022-06-13 17:16:00 +0900118 }
Jooyung Handd0a1732021-11-23 15:26:20 +0900119 }
120 } else {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100121 (ErrorCode::UNKNOWN, err.to_string())
Jooyung Handd0a1732021-11-23 15:26:20 +0900122 }
123}
124
Inseob Kim11f40d02022-06-13 17:16:00 +0900125fn write_death_reason_to_serial(err: &Error) -> Result<()> {
126 let death_reason = if let Some(e) = err.downcast_ref::<MicrodroidError>() {
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100127 Borrowed(match e {
Inseob Kim11f40d02022-06-13 17:16:00 +0900128 MicrodroidError::FailedToConnectToVirtualizationService(_) => {
129 "MICRODROID_FAILED_TO_CONNECT_TO_VIRTUALIZATION_SERVICE"
130 }
131 MicrodroidError::PayloadChanged(_) => "MICRODROID_PAYLOAD_HAS_CHANGED",
132 MicrodroidError::PayloadVerificationFailed(_) => {
133 "MICRODROID_PAYLOAD_VERIFICATION_FAILED"
134 }
135 MicrodroidError::InvalidConfig(_) => "MICRODROID_INVALID_PAYLOAD_CONFIG",
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100136 })
Inseob Kim11f40d02022-06-13 17:16:00 +0900137 } else {
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100138 // Send context information back after a separator, to ease diagnosis.
139 // These errors occur before the payload runs, so this should not leak sensitive
140 // information.
141 Owned(format!("MICRODROID_UNKNOWN_RUNTIME_ERROR|{:?}", err))
Inseob Kim11f40d02022-06-13 17:16:00 +0900142 };
143
144 let death_reason_bytes = death_reason.as_bytes();
145 let mut sent_total = 0;
146 while sent_total < death_reason_bytes.len() {
147 // TODO(b/220071963): Sometimes, sending more than 16 bytes at once makes MM hang.
148 let begin = sent_total;
149 let end = std::cmp::min(begin.saturating_add(16), death_reason_bytes.len());
150 OpenOptions::new()
151 .read(false)
152 .write(true)
153 .open(FAILURE_SERIAL_DEVICE)?
154 .write_all(&death_reason_bytes[begin..end])?;
155 sent_total = end;
156 }
157
158 Ok(())
159}
160
Inseob Kim1b95f2e2021-08-19 13:17:40 +0900161fn get_vms_rpc_binder() -> Result<Strong<dyn IVirtualMachineService>> {
Andrew Walbran7eb5ca42022-08-08 15:33:34 +0000162 get_vsock_rpc_interface(VMADDR_CID_HOST, VM_BINDER_SERVICE_PORT as u32)
Andrew Walbranc4ce7872022-07-29 11:26:41 +0000163 .context("Cannot connect to RPC service")
Inseob Kim1b95f2e2021-08-19 13:17:40 +0900164}
165
Inseob Kim437f1052022-06-21 11:30:22 +0900166fn main() -> Result<()> {
Inseob Kim7ff121c2022-11-14 18:13:23 +0900167 // If debuggable, print full backtrace to console log with stdio_to_kmsg
168 if system_properties::read_bool(APP_DEBUGGABLE_PROP, true)? {
169 env::set_var("RUST_BACKTRACE", "full");
170 }
171
Inseob Kim437f1052022-06-21 11:30:22 +0900172 scopeguard::defer! {
173 info!("Shutting down...");
Jooyung Hanbfe086f2021-10-28 10:15:45 +0900174 if let Err(e) = system_properties::write("sys.powerctl", "shutdown") {
175 error!("failed to shutdown {:?}", e);
176 }
Jooyung Han311b1202021-09-14 22:00:16 +0900177 }
Inseob Kim437f1052022-06-21 11:30:22 +0900178
179 try_main().map_err(|e| {
180 error!("Failed with {:?}.", e);
181 if let Err(e) = write_death_reason_to_serial(&e) {
182 error!("Failed to write death reason {:?}", e);
183 }
184 e
185 })
Jooyung Han311b1202021-09-14 22:00:16 +0900186}
187
Inseob Kim090b70b2022-11-16 20:01:14 +0900188fn set_cloexec_on_vm_payload_service_socket() -> Result<()> {
189 let fd = android_get_control_socket(VM_PAYLOAD_SERVICE_SOCKET_NAME)?;
190
191 fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC))?;
192
193 Ok(())
194}
195
Jooyung Han311b1202021-09-14 22:00:16 +0900196fn try_main() -> Result<()> {
Andrew Sculle127cff2022-02-15 15:34:04 +0000197 let _ = kernlog::init();
Jooyung Han347d9f22021-05-28 00:05:14 +0900198 info!("started.");
199
Inseob Kim090b70b2022-11-16 20:01:14 +0900200 if let Err(e) = set_cloexec_on_vm_payload_service_socket() {
201 warn!("Failed to set cloexec on vm payload socket: {:?}", e);
202 }
203
Jiyong Park202856e2022-08-22 16:04:26 +0900204 load_crashkernel_if_supported().context("Failed to load crashkernel")?;
205
Keir Fraser933f0ac2022-10-12 08:23:28 +0000206 swap::init_swap().context("Failed to initialise swap")?;
207 info!("swap enabled.");
208
Inseob Kim11f40d02022-06-13 17:16:00 +0900209 let service = get_vms_rpc_binder()
210 .context("cannot connect to VirtualMachineService")
211 .map_err(|e| MicrodroidError::FailedToConnectToVirtualizationService(e.to_string()))?;
Seungjae Yoofd9a0622022-10-14 10:01:29 +0900212
Jooyung Han5c6d4172021-12-06 14:17:52 +0900213 match try_run_payload(&service) {
214 Ok(code) => {
215 info!("notifying payload finished");
216 service.notifyPayloadFinished(code)?;
217 if code == 0 {
218 info!("task successfully finished");
219 } else {
220 error!("task exited with exit code: {}", code);
221 }
222 Ok(())
223 }
224 Err(err) => {
Jooyung Han5c6d4172021-12-06 14:17:52 +0900225 let (error_code, message) = translate_error(&err);
226 service.notifyError(error_code, &message)?;
227 Err(err)
228 }
Jooyung Handd0a1732021-11-23 15:26:20 +0900229 }
230}
231
Alan Stokes1f417c92022-09-29 15:13:28 +0100232fn dice_derivation(
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000233 dice: DiceDriver,
Alan Stokes1f417c92022-09-29 15:13:28 +0100234 verified_data: &MicrodroidData,
235 payload_metadata: &PayloadMetadata,
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000236) -> Result<DiceContext> {
Andrew Scullb2f44472022-01-21 14:41:34 +0000237 // Calculate compound digests of code and authorities
Andrew Sculla0d1b1a2022-05-24 19:32:47 +0000238 let mut code_hash_ctx = Sha512::new();
239 let mut authority_hash_ctx = Sha512::new();
Andrew Scullb2f44472022-01-21 14:41:34 +0000240 code_hash_ctx.update(verified_data.apk_data.root_hash.as_ref());
241 authority_hash_ctx.update(verified_data.apk_data.pubkey.as_ref());
Inseob Kimb2519c52022-04-14 02:10:09 +0900242 for extra_apk in &verified_data.extra_apks_data {
Andrew Scullb2f44472022-01-21 14:41:34 +0000243 code_hash_ctx.update(extra_apk.root_hash.as_ref());
244 authority_hash_ctx.update(extra_apk.pubkey.as_ref());
245 }
Inseob Kimb2519c52022-04-14 02:10:09 +0900246 for apex in &verified_data.apex_data {
Andrew Scullb2f44472022-01-21 14:41:34 +0000247 code_hash_ctx.update(apex.root_digest.as_ref());
248 authority_hash_ctx.update(apex.public_key.as_ref());
249 }
Andrew Sculla0d1b1a2022-05-24 19:32:47 +0000250 let code_hash = code_hash_ctx.finish();
251 let authority_hash = authority_hash_ctx.finish();
Andrew Scullb2f44472022-01-21 14:41:34 +0000252
253 // {
254 // -70002: "Microdroid payload",
Alan Stokes1f417c92022-09-29 15:13:28 +0100255 // ? -71000: tstr // payload_config_path
256 // ? -71001: PayloadConfig
Andrew Scullb2f44472022-01-21 14:41:34 +0000257 // }
Alan Stokes1f417c92022-09-29 15:13:28 +0100258 // PayloadConfig = {
259 // 1: tstr // payload_binary_path
Alan Stokes1f417c92022-09-29 15:13:28 +0100260 // }
261
Andrew Scullb2f44472022-01-21 14:41:34 +0000262 let mut config_desc = vec![
Alan Stokes1f417c92022-09-29 15:13:28 +0100263 0xa2, // map(2)
264 0x3a, 0x00, 0x01, 0x11, 0x71, // -70002
265 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79,
266 0x6c, 0x6f, 0x61, 0x64, // "Microdroid payload"
Andrew Scullb2f44472022-01-21 14:41:34 +0000267 ];
Alan Stokes1f417c92022-09-29 15:13:28 +0100268
269 match payload_metadata {
270 PayloadMetadata::config_path(payload_config_path) => {
271 encode_negative_number(-71000, &mut config_desc)?;
272 encode_tstr(payload_config_path, &mut config_desc)?;
273 }
274 PayloadMetadata::config(payload_config) => {
275 encode_negative_number(-71001, &mut config_desc)?;
276 encode_header(5, 1, &mut config_desc)?; // map(1)
277 encode_number(1, &mut config_desc)?;
278 encode_tstr(&payload_config.payload_binary_path, &mut config_desc)?;
279 }
280 }
Andrew Scullb2f44472022-01-21 14:41:34 +0000281
Andrew Scull65ddfc42022-02-14 21:03:58 +0000282 // Check app debuggability, conervatively assuming it is debuggable
283 let app_debuggable = system_properties::read_bool(APP_DEBUGGABLE_PROP, true)?;
284
Andrew Scullb2f44472022-01-21 14:41:34 +0000285 // Send the details to diced
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000286 let hidden = verified_data.salt.clone().try_into().unwrap();
287 dice.derive(code_hash, &config_desc, authority_hash, app_debuggable, hidden)
Andrew Scullb2f44472022-01-21 14:41:34 +0000288}
289
Alan Stokes1f417c92022-09-29 15:13:28 +0100290fn encode_tstr(tstr: &str, buffer: &mut Vec<u8>) -> Result<()> {
291 let bytes = tstr.as_bytes();
292 encode_header(3, bytes.len().try_into().unwrap(), buffer)?;
293 buffer.extend_from_slice(bytes);
294 Ok(())
295}
296
297fn encode_negative_number(n: i64, buffer: &mut dyn Write) -> Result<()> {
298 ensure!(n < 0);
299 let n = -1 - n;
300 encode_header(1, n.try_into().unwrap(), buffer)
301}
302
Andrew Scullab72ec52022-03-14 09:10:52 +0000303fn is_strict_boot() -> bool {
304 Path::new(AVF_STRICT_BOOT).exists()
305}
306
307fn is_new_instance() -> bool {
308 Path::new(AVF_NEW_INSTANCE).exists()
309}
310
Inseob Kime379e7d2022-07-22 18:55:18 +0900311fn is_verified_boot() -> bool {
312 !Path::new(DEBUG_MICRODROID_NO_VERIFIED_BOOT).exists()
313}
314
Jooyung Han5c6d4172021-12-06 14:17:52 +0900315fn try_run_payload(service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
Jooyung Han311b1202021-09-14 22:00:16 +0900316 let metadata = load_metadata().context("Failed to load payload metadata")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000317 let dice = DiceDriver::new(Path::new("/dev/open-dice0")).context("Failed to load DICE")?;
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900318
Jooyung Han311b1202021-09-14 22:00:16 +0900319 let mut instance = InstanceDisk::new().context("Failed to load instance.img")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000320 let saved_data =
321 instance.read_microdroid_data(&dice).context("Failed to read identity data")?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900322
Andrew Scullab72ec52022-03-14 09:10:52 +0000323 if is_strict_boot() {
324 // Provisioning must happen on the first boot and never again.
325 if is_new_instance() {
326 ensure!(
327 saved_data.is_none(),
328 MicrodroidError::InvalidConfig("Found instance data on first boot.".to_string())
329 );
330 } else {
331 ensure!(
332 saved_data.is_some(),
333 MicrodroidError::InvalidConfig("Instance data not found.".to_string())
334 );
335 };
336 }
337
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900338 // Verify the payload before using it.
Inseob Kim11f40d02022-06-13 17:16:00 +0900339 let verified_data = verify_payload(&metadata, saved_data.as_ref())
340 .context("Payload verification failed")
341 .map_err(|e| MicrodroidError::PayloadVerificationFailed(e.to_string()))?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900342
343 // In case identity is ignored (by debug policy), we should reuse existing payload data, even
344 // when the payload is changed. This is to keep the derived secret same as before.
345 let verified_data = if let Some(saved_data) = saved_data {
346 if !is_verified_boot() {
347 if saved_data != verified_data {
348 info!("Detected an update of the payload, but continue (regarding debug policy)")
349 }
350 } else {
351 ensure!(
352 saved_data == verified_data,
353 MicrodroidError::PayloadChanged(String::from(
354 "Detected an update of the payload which isn't supported yet."
355 ))
356 );
357 info!("Saved data is verified.");
358 }
359 saved_data
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900360 } else {
Jooyung Han7a343f92021-09-08 22:53:11 +0900361 info!("Saving verified data.");
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000362 instance
363 .write_microdroid_data(&verified_data, &dice)
364 .context("Failed to write identity data")?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900365 verified_data
366 };
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900367
Alan Stokes1f417c92022-09-29 15:13:28 +0100368 let payload_metadata = metadata.payload.ok_or_else(|| {
369 MicrodroidError::InvalidConfig("No payload config in metadata".to_string())
370 })?;
Alan Stokes0d1ef782022-09-27 13:46:35 +0100371
Inseob Kimb2519c52022-04-14 02:10:09 +0900372 // To minimize the exposure to untrusted data, derive dice profile as soon as possible.
373 info!("DICE derivation for payload");
Shikha Panwar566c9672022-11-15 14:39:58 +0000374 let dice_context = dice_derivation(dice, &verified_data, &payload_metadata)?;
375
376 // Run encryptedstore binary to prepare the storage
377 let encryptedstore_child = if Path::new(ENCRYPTEDSTORE_BACKING_DEVICE).exists() {
378 info!("Preparing encryptedstore ...");
379 Some(prepare_encryptedstore(&dice_context).context("encryptedstore run")?)
380 } else {
381 None
382 };
Inseob Kimb2519c52022-04-14 02:10:09 +0900383
Jooyung Hana6d11eb2021-09-10 11:48:05 +0900384 // Before reading a file from the APK, start zipfuse
Inseob Kim217038e2021-11-25 11:15:06 +0900385 run_zipfuse(
Alan Stokes60f82202022-10-07 16:40:07 +0100386 MountForExec::Allowed,
Inseob Kim217038e2021-11-25 11:15:06 +0900387 "fscontext=u:object_r:zipfusefs:s0,context=u:object_r:system_file:s0",
388 Path::new("/dev/block/mapper/microdroid-apk"),
Alice Wang6bbb6da2022-10-26 12:44:06 +0000389 Path::new(VM_APK_CONTENTS_PATH),
Alan Stokes60f82202022-10-07 16:40:07 +0100390 Some(APK_MOUNT_DONE_PROP),
Inseob Kim217038e2021-11-25 11:15:06 +0900391 )
392 .context("Failed to run zipfuse")?;
Jiyong Park21ce2c52021-08-28 02:32:17 +0900393
Andrew Scull4d262dc2022-10-21 13:14:33 +0000394 // Restricted APIs are only allowed to be used by platform or test components. Infer this from
395 // the use of a VM config file since those can only be used by platform and test components.
396 let allow_restricted_apis = match payload_metadata {
397 PayloadMetadata::config_path(_) => true,
398 PayloadMetadata::config(_) => false,
399 };
400
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100401 let config = load_config(payload_metadata).context("Failed to load payload metadata")?;
Shikha Panwar6f03c942022-04-13 20:26:50 +0000402
Alan Stokes01b3ef02022-09-22 17:43:24 +0100403 let task = config
404 .task
405 .as_ref()
406 .ok_or_else(|| MicrodroidError::InvalidConfig("No task in VM config".to_string()))?;
407
Inseob Kim197748b2021-12-01 19:49:00 +0900408 if config.extra_apks.len() != verified_data.extra_apks_data.len() {
409 return Err(anyhow!(
Alan Stokes1f417c92022-09-29 15:13:28 +0100410 "config expects {} extra apks, but found {}",
Inseob Kim197748b2021-12-01 19:49:00 +0900411 config.extra_apks.len(),
412 verified_data.extra_apks_data.len()
413 ));
414 }
415 mount_extra_apks(&config)?;
Jooyung Han634e2d72021-06-10 16:27:38 +0900416
Jooyung Han5c6d4172021-12-06 14:17:52 +0900417 // Wait until apex config is done. (e.g. linker configuration for apexes)
418 // TODO(jooyung): wait until sys.boot_completed?
419 wait_for_apex_config_done()?;
420
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900421 // Start tombstone_transmit if enabled
422 if config.export_tombstones {
Alan Stokes01b3ef02022-09-22 17:43:24 +0100423 control_service("start", "tombstone_transmit")?;
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900424 } else {
Alan Stokes01b3ef02022-09-22 17:43:24 +0100425 control_service("stop", "tombstoned")?;
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900426 }
427
Alan Stokes01b3ef02022-09-22 17:43:24 +0100428 // Start authfs if enabled
429 if config.enable_authfs {
430 control_service("start", "authfs_service")?;
431 }
432
Alan Stokes60f82202022-10-07 16:40:07 +0100433 // Wait until zipfuse has mounted the APK so we can access the payload
434 wait_for_property_true(APK_MOUNT_DONE_PROP).context("Failed waiting for APK mount done")?;
435
Shikha Panwar566c9672022-11-15 14:39:58 +0000436 register_vm_payload_service(allow_restricted_apis, service.clone(), dice_context)?;
437
438 if let Some(mut child) = encryptedstore_child {
439 let exitcode = child.wait().context("Wait for encryptedstore child")?;
440 ensure!(exitcode.success(), "Unable to prepare encrypted storage. Exitcode={}", exitcode);
441 }
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100442
443 system_properties::write("dev.bootcomplete", "1").context("set dev.bootcomplete")?;
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100444 exec_task(task, service).context("Failed to run payload")
Alan Stokes01b3ef02022-09-22 17:43:24 +0100445}
446
447fn control_service(action: &str, service: &str) -> Result<()> {
448 system_properties::write(&format!("ctl.{}", action), service)
449 .with_context(|| format!("Failed to {} {}", action, service))
Jooyung Han347d9f22021-05-28 00:05:14 +0900450}
451
Inseob Kim217038e2021-11-25 11:15:06 +0900452struct ApkDmverityArgument<'a> {
453 apk: &'a str,
454 idsig: &'a str,
455 name: &'a str,
Inseob Kim197748b2021-12-01 19:49:00 +0900456 saved_root_hash: Option<&'a RootHash>,
Inseob Kim217038e2021-11-25 11:15:06 +0900457}
458
459fn run_apkdmverity(args: &[ApkDmverityArgument]) -> Result<Child> {
460 let mut cmd = Command::new(APKDMVERITY_BIN);
461
Inseob Kim217038e2021-11-25 11:15:06 +0900462 for argument in args {
463 cmd.arg("--apk").arg(argument.apk).arg(argument.idsig).arg(argument.name);
Inseob Kim197748b2021-12-01 19:49:00 +0900464 if let Some(root_hash) = argument.saved_root_hash {
465 cmd.arg(&to_hex_string(root_hash));
466 } else {
467 cmd.arg("none");
468 }
Inseob Kim217038e2021-11-25 11:15:06 +0900469 }
470
471 cmd.spawn().context("Spawn apkdmverity")
472}
473
Alan Stokes60f82202022-10-07 16:40:07 +0100474enum MountForExec {
475 Allowed,
476 Disallowed,
477}
478
479fn run_zipfuse(
480 noexec: MountForExec,
481 option: &str,
482 zip_path: &Path,
483 mount_dir: &Path,
484 ready_prop: Option<&str>,
485) -> Result<Child> {
Andrew Scullcc339a12022-07-04 12:44:19 +0000486 let mut cmd = Command::new(ZIPFUSE_BIN);
Alan Stokes60f82202022-10-07 16:40:07 +0100487 if let MountForExec::Disallowed = noexec {
Andrew Scullcc339a12022-07-04 12:44:19 +0000488 cmd.arg("--noexec");
489 }
Alan Stokes60f82202022-10-07 16:40:07 +0100490 if let Some(property_name) = ready_prop {
491 cmd.args(["-p", property_name]);
492 }
Inseob Kimadd7b7f2022-11-21 15:06:05 +0900493 cmd.arg("-o").arg(option).arg(zip_path).arg(mount_dir).spawn().context("Spawn zipfuse")
Inseob Kim217038e2021-11-25 11:15:06 +0900494}
495
Inseob Kime379e7d2022-07-22 18:55:18 +0900496fn write_apex_payload_data(
497 saved_data: Option<&MicrodroidData>,
498 apex_data_from_payload: &[ApexData],
499) -> Result<()> {
500 if let Some(saved_apex_data) = saved_data.map(|d| &d.apex_data) {
501 // We don't support APEX updates. (assuming that update will change root digest)
502 ensure!(
503 saved_apex_data == apex_data_from_payload,
504 MicrodroidError::PayloadChanged(String::from("APEXes have changed."))
505 );
506 let apex_metadata = to_metadata(apex_data_from_payload);
507 // Pass metadata(with public keys and root digests) to apexd so that it uses the passed
508 // metadata instead of the default one (/dev/block/by-name/payload-metadata)
509 OpenOptions::new()
510 .create_new(true)
511 .write(true)
512 .open("/apex/vm-payload-metadata")
513 .context("Failed to open /apex/vm-payload-metadata")
514 .and_then(|f| write_metadata(&apex_metadata, f))?;
515 }
516 Ok(())
517}
518
Jooyung Han7a343f92021-09-08 22:53:11 +0900519// Verify payload before executing it. For APK payload, Full verification (which is slow) is done
520// when the root_hash values from the idsig file and the instance disk are different. This function
521// returns the verified root hash (for APK payload) and pubkeys (for APEX payloads) that can be
522// saved to the instance disk.
523fn verify_payload(
524 metadata: &Metadata,
525 saved_data: Option<&MicrodroidData>,
526) -> Result<MicrodroidData> {
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900527 let start_time = SystemTime::now();
528
Inseob Kim197748b2021-12-01 19:49:00 +0900529 // Verify main APK
Jooyung Han7a343f92021-09-08 22:53:11 +0900530 let root_hash = saved_data.map(|d| &d.apk_data.root_hash);
Inseob Kim197748b2021-12-01 19:49:00 +0900531 let root_hash_from_idsig = get_apk_root_hash_from_idsig(MAIN_APK_IDSIG_PATH)?;
Jiyong Parkf7dea252021-09-08 01:42:54 +0900532 let root_hash_trustful = root_hash == Some(&root_hash_from_idsig);
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900533
Jiyong Parkf7dea252021-09-08 01:42:54 +0900534 // 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 +0900535 // instead of the value read from the idsig file.
Inseob Kim197748b2021-12-01 19:49:00 +0900536 let main_apk_argument = {
537 ApkDmverityArgument {
538 apk: MAIN_APK_PATH,
539 idsig: MAIN_APK_IDSIG_PATH,
540 name: MAIN_APK_DEVICE_NAME,
541 saved_root_hash: if root_hash_trustful {
542 Some(root_hash_from_idsig.as_ref())
543 } else {
544 None
545 },
546 }
547 };
548 let mut apkdmverity_arguments = vec![main_apk_argument];
549
550 // Verify extra APKs
551 // For now, we can't read the payload config, so glob APKs and idsigs.
552 // Later, we'll see if it matches with the payload config.
553
554 // sort globbed paths to match apks (extra-apk-{idx}) and idsigs (extra-idsig-{idx})
555 // e.g. "extra-apk-0" corresponds to "extra-idsig-0"
556 let extra_apks =
557 sorted(glob(EXTRA_APK_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
558 let extra_idsigs =
559 sorted(glob(EXTRA_IDSIG_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
560 if extra_apks.len() != extra_idsigs.len() {
561 return Err(anyhow!(
562 "Extra apks/idsigs mismatch: {} apks but {} idsigs",
563 extra_apks.len(),
564 extra_idsigs.len()
565 ));
566 }
567 let extra_apks_count = extra_apks.len();
568
569 let (extra_apk_names, extra_root_hashes_from_idsig): (Vec<_>, Vec<_>) = extra_idsigs
570 .iter()
571 .enumerate()
572 .map(|(i, extra_idsig)| {
573 (
574 format!("extra-apk-{}", i),
Alice Wang89cff012022-09-26 10:05:16 +0000575 get_apk_root_hash_from_idsig(extra_idsig)
Inseob Kim197748b2021-12-01 19:49:00 +0900576 .expect("Can't find root hash from extra idsig"),
577 )
578 })
579 .unzip();
580
581 let saved_extra_root_hashes: Vec<_> = saved_data
582 .map(|d| d.extra_apks_data.iter().map(|apk_data| &apk_data.root_hash).collect())
583 .unwrap_or_else(Vec::new);
584 let extra_root_hashes_trustful: Vec<_> = extra_root_hashes_from_idsig
585 .iter()
586 .enumerate()
587 .map(|(i, root_hash_from_idsig)| {
588 saved_extra_root_hashes.get(i).copied() == Some(root_hash_from_idsig)
589 })
590 .collect();
591
592 for i in 0..extra_apks_count {
593 apkdmverity_arguments.push({
594 ApkDmverityArgument {
595 apk: extra_apks[i].to_str().unwrap(),
596 idsig: extra_idsigs[i].to_str().unwrap(),
597 name: &extra_apk_names[i],
598 saved_root_hash: if extra_root_hashes_trustful[i] {
599 Some(&extra_root_hashes_from_idsig[i])
600 } else {
601 None
602 },
603 }
604 });
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900605 }
606
607 // Start apkdmverity and wait for the dm-verify block
Inseob Kim197748b2021-12-01 19:49:00 +0900608 let mut apkdmverity_child = run_apkdmverity(&apkdmverity_arguments)?;
Jooyung Han7a343f92021-09-08 22:53:11 +0900609
Jooyung Hanc8deb472021-09-13 13:48:25 +0900610 // While waiting for apkdmverity to mount APK, gathers public keys and root digests from
611 // APEX payload.
Jooyung Han7a343f92021-09-08 22:53:11 +0900612 let apex_data_from_payload = get_apex_data_from_payload(metadata)?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900613
614 // Writing /apex/vm-payload-metadata is to verify that the payload isn't changed.
615 // Skip writing it if the debug policy ignoring identity is on
616 if is_verified_boot() {
617 write_apex_payload_data(saved_data, &apex_data_from_payload)?;
Jooyung Han4a9b3bf2021-09-10 17:19:00 +0900618 }
Inseob Kime379e7d2022-07-22 18:55:18 +0900619
Jooyung Han4a9b3bf2021-09-10 17:19:00 +0900620 // Start apexd to activate APEXes
621 system_properties::write("ctl.start", "apexd-vm")?;
Jooyung Han7a343f92021-09-08 22:53:11 +0900622
Inseob Kim217038e2021-11-25 11:15:06 +0900623 // TODO(inseob): add timeout
624 apkdmverity_child.wait()?;
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900625
Jiyong Parkf7dea252021-09-08 01:42:54 +0900626 // Do the full verification if the root_hash is un-trustful. This requires the full scanning of
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900627 // 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 +0900628 // 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 +0900629 // of the VM or APK was updated in the host.
630 // TODO(jooyung): consider multithreading to make this faster
Inseob Kim197748b2021-12-01 19:49:00 +0900631 let main_apk_pubkey = get_public_key_from_apk(DM_MOUNTED_APK_PATH, root_hash_trustful)?;
632 let extra_apks_data = extra_root_hashes_from_idsig
633 .into_iter()
634 .enumerate()
635 .map(|(i, extra_root_hash)| {
636 let mount_path = format!("/dev/block/mapper/{}", &extra_apk_names[i]);
637 let apk_pubkey = get_public_key_from_apk(&mount_path, extra_root_hashes_trustful[i])?;
638 Ok(ApkData { root_hash: extra_root_hash, pubkey: apk_pubkey })
639 })
640 .collect::<Result<Vec<_>>>()?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900641
642 info!("payload verification successful. took {:#?}", start_time.elapsed().unwrap());
643
Andrew Scull34916a72022-01-30 21:34:24 +0000644 // Use the salt from a verified instance, or generate a salt for a new instance.
645 let salt = if let Some(saved_data) = saved_data {
646 saved_data.salt.clone()
647 } else {
648 let mut salt = vec![0u8; 64];
649 salt.as_mut_slice().try_fill(&mut rand::thread_rng())?;
650 salt
651 };
652
Jiyong Parkf7dea252021-09-08 01:42:54 +0900653 // At this point, we can ensure that the root_hash from the idsig file is trusted, either by
654 // fully verifying the APK or by comparing it with the saved root_hash.
Jooyung Han7a343f92021-09-08 22:53:11 +0900655 Ok(MicrodroidData {
Andrew Scull34916a72022-01-30 21:34:24 +0000656 salt,
Inseob Kim197748b2021-12-01 19:49:00 +0900657 apk_data: ApkData { root_hash: root_hash_from_idsig, pubkey: main_apk_pubkey },
658 extra_apks_data,
Jooyung Han7a343f92021-09-08 22:53:11 +0900659 apex_data: apex_data_from_payload,
660 })
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900661}
662
Inseob Kim197748b2021-12-01 19:49:00 +0900663fn mount_extra_apks(config: &VmPayloadConfig) -> Result<()> {
664 // For now, only the number of apks is important, as the mount point and dm-verity name is fixed
665 for i in 0..config.extra_apks.len() {
666 let mount_dir = format!("/mnt/extra-apk/{}", i);
667 create_dir(Path::new(&mount_dir)).context("Failed to create mount dir for extra apks")?;
668
669 // don't wait, just detach
670 run_zipfuse(
Alan Stokes60f82202022-10-07 16:40:07 +0100671 MountForExec::Disallowed,
Inseob Kim197748b2021-12-01 19:49:00 +0900672 "fscontext=u:object_r:zipfusefs:s0,context=u:object_r:extra_apk_file:s0",
673 Path::new(&format!("/dev/block/mapper/extra-apk-{}", i)),
674 Path::new(&mount_dir),
Alan Stokes60f82202022-10-07 16:40:07 +0100675 None,
Inseob Kim197748b2021-12-01 19:49:00 +0900676 )
677 .context("Failed to zipfuse extra apks")?;
678 }
679
680 Ok(())
681}
682
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900683// Waits until linker config is generated
684fn wait_for_apex_config_done() -> Result<()> {
Alan Stokes60f82202022-10-07 16:40:07 +0100685 wait_for_property_true(APEX_CONFIG_DONE_PROP).context("Failed waiting for apex config done")
686}
687
688fn wait_for_property_true(property_name: &str) -> Result<()> {
689 let mut prop = PropertyWatcher::new(property_name)?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900690 loop {
691 prop.wait()?;
Alan Stokes60f82202022-10-07 16:40:07 +0100692 if system_properties::read_bool(property_name, false)? {
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900693 break;
694 }
695 }
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900696 Ok(())
697}
698
Alice Wang89cff012022-09-26 10:05:16 +0000699fn get_apk_root_hash_from_idsig<P: AsRef<Path>>(idsig_path: P) -> Result<Box<RootHash>> {
700 Ok(V4Signature::from_idsig_path(idsig_path)?.hashing_info.raw_root_hash)
Jiyong Park21ce2c52021-08-28 02:32:17 +0900701}
702
Inseob Kim197748b2021-12-01 19:49:00 +0900703fn get_public_key_from_apk(apk: &str, root_hash_trustful: bool) -> Result<Box<[u8]>> {
704 if !root_hash_trustful {
705 verify(apk).context(MicrodroidError::PayloadVerificationFailed(format!(
706 "failed to verify {}",
707 apk
708 )))
709 } else {
710 get_public_key_der(apk)
711 }
712}
713
Alan Stokes1f417c92022-09-29 15:13:28 +0100714fn load_config(payload_metadata: PayloadMetadata) -> Result<VmPayloadConfig> {
715 match payload_metadata {
716 PayloadMetadata::config_path(path) => {
717 let path = Path::new(&path);
718 info!("loading config from {:?}...", path);
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100719 let file = ioutil::wait_for_file(path, WAIT_TIMEOUT)
720 .with_context(|| format!("Failed to read {:?}", path))?;
Alan Stokes1f417c92022-09-29 15:13:28 +0100721 Ok(serde_json::from_reader(file)?)
722 }
723 PayloadMetadata::config(payload_config) => {
724 let task = Task {
725 type_: TaskType::MicrodroidLauncher,
726 command: payload_config.payload_binary_path,
Alan Stokes1f417c92022-09-29 15:13:28 +0100727 };
728 Ok(VmPayloadConfig {
729 os: OsConfig { name: "microdroid".to_owned() },
730 task: Some(task),
731 apexes: vec![],
732 extra_apks: vec![],
733 prefer_staged: false,
734 export_tombstones: false,
735 enable_authfs: false,
736 })
737 }
738 }
Jooyung Han634e2d72021-06-10 16:27:38 +0900739}
740
Jiyong Park202856e2022-08-22 16:04:26 +0900741/// Loads the crashkernel into memory using kexec if the VM is loaded with `crashkernel=' parameter
742/// in the cmdline.
743fn load_crashkernel_if_supported() -> Result<()> {
744 let supported = std::fs::read_to_string("/proc/cmdline")?.contains(" crashkernel=");
745 info!("ramdump supported: {}", supported);
746 if supported {
747 let status = Command::new("/system/bin/kexec_load").status()?;
748 if !status.success() {
749 return Err(anyhow!("Failed to load crashkernel: {:?}", status));
750 }
751 }
752 Ok(())
753}
754
Inseob Kim090b70b2022-11-16 20:01:14 +0900755/// Executes the given task.
Jooyung Han5c6d4172021-12-06 14:17:52 +0900756fn exec_task(task: &Task, service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
Jiyong Park8611a6c2021-07-09 18:17:44 +0900757 info!("executing main task {:?}...", task);
David Brazdil451cc962022-10-14 14:08:12 +0100758 let mut command = match task.type_ {
759 TaskType::Executable => Command::new(&task.command),
760 TaskType::MicrodroidLauncher => {
761 let mut command = Command::new("/system/bin/microdroid_launcher");
762 command.arg(find_library_path(&task.command)?);
763 command
764 }
765 };
Inseob Kim090b70b2022-11-16 20:01:14 +0900766 command.stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null());
Inseob Kim7f61fe72021-08-20 20:50:47 +0900767
768 info!("notifying payload started");
Inseob Kimc7d28c72021-10-25 14:28:10 +0000769 service.notifyPayloadStarted()?;
Inseob Kim7f61fe72021-08-20 20:50:47 +0900770
Inseob Kim86ca0162021-10-20 02:21:02 +0000771 let exit_status = command.spawn()?.wait()?;
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -0800772 match exit_status.code() {
773 Some(exit_code) => Ok(exit_code),
774 None => Err(match exit_status.signal() {
775 Some(signal) => anyhow!(
776 "Payload exited due to signal: {} ({})",
777 signal,
778 Signal::try_from(signal).map_or("unknown", |s| s.as_str())
779 ),
780 None => anyhow!("Payload has neither exit code nor signal"),
781 }),
782 }
Jooyung Han347d9f22021-05-28 00:05:14 +0900783}
Jooyung Han634e2d72021-06-10 16:27:38 +0900784
Jooyung Han634e2d72021-06-10 16:27:38 +0900785fn find_library_path(name: &str) -> Result<String> {
786 let mut watcher = PropertyWatcher::new("ro.product.cpu.abilist")?;
787 let value = watcher.read(|_name, value| Ok(value.trim().to_string()))?;
788 let abi = value.split(',').next().ok_or_else(|| anyhow!("no abilist"))?;
Alice Wang6bbb6da2022-10-26 12:44:06 +0000789 let path = format!("{}/lib/{}/{}", VM_APK_CONTENTS_PATH, abi, name);
Jooyung Han634e2d72021-06-10 16:27:38 +0900790
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100791 let metadata = fs::metadata(&path).with_context(|| format!("Unable to access {}", path))?;
Jooyung Han634e2d72021-06-10 16:27:38 +0900792 if !metadata.is_file() {
793 bail!("{} is not a file", &path);
794 }
795
796 Ok(path)
797}
Jiyong Park21ce2c52021-08-28 02:32:17 +0900798
799fn to_hex_string(buf: &[u8]) -> String {
800 buf.iter().map(|b| format!("{:02X}", b)).collect()
801}
Shikha Panwar566c9672022-11-15 14:39:58 +0000802
803fn prepare_encryptedstore(dice: &DiceContext) -> Result<Child> {
804 // Use a fixed salt to scope the derivation to this API.
805 // Generated using hexdump -vn32 -e'14/1 "0x%02X, " 1 "\n"' /dev/urandom
806 // TODO(b/241541860) : Move this (& other salts) to a salt container, i.e. a global enum
807 let salt = [
808 0xFC, 0x1D, 0x35, 0x7B, 0x96, 0xF3, 0xEF, 0x17, 0x78, 0x7D, 0x70, 0xED, 0xEA, 0xFE, 0x1D,
809 0x6F, 0xB3, 0xF9, 0x40, 0xCE, 0xDD, 0x99, 0x40, 0xAA, 0xA7, 0x0E, 0x92, 0x73, 0x90, 0x86,
810 0x4A, 0x75,
811 ];
812 let key = dice.get_sealing_key(
813 &salt,
814 ENCRYPTEDSTORE_KEY_IDENTIFIER.as_bytes(),
815 ENCRYPTEDSTORE_KEYSIZE,
816 )?;
817
818 let mut cmd = Command::new(ENCRYPTEDSTORE_BIN);
819 cmd.arg("--blkdevice")
820 .arg(ENCRYPTEDSTORE_BACKING_DEVICE)
821 .arg("--key")
822 .arg(hex::encode(&*key))
823 .spawn()
824 .context("encryptedstore failed")
825}