1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 use std::collections::HashSet;
6 use std::ffi::OsString;
7 use std::fs::OpenOptions;
8
9 use anyhow::anyhow;
10 use anyhow::Result;
11 use argh::CommandInfo;
12 use argh::FromArgs;
13 use argh::SubCommand;
14 use base::info;
15 use base::syslog;
16 use base::syslog::LogArgs;
17 use base::syslog::LogConfig;
18 use base::FromRawDescriptor;
19 use base::RawDescriptor;
20 use broker_ipc::common_child_setup;
21 use broker_ipc::CommonChildStartupArgs;
22 use crosvm_cli::sys::windows::exit::Exit;
23 use crosvm_cli::sys::windows::exit::ExitContext;
24 use crosvm_cli::sys::windows::exit::ExitContextAnyhow;
25 use metrics::MetricEventType;
26 #[cfg(feature = "slirp")]
27 use net_util::slirp::sys::windows::SlirpStartupConfig;
28 use tube_transporter::TubeToken;
29 use tube_transporter::TubeTransporterReader;
30 use win_util::DllNotificationData;
31 use win_util::DllWatcher;
32
33 use crate::crosvm::cmdline::RunCommand;
34 use crate::crosvm::sys::cmdline::Commands;
35 use crate::crosvm::sys::cmdline::DeviceSubcommand;
36 use crate::crosvm::sys::cmdline::RunMainCommand;
37 #[cfg(feature = "slirp")]
38 use crate::crosvm::sys::cmdline::RunSlirpCommand;
39 use crate::sys::windows::product::run_metrics;
40 use crate::CommandStatus;
41 use crate::Config;
42
43 #[cfg(feature = "slirp")]
run_slirp(args: RunSlirpCommand) -> Result<()>44 pub(crate) fn run_slirp(args: RunSlirpCommand) -> Result<()> {
45 let raw_transport_tube = args.bootstrap as RawDescriptor;
46
47 let tube_transporter =
48 // SAFETY:
49 // Safe because we know that raw_transport_tube is valid (passed by inheritance),
50 // and that the blocking & framing modes are accurate because we create them ourselves
51 // in the broker.
52 unsafe { TubeTransporterReader::from_raw_descriptor(raw_transport_tube) };
53
54 let mut tube_data_list = tube_transporter
55 .read_tubes()
56 .exit_context(Exit::TubeTransporterInit, "failed to initialize tube")?;
57
58 let bootstrap_tube = tube_data_list.get_tube(TubeToken::Bootstrap).unwrap();
59
60 let startup_args: CommonChildStartupArgs =
61 bootstrap_tube.recv::<CommonChildStartupArgs>().unwrap();
62 let _child_cleanup = common_child_setup(startup_args).exit_context(
63 Exit::CommonChildSetupError,
64 "failed to perform common child setup",
65 )?;
66
67 let slirp_config = bootstrap_tube.recv::<SlirpStartupConfig>().unwrap();
68
69 #[cfg(feature = "sandbox")]
70 if let Some(mut target) = sandbox::TargetServices::get()
71 .exit_context(Exit::SandboxError, "sandbox operation failed")?
72 {
73 target.lower_token();
74 }
75
76 net_util::Slirp::run_slirp_process(
77 slirp_config.slirp_pipe,
78 slirp_config.shutdown_event,
79 #[cfg(any(feature = "slirp-ring-capture", feature = "slirp-debug"))]
80 slirp_config.slirp_capture_file,
81 );
82 Ok(())
83 }
84
run_broker_impl(cfg: Config, log_args: LogArgs) -> Result<()>85 pub fn run_broker_impl(cfg: Config, log_args: LogArgs) -> Result<()> {
86 cros_tracing::init();
87 crate::crosvm::sys::windows::broker::run(cfg, log_args)
88 }
89
90 #[cfg(feature = "sandbox")]
initialize_sandbox() -> Result<()>91 pub fn initialize_sandbox() -> Result<()> {
92 if sandbox::is_sandbox_target() {
93 // Get the TargetServices pointer so that it gets initialized.
94 let _ = sandbox::TargetServices::get()
95 .exit_context(Exit::SandboxError, "sandbox operation failed")?;
96 }
97 Ok(())
98 }
99
100 #[cfg(feature = "sandbox")]
sandbox_lower_token() -> Result<()>101 pub fn sandbox_lower_token() -> Result<()> {
102 if let Some(mut target) = sandbox::TargetServices::get()
103 .exit_context(Exit::SandboxError, "sandbox operation failed")?
104 {
105 target.lower_token();
106 }
107 Ok(())
108 }
109
report_dll_loaded(dll_name: String)110 fn report_dll_loaded(dll_name: String) {
111 metrics::log_event(MetricEventType::DllLoaded(dll_name));
112 }
113
get_library_watcher( ) -> std::io::Result<DllWatcher<impl FnMut(DllNotificationData), impl FnMut(DllNotificationData)>>114 pub fn get_library_watcher(
115 ) -> std::io::Result<DllWatcher<impl FnMut(DllNotificationData), impl FnMut(DllNotificationData)>> {
116 let mut dlls: HashSet<OsString> = HashSet::new();
117 DllWatcher::new(
118 move |data| {
119 info!("DLL loaded: {:?}", data.base_dll_name);
120 if !dlls.insert(data.base_dll_name.clone()) && metrics::is_initialized() {
121 report_dll_loaded(data.base_dll_name.to_string_lossy().into_owned());
122 }
123 },
124 |data| info!("DLL unloaded: {:?}", data.base_dll_name),
125 )
126 }
127
start_device(command: DeviceSubcommand) -> Result<()>128 pub(crate) fn start_device(command: DeviceSubcommand) -> Result<()> {
129 Err(anyhow!("unknown device name: {:?}", command))
130 }
131
run_vm_for_broker(args: RunMainCommand) -> Result<()>132 pub(crate) fn run_vm_for_broker(args: RunMainCommand) -> Result<()> {
133 // This is a noop on unix.
134 #[cfg(feature = "sandbox")]
135 initialize_sandbox()?;
136
137 let raw_transport_tube = args.bootstrap as RawDescriptor;
138
139 let exit_state = crate::sys::windows::run_config_for_broker(raw_transport_tube)?;
140 info!("{}", CommandStatus::from(exit_state).message());
141 Ok(())
142 }
143
cleanup()144 pub(crate) fn cleanup() {
145 // We've already cleaned everything up by waiting for all the vcpu threads on windows.
146 // TODO: b/142733266. When we sandbox each device, have a way to terminate the other sandboxed
147 // processes.
148 }
149
run_broker(cmd: RunCommand, log_args: LogArgs) -> Result<()>150 fn run_broker(cmd: RunCommand, log_args: LogArgs) -> Result<()> {
151 match TryInto::<Config>::try_into(cmd) {
152 Ok(cfg) => run_broker_impl(cfg, log_args),
153 Err(e) => Err(anyhow!("{}", e)),
154 }
155 }
156
run_command(cmd: Commands, log_args: LogArgs) -> anyhow::Result<()>157 pub(crate) fn run_command(cmd: Commands, log_args: LogArgs) -> anyhow::Result<()> {
158 match cmd {
159 Commands::RunMetrics(cmd) => run_metrics(cmd),
160 Commands::RunMP(cmd) => run_broker(cmd.run, log_args),
161 Commands::RunMain(cmd) => run_vm_for_broker(cmd),
162 #[cfg(feature = "slirp")]
163 Commands::RunSlirp(cmd) => run_slirp(cmd),
164 }
165 }
166
init_log(log_config: LogConfig, cfg: &Config) -> Result<()>167 pub(crate) fn init_log(log_config: LogConfig, cfg: &Config) -> Result<()> {
168 if let Err(e) = syslog::init_with(LogConfig {
169 log_args: LogArgs {
170 stderr: cfg.log_file.is_none(),
171 ..log_config.log_args
172 },
173 pipe: if let Some(log_file_path) = &cfg.log_file {
174 let file = OpenOptions::new()
175 .create(true)
176 .append(true)
177 .open(log_file_path)
178 .with_exit_context(Exit::LogFile, || {
179 format!("failed to open log file {}", log_file_path)
180 })?;
181 Some(Box::new(file))
182 } else {
183 None
184 },
185 ..log_config
186 }) {
187 eprintln!("failed to initialize syslog: {}", e);
188 return Err(anyhow!("failed to initialize syslog: {}", e));
189 }
190 Ok(())
191 }
192
error_to_exit_code(res: &std::result::Result<CommandStatus, anyhow::Error>) -> i32193 pub(crate) fn error_to_exit_code(res: &std::result::Result<CommandStatus, anyhow::Error>) -> i32 {
194 res.to_exit_code().unwrap_or(Exit::UnknownError.into())
195 }
196