blob: a706dbe115116a355bf40541a79c965c56c5c0c5 [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,
32};
Jooyung Handd0a1732021-11-23 15:26:20 +090033use anyhow::{anyhow, bail, ensure, Context, Error, Result};
Alice Wang1bf3d782022-09-28 07:56:36 +000034use apkverify::{get_public_key_der, verify, V4Signature};
Alice Wang43c884b2022-10-24 09:42:40 +000035use binder::Strong;
Alan Stokes1f417c92022-09-29 15:13:28 +010036use diced_utils::cbor::{encode_header, encode_number};
Inseob Kim197748b2021-12-01 19:49:00 +090037use glob::glob;
Inseob Kim197748b2021-12-01 19:49:00 +090038use itertools::sorted;
David Brazdila07a1792022-10-25 13:37:57 +010039use libc::VMADDR_CID_HOST;
Inseob Kim090b70b2022-11-16 20:01:14 +090040use log::{error, info, warn};
Alan Stokes0d1ef782022-09-27 13:46:35 +010041use microdroid_metadata::{write_metadata, Metadata, PayloadMetadata};
Seungjae Yoofd9a0622022-10-14 10:01:29 +090042use microdroid_payload_config::{OsConfig, Task, TaskType, VmPayloadConfig};
Inseob Kim090b70b2022-11-16 20:01:14 +090043use nix::fcntl::{fcntl, F_SETFD, FdFlag};
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -080044use nix::sys::signal::Signal;
Andrew Sculla0d1b1a2022-05-24 19:32:47 +000045use openssl::sha::Sha512;
Jooyung Han4a9b3bf2021-09-10 17:19:00 +090046use payload::{get_apex_data_from_payload, load_metadata, to_metadata};
Andrew Scull34916a72022-01-30 21:34:24 +000047use rand::Fill;
Andrew Walbran7eb5ca42022-08-08 15:33:34 +000048use rpcbinder::get_vsock_rpc_interface;
Inseob Kim090b70b2022-11-16 20:01:14 +090049use rustutils::sockets::android_get_control_socket;
Jiyong Parkbb4a9872021-09-06 15:59:21 +090050use rustutils::system_properties;
Joel Galenson482704c2021-07-29 15:53:53 -070051use rustutils::system_properties::PropertyWatcher;
Alan Stokes3ba10fd2022-10-06 15:46:51 +010052use std::borrow::Cow::{Borrowed, Owned};
Andrew Scullb2f44472022-01-21 14:41:34 +000053use std::convert::TryInto;
Inseob Kim7ff121c2022-11-14 18:13:23 +090054use std::env;
David Brazdil451cc962022-10-14 14:08:12 +010055use std::fs::{self, create_dir, OpenOptions};
Inseob Kim11f40d02022-06-13 17:16:00 +090056use std::io::Write;
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -080057use std::os::unix::process::ExitStatusExt;
Jooyung Hanf48ceb42021-06-01 18:00:04 +090058use std::path::Path;
Inseob Kim217038e2021-11-25 11:15:06 +090059use std::process::{Child, Command, Stdio};
Jiyong Park8611a6c2021-07-09 18:17:44 +090060use std::str;
Jiyong Parkbb4a9872021-09-06 15:59:21 +090061use std::time::{Duration, SystemTime};
Jooyung Han634e2d72021-06-10 16:27:38 +090062
63const WAIT_TIMEOUT: Duration = Duration::from_secs(10);
Inseob Kim197748b2021-12-01 19:49:00 +090064const MAIN_APK_PATH: &str = "/dev/block/by-name/microdroid-apk";
65const MAIN_APK_IDSIG_PATH: &str = "/dev/block/by-name/microdroid-apk-idsig";
66const MAIN_APK_DEVICE_NAME: &str = "microdroid-apk";
67const EXTRA_APK_PATH_PATTERN: &str = "/dev/block/by-name/extra-apk-*";
68const EXTRA_IDSIG_PATH_PATTERN: &str = "/dev/block/by-name/extra-idsig-*";
Jooyung Han19c1d6c2021-08-06 14:08:16 +090069const DM_MOUNTED_APK_PATH: &str = "/dev/block/mapper/microdroid-apk";
Inseob Kim217038e2021-11-25 11:15:06 +090070const APKDMVERITY_BIN: &str = "/system/bin/apkdmverity";
71const ZIPFUSE_BIN: &str = "/system/bin/zipfuse";
Andrew Scullab72ec52022-03-14 09:10:52 +000072const AVF_STRICT_BOOT: &str = "/sys/firmware/devicetree/base/chosen/avf,strict-boot";
73const AVF_NEW_INSTANCE: &str = "/sys/firmware/devicetree/base/chosen/avf,new-instance";
Inseob Kime379e7d2022-07-22 18:55:18 +090074const DEBUG_MICRODROID_NO_VERIFIED_BOOT: &str =
75 "/sys/firmware/devicetree/base/virtualization/guest/debug-microdroid,no-verified-boot";
Jooyung Han347d9f22021-05-28 00:05:14 +090076
Jiyong Parkbb4a9872021-09-06 15:59:21 +090077const APEX_CONFIG_DONE_PROP: &str = "apex_config.done";
Andrew Scull65ddfc42022-02-14 21:03:58 +000078const APP_DEBUGGABLE_PROP: &str = "ro.boot.microdroid.app_debuggable";
Alan Stokes60f82202022-10-07 16:40:07 +010079const APK_MOUNT_DONE_PROP: &str = "microdroid_manager.apk.mounted";
Jiyong Parkbb4a9872021-09-06 15:59:21 +090080
Inseob Kim11f40d02022-06-13 17:16:00 +090081// SYNC WITH virtualizationservice/src/crosvm.rs
82const FAILURE_SERIAL_DEVICE: &str = "/dev/ttyS1";
83
Shikha Panwar566c9672022-11-15 14:39:58 +000084/// Identifier for the key used for encrypted store.
85const ENCRYPTEDSTORE_BACKING_DEVICE: &str = "/dev/block/by-name/encryptedstore";
86const ENCRYPTEDSTORE_BIN: &str = "/system/bin/encryptedstore";
87const ENCRYPTEDSTORE_KEY_IDENTIFIER: &str = "encryptedstore_key";
88const ENCRYPTEDSTORE_KEYSIZE: u32 = 64;
Shikha Panwar9fd198f2022-11-18 17:43:43 +000089const ENCRYPTEDSTORE_MOUNTPOINT: &str = "/mnt/encryptedstore";
Shikha Panwar566c9672022-11-15 14:39:58 +000090
Jooyung Handd0a1732021-11-23 15:26:20 +090091#[derive(thiserror::Error, Debug)]
92enum MicrodroidError {
Inseob Kim11f40d02022-06-13 17:16:00 +090093 #[error("Cannot connect to virtualization service: {0}")]
94 FailedToConnectToVirtualizationService(String),
Jooyung Handd0a1732021-11-23 15:26:20 +090095 #[error("Payload has changed: {0}")]
96 PayloadChanged(String),
97 #[error("Payload verification has failed: {0}")]
98 PayloadVerificationFailed(String),
Jooyung Han5c6d4172021-12-06 14:17:52 +090099 #[error("Payload config is invalid: {0}")]
100 InvalidConfig(String),
Jooyung Handd0a1732021-11-23 15:26:20 +0900101}
102
Alan Stokes2bead0d2022-09-05 16:58:34 +0100103fn translate_error(err: &Error) -> (ErrorCode, String) {
Jooyung Handd0a1732021-11-23 15:26:20 +0900104 if let Some(e) = err.downcast_ref::<MicrodroidError>() {
105 match e {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100106 MicrodroidError::PayloadChanged(msg) => (ErrorCode::PAYLOAD_CHANGED, msg.to_string()),
Jooyung Handd0a1732021-11-23 15:26:20 +0900107 MicrodroidError::PayloadVerificationFailed(msg) => {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100108 (ErrorCode::PAYLOAD_VERIFICATION_FAILED, msg.to_string())
Jooyung Handd0a1732021-11-23 15:26:20 +0900109 }
Alan Stokes2bead0d2022-09-05 16:58:34 +0100110 MicrodroidError::InvalidConfig(msg) => {
111 (ErrorCode::PAYLOAD_CONFIG_INVALID, msg.to_string())
112 }
Inseob Kim11f40d02022-06-13 17:16:00 +0900113
114 // Connection failure won't be reported to VS; return the default value
115 MicrodroidError::FailedToConnectToVirtualizationService(msg) => {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100116 (ErrorCode::UNKNOWN, msg.to_string())
Inseob Kim11f40d02022-06-13 17:16:00 +0900117 }
Jooyung Handd0a1732021-11-23 15:26:20 +0900118 }
119 } else {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100120 (ErrorCode::UNKNOWN, err.to_string())
Jooyung Handd0a1732021-11-23 15:26:20 +0900121 }
122}
123
Inseob Kim11f40d02022-06-13 17:16:00 +0900124fn write_death_reason_to_serial(err: &Error) -> Result<()> {
125 let death_reason = if let Some(e) = err.downcast_ref::<MicrodroidError>() {
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100126 Borrowed(match e {
Inseob Kim11f40d02022-06-13 17:16:00 +0900127 MicrodroidError::FailedToConnectToVirtualizationService(_) => {
128 "MICRODROID_FAILED_TO_CONNECT_TO_VIRTUALIZATION_SERVICE"
129 }
130 MicrodroidError::PayloadChanged(_) => "MICRODROID_PAYLOAD_HAS_CHANGED",
131 MicrodroidError::PayloadVerificationFailed(_) => {
132 "MICRODROID_PAYLOAD_VERIFICATION_FAILED"
133 }
134 MicrodroidError::InvalidConfig(_) => "MICRODROID_INVALID_PAYLOAD_CONFIG",
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100135 })
Inseob Kim11f40d02022-06-13 17:16:00 +0900136 } else {
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100137 // Send context information back after a separator, to ease diagnosis.
138 // These errors occur before the payload runs, so this should not leak sensitive
139 // information.
140 Owned(format!("MICRODROID_UNKNOWN_RUNTIME_ERROR|{:?}", err))
Inseob Kim11f40d02022-06-13 17:16:00 +0900141 };
142
143 let death_reason_bytes = death_reason.as_bytes();
144 let mut sent_total = 0;
145 while sent_total < death_reason_bytes.len() {
146 // TODO(b/220071963): Sometimes, sending more than 16 bytes at once makes MM hang.
147 let begin = sent_total;
148 let end = std::cmp::min(begin.saturating_add(16), death_reason_bytes.len());
149 OpenOptions::new()
150 .read(false)
151 .write(true)
152 .open(FAILURE_SERIAL_DEVICE)?
153 .write_all(&death_reason_bytes[begin..end])?;
154 sent_total = end;
155 }
156
157 Ok(())
158}
159
Inseob Kim1b95f2e2021-08-19 13:17:40 +0900160fn get_vms_rpc_binder() -> Result<Strong<dyn IVirtualMachineService>> {
David Brazdil73988ea2022-11-11 15:10:32 +0000161 // The host is running a VirtualMachineService for this VM on a port equal
162 // to the CID of this VM.
163 let port = vsock::get_local_cid().context("Could not determine local CID")?;
164 get_vsock_rpc_interface(VMADDR_CID_HOST, port)
165 .context("Could not connect to IVirtualMachineService")
Inseob Kim1b95f2e2021-08-19 13:17:40 +0900166}
167
Inseob Kim437f1052022-06-21 11:30:22 +0900168fn main() -> Result<()> {
Inseob Kim7ff121c2022-11-14 18:13:23 +0900169 // If debuggable, print full backtrace to console log with stdio_to_kmsg
170 if system_properties::read_bool(APP_DEBUGGABLE_PROP, true)? {
171 env::set_var("RUST_BACKTRACE", "full");
172 }
173
Inseob Kim437f1052022-06-21 11:30:22 +0900174 scopeguard::defer! {
175 info!("Shutting down...");
Jooyung Hanbfe086f2021-10-28 10:15:45 +0900176 if let Err(e) = system_properties::write("sys.powerctl", "shutdown") {
177 error!("failed to shutdown {:?}", e);
178 }
Jooyung Han311b1202021-09-14 22:00:16 +0900179 }
Inseob Kim437f1052022-06-21 11:30:22 +0900180
181 try_main().map_err(|e| {
182 error!("Failed with {:?}.", e);
183 if let Err(e) = write_death_reason_to_serial(&e) {
184 error!("Failed to write death reason {:?}", e);
185 }
186 e
187 })
Jooyung Han311b1202021-09-14 22:00:16 +0900188}
189
Inseob Kim090b70b2022-11-16 20:01:14 +0900190fn set_cloexec_on_vm_payload_service_socket() -> Result<()> {
191 let fd = android_get_control_socket(VM_PAYLOAD_SERVICE_SOCKET_NAME)?;
192
193 fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC))?;
194
195 Ok(())
196}
197
Jooyung Han311b1202021-09-14 22:00:16 +0900198fn try_main() -> Result<()> {
Andrew Sculle127cff2022-02-15 15:34:04 +0000199 let _ = kernlog::init();
Jooyung Han347d9f22021-05-28 00:05:14 +0900200 info!("started.");
201
Inseob Kim090b70b2022-11-16 20:01:14 +0900202 if let Err(e) = set_cloexec_on_vm_payload_service_socket() {
203 warn!("Failed to set cloexec on vm payload socket: {:?}", e);
204 }
205
Jiyong Park202856e2022-08-22 16:04:26 +0900206 load_crashkernel_if_supported().context("Failed to load crashkernel")?;
207
Keir Fraser933f0ac2022-10-12 08:23:28 +0000208 swap::init_swap().context("Failed to initialise swap")?;
209 info!("swap enabled.");
210
Inseob Kim11f40d02022-06-13 17:16:00 +0900211 let service = get_vms_rpc_binder()
212 .context("cannot connect to VirtualMachineService")
213 .map_err(|e| MicrodroidError::FailedToConnectToVirtualizationService(e.to_string()))?;
Seungjae Yoofd9a0622022-10-14 10:01:29 +0900214
Jooyung Han5c6d4172021-12-06 14:17:52 +0900215 match try_run_payload(&service) {
216 Ok(code) => {
217 info!("notifying payload finished");
218 service.notifyPayloadFinished(code)?;
219 if code == 0 {
220 info!("task successfully finished");
221 } else {
222 error!("task exited with exit code: {}", code);
223 }
224 Ok(())
225 }
226 Err(err) => {
Jooyung Han5c6d4172021-12-06 14:17:52 +0900227 let (error_code, message) = translate_error(&err);
228 service.notifyError(error_code, &message)?;
229 Err(err)
230 }
Jooyung Handd0a1732021-11-23 15:26:20 +0900231 }
232}
233
Alan Stokes1f417c92022-09-29 15:13:28 +0100234fn dice_derivation(
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000235 dice: DiceDriver,
Alan Stokes1f417c92022-09-29 15:13:28 +0100236 verified_data: &MicrodroidData,
237 payload_metadata: &PayloadMetadata,
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000238) -> Result<DiceContext> {
Andrew Scullb2f44472022-01-21 14:41:34 +0000239 // Calculate compound digests of code and authorities
Andrew Sculla0d1b1a2022-05-24 19:32:47 +0000240 let mut code_hash_ctx = Sha512::new();
241 let mut authority_hash_ctx = Sha512::new();
Andrew Scullb2f44472022-01-21 14:41:34 +0000242 code_hash_ctx.update(verified_data.apk_data.root_hash.as_ref());
243 authority_hash_ctx.update(verified_data.apk_data.pubkey.as_ref());
Inseob Kimb2519c52022-04-14 02:10:09 +0900244 for extra_apk in &verified_data.extra_apks_data {
Andrew Scullb2f44472022-01-21 14:41:34 +0000245 code_hash_ctx.update(extra_apk.root_hash.as_ref());
246 authority_hash_ctx.update(extra_apk.pubkey.as_ref());
247 }
Inseob Kimb2519c52022-04-14 02:10:09 +0900248 for apex in &verified_data.apex_data {
Andrew Scullb2f44472022-01-21 14:41:34 +0000249 code_hash_ctx.update(apex.root_digest.as_ref());
250 authority_hash_ctx.update(apex.public_key.as_ref());
251 }
Andrew Sculla0d1b1a2022-05-24 19:32:47 +0000252 let code_hash = code_hash_ctx.finish();
253 let authority_hash = authority_hash_ctx.finish();
Andrew Scullb2f44472022-01-21 14:41:34 +0000254
255 // {
256 // -70002: "Microdroid payload",
Alan Stokes1f417c92022-09-29 15:13:28 +0100257 // ? -71000: tstr // payload_config_path
258 // ? -71001: PayloadConfig
Andrew Scullb2f44472022-01-21 14:41:34 +0000259 // }
Alan Stokes1f417c92022-09-29 15:13:28 +0100260 // PayloadConfig = {
261 // 1: tstr // payload_binary_path
Alan Stokes1f417c92022-09-29 15:13:28 +0100262 // }
263
Andrew Scullb2f44472022-01-21 14:41:34 +0000264 let mut config_desc = vec![
Alan Stokes1f417c92022-09-29 15:13:28 +0100265 0xa2, // map(2)
266 0x3a, 0x00, 0x01, 0x11, 0x71, // -70002
267 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79,
268 0x6c, 0x6f, 0x61, 0x64, // "Microdroid payload"
Andrew Scullb2f44472022-01-21 14:41:34 +0000269 ];
Alan Stokes1f417c92022-09-29 15:13:28 +0100270
271 match payload_metadata {
272 PayloadMetadata::config_path(payload_config_path) => {
273 encode_negative_number(-71000, &mut config_desc)?;
274 encode_tstr(payload_config_path, &mut config_desc)?;
275 }
276 PayloadMetadata::config(payload_config) => {
277 encode_negative_number(-71001, &mut config_desc)?;
278 encode_header(5, 1, &mut config_desc)?; // map(1)
279 encode_number(1, &mut config_desc)?;
280 encode_tstr(&payload_config.payload_binary_path, &mut config_desc)?;
281 }
282 }
Andrew Scullb2f44472022-01-21 14:41:34 +0000283
Andrew Scull65ddfc42022-02-14 21:03:58 +0000284 // Check app debuggability, conervatively assuming it is debuggable
285 let app_debuggable = system_properties::read_bool(APP_DEBUGGABLE_PROP, true)?;
286
Andrew Scullb2f44472022-01-21 14:41:34 +0000287 // Send the details to diced
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000288 let hidden = verified_data.salt.clone().try_into().unwrap();
289 dice.derive(code_hash, &config_desc, authority_hash, app_debuggable, hidden)
Andrew Scullb2f44472022-01-21 14:41:34 +0000290}
291
Alan Stokes1f417c92022-09-29 15:13:28 +0100292fn encode_tstr(tstr: &str, buffer: &mut Vec<u8>) -> Result<()> {
293 let bytes = tstr.as_bytes();
294 encode_header(3, bytes.len().try_into().unwrap(), buffer)?;
295 buffer.extend_from_slice(bytes);
296 Ok(())
297}
298
299fn encode_negative_number(n: i64, buffer: &mut dyn Write) -> Result<()> {
300 ensure!(n < 0);
301 let n = -1 - n;
302 encode_header(1, n.try_into().unwrap(), buffer)
303}
304
Andrew Scullab72ec52022-03-14 09:10:52 +0000305fn is_strict_boot() -> bool {
306 Path::new(AVF_STRICT_BOOT).exists()
307}
308
309fn is_new_instance() -> bool {
310 Path::new(AVF_NEW_INSTANCE).exists()
311}
312
Inseob Kime379e7d2022-07-22 18:55:18 +0900313fn is_verified_boot() -> bool {
314 !Path::new(DEBUG_MICRODROID_NO_VERIFIED_BOOT).exists()
315}
316
Jooyung Han5c6d4172021-12-06 14:17:52 +0900317fn try_run_payload(service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
Jooyung Han311b1202021-09-14 22:00:16 +0900318 let metadata = load_metadata().context("Failed to load payload metadata")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000319 let dice = DiceDriver::new(Path::new("/dev/open-dice0")).context("Failed to load DICE")?;
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900320
Jooyung Han311b1202021-09-14 22:00:16 +0900321 let mut instance = InstanceDisk::new().context("Failed to load instance.img")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000322 let saved_data =
323 instance.read_microdroid_data(&dice).context("Failed to read identity data")?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900324
Andrew Scullab72ec52022-03-14 09:10:52 +0000325 if is_strict_boot() {
326 // Provisioning must happen on the first boot and never again.
327 if is_new_instance() {
328 ensure!(
329 saved_data.is_none(),
330 MicrodroidError::InvalidConfig("Found instance data on first boot.".to_string())
331 );
332 } else {
333 ensure!(
334 saved_data.is_some(),
335 MicrodroidError::InvalidConfig("Instance data not found.".to_string())
336 );
337 };
338 }
339
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900340 // Verify the payload before using it.
Inseob Kim11f40d02022-06-13 17:16:00 +0900341 let verified_data = verify_payload(&metadata, saved_data.as_ref())
342 .context("Payload verification failed")
343 .map_err(|e| MicrodroidError::PayloadVerificationFailed(e.to_string()))?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900344
345 // In case identity is ignored (by debug policy), we should reuse existing payload data, even
346 // when the payload is changed. This is to keep the derived secret same as before.
347 let verified_data = if let Some(saved_data) = saved_data {
348 if !is_verified_boot() {
349 if saved_data != verified_data {
350 info!("Detected an update of the payload, but continue (regarding debug policy)")
351 }
352 } else {
353 ensure!(
354 saved_data == verified_data,
355 MicrodroidError::PayloadChanged(String::from(
356 "Detected an update of the payload which isn't supported yet."
357 ))
358 );
359 info!("Saved data is verified.");
360 }
361 saved_data
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900362 } else {
Jooyung Han7a343f92021-09-08 22:53:11 +0900363 info!("Saving verified data.");
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000364 instance
365 .write_microdroid_data(&verified_data, &dice)
366 .context("Failed to write identity data")?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900367 verified_data
368 };
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900369
Alan Stokes1f417c92022-09-29 15:13:28 +0100370 let payload_metadata = metadata.payload.ok_or_else(|| {
371 MicrodroidError::InvalidConfig("No payload config in metadata".to_string())
372 })?;
Alan Stokes0d1ef782022-09-27 13:46:35 +0100373
Inseob Kimb2519c52022-04-14 02:10:09 +0900374 // To minimize the exposure to untrusted data, derive dice profile as soon as possible.
375 info!("DICE derivation for payload");
Shikha Panwar566c9672022-11-15 14:39:58 +0000376 let dice_context = dice_derivation(dice, &verified_data, &payload_metadata)?;
377
378 // Run encryptedstore binary to prepare the storage
379 let encryptedstore_child = if Path::new(ENCRYPTEDSTORE_BACKING_DEVICE).exists() {
380 info!("Preparing encryptedstore ...");
381 Some(prepare_encryptedstore(&dice_context).context("encryptedstore run")?)
382 } else {
383 None
384 };
Inseob Kimb2519c52022-04-14 02:10:09 +0900385
Jooyung Hana6d11eb2021-09-10 11:48:05 +0900386 // Before reading a file from the APK, start zipfuse
Inseob Kim217038e2021-11-25 11:15:06 +0900387 run_zipfuse(
Alan Stokes60f82202022-10-07 16:40:07 +0100388 MountForExec::Allowed,
Inseob Kim217038e2021-11-25 11:15:06 +0900389 "fscontext=u:object_r:zipfusefs:s0,context=u:object_r:system_file:s0",
390 Path::new("/dev/block/mapper/microdroid-apk"),
Alice Wang6bbb6da2022-10-26 12:44:06 +0000391 Path::new(VM_APK_CONTENTS_PATH),
Alan Stokes60f82202022-10-07 16:40:07 +0100392 Some(APK_MOUNT_DONE_PROP),
Inseob Kim217038e2021-11-25 11:15:06 +0900393 )
394 .context("Failed to run zipfuse")?;
Jiyong Park21ce2c52021-08-28 02:32:17 +0900395
Andrew Scull4d262dc2022-10-21 13:14:33 +0000396 // Restricted APIs are only allowed to be used by platform or test components. Infer this from
397 // the use of a VM config file since those can only be used by platform and test components.
398 let allow_restricted_apis = match payload_metadata {
399 PayloadMetadata::config_path(_) => true,
400 PayloadMetadata::config(_) => false,
401 };
402
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100403 let config = load_config(payload_metadata).context("Failed to load payload metadata")?;
Shikha Panwar6f03c942022-04-13 20:26:50 +0000404
Alan Stokes01b3ef02022-09-22 17:43:24 +0100405 let task = config
406 .task
407 .as_ref()
408 .ok_or_else(|| MicrodroidError::InvalidConfig("No task in VM config".to_string()))?;
409
Inseob Kim197748b2021-12-01 19:49:00 +0900410 if config.extra_apks.len() != verified_data.extra_apks_data.len() {
411 return Err(anyhow!(
Alan Stokes1f417c92022-09-29 15:13:28 +0100412 "config expects {} extra apks, but found {}",
Inseob Kim197748b2021-12-01 19:49:00 +0900413 config.extra_apks.len(),
414 verified_data.extra_apks_data.len()
415 ));
416 }
417 mount_extra_apks(&config)?;
Jooyung Han634e2d72021-06-10 16:27:38 +0900418
Jooyung Han5c6d4172021-12-06 14:17:52 +0900419 // Wait until apex config is done. (e.g. linker configuration for apexes)
420 // TODO(jooyung): wait until sys.boot_completed?
421 wait_for_apex_config_done()?;
422
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900423 // Start tombstone_transmit if enabled
424 if config.export_tombstones {
Alan Stokes01b3ef02022-09-22 17:43:24 +0100425 control_service("start", "tombstone_transmit")?;
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900426 } else {
Alan Stokes01b3ef02022-09-22 17:43:24 +0100427 control_service("stop", "tombstoned")?;
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900428 }
429
Alan Stokes01b3ef02022-09-22 17:43:24 +0100430 // Start authfs if enabled
431 if config.enable_authfs {
432 control_service("start", "authfs_service")?;
433 }
434
Alan Stokes60f82202022-10-07 16:40:07 +0100435 // Wait until zipfuse has mounted the APK so we can access the payload
436 wait_for_property_true(APK_MOUNT_DONE_PROP).context("Failed waiting for APK mount done")?;
437
Shikha Panwar566c9672022-11-15 14:39:58 +0000438 register_vm_payload_service(allow_restricted_apis, service.clone(), dice_context)?;
439
440 if let Some(mut child) = encryptedstore_child {
441 let exitcode = child.wait().context("Wait for encryptedstore child")?;
442 ensure!(exitcode.success(), "Unable to prepare encrypted storage. Exitcode={}", exitcode);
443 }
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100444
445 system_properties::write("dev.bootcomplete", "1").context("set dev.bootcomplete")?;
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100446 exec_task(task, service).context("Failed to run payload")
Alan Stokes01b3ef02022-09-22 17:43:24 +0100447}
448
449fn control_service(action: &str, service: &str) -> Result<()> {
450 system_properties::write(&format!("ctl.{}", action), service)
451 .with_context(|| format!("Failed to {} {}", action, service))
Jooyung Han347d9f22021-05-28 00:05:14 +0900452}
453
Inseob Kim217038e2021-11-25 11:15:06 +0900454struct ApkDmverityArgument<'a> {
455 apk: &'a str,
456 idsig: &'a str,
457 name: &'a str,
Inseob Kim197748b2021-12-01 19:49:00 +0900458 saved_root_hash: Option<&'a RootHash>,
Inseob Kim217038e2021-11-25 11:15:06 +0900459}
460
461fn run_apkdmverity(args: &[ApkDmverityArgument]) -> Result<Child> {
462 let mut cmd = Command::new(APKDMVERITY_BIN);
463
Inseob Kim217038e2021-11-25 11:15:06 +0900464 for argument in args {
465 cmd.arg("--apk").arg(argument.apk).arg(argument.idsig).arg(argument.name);
Inseob Kim197748b2021-12-01 19:49:00 +0900466 if let Some(root_hash) = argument.saved_root_hash {
467 cmd.arg(&to_hex_string(root_hash));
468 } else {
469 cmd.arg("none");
470 }
Inseob Kim217038e2021-11-25 11:15:06 +0900471 }
472
473 cmd.spawn().context("Spawn apkdmverity")
474}
475
Alan Stokes60f82202022-10-07 16:40:07 +0100476enum MountForExec {
477 Allowed,
478 Disallowed,
479}
480
481fn run_zipfuse(
482 noexec: MountForExec,
483 option: &str,
484 zip_path: &Path,
485 mount_dir: &Path,
486 ready_prop: Option<&str>,
487) -> Result<Child> {
Andrew Scullcc339a12022-07-04 12:44:19 +0000488 let mut cmd = Command::new(ZIPFUSE_BIN);
Alan Stokes60f82202022-10-07 16:40:07 +0100489 if let MountForExec::Disallowed = noexec {
Andrew Scullcc339a12022-07-04 12:44:19 +0000490 cmd.arg("--noexec");
491 }
Alan Stokes60f82202022-10-07 16:40:07 +0100492 if let Some(property_name) = ready_prop {
493 cmd.args(["-p", property_name]);
494 }
Inseob Kimadd7b7f2022-11-21 15:06:05 +0900495 cmd.arg("-o").arg(option).arg(zip_path).arg(mount_dir).spawn().context("Spawn zipfuse")
Inseob Kim217038e2021-11-25 11:15:06 +0900496}
497
Inseob Kime379e7d2022-07-22 18:55:18 +0900498fn write_apex_payload_data(
499 saved_data: Option<&MicrodroidData>,
500 apex_data_from_payload: &[ApexData],
501) -> Result<()> {
502 if let Some(saved_apex_data) = saved_data.map(|d| &d.apex_data) {
503 // We don't support APEX updates. (assuming that update will change root digest)
504 ensure!(
505 saved_apex_data == apex_data_from_payload,
506 MicrodroidError::PayloadChanged(String::from("APEXes have changed."))
507 );
508 let apex_metadata = to_metadata(apex_data_from_payload);
509 // Pass metadata(with public keys and root digests) to apexd so that it uses the passed
510 // metadata instead of the default one (/dev/block/by-name/payload-metadata)
511 OpenOptions::new()
512 .create_new(true)
513 .write(true)
514 .open("/apex/vm-payload-metadata")
515 .context("Failed to open /apex/vm-payload-metadata")
516 .and_then(|f| write_metadata(&apex_metadata, f))?;
517 }
518 Ok(())
519}
520
Jooyung Han7a343f92021-09-08 22:53:11 +0900521// Verify payload before executing it. For APK payload, Full verification (which is slow) is done
522// when the root_hash values from the idsig file and the instance disk are different. This function
523// returns the verified root hash (for APK payload) and pubkeys (for APEX payloads) that can be
524// saved to the instance disk.
525fn verify_payload(
526 metadata: &Metadata,
527 saved_data: Option<&MicrodroidData>,
528) -> Result<MicrodroidData> {
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900529 let start_time = SystemTime::now();
530
Inseob Kim197748b2021-12-01 19:49:00 +0900531 // Verify main APK
Jooyung Han7a343f92021-09-08 22:53:11 +0900532 let root_hash = saved_data.map(|d| &d.apk_data.root_hash);
Inseob Kim197748b2021-12-01 19:49:00 +0900533 let root_hash_from_idsig = get_apk_root_hash_from_idsig(MAIN_APK_IDSIG_PATH)?;
Jiyong Parkf7dea252021-09-08 01:42:54 +0900534 let root_hash_trustful = root_hash == Some(&root_hash_from_idsig);
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900535
Jiyong Parkf7dea252021-09-08 01:42:54 +0900536 // 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 +0900537 // instead of the value read from the idsig file.
Inseob Kim197748b2021-12-01 19:49:00 +0900538 let main_apk_argument = {
539 ApkDmverityArgument {
540 apk: MAIN_APK_PATH,
541 idsig: MAIN_APK_IDSIG_PATH,
542 name: MAIN_APK_DEVICE_NAME,
543 saved_root_hash: if root_hash_trustful {
544 Some(root_hash_from_idsig.as_ref())
545 } else {
546 None
547 },
548 }
549 };
550 let mut apkdmverity_arguments = vec![main_apk_argument];
551
552 // Verify extra APKs
553 // For now, we can't read the payload config, so glob APKs and idsigs.
554 // Later, we'll see if it matches with the payload config.
555
556 // sort globbed paths to match apks (extra-apk-{idx}) and idsigs (extra-idsig-{idx})
557 // e.g. "extra-apk-0" corresponds to "extra-idsig-0"
558 let extra_apks =
559 sorted(glob(EXTRA_APK_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
560 let extra_idsigs =
561 sorted(glob(EXTRA_IDSIG_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
562 if extra_apks.len() != extra_idsigs.len() {
563 return Err(anyhow!(
564 "Extra apks/idsigs mismatch: {} apks but {} idsigs",
565 extra_apks.len(),
566 extra_idsigs.len()
567 ));
568 }
569 let extra_apks_count = extra_apks.len();
570
571 let (extra_apk_names, extra_root_hashes_from_idsig): (Vec<_>, Vec<_>) = extra_idsigs
572 .iter()
573 .enumerate()
574 .map(|(i, extra_idsig)| {
575 (
576 format!("extra-apk-{}", i),
Alice Wang89cff012022-09-26 10:05:16 +0000577 get_apk_root_hash_from_idsig(extra_idsig)
Inseob Kim197748b2021-12-01 19:49:00 +0900578 .expect("Can't find root hash from extra idsig"),
579 )
580 })
581 .unzip();
582
583 let saved_extra_root_hashes: Vec<_> = saved_data
584 .map(|d| d.extra_apks_data.iter().map(|apk_data| &apk_data.root_hash).collect())
585 .unwrap_or_else(Vec::new);
586 let extra_root_hashes_trustful: Vec<_> = extra_root_hashes_from_idsig
587 .iter()
588 .enumerate()
589 .map(|(i, root_hash_from_idsig)| {
590 saved_extra_root_hashes.get(i).copied() == Some(root_hash_from_idsig)
591 })
592 .collect();
593
594 for i in 0..extra_apks_count {
595 apkdmverity_arguments.push({
596 ApkDmverityArgument {
597 apk: extra_apks[i].to_str().unwrap(),
598 idsig: extra_idsigs[i].to_str().unwrap(),
599 name: &extra_apk_names[i],
600 saved_root_hash: if extra_root_hashes_trustful[i] {
601 Some(&extra_root_hashes_from_idsig[i])
602 } else {
603 None
604 },
605 }
606 });
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900607 }
608
609 // Start apkdmverity and wait for the dm-verify block
Inseob Kim197748b2021-12-01 19:49:00 +0900610 let mut apkdmverity_child = run_apkdmverity(&apkdmverity_arguments)?;
Jooyung Han7a343f92021-09-08 22:53:11 +0900611
Jooyung Hanc8deb472021-09-13 13:48:25 +0900612 // While waiting for apkdmverity to mount APK, gathers public keys and root digests from
613 // APEX payload.
Jooyung Han7a343f92021-09-08 22:53:11 +0900614 let apex_data_from_payload = get_apex_data_from_payload(metadata)?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900615
616 // Writing /apex/vm-payload-metadata is to verify that the payload isn't changed.
617 // Skip writing it if the debug policy ignoring identity is on
618 if is_verified_boot() {
619 write_apex_payload_data(saved_data, &apex_data_from_payload)?;
Jooyung Han4a9b3bf2021-09-10 17:19:00 +0900620 }
Inseob Kime379e7d2022-07-22 18:55:18 +0900621
Jooyung Han4a9b3bf2021-09-10 17:19:00 +0900622 // Start apexd to activate APEXes
623 system_properties::write("ctl.start", "apexd-vm")?;
Jooyung Han7a343f92021-09-08 22:53:11 +0900624
Inseob Kim217038e2021-11-25 11:15:06 +0900625 // TODO(inseob): add timeout
626 apkdmverity_child.wait()?;
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900627
Jiyong Parkf7dea252021-09-08 01:42:54 +0900628 // Do the full verification if the root_hash is un-trustful. This requires the full scanning of
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900629 // 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 +0900630 // 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 +0900631 // of the VM or APK was updated in the host.
632 // TODO(jooyung): consider multithreading to make this faster
Inseob Kim197748b2021-12-01 19:49:00 +0900633 let main_apk_pubkey = get_public_key_from_apk(DM_MOUNTED_APK_PATH, root_hash_trustful)?;
634 let extra_apks_data = extra_root_hashes_from_idsig
635 .into_iter()
636 .enumerate()
637 .map(|(i, extra_root_hash)| {
638 let mount_path = format!("/dev/block/mapper/{}", &extra_apk_names[i]);
639 let apk_pubkey = get_public_key_from_apk(&mount_path, extra_root_hashes_trustful[i])?;
640 Ok(ApkData { root_hash: extra_root_hash, pubkey: apk_pubkey })
641 })
642 .collect::<Result<Vec<_>>>()?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900643
644 info!("payload verification successful. took {:#?}", start_time.elapsed().unwrap());
645
Andrew Scull34916a72022-01-30 21:34:24 +0000646 // Use the salt from a verified instance, or generate a salt for a new instance.
647 let salt = if let Some(saved_data) = saved_data {
648 saved_data.salt.clone()
649 } else {
650 let mut salt = vec![0u8; 64];
651 salt.as_mut_slice().try_fill(&mut rand::thread_rng())?;
652 salt
653 };
654
Jiyong Parkf7dea252021-09-08 01:42:54 +0900655 // At this point, we can ensure that the root_hash from the idsig file is trusted, either by
656 // fully verifying the APK or by comparing it with the saved root_hash.
Jooyung Han7a343f92021-09-08 22:53:11 +0900657 Ok(MicrodroidData {
Andrew Scull34916a72022-01-30 21:34:24 +0000658 salt,
Inseob Kim197748b2021-12-01 19:49:00 +0900659 apk_data: ApkData { root_hash: root_hash_from_idsig, pubkey: main_apk_pubkey },
660 extra_apks_data,
Jooyung Han7a343f92021-09-08 22:53:11 +0900661 apex_data: apex_data_from_payload,
662 })
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900663}
664
Inseob Kim197748b2021-12-01 19:49:00 +0900665fn mount_extra_apks(config: &VmPayloadConfig) -> Result<()> {
666 // For now, only the number of apks is important, as the mount point and dm-verity name is fixed
667 for i in 0..config.extra_apks.len() {
668 let mount_dir = format!("/mnt/extra-apk/{}", i);
669 create_dir(Path::new(&mount_dir)).context("Failed to create mount dir for extra apks")?;
670
671 // don't wait, just detach
672 run_zipfuse(
Alan Stokes60f82202022-10-07 16:40:07 +0100673 MountForExec::Disallowed,
Inseob Kim197748b2021-12-01 19:49:00 +0900674 "fscontext=u:object_r:zipfusefs:s0,context=u:object_r:extra_apk_file:s0",
675 Path::new(&format!("/dev/block/mapper/extra-apk-{}", i)),
676 Path::new(&mount_dir),
Alan Stokes60f82202022-10-07 16:40:07 +0100677 None,
Inseob Kim197748b2021-12-01 19:49:00 +0900678 )
679 .context("Failed to zipfuse extra apks")?;
680 }
681
682 Ok(())
683}
684
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900685// Waits until linker config is generated
686fn wait_for_apex_config_done() -> Result<()> {
Alan Stokes60f82202022-10-07 16:40:07 +0100687 wait_for_property_true(APEX_CONFIG_DONE_PROP).context("Failed waiting for apex config done")
688}
689
690fn wait_for_property_true(property_name: &str) -> Result<()> {
691 let mut prop = PropertyWatcher::new(property_name)?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900692 loop {
693 prop.wait()?;
Alan Stokes60f82202022-10-07 16:40:07 +0100694 if system_properties::read_bool(property_name, false)? {
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900695 break;
696 }
697 }
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900698 Ok(())
699}
700
Alice Wang89cff012022-09-26 10:05:16 +0000701fn get_apk_root_hash_from_idsig<P: AsRef<Path>>(idsig_path: P) -> Result<Box<RootHash>> {
702 Ok(V4Signature::from_idsig_path(idsig_path)?.hashing_info.raw_root_hash)
Jiyong Park21ce2c52021-08-28 02:32:17 +0900703}
704
Inseob Kim197748b2021-12-01 19:49:00 +0900705fn get_public_key_from_apk(apk: &str, root_hash_trustful: bool) -> Result<Box<[u8]>> {
706 if !root_hash_trustful {
707 verify(apk).context(MicrodroidError::PayloadVerificationFailed(format!(
708 "failed to verify {}",
709 apk
710 )))
711 } else {
712 get_public_key_der(apk)
713 }
714}
715
Alan Stokes1f417c92022-09-29 15:13:28 +0100716fn load_config(payload_metadata: PayloadMetadata) -> Result<VmPayloadConfig> {
717 match payload_metadata {
718 PayloadMetadata::config_path(path) => {
719 let path = Path::new(&path);
720 info!("loading config from {:?}...", path);
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100721 let file = ioutil::wait_for_file(path, WAIT_TIMEOUT)
722 .with_context(|| format!("Failed to read {:?}", path))?;
Alan Stokes1f417c92022-09-29 15:13:28 +0100723 Ok(serde_json::from_reader(file)?)
724 }
725 PayloadMetadata::config(payload_config) => {
726 let task = Task {
727 type_: TaskType::MicrodroidLauncher,
728 command: payload_config.payload_binary_path,
Alan Stokes1f417c92022-09-29 15:13:28 +0100729 };
730 Ok(VmPayloadConfig {
731 os: OsConfig { name: "microdroid".to_owned() },
732 task: Some(task),
733 apexes: vec![],
734 extra_apks: vec![],
735 prefer_staged: false,
736 export_tombstones: false,
737 enable_authfs: false,
738 })
739 }
740 }
Jooyung Han634e2d72021-06-10 16:27:38 +0900741}
742
Jiyong Park202856e2022-08-22 16:04:26 +0900743/// Loads the crashkernel into memory using kexec if the VM is loaded with `crashkernel=' parameter
744/// in the cmdline.
745fn load_crashkernel_if_supported() -> Result<()> {
746 let supported = std::fs::read_to_string("/proc/cmdline")?.contains(" crashkernel=");
747 info!("ramdump supported: {}", supported);
748 if supported {
749 let status = Command::new("/system/bin/kexec_load").status()?;
750 if !status.success() {
751 return Err(anyhow!("Failed to load crashkernel: {:?}", status));
752 }
753 }
754 Ok(())
755}
756
Inseob Kim090b70b2022-11-16 20:01:14 +0900757/// Executes the given task.
Jooyung Han5c6d4172021-12-06 14:17:52 +0900758fn exec_task(task: &Task, service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
Jiyong Park8611a6c2021-07-09 18:17:44 +0900759 info!("executing main task {:?}...", task);
David Brazdil451cc962022-10-14 14:08:12 +0100760 let mut command = match task.type_ {
761 TaskType::Executable => Command::new(&task.command),
762 TaskType::MicrodroidLauncher => {
763 let mut command = Command::new("/system/bin/microdroid_launcher");
764 command.arg(find_library_path(&task.command)?);
765 command
766 }
767 };
Inseob Kim090b70b2022-11-16 20:01:14 +0900768 command.stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null());
Inseob Kim7f61fe72021-08-20 20:50:47 +0900769
770 info!("notifying payload started");
Inseob Kimc7d28c72021-10-25 14:28:10 +0000771 service.notifyPayloadStarted()?;
Inseob Kim7f61fe72021-08-20 20:50:47 +0900772
Inseob Kim86ca0162021-10-20 02:21:02 +0000773 let exit_status = command.spawn()?.wait()?;
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -0800774 match exit_status.code() {
775 Some(exit_code) => Ok(exit_code),
776 None => Err(match exit_status.signal() {
777 Some(signal) => anyhow!(
778 "Payload exited due to signal: {} ({})",
779 signal,
780 Signal::try_from(signal).map_or("unknown", |s| s.as_str())
781 ),
782 None => anyhow!("Payload has neither exit code nor signal"),
783 }),
784 }
Jooyung Han347d9f22021-05-28 00:05:14 +0900785}
Jooyung Han634e2d72021-06-10 16:27:38 +0900786
Jooyung Han634e2d72021-06-10 16:27:38 +0900787fn find_library_path(name: &str) -> Result<String> {
788 let mut watcher = PropertyWatcher::new("ro.product.cpu.abilist")?;
789 let value = watcher.read(|_name, value| Ok(value.trim().to_string()))?;
790 let abi = value.split(',').next().ok_or_else(|| anyhow!("no abilist"))?;
Alice Wang6bbb6da2022-10-26 12:44:06 +0000791 let path = format!("{}/lib/{}/{}", VM_APK_CONTENTS_PATH, abi, name);
Jooyung Han634e2d72021-06-10 16:27:38 +0900792
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100793 let metadata = fs::metadata(&path).with_context(|| format!("Unable to access {}", path))?;
Jooyung Han634e2d72021-06-10 16:27:38 +0900794 if !metadata.is_file() {
795 bail!("{} is not a file", &path);
796 }
797
798 Ok(path)
799}
Jiyong Park21ce2c52021-08-28 02:32:17 +0900800
801fn to_hex_string(buf: &[u8]) -> String {
802 buf.iter().map(|b| format!("{:02X}", b)).collect()
803}
Shikha Panwar566c9672022-11-15 14:39:58 +0000804
805fn prepare_encryptedstore(dice: &DiceContext) -> Result<Child> {
806 // Use a fixed salt to scope the derivation to this API.
807 // Generated using hexdump -vn32 -e'14/1 "0x%02X, " 1 "\n"' /dev/urandom
808 // TODO(b/241541860) : Move this (& other salts) to a salt container, i.e. a global enum
809 let salt = [
810 0xFC, 0x1D, 0x35, 0x7B, 0x96, 0xF3, 0xEF, 0x17, 0x78, 0x7D, 0x70, 0xED, 0xEA, 0xFE, 0x1D,
811 0x6F, 0xB3, 0xF9, 0x40, 0xCE, 0xDD, 0x99, 0x40, 0xAA, 0xA7, 0x0E, 0x92, 0x73, 0x90, 0x86,
812 0x4A, 0x75,
813 ];
814 let key = dice.get_sealing_key(
815 &salt,
816 ENCRYPTEDSTORE_KEY_IDENTIFIER.as_bytes(),
817 ENCRYPTEDSTORE_KEYSIZE,
818 )?;
819
820 let mut cmd = Command::new(ENCRYPTEDSTORE_BIN);
821 cmd.arg("--blkdevice")
822 .arg(ENCRYPTEDSTORE_BACKING_DEVICE)
823 .arg("--key")
824 .arg(hex::encode(&*key))
Shikha Panwar9fd198f2022-11-18 17:43:43 +0000825 .args(["--mountpoint", ENCRYPTEDSTORE_MOUNTPOINT])
Shikha Panwar566c9672022-11-15 14:39:58 +0000826 .spawn()
827 .context("encryptedstore failed")
828}