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