blob: 53302e83dc91593e79533f1fc6227aa40353b62e [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
17use anyhow::{bail, Context, Result};
18use log::error;
19use minijail::{self, Minijail};
20use std::os::unix::io::AsRawFd;
21use std::path::Path;
22
23use authfs_aidl_interface::aidl::com::android::virt::fs::{
24 AuthFsConfig::AuthFsConfig, IAuthFs::IAuthFs, IAuthFsService::IAuthFsService,
25 InputFdAnnotation::InputFdAnnotation, OutputFdAnnotation::OutputFdAnnotation,
26};
27use authfs_aidl_interface::binder::{ParcelFileDescriptor, Strong};
28use compos_aidl_interface::aidl::com::android::compos::Metadata::Metadata;
29
30/// The number that represents the file descriptor number expecting by the task. The number may be
31/// meaningless in the current process.
32pub type PseudoRawFd = i32;
33
34/// Runs the compiler with given flags with file descriptors described in `metadata` retrieved via
35/// `authfs_service`. Returns exit code of the compiler process.
36pub fn compile(
37 compiler_path: &Path,
38 compiler_args: &[String],
39 authfs_service: Strong<dyn IAuthFsService>,
40 metadata: &Metadata,
41) -> Result<i8> {
42 // Mount authfs (via authfs_service).
43 let authfs_config = build_authfs_config(metadata);
44 let authfs = authfs_service.mount(&authfs_config)?;
45
46 // The task expects to receive FD numbers that match its flags (e.g. --zip-fd=42) prepared
47 // on the host side. Since the local FD opened from authfs (e.g. /authfs/42) may not match
48 // the task's expectation, prepare a FD mapping and let minijail prepare the correct FD
49 // setup.
50 let fd_mapping =
51 open_authfs_files_for_fd_mapping(&authfs, &authfs_config).context("Open on authfs")?;
52
53 let jail =
54 spawn_jailed_task(compiler_path, compiler_args, fd_mapping).context("Spawn dex2oat")?;
55 let jail_result = jail.wait();
56
57 // Be explicit about the lifetime, which should last at least until the task is finished.
58 drop(authfs);
59
60 match jail_result {
61 Ok(()) => Ok(0), // TODO(b/161471326): Sign the output on succeed.
62 Err(minijail::Error::ReturnCode(exit_code)) => {
63 error!("Task failed with exit code {}", exit_code);
64 Ok(exit_code as i8)
65 }
66 Err(e) => {
67 bail!("Unexpected minijail error: {}", e)
68 }
69 }
70}
71
72fn build_authfs_config(metadata: &Metadata) -> AuthFsConfig {
73 AuthFsConfig {
74 port: 3264, // TODO: support dynamic port
75 inputFdAnnotations: metadata
76 .input_fd_annotations
77 .iter()
78 .map(|x| InputFdAnnotation { fd: x.fd, fileSize: x.file_size })
79 .collect(),
80 outputFdAnnotations: metadata
81 .output_fd_annotations
82 .iter()
83 .map(|x| OutputFdAnnotation { fd: x.fd })
84 .collect(),
85 }
86}
87
88fn open_authfs_files_for_fd_mapping(
89 authfs: &Strong<dyn IAuthFs>,
90 config: &AuthFsConfig,
91) -> Result<Vec<(ParcelFileDescriptor, PseudoRawFd)>> {
92 let mut fd_mapping = Vec::new();
93
94 let results: Result<Vec<_>> = config
95 .inputFdAnnotations
96 .iter()
97 .map(|annotation| Ok((authfs.openFile(annotation.fd, false)?, annotation.fd)))
98 .collect();
99 fd_mapping.append(&mut results?);
100
101 let results: Result<Vec<_>> = config
102 .outputFdAnnotations
103 .iter()
104 .map(|annotation| Ok((authfs.openFile(annotation.fd, true)?, annotation.fd)))
105 .collect();
106 fd_mapping.append(&mut results?);
107
108 Ok(fd_mapping)
109}
110
111fn spawn_jailed_task(
112 executable: &Path,
113 args: &[String],
114 fd_mapping: Vec<(ParcelFileDescriptor, PseudoRawFd)>,
115) -> Result<Minijail> {
116 // TODO(b/185175567): Run in a more restricted sandbox.
117 let jail = Minijail::new()?;
118 let preserve_fds: Vec<_> = fd_mapping.iter().map(|(f, id)| (f.as_raw_fd(), *id)).collect();
119 let _pid = jail.run_remap(executable, preserve_fds.as_slice(), args)?;
120 Ok(jail)
121}