1 /*
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
17 //! A helper library to start a fd_server.
18
19 use anyhow::{Context, Result};
20 use log::{debug, warn};
21 use minijail::Minijail;
22 use nix::fcntl::OFlag;
23 use nix::unistd::pipe2;
24 use std::fs::File;
25 use std::io::Read;
26 use std::os::unix::io::{AsRawFd, OwnedFd};
27 use std::path::Path;
28
29 const FD_SERVER_BIN: &str = "/apex/com.android.virt/bin/fd_server";
30
31 /// Config for starting a `FdServer`
32 #[derive(Default)]
33 pub struct FdServerConfig {
34 /// List of file FDs exposed for read-only operations.
35 pub ro_file_fds: Vec<OwnedFd>,
36 /// List of file FDs exposed for read-write operations.
37 pub rw_file_fds: Vec<OwnedFd>,
38 /// List of directory FDs exposed for read-only operations.
39 pub ro_dir_fds: Vec<OwnedFd>,
40 /// List of directory FDs exposed for read-write operations.
41 pub rw_dir_fds: Vec<OwnedFd>,
42 }
43
44 impl FdServerConfig {
45 /// Creates a `FdServer` based on the current config.
into_fd_server(self) -> Result<FdServer>46 pub fn into_fd_server(self) -> Result<FdServer> {
47 let (ready_read_fd, ready_write_fd) = create_pipe()?;
48 let fd_server_jail = self.do_spawn_fd_server(ready_write_fd)?;
49 wait_for_fd_server_ready(ready_read_fd)?;
50 Ok(FdServer { jailed_process: fd_server_jail })
51 }
52
do_spawn_fd_server(self, ready_file: File) -> Result<Minijail>53 fn do_spawn_fd_server(self, ready_file: File) -> Result<Minijail> {
54 let mut inheritable_fds = Vec::new();
55 let mut args = vec![FD_SERVER_BIN.to_string()];
56 for fd in &self.ro_file_fds {
57 let raw_fd = fd.as_raw_fd();
58 args.push("--ro-fds".to_string());
59 args.push(raw_fd.to_string());
60 inheritable_fds.push(raw_fd);
61 }
62 for fd in &self.rw_file_fds {
63 let raw_fd = fd.as_raw_fd();
64 args.push("--rw-fds".to_string());
65 args.push(raw_fd.to_string());
66 inheritable_fds.push(raw_fd);
67 }
68 for fd in &self.ro_dir_fds {
69 let raw_fd = fd.as_raw_fd();
70 args.push("--ro-dirs".to_string());
71 args.push(raw_fd.to_string());
72 inheritable_fds.push(raw_fd);
73 }
74 for fd in &self.rw_dir_fds {
75 let raw_fd = fd.as_raw_fd();
76 args.push("--rw-dirs".to_string());
77 args.push(raw_fd.to_string());
78 inheritable_fds.push(raw_fd);
79 }
80 let ready_fd = ready_file.as_raw_fd();
81 args.push("--ready-fd".to_string());
82 args.push(ready_fd.to_string());
83 inheritable_fds.push(ready_fd);
84
85 debug!("Spawn fd_server {:?} (inheriting FDs: {:?})", args, inheritable_fds);
86 let jail = Minijail::new()?;
87 let _pid = jail.run(Path::new(FD_SERVER_BIN), &inheritable_fds, &args)?;
88 Ok(jail)
89 }
90 }
91
92 /// `FdServer` represents a running `fd_server` process. The process lifetime is associated with
93 /// the instance lifetime.
94 pub struct FdServer {
95 jailed_process: Minijail,
96 }
97
98 impl Drop for FdServer {
drop(&mut self)99 fn drop(&mut self) {
100 if let Err(e) = self.jailed_process.kill() {
101 if !matches!(e, minijail::Error::Killed(_)) {
102 warn!("Failed to kill fd_server: {}", e);
103 }
104 }
105 }
106 }
107
create_pipe() -> Result<(File, File)>108 fn create_pipe() -> Result<(File, File)> {
109 let (read_fd, write_fd) = pipe2(OFlag::O_CLOEXEC)?;
110 Ok((read_fd.into(), write_fd.into()))
111 }
112
wait_for_fd_server_ready(mut ready_fd: File) -> Result<()>113 fn wait_for_fd_server_ready(mut ready_fd: File) -> Result<()> {
114 let mut buffer = [0];
115 // When fd_server is ready it closes its end of the pipe. And if it exits, the pipe is also
116 // closed. Either way this read will return 0 bytes at that point, and there's no point waiting
117 // any longer.
118 let _ = ready_fd.read(&mut buffer).context("Waiting for fd_server to be ready")?;
119 debug!("fd_server is ready");
120 Ok(())
121 }
122