From b971dcae195289660edc88246305fc7c6251f406 Mon Sep 17 00:00:00 2001 From: Valentin Obst Date: Tue, 10 Dec 2024 12:55:53 +0100 Subject: [PATCH 1/3] lib/utils: fall back to env for configs and Ghidra plugins If config files or Ghidra plugins are not found in the respective project directories, fall back to env vars that contain an alternative search directory. --- src/cwe_checker_lib/src/utils/ghidra.rs | 2 +- src/cwe_checker_lib/src/utils/mod.rs | 76 +++++++++++++++++++++---- 2 files changed, 67 insertions(+), 11 deletions(-) diff --git a/src/cwe_checker_lib/src/utils/ghidra.rs b/src/cwe_checker_lib/src/utils/ghidra.rs index da7441f16..166fd9902 100644 --- a/src/cwe_checker_lib/src/utils/ghidra.rs +++ b/src/cwe_checker_lib/src/utils/ghidra.rs @@ -183,7 +183,7 @@ fn generate_ghidra_call_command( .ok_or_else(|| anyhow!("Invalid file name"))? .to_string_lossy() .to_string(); - let ghidra_plugin_path = get_ghidra_plugin_path("p_code_extractor"); + let ghidra_plugin_path = get_ghidra_plugin_path("p_code_extractor")?; let mut ghidra_command = Command::new(headless_path); ghidra_command diff --git a/src/cwe_checker_lib/src/utils/mod.rs b/src/cwe_checker_lib/src/utils/mod.rs index 93beae261..f142781be 100644 --- a/src/cwe_checker_lib/src/utils/mod.rs +++ b/src/cwe_checker_lib/src/utils/mod.rs @@ -10,21 +10,77 @@ pub mod symbol_utils; use crate::prelude::*; +use std::{env, fs, path}; + +use anyhow::bail; + +const ENV_CWE_CHECKER_CONFIGS_PATH: &str = "CWE_CHECKER_CONFIGS_PATH"; +const ENV_CWE_CHECKER_GHIDRA_PLUGINS_PATH: &str = "CWE_CHECKER_GHIDRA_PLUGINS_PATH"; + /// Get the contents of a configuration file. +/// +/// We first search the file in our config directory. Then, we fall back to +/// the CWE_CHECKER_CONFIG environment variable. pub fn read_config_file(filename: &str) -> Result { - let project_dirs = directories::ProjectDirs::from("", "", "cwe_checker") - .context("Could not discern location of configuration files.")?; + let config_path = if let Some(config_path) = get_config_path_from_project_dir(filename) { + config_path + } else if let Some(config_path) = get_path_from_env(ENV_CWE_CHECKER_CONFIGS_PATH, filename) { + config_path + } else { + bail!("Unable to find configuration file: {}.", filename) + }; + let config_file = fs::read_to_string(config_path) + .context(format!("Could not read configuration file: {}", filename))?; + Ok(serde_json::from_str(&config_file)?) +} + +fn get_config_path_from_project_dir(filename: &str) -> Option { + let project_dirs = directories::ProjectDirs::from("", "", "cwe_checker")?; let config_dir = project_dirs.config_dir(); let config_path = config_dir.join(filename); - let config_file = - std::fs::read_to_string(config_path).context("Could not read configuration file")?; - Ok(serde_json::from_str(&config_file)?) + + if config_path.exists() { + Some(config_path) + } else { + None + } +} + +/// Get the path to a Ghidra plugin that is bundled with the cwe_checker. +/// +/// We first search the plugin in our data directory, then we fall back to +/// the CWE_CHECKER_GHIDRA_PLUGIN_PATH environment variable. +pub fn get_ghidra_plugin_path(plugin_name: &str) -> Result { + if let Some(ghidra_plugin_path) = get_ghidra_plugin_path_from_project_dirs(plugin_name) { + Ok(ghidra_plugin_path) + } else if let Some(ghidra_plugin_path) = + get_path_from_env(ENV_CWE_CHECKER_GHIDRA_PLUGINS_PATH, plugin_name) + { + Ok(ghidra_plugin_path) + } else { + bail!("Unable to find Ghidra plugin: {}", plugin_name) + } } -/// Get the folder path to a Ghidra plugin bundled with the cwe_checker. -pub fn get_ghidra_plugin_path(plugin_name: &str) -> std::path::PathBuf { - let project_dirs = directories::ProjectDirs::from("", "", "cwe_checker") - .expect("Could not discern location of data directory."); +fn get_ghidra_plugin_path_from_project_dirs(plugin_name: &str) -> Option { + let project_dirs = directories::ProjectDirs::from("", "", "cwe_checker")?; let data_dir = project_dirs.data_dir(); - data_dir.join("ghidra").join(plugin_name) + let plugin_path = data_dir.join("ghidra").join(plugin_name); + + if plugin_path.exists() { + Some(plugin_path) + } else { + None + } +} + +fn get_path_from_env(var: &str, filename: &str) -> Option { + let val = env::var(var).ok()?; + let path = path::PathBuf::from(val).join(filename); + + if path.exists() { + Some(path) + } else { + None + } } From 80db01dc8d6aa6cc227f2c09537bc92f4bdfce3a Mon Sep 17 00:00:00 2001 From: Felix Ulonska Date: Wed, 11 Dec 2024 16:50:17 +0100 Subject: [PATCH 2/3] flake.nix: added working nix flake --- flake.lock | 27 +++++++++++++++++ flake.nix | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/flake.lock b/flake.lock new file mode 100644 index 000000000..8fcd25fe1 --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1733759999, + "narHash": "sha256-463SNPWmz46iLzJKRzO3Q2b0Aurff3U1n0nYItxq7jU=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "a73246e2eef4c6ed172979932bc80e1404ba2d56", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 000000000..08c38ccf0 --- /dev/null +++ b/flake.nix @@ -0,0 +1,85 @@ +{ + description = "Nix flake with Ghidra as a dependency"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + }; + + outputs = { self, nixpkgs }: + let + pkgs = nixpkgs.legacyPackages."x86_64-linux"; + # == Building Ghidra == + ghidra-cwe-checker-plugin = pkgs.ghidra.buildGhidraScripts { + pname = "cwe_checker"; + name = "cwe_checker"; + src = ./ghidra_plugin; + }; + cwe-ghidra = pkgs.ghidra.withExtensions (p: with p; [ ghidra-cwe-checker-plugin ]); + # Path to java ghidra plugin + ghidra_pcode_extract = pkgs.runCommand + "pcode_extractor" { src = ./src/ghidra/p_code_extractor; } + '' + mkdir -p $out/p_code_extractor + cp -rf $src/* $out/p_code_extractor + ''; + # Build ghidra package with analyzeHeadless in support/ where it is the default + # cwe_checker expectes it in support/ + cwe-ghidra-path-fix = pkgs.stdenv.mkDerivation { + name = "analyzeHeadless"; + pname = "analyzeHeadless"; + buildInputs = [ cwe-ghidra ]; + src = cwe-ghidra; + buildPhase = '' + mkdir -p $out + cp -rf ${cwe-ghidra} $out + # cwe checker expects + mkdir -p $out/support + cp ${cwe-ghidra}/bin/ghidra-analyzeHeadless $out/support/analyzeHeadless + ''; + }; + # == Building cwe_checker == + cwe-checker-bins = pkgs.rustPlatform.buildRustPackage { + pname = "cwe_checker"; + name = "cwe_checker"; + src = ./.; + cargoLock = { + lockFile = ./Cargo.lock; + }; + }; + # Build ghidra.json + cwe-ghidra-json = pkgs.writeTextFile { + name = "GhidraConfigFile"; + text = builtins.toJSON { ghidra_path = ''${cwe-ghidra-path-fix}''; }; + }; + # creates config dir for cwe_checker + cwe-checker-config = pkgs.runCommand "configs" { src = ./src; } + '' + mkdir -p $out + cp $src/config.json $out + cp $src/lkm_config.json $out + ln -s ${cwe-ghidra-json} $out/ghidra.json + ''; + # target bin for nix run .# + cwe-checker = pkgs.writeScriptBin "cwe-checker" '' + #!/bin/sh + CWE_CHECKER_CONFIGS_PATH=${cwe-checker-config} \ + CWE_CHECKER_GHIDRA_PLUGINS_PATH=${ghidra_pcode_extract} \ + ${cwe-checker-bins}/bin/cwe_checker $@; + ''; + in + { + devShell.x86_64-linux = pkgs.mkShell { + buildInputs = with pkgs; [ + rustc + cargo + cwe-ghidra-path-fix + ]; + shellHook = '' + export CWE_CHECKER_CONFIGS_PATH=${cwe-checker-config} \ + export CWE_CHECKER_GHIDRA_PLUGINS_PATH=${ghidra_pcode_extract} \ + ''; + }; + packages.x86_64-linux.default = cwe-checker; + }; +} + From 9b2e925596fccdce142d3f67cf140d2ae03c5147 Mon Sep 17 00:00:00 2001 From: Felix Ulonska Date: Sun, 15 Dec 2024 11:58:35 +0100 Subject: [PATCH 3/3] fix: PR notes --- README.md | 4 ++++ flake.nix | 21 +++++++++++---------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index ca35e1f86..e2d61ff35 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,10 @@ If you installed the *cwe_checker* locally, run ```bash cwe_checker BINARY ``` +If you use nix flakes, run +```bash +nix run github:fkie-cad/cwe_checker -- BINARY +``` You can adjust the behavior of most checks via a configuration file located at `src/config.json`. If you modify it, add the command line flag `--config=src/config.json` to tell the *cwe_checker* to use the modified file. For information about other available command line flags you can pass the `--help` flag to the *cwe_checker*. diff --git a/flake.nix b/flake.nix index 08c38ccf0..7cc166514 100644 --- a/flake.nix +++ b/flake.nix @@ -1,7 +1,8 @@ { - description = "Nix flake with Ghidra as a dependency"; + description = "Nix flake for the cwe_checker with patched Ghidra as a dependency"; inputs = { + # depend on nixos-unstable for the latest rust version. nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; }; @@ -16,14 +17,14 @@ }; cwe-ghidra = pkgs.ghidra.withExtensions (p: with p; [ ghidra-cwe-checker-plugin ]); # Path to java ghidra plugin - ghidra_pcode_extract = pkgs.runCommand - "pcode_extractor" { src = ./src/ghidra/p_code_extractor; } + cwe-checker-ghidra-plugins = pkgs.runCommand + "cwe-checker-ghidra-plugins" { src = ./src/ghidra/p_code_extractor; } '' mkdir -p $out/p_code_extractor cp -rf $src/* $out/p_code_extractor ''; - # Build ghidra package with analyzeHeadless in support/ where it is the default - # cwe_checker expectes it in support/ + # Build ghidra package with analyzeHeadless in support/ instead of bin/. + # This is where the cwe_checker expects it to be cwe-ghidra-path-fix = pkgs.stdenv.mkDerivation { name = "analyzeHeadless"; pname = "analyzeHeadless"; @@ -52,7 +53,7 @@ text = builtins.toJSON { ghidra_path = ''${cwe-ghidra-path-fix}''; }; }; # creates config dir for cwe_checker - cwe-checker-config = pkgs.runCommand "configs" { src = ./src; } + cwe-checker-configs = pkgs.runCommand "cwe-checker-configs" { src = ./src; } '' mkdir -p $out cp $src/config.json $out @@ -62,8 +63,8 @@ # target bin for nix run .# cwe-checker = pkgs.writeScriptBin "cwe-checker" '' #!/bin/sh - CWE_CHECKER_CONFIGS_PATH=${cwe-checker-config} \ - CWE_CHECKER_GHIDRA_PLUGINS_PATH=${ghidra_pcode_extract} \ + CWE_CHECKER_CONFIGS_PATH=${cwe-checker-configs} \ + CWE_CHECKER_GHIDRA_PLUGINS_PATH=${cwe-checker-ghidra-plugins} \ ${cwe-checker-bins}/bin/cwe_checker $@; ''; in @@ -75,8 +76,8 @@ cwe-ghidra-path-fix ]; shellHook = '' - export CWE_CHECKER_CONFIGS_PATH=${cwe-checker-config} \ - export CWE_CHECKER_GHIDRA_PLUGINS_PATH=${ghidra_pcode_extract} \ + export CWE_CHECKER_CONFIGS_PATH=${cwe-checker-configs} \ + export CWE_CHECKER_GHIDRA_PLUGINS_PATH=${cwe-checker-ghidra-plugins} \ ''; }; packages.x86_64-linux.default = cwe-checker;