[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())?;