xref: /aosp_15_r20/external/crosvm/jail/build.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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::env;
6 use std::ffi::OsStr;
7 use std::fs;
8 use std::path::Path;
9 use std::path::PathBuf;
10 use std::process::Command;
11 
12 use rayon::prelude::*;
13 
rewrite_policies(seccomp_policy_path: &Path, rewrote_policy_folder: &Path)14 fn rewrite_policies(seccomp_policy_path: &Path, rewrote_policy_folder: &Path) {
15     for entry in fs::read_dir(seccomp_policy_path).unwrap() {
16         let policy_file = entry.unwrap();
17         let policy_file_content = fs::read_to_string(policy_file.path()).unwrap();
18         let policy_file_content_rewrote =
19             policy_file_content.replace("/usr/share/policy/crosvm", ".");
20         fs::write(
21             rewrote_policy_folder.join(policy_file.file_name()),
22             policy_file_content_rewrote,
23         )
24         .unwrap();
25     }
26 }
27 
compile_policy( compile_script: &Path, compile_policy_folder: &Path, output_folder: &Path, policy_file: &fs::DirEntry, ) -> String28 fn compile_policy(
29     compile_script: &Path,
30     compile_policy_folder: &Path,
31     output_folder: &Path,
32     policy_file: &fs::DirEntry,
33 ) -> String {
34     let output_file_path = compile_policy_folder.join(
35         policy_file
36             .path()
37             .with_extension("bpf")
38             .file_name()
39             .unwrap(),
40     );
41     let status = Command::new(compile_script)
42         .arg("--arch-json")
43         .arg(output_folder.join("constants.json"))
44         .arg("--default-action")
45         .arg("trap")
46         .arg(policy_file.path())
47         .arg(&output_file_path)
48         .spawn()
49         .unwrap()
50         .wait()
51         .expect("Spawning the bpf compiler failed");
52     if !status.success() {
53         panic!("Compile bpf failed");
54     }
55     format!(
56         r#"("{}", include_bytes!("{}").to_vec()),"#,
57         policy_file.path().file_stem().unwrap().to_str().unwrap(),
58         output_file_path.to_str().unwrap()
59     )
60 }
61 
compile_policies(out_dir: &Path, rewrote_policy_folder: &Path, compile_seccomp_policy: &Path)62 fn compile_policies(out_dir: &Path, rewrote_policy_folder: &Path, compile_seccomp_policy: &Path) {
63     let compiled_policy_folder = out_dir.join("policy_output");
64     fs::create_dir_all(&compiled_policy_folder).unwrap();
65     let mut include_all_bytes = String::from("std::collections::HashMap::from([\n");
66 
67     let entries = fs::read_dir(rewrote_policy_folder)
68         .unwrap()
69         .map(|ent| ent.unwrap())
70         .collect::<Vec<_>>();
71 
72     let s = entries
73         .par_iter()
74         .filter(|ent| ent.path().extension() == Some(OsStr::new("policy")))
75         .map(|policy_file| {
76             compile_policy(
77                 compile_seccomp_policy,
78                 &compiled_policy_folder,
79                 rewrote_policy_folder,
80                 policy_file,
81             )
82         })
83         .collect::<Vec<_>>()
84         .join("");
85     include_all_bytes += &s;
86 
87     include_all_bytes += "])";
88     fs::write(out_dir.join("bpf_includes.in"), include_all_bytes).unwrap();
89 }
90 
main()91 fn main() {
92     println!("cargo:rerun-if-changed=build.rs");
93     println!("cargo:rerun-if-changed=seccomp");
94 
95     if env::var("CARGO_CFG_TARGET_FAMILY").unwrap() != "unix" {
96         return;
97     }
98 
99     let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
100     let src_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
101 
102     let compile_seccomp_policy = if let Ok(path) = which::which("compile_seccomp_policy") {
103         // If `compile_seccomp_policy` exists in the path (e.g. ChromeOS builds), use it.
104         path
105     } else {
106         // Otherwise, use compile_seccomp_policy.py from the minijail submodule.
107         let minijail_dir = if let Ok(minijail_dir_env) = env::var("MINIJAIL_DIR") {
108             PathBuf::from(minijail_dir_env)
109         } else {
110             src_dir.join("../third_party/minijail")
111         };
112         minijail_dir.join("tools/compile_seccomp_policy.py")
113     };
114 
115     // check policies exist for target architecture
116     let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
117     let seccomp_arch_name = match target_arch.as_str() {
118         "armv7" => "arm",
119         x => x,
120     };
121     let seccomp_policy_path = src_dir.join("seccomp").join(seccomp_arch_name);
122     assert!(
123         seccomp_policy_path.is_dir(),
124         "Seccomp policy dir doesn't exist"
125     );
126 
127     let rewrote_policy_folder = out_dir.join("policy_input");
128     fs::create_dir_all(&rewrote_policy_folder).unwrap();
129     rewrite_policies(&seccomp_policy_path, &rewrote_policy_folder);
130     compile_policies(&out_dir, &rewrote_policy_folder, &compile_seccomp_policy);
131 }
132