| // Copyright 2022 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use std::env; |
| use std::ffi::OsStr; |
| use std::fs; |
| use std::path::Path; |
| use std::path::PathBuf; |
| use std::process::Command; |
| |
| use rayon::prelude::*; |
| |
| fn rewrite_policies(seccomp_policy_path: &Path, rewrote_policy_folder: &Path) { |
| for entry in fs::read_dir(seccomp_policy_path).unwrap() { |
| let policy_file = entry.unwrap(); |
| let policy_file_content = fs::read_to_string(policy_file.path()).unwrap(); |
| let policy_file_content_rewrote = |
| policy_file_content.replace("/usr/share/policy/crosvm", "."); |
| fs::write( |
| rewrote_policy_folder.join(policy_file.file_name()), |
| policy_file_content_rewrote, |
| ) |
| .unwrap(); |
| } |
| } |
| |
| fn compile_policy( |
| compile_script: &Path, |
| out_dir: &Path, |
| compile_policy_folder_relative: &Path, |
| output_folder: &Path, |
| policy_file: &fs::DirEntry, |
| ) -> String { |
| let output_file_path_relative = compile_policy_folder_relative.join( |
| policy_file |
| .path() |
| .with_extension("bpf") |
| .file_name() |
| .unwrap(), |
| ); |
| let status = Command::new(compile_script) |
| .arg("--arch-json") |
| .arg(output_folder.join("constants.json")) |
| .arg("--default-action") |
| .arg("trap") |
| .arg(policy_file.path()) |
| .arg(out_dir.join(&output_file_path_relative)) |
| .spawn() |
| .unwrap() |
| .wait() |
| .expect("Spawning the bpf compiler failed"); |
| if !status.success() { |
| panic!("Compile bpf failed"); |
| } |
| format!( |
| r#"("{}", include_bytes!("{}").to_vec()),"#, |
| policy_file.path().file_stem().unwrap().to_str().unwrap(), |
| output_file_path_relative.to_str().unwrap() |
| ) |
| } |
| |
| fn compile_policies(out_dir: &Path, rewrote_policy_folder: &Path, compile_seccomp_policy: &Path) { |
| let compiled_policy_folder_relative = Path::new("policy_output"); |
| fs::create_dir_all(out_dir.join(compiled_policy_folder_relative)).unwrap(); |
| let mut include_all_bytes = String::from("std::collections::HashMap::from([\n"); |
| |
| let entries = fs::read_dir(rewrote_policy_folder) |
| .unwrap() |
| .map(|ent| ent.unwrap()) |
| .collect::<Vec<_>>(); |
| |
| let s = entries |
| .par_iter() |
| .filter(|ent| ent.path().extension() == Some(OsStr::new("policy"))) |
| .map(|policy_file| { |
| compile_policy( |
| compile_seccomp_policy, |
| out_dir, |
| compiled_policy_folder_relative, |
| rewrote_policy_folder, |
| policy_file, |
| ) |
| }) |
| .collect::<Vec<_>>() |
| .join(""); |
| include_all_bytes += &s; |
| |
| include_all_bytes += "])"; |
| fs::write(out_dir.join("bpf_includes.in"), include_all_bytes).unwrap(); |
| } |
| |
| fn main() { |
| println!("cargo:rerun-if-changed=build.rs"); |
| println!("cargo:rerun-if-changed=seccomp"); |
| |
| if env::var("CARGO_CFG_TARGET_FAMILY").unwrap() != "unix" { |
| return; |
| } |
| |
| let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); |
| let src_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); |
| |
| let compile_seccomp_policy = if let Ok(path) = which::which("compile_seccomp_policy") { |
| // If `compile_seccomp_policy` exists in the path (e.g. ChromeOS builds), use it. |
| path |
| // Otherwise, use compile_seccomp_policy.py from the minijail submodule. |
| } else if let Ok(minijail_dir_env) = env::var("MINIJAIL_DIR") { |
| PathBuf::from(minijail_dir_env).join("tools/compile_seccomp_policy.py") |
| } else if let Ok(compile_seccomp_policy_env) = env::var("COMPILE_SECCOMP_POLICY") { |
| PathBuf::from(compile_seccomp_policy_env) |
| } else { |
| src_dir.join("../third_party/minijail/tools/compile_seccomp_policy.py") |
| }; |
| |
| // check policies exist for target architecture |
| let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); |
| let seccomp_arch_name = match target_arch.as_str() { |
| "armv7" => "arm", |
| x => x, |
| }; |
| let seccomp_policy_path = src_dir.join("seccomp").join(seccomp_arch_name); |
| assert!( |
| seccomp_policy_path.is_dir(), |
| "Seccomp policy dir doesn't exist" |
| ); |
| |
| let rewrote_policy_folder = out_dir.join("policy_input"); |
| fs::create_dir_all(&rewrote_policy_folder).unwrap(); |
| rewrite_policies(&seccomp_policy_path, &rewrote_policy_folder); |
| compile_policies(&out_dir, &rewrote_policy_folder, &compile_seccomp_policy); |
| } |