blob: 72dca146d3d2ddea49f7a66658534d3b4609e1a7 [file] [log] [blame]
Victor Hsieh51789de2021-08-06 16:50:49 -07001/*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Victor Hsieh6e340382021-08-13 12:18:02 -070017use anyhow::{anyhow, bail, Context, Result};
Victor Hsieh51789de2021-08-06 16:50:49 -070018use log::error;
19use minijail::{self, Minijail};
Victor Hsieh6e340382021-08-13 12:18:02 -070020use std::fs::File;
Victor Hsieh6e340382021-08-13 12:18:02 -070021use std::os::unix::io::{AsRawFd, RawFd};
Victor Hsieh51789de2021-08-06 16:50:49 -070022use std::path::Path;
23
Victor Hsieh9ed27182021-08-25 15:52:42 -070024use crate::fsverity;
Victor Hsieh51789de2021-08-06 16:50:49 -070025use authfs_aidl_interface::aidl::com::android::virt::fs::{
Victor Hsieh015bcb52021-11-17 17:28:01 -080026 AuthFsConfig::{
27 AuthFsConfig, InputFdAnnotation::InputFdAnnotation, OutputFdAnnotation::OutputFdAnnotation,
28 },
29 IAuthFs::IAuthFs,
30 IAuthFsService::IAuthFsService,
Victor Hsieh51789de2021-08-06 16:50:49 -070031};
32use authfs_aidl_interface::binder::{ParcelFileDescriptor, Strong};
Victor Hsieh13333e82021-09-03 15:17:32 -070033use compos_aidl_interface::aidl::com::android::compos::FdAnnotation::FdAnnotation;
Victor Hsieh51789de2021-08-06 16:50:49 -070034
35/// The number that represents the file descriptor number expecting by the task. The number may be
36/// meaningless in the current process.
37pub type PseudoRawFd = i32;
38
Victor Hsieh6e340382021-08-13 12:18:02 -070039pub enum CompilerOutput {
40 /// Fs-verity digests of output files, if the compiler finishes successfully.
Victor Hsieh9ed27182021-08-25 15:52:42 -070041 Digests {
42 oat: fsverity::Sha256Digest,
43 vdex: fsverity::Sha256Digest,
44 image: fsverity::Sha256Digest,
45 },
Victor Hsieh6e340382021-08-13 12:18:02 -070046 /// Exit code returned by the compiler, if not 0.
47 ExitCode(i8),
48}
49
50struct CompilerOutputParcelFds {
51 oat: ParcelFileDescriptor,
52 vdex: ParcelFileDescriptor,
53 image: ParcelFileDescriptor,
54}
55
Victor Hsieh13333e82021-09-03 15:17:32 -070056/// Runs the compiler with given flags with file descriptors described in `fd_annotation` retrieved
57/// via `authfs_service`. Returns exit code of the compiler process.
Victor Hsieh3c044c42021-10-01 17:17:10 -070058pub fn compile_cmd(
Victor Hsieh51789de2021-08-06 16:50:49 -070059 compiler_path: &Path,
60 compiler_args: &[String],
61 authfs_service: Strong<dyn IAuthFsService>,
Victor Hsieh13333e82021-09-03 15:17:32 -070062 fd_annotation: &FdAnnotation,
Victor Hsieh6e340382021-08-13 12:18:02 -070063) -> Result<CompilerOutput> {
64 // Mount authfs (via authfs_service). The authfs instance unmounts once the `authfs` variable
65 // is out of scope.
Victor Hsieh13333e82021-09-03 15:17:32 -070066 let authfs_config = build_authfs_config(fd_annotation);
Victor Hsieh51789de2021-08-06 16:50:49 -070067 let authfs = authfs_service.mount(&authfs_config)?;
68
69 // The task expects to receive FD numbers that match its flags (e.g. --zip-fd=42) prepared
70 // on the host side. Since the local FD opened from authfs (e.g. /authfs/42) may not match
71 // the task's expectation, prepare a FD mapping and let minijail prepare the correct FD
72 // setup.
73 let fd_mapping =
74 open_authfs_files_for_fd_mapping(&authfs, &authfs_config).context("Open on authfs")?;
75
76 let jail =
77 spawn_jailed_task(compiler_path, compiler_args, fd_mapping).context("Spawn dex2oat")?;
78 let jail_result = jail.wait();
79
Victor Hsieh6e340382021-08-13 12:18:02 -070080 let parcel_fds = parse_compiler_args(&authfs, compiler_args)?;
81 let oat_file: &File = parcel_fds.oat.as_ref();
82 let vdex_file: &File = parcel_fds.vdex.as_ref();
83 let image_file: &File = parcel_fds.image.as_ref();
Victor Hsieh51789de2021-08-06 16:50:49 -070084
85 match jail_result {
Victor Hsieh6e340382021-08-13 12:18:02 -070086 Ok(()) => Ok(CompilerOutput::Digests {
Victor Hsieh9ed27182021-08-25 15:52:42 -070087 oat: fsverity::measure(oat_file.as_raw_fd())?,
88 vdex: fsverity::measure(vdex_file.as_raw_fd())?,
89 image: fsverity::measure(image_file.as_raw_fd())?,
Victor Hsieh6e340382021-08-13 12:18:02 -070090 }),
Victor Hsieh51789de2021-08-06 16:50:49 -070091 Err(minijail::Error::ReturnCode(exit_code)) => {
Victor Hsieh6e340382021-08-13 12:18:02 -070092 error!("dex2oat failed with exit code {}", exit_code);
93 Ok(CompilerOutput::ExitCode(exit_code as i8))
Victor Hsieh51789de2021-08-06 16:50:49 -070094 }
95 Err(e) => {
96 bail!("Unexpected minijail error: {}", e)
97 }
98 }
99}
100
Victor Hsieh6e340382021-08-13 12:18:02 -0700101fn parse_compiler_args(
102 authfs: &Strong<dyn IAuthFs>,
103 args: &[String],
104) -> Result<CompilerOutputParcelFds> {
105 const OAT_FD_PREFIX: &str = "--oat-fd=";
106 const VDEX_FD_PREFIX: &str = "--output-vdex-fd=";
107 const IMAGE_FD_PREFIX: &str = "--image-fd=";
108 const APP_IMAGE_FD_PREFIX: &str = "--app-image-fd=";
109
110 let mut oat = None;
111 let mut vdex = None;
112 let mut image = None;
113
114 for arg in args {
115 if let Some(value) = arg.strip_prefix(OAT_FD_PREFIX) {
116 let fd = value.parse::<RawFd>().context("Invalid --oat-fd flag")?;
117 debug_assert!(oat.is_none());
118 oat = Some(authfs.openFile(fd, false)?);
119 } else if let Some(value) = arg.strip_prefix(VDEX_FD_PREFIX) {
120 let fd = value.parse::<RawFd>().context("Invalid --output-vdex-fd flag")?;
121 debug_assert!(vdex.is_none());
122 vdex = Some(authfs.openFile(fd, false)?);
123 } else if let Some(value) = arg.strip_prefix(IMAGE_FD_PREFIX) {
124 let fd = value.parse::<RawFd>().context("Invalid --image-fd flag")?;
125 debug_assert!(image.is_none());
126 image = Some(authfs.openFile(fd, false)?);
127 } else if let Some(value) = arg.strip_prefix(APP_IMAGE_FD_PREFIX) {
128 let fd = value.parse::<RawFd>().context("Invalid --app-image-fd flag")?;
129 debug_assert!(image.is_none());
130 image = Some(authfs.openFile(fd, false)?);
131 }
132 }
133
134 Ok(CompilerOutputParcelFds {
135 oat: oat.ok_or_else(|| anyhow!("Missing --oat-fd"))?,
136 vdex: vdex.ok_or_else(|| anyhow!("Missing --vdex-fd"))?,
137 image: image.ok_or_else(|| anyhow!("Missing --image-fd or --app-image-fd"))?,
138 })
139}
140
Victor Hsieh13333e82021-09-03 15:17:32 -0700141fn build_authfs_config(fd_annotation: &FdAnnotation) -> AuthFsConfig {
Victor Hsieh51789de2021-08-06 16:50:49 -0700142 AuthFsConfig {
143 port: 3264, // TODO: support dynamic port
Victor Hsieh13333e82021-09-03 15:17:32 -0700144 inputFdAnnotations: fd_annotation
145 .input_fds
Victor Hsieh51789de2021-08-06 16:50:49 -0700146 .iter()
Victor Hsieh13333e82021-09-03 15:17:32 -0700147 .map(|fd| InputFdAnnotation { fd: *fd })
Victor Hsieh51789de2021-08-06 16:50:49 -0700148 .collect(),
Victor Hsieh13333e82021-09-03 15:17:32 -0700149 outputFdAnnotations: fd_annotation
150 .output_fds
Victor Hsieh51789de2021-08-06 16:50:49 -0700151 .iter()
Victor Hsieh13333e82021-09-03 15:17:32 -0700152 .map(|fd| OutputFdAnnotation { fd: *fd })
Victor Hsieh51789de2021-08-06 16:50:49 -0700153 .collect(),
Victor Hsieh015bcb52021-11-17 17:28:01 -0800154 inputDirFdAnnotations: vec![],
155 outputDirFdAnnotations: vec![],
Victor Hsieh51789de2021-08-06 16:50:49 -0700156 }
157}
158
159fn open_authfs_files_for_fd_mapping(
160 authfs: &Strong<dyn IAuthFs>,
161 config: &AuthFsConfig,
162) -> Result<Vec<(ParcelFileDescriptor, PseudoRawFd)>> {
163 let mut fd_mapping = Vec::new();
164
165 let results: Result<Vec<_>> = config
166 .inputFdAnnotations
167 .iter()
168 .map(|annotation| Ok((authfs.openFile(annotation.fd, false)?, annotation.fd)))
169 .collect();
170 fd_mapping.append(&mut results?);
171
172 let results: Result<Vec<_>> = config
173 .outputFdAnnotations
174 .iter()
175 .map(|annotation| Ok((authfs.openFile(annotation.fd, true)?, annotation.fd)))
176 .collect();
177 fd_mapping.append(&mut results?);
178
179 Ok(fd_mapping)
180}
181
182fn spawn_jailed_task(
183 executable: &Path,
184 args: &[String],
185 fd_mapping: Vec<(ParcelFileDescriptor, PseudoRawFd)>,
186) -> Result<Minijail> {
187 // TODO(b/185175567): Run in a more restricted sandbox.
188 let jail = Minijail::new()?;
189 let preserve_fds: Vec<_> = fd_mapping.iter().map(|(f, id)| (f.as_raw_fd(), *id)).collect();
190 let _pid = jail.run_remap(executable, preserve_fds.as_slice(), args)?;
191 Ok(jail)
192}