blob: cc4b9dc04514fb4747fc55ba9c0bfbb8a2bd7433 [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::{
Seungjae Yoofd9a0622022-10-14 10:01:29 +090029 IVirtualMachineService, VM_BINDER_SERVICE_PORT, VM_STREAM_SERVICE_PORT,
Alan Stokes2bead0d2022-09-05 16:58:34 +010030};
Alice Wang6bbb6da2022-10-26 12:44:06 +000031use android_system_virtualization_payload::aidl::android::system::virtualization::payload::IVmPayloadService::VM_APK_CONTENTS_PATH;
Jooyung Handd0a1732021-11-23 15:26:20 +090032use anyhow::{anyhow, bail, ensure, Context, Error, Result};
Alice Wang1bf3d782022-09-28 07:56:36 +000033use apkverify::{get_public_key_der, verify, V4Signature};
Alice Wang43c884b2022-10-24 09:42:40 +000034use binder::Strong;
Alan Stokes1f417c92022-09-29 15:13:28 +010035use diced_utils::cbor::{encode_header, encode_number};
Inseob Kim197748b2021-12-01 19:49:00 +090036use glob::glob;
Inseob Kim197748b2021-12-01 19:49:00 +090037use itertools::sorted;
David Brazdila07a1792022-10-25 13:37:57 +010038use libc::VMADDR_CID_HOST;
Andrew Scull684590f2022-01-27 16:14:26 +000039use log::{error, info};
Alan Stokes0d1ef782022-09-27 13:46:35 +010040use microdroid_metadata::{write_metadata, Metadata, PayloadMetadata};
Seungjae Yoofd9a0622022-10-14 10:01:29 +090041use microdroid_payload_config::{OsConfig, Task, TaskType, VmPayloadConfig};
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -080042use nix::sys::signal::Signal;
Andrew Sculla0d1b1a2022-05-24 19:32:47 +000043use openssl::sha::Sha512;
Jooyung Han4a9b3bf2021-09-10 17:19:00 +090044use payload::{get_apex_data_from_payload, load_metadata, to_metadata};
Andrew Scull34916a72022-01-30 21:34:24 +000045use rand::Fill;
Andrew Walbran7eb5ca42022-08-08 15:33:34 +000046use rpcbinder::get_vsock_rpc_interface;
Jiyong Parkbb4a9872021-09-06 15:59:21 +090047use rustutils::system_properties;
Joel Galenson482704c2021-07-29 15:53:53 -070048use rustutils::system_properties::PropertyWatcher;
Alan Stokes3ba10fd2022-10-06 15:46:51 +010049use std::borrow::Cow::{Borrowed, Owned};
Andrew Scullb2f44472022-01-21 14:41:34 +000050use std::convert::TryInto;
Inseob Kim7ff121c2022-11-14 18:13:23 +090051use std::env;
Inseob Kim197748b2021-12-01 19:49:00 +090052use std::fs::{self, create_dir, File, OpenOptions};
Inseob Kim11f40d02022-06-13 17:16:00 +090053use std::io::Write;
Inseob Kimc7d28c72021-10-25 14:28:10 +000054use std::os::unix::io::{FromRawFd, IntoRawFd};
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -080055use std::os::unix::process::ExitStatusExt;
Jooyung Hanf48ceb42021-06-01 18:00:04 +090056use std::path::Path;
Inseob Kim217038e2021-11-25 11:15:06 +090057use std::process::{Child, Command, Stdio};
Jiyong Park8611a6c2021-07-09 18:17:44 +090058use std::str;
Jiyong Parkbb4a9872021-09-06 15:59:21 +090059use std::time::{Duration, SystemTime};
Jiyong Park8611a6c2021-07-09 18:17:44 +090060use vsock::VsockStream;
Jooyung Han634e2d72021-06-10 16:27:38 +090061
62const WAIT_TIMEOUT: Duration = Duration::from_secs(10);
Inseob Kim197748b2021-12-01 19:49:00 +090063const MAIN_APK_PATH: &str = "/dev/block/by-name/microdroid-apk";
64const MAIN_APK_IDSIG_PATH: &str = "/dev/block/by-name/microdroid-apk-idsig";
65const MAIN_APK_DEVICE_NAME: &str = "microdroid-apk";
66const EXTRA_APK_PATH_PATTERN: &str = "/dev/block/by-name/extra-apk-*";
67const EXTRA_IDSIG_PATH_PATTERN: &str = "/dev/block/by-name/extra-idsig-*";
Jooyung Han19c1d6c2021-08-06 14:08:16 +090068const DM_MOUNTED_APK_PATH: &str = "/dev/block/mapper/microdroid-apk";
Inseob Kim217038e2021-11-25 11:15:06 +090069const APKDMVERITY_BIN: &str = "/system/bin/apkdmverity";
70const ZIPFUSE_BIN: &str = "/system/bin/zipfuse";
Andrew Scullab72ec52022-03-14 09:10:52 +000071const AVF_STRICT_BOOT: &str = "/sys/firmware/devicetree/base/chosen/avf,strict-boot";
72const AVF_NEW_INSTANCE: &str = "/sys/firmware/devicetree/base/chosen/avf,new-instance";
Inseob Kime379e7d2022-07-22 18:55:18 +090073const DEBUG_MICRODROID_NO_VERIFIED_BOOT: &str =
74 "/sys/firmware/devicetree/base/virtualization/guest/debug-microdroid,no-verified-boot";
Jooyung Han347d9f22021-05-28 00:05:14 +090075
Jiyong Parkbb4a9872021-09-06 15:59:21 +090076const APEX_CONFIG_DONE_PROP: &str = "apex_config.done";
Andrew Scull65ddfc42022-02-14 21:03:58 +000077const APP_DEBUGGABLE_PROP: &str = "ro.boot.microdroid.app_debuggable";
Alan Stokes60f82202022-10-07 16:40:07 +010078const APK_MOUNT_DONE_PROP: &str = "microdroid_manager.apk.mounted";
Jiyong Parkbb4a9872021-09-06 15:59:21 +090079
Inseob Kim11f40d02022-06-13 17:16:00 +090080// SYNC WITH virtualizationservice/src/crosvm.rs
81const FAILURE_SERIAL_DEVICE: &str = "/dev/ttyS1";
82
Shikha Panwar566c9672022-11-15 14:39:58 +000083/// Identifier for the key used for encrypted store.
84const ENCRYPTEDSTORE_BACKING_DEVICE: &str = "/dev/block/by-name/encryptedstore";
85const ENCRYPTEDSTORE_BIN: &str = "/system/bin/encryptedstore";
86const ENCRYPTEDSTORE_KEY_IDENTIFIER: &str = "encryptedstore_key";
87const ENCRYPTEDSTORE_KEYSIZE: u32 = 64;
88
Jooyung Handd0a1732021-11-23 15:26:20 +090089#[derive(thiserror::Error, Debug)]
90enum MicrodroidError {
Inseob Kim11f40d02022-06-13 17:16:00 +090091 #[error("Cannot connect to virtualization service: {0}")]
92 FailedToConnectToVirtualizationService(String),
Jooyung Handd0a1732021-11-23 15:26:20 +090093 #[error("Payload has changed: {0}")]
94 PayloadChanged(String),
95 #[error("Payload verification has failed: {0}")]
96 PayloadVerificationFailed(String),
Jooyung Han5c6d4172021-12-06 14:17:52 +090097 #[error("Payload config is invalid: {0}")]
98 InvalidConfig(String),
Jooyung Handd0a1732021-11-23 15:26:20 +090099}
100
Alan Stokes2bead0d2022-09-05 16:58:34 +0100101fn translate_error(err: &Error) -> (ErrorCode, String) {
Jooyung Handd0a1732021-11-23 15:26:20 +0900102 if let Some(e) = err.downcast_ref::<MicrodroidError>() {
103 match e {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100104 MicrodroidError::PayloadChanged(msg) => (ErrorCode::PAYLOAD_CHANGED, msg.to_string()),
Jooyung Handd0a1732021-11-23 15:26:20 +0900105 MicrodroidError::PayloadVerificationFailed(msg) => {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100106 (ErrorCode::PAYLOAD_VERIFICATION_FAILED, msg.to_string())
Jooyung Handd0a1732021-11-23 15:26:20 +0900107 }
Alan Stokes2bead0d2022-09-05 16:58:34 +0100108 MicrodroidError::InvalidConfig(msg) => {
109 (ErrorCode::PAYLOAD_CONFIG_INVALID, msg.to_string())
110 }
Inseob Kim11f40d02022-06-13 17:16:00 +0900111
112 // Connection failure won't be reported to VS; return the default value
113 MicrodroidError::FailedToConnectToVirtualizationService(msg) => {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100114 (ErrorCode::UNKNOWN, msg.to_string())
Inseob Kim11f40d02022-06-13 17:16:00 +0900115 }
Jooyung Handd0a1732021-11-23 15:26:20 +0900116 }
117 } else {
Alan Stokes2bead0d2022-09-05 16:58:34 +0100118 (ErrorCode::UNKNOWN, err.to_string())
Jooyung Handd0a1732021-11-23 15:26:20 +0900119 }
120}
121
Inseob Kim11f40d02022-06-13 17:16:00 +0900122fn write_death_reason_to_serial(err: &Error) -> Result<()> {
123 let death_reason = if let Some(e) = err.downcast_ref::<MicrodroidError>() {
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100124 Borrowed(match e {
Inseob Kim11f40d02022-06-13 17:16:00 +0900125 MicrodroidError::FailedToConnectToVirtualizationService(_) => {
126 "MICRODROID_FAILED_TO_CONNECT_TO_VIRTUALIZATION_SERVICE"
127 }
128 MicrodroidError::PayloadChanged(_) => "MICRODROID_PAYLOAD_HAS_CHANGED",
129 MicrodroidError::PayloadVerificationFailed(_) => {
130 "MICRODROID_PAYLOAD_VERIFICATION_FAILED"
131 }
132 MicrodroidError::InvalidConfig(_) => "MICRODROID_INVALID_PAYLOAD_CONFIG",
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100133 })
Inseob Kim11f40d02022-06-13 17:16:00 +0900134 } else {
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100135 // Send context information back after a separator, to ease diagnosis.
136 // These errors occur before the payload runs, so this should not leak sensitive
137 // information.
138 Owned(format!("MICRODROID_UNKNOWN_RUNTIME_ERROR|{:?}", err))
Inseob Kim11f40d02022-06-13 17:16:00 +0900139 };
140
141 let death_reason_bytes = death_reason.as_bytes();
142 let mut sent_total = 0;
143 while sent_total < death_reason_bytes.len() {
144 // TODO(b/220071963): Sometimes, sending more than 16 bytes at once makes MM hang.
145 let begin = sent_total;
146 let end = std::cmp::min(begin.saturating_add(16), death_reason_bytes.len());
147 OpenOptions::new()
148 .read(false)
149 .write(true)
150 .open(FAILURE_SERIAL_DEVICE)?
151 .write_all(&death_reason_bytes[begin..end])?;
152 sent_total = end;
153 }
154
155 Ok(())
156}
157
Inseob Kim1b95f2e2021-08-19 13:17:40 +0900158fn get_vms_rpc_binder() -> Result<Strong<dyn IVirtualMachineService>> {
Andrew Walbran7eb5ca42022-08-08 15:33:34 +0000159 get_vsock_rpc_interface(VMADDR_CID_HOST, VM_BINDER_SERVICE_PORT as u32)
Andrew Walbranc4ce7872022-07-29 11:26:41 +0000160 .context("Cannot connect to RPC service")
Inseob Kim1b95f2e2021-08-19 13:17:40 +0900161}
162
Inseob Kim437f1052022-06-21 11:30:22 +0900163fn main() -> Result<()> {
Inseob Kim7ff121c2022-11-14 18:13:23 +0900164 // If debuggable, print full backtrace to console log with stdio_to_kmsg
165 if system_properties::read_bool(APP_DEBUGGABLE_PROP, true)? {
166 env::set_var("RUST_BACKTRACE", "full");
167 }
168
Inseob Kim437f1052022-06-21 11:30:22 +0900169 scopeguard::defer! {
170 info!("Shutting down...");
Jooyung Hanbfe086f2021-10-28 10:15:45 +0900171 if let Err(e) = system_properties::write("sys.powerctl", "shutdown") {
172 error!("failed to shutdown {:?}", e);
173 }
Jooyung Han311b1202021-09-14 22:00:16 +0900174 }
Inseob Kim437f1052022-06-21 11:30:22 +0900175
176 try_main().map_err(|e| {
177 error!("Failed with {:?}.", e);
178 if let Err(e) = write_death_reason_to_serial(&e) {
179 error!("Failed to write death reason {:?}", e);
180 }
181 e
182 })
Jooyung Han311b1202021-09-14 22:00:16 +0900183}
184
185fn try_main() -> Result<()> {
Andrew Sculle127cff2022-02-15 15:34:04 +0000186 let _ = kernlog::init();
Jooyung Han347d9f22021-05-28 00:05:14 +0900187 info!("started.");
188
Jiyong Park202856e2022-08-22 16:04:26 +0900189 load_crashkernel_if_supported().context("Failed to load crashkernel")?;
190
Keir Fraser933f0ac2022-10-12 08:23:28 +0000191 swap::init_swap().context("Failed to initialise swap")?;
192 info!("swap enabled.");
193
Inseob Kim11f40d02022-06-13 17:16:00 +0900194 let service = get_vms_rpc_binder()
195 .context("cannot connect to VirtualMachineService")
196 .map_err(|e| MicrodroidError::FailedToConnectToVirtualizationService(e.to_string()))?;
Seungjae Yoofd9a0622022-10-14 10:01:29 +0900197
Jooyung Han5c6d4172021-12-06 14:17:52 +0900198 match try_run_payload(&service) {
199 Ok(code) => {
200 info!("notifying payload finished");
201 service.notifyPayloadFinished(code)?;
202 if code == 0 {
203 info!("task successfully finished");
204 } else {
205 error!("task exited with exit code: {}", code);
206 }
207 Ok(())
208 }
209 Err(err) => {
Jooyung Han5c6d4172021-12-06 14:17:52 +0900210 let (error_code, message) = translate_error(&err);
211 service.notifyError(error_code, &message)?;
212 Err(err)
213 }
Jooyung Handd0a1732021-11-23 15:26:20 +0900214 }
215}
216
Alan Stokes1f417c92022-09-29 15:13:28 +0100217fn dice_derivation(
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000218 dice: DiceDriver,
Alan Stokes1f417c92022-09-29 15:13:28 +0100219 verified_data: &MicrodroidData,
220 payload_metadata: &PayloadMetadata,
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000221) -> Result<DiceContext> {
Andrew Scullb2f44472022-01-21 14:41:34 +0000222 // Calculate compound digests of code and authorities
Andrew Sculla0d1b1a2022-05-24 19:32:47 +0000223 let mut code_hash_ctx = Sha512::new();
224 let mut authority_hash_ctx = Sha512::new();
Andrew Scullb2f44472022-01-21 14:41:34 +0000225 code_hash_ctx.update(verified_data.apk_data.root_hash.as_ref());
226 authority_hash_ctx.update(verified_data.apk_data.pubkey.as_ref());
Inseob Kimb2519c52022-04-14 02:10:09 +0900227 for extra_apk in &verified_data.extra_apks_data {
Andrew Scullb2f44472022-01-21 14:41:34 +0000228 code_hash_ctx.update(extra_apk.root_hash.as_ref());
229 authority_hash_ctx.update(extra_apk.pubkey.as_ref());
230 }
Inseob Kimb2519c52022-04-14 02:10:09 +0900231 for apex in &verified_data.apex_data {
Andrew Scullb2f44472022-01-21 14:41:34 +0000232 code_hash_ctx.update(apex.root_digest.as_ref());
233 authority_hash_ctx.update(apex.public_key.as_ref());
234 }
Andrew Sculla0d1b1a2022-05-24 19:32:47 +0000235 let code_hash = code_hash_ctx.finish();
236 let authority_hash = authority_hash_ctx.finish();
Andrew Scullb2f44472022-01-21 14:41:34 +0000237
238 // {
239 // -70002: "Microdroid payload",
Alan Stokes1f417c92022-09-29 15:13:28 +0100240 // ? -71000: tstr // payload_config_path
241 // ? -71001: PayloadConfig
Andrew Scullb2f44472022-01-21 14:41:34 +0000242 // }
Alan Stokes1f417c92022-09-29 15:13:28 +0100243 // PayloadConfig = {
244 // 1: tstr // payload_binary_path
Alan Stokes1f417c92022-09-29 15:13:28 +0100245 // }
246
Andrew Scullb2f44472022-01-21 14:41:34 +0000247 let mut config_desc = vec![
Alan Stokes1f417c92022-09-29 15:13:28 +0100248 0xa2, // map(2)
249 0x3a, 0x00, 0x01, 0x11, 0x71, // -70002
250 0x72, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x20, 0x70, 0x61, 0x79,
251 0x6c, 0x6f, 0x61, 0x64, // "Microdroid payload"
Andrew Scullb2f44472022-01-21 14:41:34 +0000252 ];
Alan Stokes1f417c92022-09-29 15:13:28 +0100253
254 match payload_metadata {
255 PayloadMetadata::config_path(payload_config_path) => {
256 encode_negative_number(-71000, &mut config_desc)?;
257 encode_tstr(payload_config_path, &mut config_desc)?;
258 }
259 PayloadMetadata::config(payload_config) => {
260 encode_negative_number(-71001, &mut config_desc)?;
261 encode_header(5, 1, &mut config_desc)?; // map(1)
262 encode_number(1, &mut config_desc)?;
263 encode_tstr(&payload_config.payload_binary_path, &mut config_desc)?;
264 }
265 }
Andrew Scullb2f44472022-01-21 14:41:34 +0000266
Andrew Scull65ddfc42022-02-14 21:03:58 +0000267 // Check app debuggability, conervatively assuming it is debuggable
268 let app_debuggable = system_properties::read_bool(APP_DEBUGGABLE_PROP, true)?;
269
Andrew Scullb2f44472022-01-21 14:41:34 +0000270 // Send the details to diced
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000271 let hidden = verified_data.salt.clone().try_into().unwrap();
272 dice.derive(code_hash, &config_desc, authority_hash, app_debuggable, hidden)
Andrew Scullb2f44472022-01-21 14:41:34 +0000273}
274
Alan Stokes1f417c92022-09-29 15:13:28 +0100275fn encode_tstr(tstr: &str, buffer: &mut Vec<u8>) -> Result<()> {
276 let bytes = tstr.as_bytes();
277 encode_header(3, bytes.len().try_into().unwrap(), buffer)?;
278 buffer.extend_from_slice(bytes);
279 Ok(())
280}
281
282fn encode_negative_number(n: i64, buffer: &mut dyn Write) -> Result<()> {
283 ensure!(n < 0);
284 let n = -1 - n;
285 encode_header(1, n.try_into().unwrap(), buffer)
286}
287
Andrew Scullab72ec52022-03-14 09:10:52 +0000288fn is_strict_boot() -> bool {
289 Path::new(AVF_STRICT_BOOT).exists()
290}
291
292fn is_new_instance() -> bool {
293 Path::new(AVF_NEW_INSTANCE).exists()
294}
295
Inseob Kime379e7d2022-07-22 18:55:18 +0900296fn is_verified_boot() -> bool {
297 !Path::new(DEBUG_MICRODROID_NO_VERIFIED_BOOT).exists()
298}
299
Jooyung Han5c6d4172021-12-06 14:17:52 +0900300fn try_run_payload(service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
Jooyung Han311b1202021-09-14 22:00:16 +0900301 let metadata = load_metadata().context("Failed to load payload metadata")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000302 let dice = DiceDriver::new(Path::new("/dev/open-dice0")).context("Failed to load DICE")?;
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900303
Jooyung Han311b1202021-09-14 22:00:16 +0900304 let mut instance = InstanceDisk::new().context("Failed to load instance.img")?;
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000305 let saved_data =
306 instance.read_microdroid_data(&dice).context("Failed to read identity data")?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900307
Andrew Scullab72ec52022-03-14 09:10:52 +0000308 if is_strict_boot() {
309 // Provisioning must happen on the first boot and never again.
310 if is_new_instance() {
311 ensure!(
312 saved_data.is_none(),
313 MicrodroidError::InvalidConfig("Found instance data on first boot.".to_string())
314 );
315 } else {
316 ensure!(
317 saved_data.is_some(),
318 MicrodroidError::InvalidConfig("Instance data not found.".to_string())
319 );
320 };
321 }
322
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900323 // Verify the payload before using it.
Inseob Kim11f40d02022-06-13 17:16:00 +0900324 let verified_data = verify_payload(&metadata, saved_data.as_ref())
325 .context("Payload verification failed")
326 .map_err(|e| MicrodroidError::PayloadVerificationFailed(e.to_string()))?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900327
328 // In case identity is ignored (by debug policy), we should reuse existing payload data, even
329 // when the payload is changed. This is to keep the derived secret same as before.
330 let verified_data = if let Some(saved_data) = saved_data {
331 if !is_verified_boot() {
332 if saved_data != verified_data {
333 info!("Detected an update of the payload, but continue (regarding debug policy)")
334 }
335 } else {
336 ensure!(
337 saved_data == verified_data,
338 MicrodroidError::PayloadChanged(String::from(
339 "Detected an update of the payload which isn't supported yet."
340 ))
341 );
342 info!("Saved data is verified.");
343 }
344 saved_data
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900345 } else {
Jooyung Han7a343f92021-09-08 22:53:11 +0900346 info!("Saving verified data.");
Andrew Sculld64ae7d2022-10-05 17:41:43 +0000347 instance
348 .write_microdroid_data(&verified_data, &dice)
349 .context("Failed to write identity data")?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900350 verified_data
351 };
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900352
Alan Stokes1f417c92022-09-29 15:13:28 +0100353 let payload_metadata = metadata.payload.ok_or_else(|| {
354 MicrodroidError::InvalidConfig("No payload config in metadata".to_string())
355 })?;
Alan Stokes0d1ef782022-09-27 13:46:35 +0100356
Inseob Kimb2519c52022-04-14 02:10:09 +0900357 // To minimize the exposure to untrusted data, derive dice profile as soon as possible.
358 info!("DICE derivation for payload");
Shikha Panwar566c9672022-11-15 14:39:58 +0000359 let dice_context = dice_derivation(dice, &verified_data, &payload_metadata)?;
360
361 // Run encryptedstore binary to prepare the storage
362 let encryptedstore_child = if Path::new(ENCRYPTEDSTORE_BACKING_DEVICE).exists() {
363 info!("Preparing encryptedstore ...");
364 Some(prepare_encryptedstore(&dice_context).context("encryptedstore run")?)
365 } else {
366 None
367 };
Inseob Kimb2519c52022-04-14 02:10:09 +0900368
Jooyung Hana6d11eb2021-09-10 11:48:05 +0900369 // Before reading a file from the APK, start zipfuse
Inseob Kim217038e2021-11-25 11:15:06 +0900370 run_zipfuse(
Alan Stokes60f82202022-10-07 16:40:07 +0100371 MountForExec::Allowed,
Inseob Kim217038e2021-11-25 11:15:06 +0900372 "fscontext=u:object_r:zipfusefs:s0,context=u:object_r:system_file:s0",
373 Path::new("/dev/block/mapper/microdroid-apk"),
Alice Wang6bbb6da2022-10-26 12:44:06 +0000374 Path::new(VM_APK_CONTENTS_PATH),
Alan Stokes60f82202022-10-07 16:40:07 +0100375 Some(APK_MOUNT_DONE_PROP),
Inseob Kim217038e2021-11-25 11:15:06 +0900376 )
377 .context("Failed to run zipfuse")?;
Jiyong Park21ce2c52021-08-28 02:32:17 +0900378
Andrew Scull4d262dc2022-10-21 13:14:33 +0000379 // Restricted APIs are only allowed to be used by platform or test components. Infer this from
380 // the use of a VM config file since those can only be used by platform and test components.
381 let allow_restricted_apis = match payload_metadata {
382 PayloadMetadata::config_path(_) => true,
383 PayloadMetadata::config(_) => false,
384 };
385
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100386 let config = load_config(payload_metadata).context("Failed to load payload metadata")?;
Shikha Panwar6f03c942022-04-13 20:26:50 +0000387
Alan Stokes01b3ef02022-09-22 17:43:24 +0100388 let task = config
389 .task
390 .as_ref()
391 .ok_or_else(|| MicrodroidError::InvalidConfig("No task in VM config".to_string()))?;
392
Inseob Kim197748b2021-12-01 19:49:00 +0900393 if config.extra_apks.len() != verified_data.extra_apks_data.len() {
394 return Err(anyhow!(
Alan Stokes1f417c92022-09-29 15:13:28 +0100395 "config expects {} extra apks, but found {}",
Inseob Kim197748b2021-12-01 19:49:00 +0900396 config.extra_apks.len(),
397 verified_data.extra_apks_data.len()
398 ));
399 }
400 mount_extra_apks(&config)?;
Jooyung Han634e2d72021-06-10 16:27:38 +0900401
Jooyung Han5c6d4172021-12-06 14:17:52 +0900402 // Wait until apex config is done. (e.g. linker configuration for apexes)
403 // TODO(jooyung): wait until sys.boot_completed?
404 wait_for_apex_config_done()?;
405
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900406 // Start tombstone_transmit if enabled
407 if config.export_tombstones {
Alan Stokes01b3ef02022-09-22 17:43:24 +0100408 control_service("start", "tombstone_transmit")?;
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900409 } else {
Alan Stokes01b3ef02022-09-22 17:43:24 +0100410 control_service("stop", "tombstoned")?;
Inseob Kimcd9c1dd2022-07-13 17:13:45 +0900411 }
412
Alan Stokes01b3ef02022-09-22 17:43:24 +0100413 // Start authfs if enabled
414 if config.enable_authfs {
415 control_service("start", "authfs_service")?;
416 }
417
Alan Stokes60f82202022-10-07 16:40:07 +0100418 // Wait until zipfuse has mounted the APK so we can access the payload
419 wait_for_property_true(APK_MOUNT_DONE_PROP).context("Failed waiting for APK mount done")?;
420
Shikha Panwar566c9672022-11-15 14:39:58 +0000421 register_vm_payload_service(allow_restricted_apis, service.clone(), dice_context)?;
422
423 if let Some(mut child) = encryptedstore_child {
424 let exitcode = child.wait().context("Wait for encryptedstore child")?;
425 ensure!(exitcode.success(), "Unable to prepare encrypted storage. Exitcode={}", exitcode);
426 }
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100427
428 system_properties::write("dev.bootcomplete", "1").context("set dev.bootcomplete")?;
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100429 exec_task(task, service).context("Failed to run payload")
Alan Stokes01b3ef02022-09-22 17:43:24 +0100430}
431
432fn control_service(action: &str, service: &str) -> Result<()> {
433 system_properties::write(&format!("ctl.{}", action), service)
434 .with_context(|| format!("Failed to {} {}", action, service))
Jooyung Han347d9f22021-05-28 00:05:14 +0900435}
436
Inseob Kim217038e2021-11-25 11:15:06 +0900437struct ApkDmverityArgument<'a> {
438 apk: &'a str,
439 idsig: &'a str,
440 name: &'a str,
Inseob Kim197748b2021-12-01 19:49:00 +0900441 saved_root_hash: Option<&'a RootHash>,
Inseob Kim217038e2021-11-25 11:15:06 +0900442}
443
444fn run_apkdmverity(args: &[ApkDmverityArgument]) -> Result<Child> {
445 let mut cmd = Command::new(APKDMVERITY_BIN);
446
447 cmd.stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null());
448
449 for argument in args {
450 cmd.arg("--apk").arg(argument.apk).arg(argument.idsig).arg(argument.name);
Inseob Kim197748b2021-12-01 19:49:00 +0900451 if let Some(root_hash) = argument.saved_root_hash {
452 cmd.arg(&to_hex_string(root_hash));
453 } else {
454 cmd.arg("none");
455 }
Inseob Kim217038e2021-11-25 11:15:06 +0900456 }
457
458 cmd.spawn().context("Spawn apkdmverity")
459}
460
Alan Stokes60f82202022-10-07 16:40:07 +0100461enum MountForExec {
462 Allowed,
463 Disallowed,
464}
465
466fn run_zipfuse(
467 noexec: MountForExec,
468 option: &str,
469 zip_path: &Path,
470 mount_dir: &Path,
471 ready_prop: Option<&str>,
472) -> Result<Child> {
Andrew Scullcc339a12022-07-04 12:44:19 +0000473 let mut cmd = Command::new(ZIPFUSE_BIN);
Alan Stokes60f82202022-10-07 16:40:07 +0100474 if let MountForExec::Disallowed = noexec {
Andrew Scullcc339a12022-07-04 12:44:19 +0000475 cmd.arg("--noexec");
476 }
Alan Stokes60f82202022-10-07 16:40:07 +0100477 if let Some(property_name) = ready_prop {
478 cmd.args(["-p", property_name]);
479 }
Andrew Scullcc339a12022-07-04 12:44:19 +0000480 cmd.arg("-o")
Inseob Kim217038e2021-11-25 11:15:06 +0900481 .arg(option)
482 .arg(zip_path)
483 .arg(mount_dir)
484 .stdin(Stdio::null())
485 .stdout(Stdio::null())
486 .stderr(Stdio::null())
487 .spawn()
488 .context("Spawn zipfuse")
489}
490
Inseob Kime379e7d2022-07-22 18:55:18 +0900491fn write_apex_payload_data(
492 saved_data: Option<&MicrodroidData>,
493 apex_data_from_payload: &[ApexData],
494) -> Result<()> {
495 if let Some(saved_apex_data) = saved_data.map(|d| &d.apex_data) {
496 // We don't support APEX updates. (assuming that update will change root digest)
497 ensure!(
498 saved_apex_data == apex_data_from_payload,
499 MicrodroidError::PayloadChanged(String::from("APEXes have changed."))
500 );
501 let apex_metadata = to_metadata(apex_data_from_payload);
502 // Pass metadata(with public keys and root digests) to apexd so that it uses the passed
503 // metadata instead of the default one (/dev/block/by-name/payload-metadata)
504 OpenOptions::new()
505 .create_new(true)
506 .write(true)
507 .open("/apex/vm-payload-metadata")
508 .context("Failed to open /apex/vm-payload-metadata")
509 .and_then(|f| write_metadata(&apex_metadata, f))?;
510 }
511 Ok(())
512}
513
Jooyung Han7a343f92021-09-08 22:53:11 +0900514// Verify payload before executing it. For APK payload, Full verification (which is slow) is done
515// when the root_hash values from the idsig file and the instance disk are different. This function
516// returns the verified root hash (for APK payload) and pubkeys (for APEX payloads) that can be
517// saved to the instance disk.
518fn verify_payload(
519 metadata: &Metadata,
520 saved_data: Option<&MicrodroidData>,
521) -> Result<MicrodroidData> {
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900522 let start_time = SystemTime::now();
523
Inseob Kim197748b2021-12-01 19:49:00 +0900524 // Verify main APK
Jooyung Han7a343f92021-09-08 22:53:11 +0900525 let root_hash = saved_data.map(|d| &d.apk_data.root_hash);
Inseob Kim197748b2021-12-01 19:49:00 +0900526 let root_hash_from_idsig = get_apk_root_hash_from_idsig(MAIN_APK_IDSIG_PATH)?;
Jiyong Parkf7dea252021-09-08 01:42:54 +0900527 let root_hash_trustful = root_hash == Some(&root_hash_from_idsig);
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900528
Jiyong Parkf7dea252021-09-08 01:42:54 +0900529 // 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 +0900530 // instead of the value read from the idsig file.
Inseob Kim197748b2021-12-01 19:49:00 +0900531 let main_apk_argument = {
532 ApkDmverityArgument {
533 apk: MAIN_APK_PATH,
534 idsig: MAIN_APK_IDSIG_PATH,
535 name: MAIN_APK_DEVICE_NAME,
536 saved_root_hash: if root_hash_trustful {
537 Some(root_hash_from_idsig.as_ref())
538 } else {
539 None
540 },
541 }
542 };
543 let mut apkdmverity_arguments = vec![main_apk_argument];
544
545 // Verify extra APKs
546 // For now, we can't read the payload config, so glob APKs and idsigs.
547 // Later, we'll see if it matches with the payload config.
548
549 // sort globbed paths to match apks (extra-apk-{idx}) and idsigs (extra-idsig-{idx})
550 // e.g. "extra-apk-0" corresponds to "extra-idsig-0"
551 let extra_apks =
552 sorted(glob(EXTRA_APK_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
553 let extra_idsigs =
554 sorted(glob(EXTRA_IDSIG_PATH_PATTERN)?.collect::<Result<Vec<_>, _>>()?).collect::<Vec<_>>();
555 if extra_apks.len() != extra_idsigs.len() {
556 return Err(anyhow!(
557 "Extra apks/idsigs mismatch: {} apks but {} idsigs",
558 extra_apks.len(),
559 extra_idsigs.len()
560 ));
561 }
562 let extra_apks_count = extra_apks.len();
563
564 let (extra_apk_names, extra_root_hashes_from_idsig): (Vec<_>, Vec<_>) = extra_idsigs
565 .iter()
566 .enumerate()
567 .map(|(i, extra_idsig)| {
568 (
569 format!("extra-apk-{}", i),
Alice Wang89cff012022-09-26 10:05:16 +0000570 get_apk_root_hash_from_idsig(extra_idsig)
Inseob Kim197748b2021-12-01 19:49:00 +0900571 .expect("Can't find root hash from extra idsig"),
572 )
573 })
574 .unzip();
575
576 let saved_extra_root_hashes: Vec<_> = saved_data
577 .map(|d| d.extra_apks_data.iter().map(|apk_data| &apk_data.root_hash).collect())
578 .unwrap_or_else(Vec::new);
579 let extra_root_hashes_trustful: Vec<_> = extra_root_hashes_from_idsig
580 .iter()
581 .enumerate()
582 .map(|(i, root_hash_from_idsig)| {
583 saved_extra_root_hashes.get(i).copied() == Some(root_hash_from_idsig)
584 })
585 .collect();
586
587 for i in 0..extra_apks_count {
588 apkdmverity_arguments.push({
589 ApkDmverityArgument {
590 apk: extra_apks[i].to_str().unwrap(),
591 idsig: extra_idsigs[i].to_str().unwrap(),
592 name: &extra_apk_names[i],
593 saved_root_hash: if extra_root_hashes_trustful[i] {
594 Some(&extra_root_hashes_from_idsig[i])
595 } else {
596 None
597 },
598 }
599 });
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900600 }
601
602 // Start apkdmverity and wait for the dm-verify block
Inseob Kim197748b2021-12-01 19:49:00 +0900603 let mut apkdmverity_child = run_apkdmverity(&apkdmverity_arguments)?;
Jooyung Han7a343f92021-09-08 22:53:11 +0900604
Jooyung Hanc8deb472021-09-13 13:48:25 +0900605 // While waiting for apkdmverity to mount APK, gathers public keys and root digests from
606 // APEX payload.
Jooyung Han7a343f92021-09-08 22:53:11 +0900607 let apex_data_from_payload = get_apex_data_from_payload(metadata)?;
Inseob Kime379e7d2022-07-22 18:55:18 +0900608
609 // Writing /apex/vm-payload-metadata is to verify that the payload isn't changed.
610 // Skip writing it if the debug policy ignoring identity is on
611 if is_verified_boot() {
612 write_apex_payload_data(saved_data, &apex_data_from_payload)?;
Jooyung Han4a9b3bf2021-09-10 17:19:00 +0900613 }
Inseob Kime379e7d2022-07-22 18:55:18 +0900614
Jooyung Han4a9b3bf2021-09-10 17:19:00 +0900615 // Start apexd to activate APEXes
616 system_properties::write("ctl.start", "apexd-vm")?;
Jooyung Han7a343f92021-09-08 22:53:11 +0900617
Inseob Kim217038e2021-11-25 11:15:06 +0900618 // TODO(inseob): add timeout
619 apkdmverity_child.wait()?;
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900620
Jiyong Parkf7dea252021-09-08 01:42:54 +0900621 // Do the full verification if the root_hash is un-trustful. This requires the full scanning of
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900622 // 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 +0900623 // 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 +0900624 // of the VM or APK was updated in the host.
625 // TODO(jooyung): consider multithreading to make this faster
Inseob Kim197748b2021-12-01 19:49:00 +0900626 let main_apk_pubkey = get_public_key_from_apk(DM_MOUNTED_APK_PATH, root_hash_trustful)?;
627 let extra_apks_data = extra_root_hashes_from_idsig
628 .into_iter()
629 .enumerate()
630 .map(|(i, extra_root_hash)| {
631 let mount_path = format!("/dev/block/mapper/{}", &extra_apk_names[i]);
632 let apk_pubkey = get_public_key_from_apk(&mount_path, extra_root_hashes_trustful[i])?;
633 Ok(ApkData { root_hash: extra_root_hash, pubkey: apk_pubkey })
634 })
635 .collect::<Result<Vec<_>>>()?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900636
637 info!("payload verification successful. took {:#?}", start_time.elapsed().unwrap());
638
Andrew Scull34916a72022-01-30 21:34:24 +0000639 // Use the salt from a verified instance, or generate a salt for a new instance.
640 let salt = if let Some(saved_data) = saved_data {
641 saved_data.salt.clone()
642 } else {
643 let mut salt = vec![0u8; 64];
644 salt.as_mut_slice().try_fill(&mut rand::thread_rng())?;
645 salt
646 };
647
Jiyong Parkf7dea252021-09-08 01:42:54 +0900648 // At this point, we can ensure that the root_hash from the idsig file is trusted, either by
649 // fully verifying the APK or by comparing it with the saved root_hash.
Jooyung Han7a343f92021-09-08 22:53:11 +0900650 Ok(MicrodroidData {
Andrew Scull34916a72022-01-30 21:34:24 +0000651 salt,
Inseob Kim197748b2021-12-01 19:49:00 +0900652 apk_data: ApkData { root_hash: root_hash_from_idsig, pubkey: main_apk_pubkey },
653 extra_apks_data,
Jooyung Han7a343f92021-09-08 22:53:11 +0900654 apex_data: apex_data_from_payload,
655 })
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900656}
657
Inseob Kim197748b2021-12-01 19:49:00 +0900658fn mount_extra_apks(config: &VmPayloadConfig) -> Result<()> {
659 // For now, only the number of apks is important, as the mount point and dm-verity name is fixed
660 for i in 0..config.extra_apks.len() {
661 let mount_dir = format!("/mnt/extra-apk/{}", i);
662 create_dir(Path::new(&mount_dir)).context("Failed to create mount dir for extra apks")?;
663
664 // don't wait, just detach
665 run_zipfuse(
Alan Stokes60f82202022-10-07 16:40:07 +0100666 MountForExec::Disallowed,
Inseob Kim197748b2021-12-01 19:49:00 +0900667 "fscontext=u:object_r:zipfusefs:s0,context=u:object_r:extra_apk_file:s0",
668 Path::new(&format!("/dev/block/mapper/extra-apk-{}", i)),
669 Path::new(&mount_dir),
Alan Stokes60f82202022-10-07 16:40:07 +0100670 None,
Inseob Kim197748b2021-12-01 19:49:00 +0900671 )
672 .context("Failed to zipfuse extra apks")?;
673 }
674
675 Ok(())
676}
677
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900678// Waits until linker config is generated
679fn wait_for_apex_config_done() -> Result<()> {
Alan Stokes60f82202022-10-07 16:40:07 +0100680 wait_for_property_true(APEX_CONFIG_DONE_PROP).context("Failed waiting for apex config done")
681}
682
683fn wait_for_property_true(property_name: &str) -> Result<()> {
684 let mut prop = PropertyWatcher::new(property_name)?;
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900685 loop {
686 prop.wait()?;
Alan Stokes60f82202022-10-07 16:40:07 +0100687 if system_properties::read_bool(property_name, false)? {
Jiyong Parkbb4a9872021-09-06 15:59:21 +0900688 break;
689 }
690 }
Jooyung Han19c1d6c2021-08-06 14:08:16 +0900691 Ok(())
692}
693
Alice Wang89cff012022-09-26 10:05:16 +0000694fn get_apk_root_hash_from_idsig<P: AsRef<Path>>(idsig_path: P) -> Result<Box<RootHash>> {
695 Ok(V4Signature::from_idsig_path(idsig_path)?.hashing_info.raw_root_hash)
Jiyong Park21ce2c52021-08-28 02:32:17 +0900696}
697
Inseob Kim197748b2021-12-01 19:49:00 +0900698fn get_public_key_from_apk(apk: &str, root_hash_trustful: bool) -> Result<Box<[u8]>> {
699 if !root_hash_trustful {
700 verify(apk).context(MicrodroidError::PayloadVerificationFailed(format!(
701 "failed to verify {}",
702 apk
703 )))
704 } else {
705 get_public_key_der(apk)
706 }
707}
708
Alan Stokes1f417c92022-09-29 15:13:28 +0100709fn load_config(payload_metadata: PayloadMetadata) -> Result<VmPayloadConfig> {
710 match payload_metadata {
711 PayloadMetadata::config_path(path) => {
712 let path = Path::new(&path);
713 info!("loading config from {:?}...", path);
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100714 let file = ioutil::wait_for_file(path, WAIT_TIMEOUT)
715 .with_context(|| format!("Failed to read {:?}", path))?;
Alan Stokes1f417c92022-09-29 15:13:28 +0100716 Ok(serde_json::from_reader(file)?)
717 }
718 PayloadMetadata::config(payload_config) => {
719 let task = Task {
720 type_: TaskType::MicrodroidLauncher,
721 command: payload_config.payload_binary_path,
Alan Stokes1f417c92022-09-29 15:13:28 +0100722 };
723 Ok(VmPayloadConfig {
724 os: OsConfig { name: "microdroid".to_owned() },
725 task: Some(task),
726 apexes: vec![],
727 extra_apks: vec![],
728 prefer_staged: false,
729 export_tombstones: false,
730 enable_authfs: false,
731 })
732 }
733 }
Jooyung Han634e2d72021-06-10 16:27:38 +0900734}
735
Jiyong Park202856e2022-08-22 16:04:26 +0900736/// Loads the crashkernel into memory using kexec if the VM is loaded with `crashkernel=' parameter
737/// in the cmdline.
738fn load_crashkernel_if_supported() -> Result<()> {
739 let supported = std::fs::read_to_string("/proc/cmdline")?.contains(" crashkernel=");
740 info!("ramdump supported: {}", supported);
741 if supported {
742 let status = Command::new("/system/bin/kexec_load").status()?;
743 if !status.success() {
744 return Err(anyhow!("Failed to load crashkernel: {:?}", status));
745 }
746 }
747 Ok(())
748}
749
Jiyong Park8611a6c2021-07-09 18:17:44 +0900750/// Executes the given task. Stdout of the task is piped into the vsock stream to the
751/// virtualizationservice in the host side.
Jooyung Han5c6d4172021-12-06 14:17:52 +0900752fn exec_task(task: &Task, service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
Jiyong Park8611a6c2021-07-09 18:17:44 +0900753 info!("executing main task {:?}...", task);
Inseob Kim86ca0162021-10-20 02:21:02 +0000754 let mut command = build_command(task)?;
Inseob Kim7f61fe72021-08-20 20:50:47 +0900755
756 info!("notifying payload started");
Inseob Kimc7d28c72021-10-25 14:28:10 +0000757 service.notifyPayloadStarted()?;
Inseob Kim7f61fe72021-08-20 20:50:47 +0900758
Inseob Kim86ca0162021-10-20 02:21:02 +0000759 let exit_status = command.spawn()?.wait()?;
Frederick Mayleb5f7b6b2022-11-11 15:24:03 -0800760 match exit_status.code() {
761 Some(exit_code) => Ok(exit_code),
762 None => Err(match exit_status.signal() {
763 Some(signal) => anyhow!(
764 "Payload exited due to signal: {} ({})",
765 signal,
766 Signal::try_from(signal).map_or("unknown", |s| s.as_str())
767 ),
768 None => anyhow!("Payload has neither exit code nor signal"),
769 }),
770 }
Jooyung Han347d9f22021-05-28 00:05:14 +0900771}
Jooyung Han634e2d72021-06-10 16:27:38 +0900772
773fn build_command(task: &Task) -> Result<Command> {
Inseob Kim7f61fe72021-08-20 20:50:47 +0900774 let mut command = match task.type_ {
Alan Stokes52d3c722022-10-04 17:27:13 +0100775 TaskType::Executable => Command::new(&task.command),
Jooyung Han634e2d72021-06-10 16:27:38 +0900776 TaskType::MicrodroidLauncher => {
777 let mut command = Command::new("/system/bin/microdroid_launcher");
Alan Stokes52d3c722022-10-04 17:27:13 +0100778 command.arg(find_library_path(&task.command)?);
Jooyung Han634e2d72021-06-10 16:27:38 +0900779 command
780 }
Inseob Kim7f61fe72021-08-20 20:50:47 +0900781 };
782
Inseob Kimd0587562021-09-01 21:27:32 +0900783 match VsockStream::connect_with_cid_port(VMADDR_CID_HOST, VM_STREAM_SERVICE_PORT as u32) {
Inseob Kim7f61fe72021-08-20 20:50:47 +0900784 Ok(stream) => {
785 // SAFETY: the ownership of the underlying file descriptor is transferred from stream
786 // to the file object, and then into the Command object. When the command is finished,
787 // the file descriptor is closed.
788 let file = unsafe { File::from_raw_fd(stream.into_raw_fd()) };
789 command
790 .stdin(Stdio::from(file.try_clone()?))
791 .stdout(Stdio::from(file.try_clone()?))
792 .stderr(Stdio::from(file));
793 }
794 Err(e) => {
795 error!("failed to connect to virtualization service: {}", e);
796 // Don't fail hard here. Even if we failed to connect to the virtualizationservice,
797 // we keep executing the task. This can happen if the owner of the VM doesn't register
798 // callback to accept the stream. Use /dev/null as the stream so that the task can
799 // make progress without waiting for someone to consume the output.
800 command.stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null());
801 }
802 }
803
804 Ok(command)
Jooyung Han634e2d72021-06-10 16:27:38 +0900805}
806
807fn find_library_path(name: &str) -> Result<String> {
808 let mut watcher = PropertyWatcher::new("ro.product.cpu.abilist")?;
809 let value = watcher.read(|_name, value| Ok(value.trim().to_string()))?;
810 let abi = value.split(',').next().ok_or_else(|| anyhow!("no abilist"))?;
Alice Wang6bbb6da2022-10-26 12:44:06 +0000811 let path = format!("{}/lib/{}/{}", VM_APK_CONTENTS_PATH, abi, name);
Jooyung Han634e2d72021-06-10 16:27:38 +0900812
Alan Stokes3ba10fd2022-10-06 15:46:51 +0100813 let metadata = fs::metadata(&path).with_context(|| format!("Unable to access {}", path))?;
Jooyung Han634e2d72021-06-10 16:27:38 +0900814 if !metadata.is_file() {
815 bail!("{} is not a file", &path);
816 }
817
818 Ok(path)
819}
Jiyong Park21ce2c52021-08-28 02:32:17 +0900820
821fn to_hex_string(buf: &[u8]) -> String {
822 buf.iter().map(|b| format!("{:02X}", b)).collect()
823}
Shikha Panwar566c9672022-11-15 14:39:58 +0000824
825fn prepare_encryptedstore(dice: &DiceContext) -> Result<Child> {
826 // Use a fixed salt to scope the derivation to this API.
827 // Generated using hexdump -vn32 -e'14/1 "0x%02X, " 1 "\n"' /dev/urandom
828 // TODO(b/241541860) : Move this (& other salts) to a salt container, i.e. a global enum
829 let salt = [
830 0xFC, 0x1D, 0x35, 0x7B, 0x96, 0xF3, 0xEF, 0x17, 0x78, 0x7D, 0x70, 0xED, 0xEA, 0xFE, 0x1D,
831 0x6F, 0xB3, 0xF9, 0x40, 0xCE, 0xDD, 0x99, 0x40, 0xAA, 0xA7, 0x0E, 0x92, 0x73, 0x90, 0x86,
832 0x4A, 0x75,
833 ];
834 let key = dice.get_sealing_key(
835 &salt,
836 ENCRYPTEDSTORE_KEY_IDENTIFIER.as_bytes(),
837 ENCRYPTEDSTORE_KEYSIZE,
838 )?;
839
840 let mut cmd = Command::new(ENCRYPTEDSTORE_BIN);
841 cmd.arg("--blkdevice")
842 .arg(ENCRYPTEDSTORE_BACKING_DEVICE)
843 .arg("--key")
844 .arg(hex::encode(&*key))
845 .spawn()
846 .context("encryptedstore failed")
847}