[scrutiny] Add verify.build to Scrutiny.

This changeset introduces a new verified build that outputs the security
properties of the current image.

Bug: 61863

Change-Id: Iea3b33f89a422c4869e3e984bc898bb39f96da5f
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/474522
Commit-Queue: Benjamin Wright <benwright@google.com>
Reviewed-by: Laura Peskin <pesk@google.com>
diff --git a/src/security/scrutiny/BUILD.gn b/src/security/scrutiny/BUILD.gn
index e6b2a63..7fa4eb2 100644
--- a/src/security/scrutiny/BUILD.gn
+++ b/src/security/scrutiny/BUILD.gn
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/compiled_action.gni")
+
 group("scrutiny") {
   testonly = true
   public_deps = [
diff --git a/src/security/scrutiny/lib/frontend/src/scrutiny.rs b/src/security/scrutiny/lib/frontend/src/scrutiny.rs
index 3f1babe..23b49ce 100644
--- a/src/security/scrutiny/lib/frontend/src/scrutiny.rs
+++ b/src/security/scrutiny/lib/frontend/src/scrutiny.rs
@@ -141,12 +141,20 @@
     /// Parses all the command line arguments passed in and returns a
     /// ScrutinyConfig.
     fn cmdline_to_config(args: ArgMatches<'static>) -> Result<Config> {
+        let mut batch_mode = false;
         let mut config = Config::default();
         if let Some(command) = args.value_of("command") {
             config.launch.command = Some(command.to_string());
+            batch_mode = true;
         }
         if let Some(script_path) = args.value_of("script") {
             config.launch.script_path = Some(script_path.to_string());
+            batch_mode = true;
+        }
+        // If we are running a script or a command we disable the server as
+        // it isn't going to be used.
+        if batch_mode {
+            config.runtime.server = None;
         }
         config.runtime.logging.path = args.value_of("log").unwrap().to_string();
         config.runtime.logging.verbosity = match args.value_of("verbosity").unwrap() {
diff --git a/src/security/scrutiny/lib/plugins/BUILD.gn b/src/security/scrutiny/lib/plugins/BUILD.gn
index fc116ae..3f43bba 100644
--- a/src/security/scrutiny/lib/plugins/BUILD.gn
+++ b/src/security/scrutiny/lib/plugins/BUILD.gn
@@ -83,7 +83,7 @@
       "src/verify/collection.rs",
       "src/verify/collector/component_tree.rs",
       "src/verify/collector/mod.rs",
-      "src/verify/controller/boot_options.rs",
+      "src/verify/controller/build.rs",
       "src/verify/controller/capability_routing.rs",
       "src/verify/controller/mod.rs",
       "src/verify/mod.rs",
diff --git a/src/security/scrutiny/lib/plugins/src/verify/controller/boot_options.rs b/src/security/scrutiny/lib/plugins/src/verify/controller/boot_options.rs
deleted file mode 100644
index a420839..0000000
--- a/src/security/scrutiny/lib/plugins/src/verify/controller/boot_options.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2020 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-use {
-    crate::core::collection::Zbi,
-    anyhow::{anyhow, Result},
-    scrutiny::{model::controller::DataController, model::model::*},
-    serde_json::{json, value::Value},
-    std::sync::Arc,
-};
-
-#[derive(Default)]
-pub struct ZbiCmdlineVerifyController {}
-
-impl DataController for ZbiCmdlineVerifyController {
-    fn query(&self, model: Arc<DataModel>, _value: Value) -> Result<Value> {
-        if let Ok(zbi) = model.get::<Zbi>() {
-            if zbi.cmdline.contains("kernel.enable-debugging-syscalls=true") {
-                return Err(anyhow!("debugging syscalls are not disabled"));
-            }
-            return Ok(json!({"verified":true}));
-        }
-        Err(anyhow!("ZBI not found"))
-    }
-
-    fn description(&self) -> String {
-        "verifies the ZBI cmdline options for a _user build".to_string()
-    }
-}
diff --git a/src/security/scrutiny/lib/plugins/src/verify/controller/build.rs b/src/security/scrutiny/lib/plugins/src/verify/controller/build.rs
new file mode 100644
index 0000000..0626c97
--- /dev/null
+++ b/src/security/scrutiny/lib/plugins/src/verify/controller/build.rs
@@ -0,0 +1,90 @@
+// Copyright 2020 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use {
+    crate::core::collection::Zbi,
+    anyhow::Result,
+    scrutiny::{model::controller::DataController, model::model::*},
+    serde::{Deserialize, Serialize},
+    serde_json::{json, value::Value},
+    std::sync::Arc,
+};
+
+#[derive(Default)]
+pub struct VerifyBuildController {}
+
+/// Defines the set of security properties that the `VerifyBuildController`
+/// checks.
+#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
+struct SecurityProperties {
+    pub zbi: ZbiProperties,
+}
+
+/// Defines the subset of security properties related to the ZBI that the
+/// `VerifyBuildController` checks.
+#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
+struct ZbiProperties {
+    debug_syscalls_enabled: bool,
+}
+
+impl DataController for VerifyBuildController {
+    /// Extracts information from the `DataModel` to determine what security
+    /// properties are present in a given Fuchsia build. This is intended to
+    /// be used by third party tests to inspect the security features
+    /// present given build.
+    fn query(&self, model: Arc<DataModel>, _value: Value) -> Result<Value> {
+        let zbi = model.get::<Zbi>()?;
+        Ok(json! {SecurityProperties {
+            zbi: ZbiProperties {
+                debug_syscalls_enabled: zbi.cmdline.contains("kernel.enable-debugging-syscalls=true"),
+            },
+        }})
+    }
+
+    fn description(&self) -> String {
+        "Verifies the existence of security properties in a given build.".to_string()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use {
+        super::*, crate::core::collection::Zbi, scrutiny_utils::zbi::ZbiSection, serde_json::json,
+        std::collections::HashMap, tempfile::tempdir,
+    };
+
+    fn data_model() -> Arc<DataModel> {
+        let store_dir = tempdir().unwrap();
+        let uri = store_dir.into_path().into_os_string().into_string().unwrap();
+        Arc::new(DataModel::connect(uri).unwrap())
+    }
+
+    fn zbi() -> Zbi {
+        let bootfs: HashMap<String, Vec<u8>> = HashMap::default();
+        let sections: Vec<ZbiSection> = Vec::default();
+        return Zbi { sections: sections, bootfs: bootfs, cmdline: "".to_string() };
+    }
+
+    #[test]
+    fn test_zbi_cmdline_verify_no_debug_syscalls_exists() {
+        let model = data_model();
+        let zbi = Zbi { cmdline: "{kernel.enable-debugging-syscalls=false}".to_string(), ..zbi() };
+        model.set(zbi).unwrap();
+        let verify = VerifyBuildController::default();
+        let response: SecurityProperties =
+            serde_json::from_value(verify.query(model.clone(), json!("{}")).unwrap()).unwrap();
+        assert_eq!(response.zbi.debug_syscalls_enabled, false);
+    }
+
+    #[test]
+    fn test_zbi_cmdline_verify_debug_syscalls_exist() {
+        let model = data_model();
+        let zbi = Zbi { cmdline: "{kernel.enable-debugging-syscalls=true}".to_string(), ..zbi() };
+        model.set(zbi).unwrap();
+        let verify = VerifyBuildController::default();
+        let response: SecurityProperties =
+            serde_json::from_value(verify.query(model.clone(), json!("{}")).unwrap()).unwrap();
+        assert_eq!(response.zbi.debug_syscalls_enabled, true);
+    }
+}
diff --git a/src/security/scrutiny/lib/plugins/src/verify/controller/mod.rs b/src/security/scrutiny/lib/plugins/src/verify/controller/mod.rs
index 3230dd5..75962dd 100644
--- a/src/security/scrutiny/lib/plugins/src/verify/controller/mod.rs
+++ b/src/security/scrutiny/lib/plugins/src/verify/controller/mod.rs
@@ -2,5 +2,5 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-pub mod boot_options;
+pub mod build;
 pub mod capability_routing;
diff --git a/src/security/scrutiny/lib/plugins/src/verify/mod.rs b/src/security/scrutiny/lib/plugins/src/verify/mod.rs
index 0cccce7..cf4c061 100644
--- a/src/security/scrutiny/lib/plugins/src/verify/mod.rs
+++ b/src/security/scrutiny/lib/plugins/src/verify/mod.rs
@@ -9,7 +9,7 @@
 use {
     crate::verify::{
         collector::component_tree::V2ComponentTreeDataCollector,
-        controller::boot_options::ZbiCmdlineVerifyController,
+        controller::build::VerifyBuildController,
         controller::capability_routing::TreeMappingController,
     },
     scrutiny::prelude::*,
@@ -23,7 +23,7 @@
             "V2ComponentTreeDataCollector" => V2ComponentTreeDataCollector::new(),
         },
         controllers! {
-            "/verify/zbi_cmdline" => ZbiCmdlineVerifyController::default(),
+            "/verify/build" => VerifyBuildController::default(),
             "/verify/map_tree" => TreeMappingController::default(),
         }
     ),
@@ -34,14 +34,12 @@
 mod tests {
     use {
         super::*,
-        crate::core::collection::{Component, Components, Manifest, ManifestData, Manifests, Zbi},
+        crate::core::collection::{Component, Components, Manifest, ManifestData, Manifests},
         anyhow::Result,
         cm_rust::{ChildDecl, ComponentDecl, NativeIntoFidl},
         fidl::encoding::encode_persistent,
         fidl_fuchsia_sys2 as fsys2,
-        scrutiny_utils::zbi::ZbiSection,
-        serde_json::{json, value::Value},
-        std::collections::HashMap,
+        serde_json::json,
         tempfile::tempdir,
     };
 
@@ -51,12 +49,6 @@
         Arc::new(DataModel::connect(uri).unwrap())
     }
 
-    fn zbi() -> Zbi {
-        let bootfs: HashMap<String, Vec<u8>> = HashMap::default();
-        let sections: Vec<ZbiSection> = Vec::default();
-        return Zbi { sections: sections, bootfs: bootfs, cmdline: "".to_string() };
-    }
-
     fn new_child_decl(name: String, url: String) -> ChildDecl {
         ChildDecl { name, url, startup: fsys2::StartupMode::Lazy, environment: None }
     }
@@ -138,26 +130,6 @@
     }
 
     #[test]
-    fn test_zbi_cmdline_verify_accepts() {
-        let model = data_model();
-        let zbi = Zbi { cmdline: "{kernel.enable-debugging-syscalls=false}".to_string(), ..zbi() };
-        model.set(zbi).unwrap();
-        let verify = ZbiCmdlineVerifyController::default();
-        let response: Result<Value> = verify.query(model.clone(), json!("{}"));
-        assert!(response.is_ok());
-    }
-
-    #[test]
-    fn test_zbi_cmdline_verify_rejects() {
-        let model = data_model();
-        let zbi = Zbi { cmdline: "{kernel.enable-debugging-syscalls=true}".to_string(), ..zbi() };
-        model.set(zbi).unwrap();
-        let verify = ZbiCmdlineVerifyController::default();
-        let response: Result<Value> = verify.query(model.clone(), json!("{}"));
-        assert!(response.is_err());
-    }
-
-    #[test]
     fn test_map_tree_single_node() -> Result<()> {
         let model = single_v2_component_model()?;
         V2ComponentTreeDataCollector::new().collect(model.clone())?;