add drop-ins and color-eyre

This commit is contained in:
slonkazoid 2024-08-01 19:32:15 +03:00
parent 518ad3ba79
commit 9f26c8f50d
Signed by: slonk
SSH key fingerprint: SHA256:tbZfJX4IOvZ0LGWOWu5Ijo8jfMPi78TU7x1VoEeCIjM
4 changed files with 374 additions and 18 deletions

221
Cargo.lock generated
View file

@ -2,6 +2,15 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "addr2line"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "1.0.2"
@ -87,7 +96,7 @@ dependencies = [
"const-oid",
"der",
"digest",
"object",
"object 0.36.2",
"rsa",
"sha1",
"sha2",
@ -101,6 +110,21 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]]
name = "backtrace"
version = "0.3.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
"miniz_oxide",
"object 0.32.2",
"rustc-demangle",
]
[[package]]
name = "base64"
version = "0.13.1"
@ -113,6 +137,21 @@ version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "bit-set"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
dependencies = [
"bit-vec",
]
[[package]]
name = "bit-vec"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
[[package]]
name = "bitflags"
version = "2.6.0"
@ -140,11 +179,15 @@ version = "0.1.0"
dependencies = [
"authenticode",
"clap",
"color-eyre",
"digest",
"fallible-iterator",
"fancy-regex",
"hex",
"libc",
"object",
"object 0.36.2",
"serde",
"serde_json",
"sha1",
"sha2",
"thiserror",
@ -217,6 +260,33 @@ dependencies = [
"x509-cert",
]
[[package]]
name = "color-eyre"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5"
dependencies = [
"backtrace",
"color-spantrace",
"eyre",
"indenter",
"once_cell",
"owo-colors",
"tracing-error",
]
[[package]]
name = "color-spantrace"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2"
dependencies = [
"once_cell",
"owo-colors",
"tracing-core",
"tracing-error",
]
[[package]]
name = "colorchoice"
version = "1.0.2"
@ -305,12 +375,33 @@ dependencies = [
"termcolor",
]
[[package]]
name = "eyre"
version = "0.6.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec"
dependencies = [
"indenter",
"once_cell",
]
[[package]]
name = "fallible-iterator"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
[[package]]
name = "fancy-regex"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "531e46835a22af56d1e3b66f04844bed63158bc094a628bec1d321d9b4c44bf2"
dependencies = [
"bit-set",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "flagset"
version = "0.4.6"
@ -352,6 +443,12 @@ dependencies = [
"version_check",
]
[[package]]
name = "gimli"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
[[package]]
name = "hashbrown"
version = "0.12.3"
@ -378,6 +475,9 @@ name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
dependencies = [
"serde",
]
[[package]]
name = "humantime"
@ -388,6 +488,12 @@ dependencies = [
"quick-error",
]
[[package]]
name = "indenter"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
[[package]]
name = "indexmap"
version = "1.9.3"
@ -404,6 +510,12 @@ version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "lazy_static"
version = "1.5.0"
@ -510,6 +622,15 @@ dependencies = [
"libm",
]
[[package]]
name = "object"
version = "0.32.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
dependencies = [
"memchr",
]
[[package]]
name = "object"
version = "0.36.2"
@ -576,6 +697,12 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "owo-colors"
version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
[[package]]
name = "pem-rfc7468"
version = "0.7.0"
@ -585,6 +712,12 @@ dependencies = [
"base64ct",
]
[[package]]
name = "pin-project-lite"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
[[package]]
name = "pkcs1"
version = "0.7.5"
@ -730,6 +863,12 @@ dependencies = [
"zeroize",
]
[[package]]
name = "rustc-demangle"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "ruzstd"
version = "0.7.0"
@ -766,6 +905,18 @@ dependencies = [
"syn 2.0.72",
]
[[package]]
name = "serde_json"
version = "1.0.121"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]]
name = "serde_yaml"
version = "0.8.26"
@ -800,6 +951,15 @@ dependencies = [
"digest",
]
[[package]]
name = "sharded-slab"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
dependencies = [
"lazy_static",
]
[[package]]
name = "signature"
version = "2.2.0"
@ -901,6 +1061,16 @@ dependencies = [
"syn 2.0.72",
]
[[package]]
name = "thread_local"
version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
dependencies = [
"cfg-if",
"once_cell",
]
[[package]]
name = "tpmless-tpm2"
version = "0.4.0"
@ -915,6 +1085,47 @@ dependencies = [
"thiserror",
]
[[package]]
name = "tracing"
version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
dependencies = [
"pin-project-lite",
"tracing-core",
]
[[package]]
name = "tracing-core"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
dependencies = [
"once_cell",
"valuable",
]
[[package]]
name = "tracing-error"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e"
dependencies = [
"tracing",
"tracing-subscriber",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
dependencies = [
"sharded-slab",
"thread_local",
"tracing-core",
]
[[package]]
name = "twox-hash"
version = "1.6.3"
@ -985,6 +1196,12 @@ version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
[[package]]
name = "valuable"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "vcpkg"
version = "0.2.15"

View file

@ -6,11 +6,15 @@ edition = "2021"
[dependencies]
authenticode = { version = "0.4.3", features = ["object"] }
clap = { version = "4.5.11", features = ["derive"] }
color-eyre = "0.6.3"
digest = "0.10.7"
fallible-iterator = "0.2.0"
hex = "0.4.3"
fancy-regex = "0.13.0"
hex = { version = "0.4.3", features = ["serde"] }
libc = "0.2.155"
object = "0.36.2"
serde = { version = "1.0.204", features = ["derive"] }
serde_json = "1.0.121"
sha1 = "0.10.6"
sha2 = "0.10.8"
thiserror = "1.0.63"

86
src/drop_ins.rs Normal file
View file

@ -0,0 +1,86 @@
use std::path::{Path, PathBuf};
use fancy_regex::Regex;
use serde::{de::Visitor, Deserialize};
#[derive(Deserialize)]
#[serde(tag = "type", rename_all = "kebab-case")]
enum Matcher {
RecordedHash {
#[serde(deserialize_with = "hex::serde::deserialize")]
hash: Vec<u8>,
},
PathRegex {
#[serde(deserialize_with = "deserialize_regex")]
regex: Regex,
},
Path {
path: PathBuf,
},
}
#[derive(Deserialize)]
pub struct DropIn {
matcher: Matcher,
path: PathBuf,
}
#[derive(Deserialize)]
pub struct DropIns(Vec<DropIn>);
pub trait FindDropIn {
fn find_drop_in(&self, path: &Path, hash: &[u8]) -> Option<PathBuf>;
}
impl FindDropIn for Option<DropIns> {
fn find_drop_in(&self, path: &Path, hash: &[u8]) -> Option<PathBuf> {
match self {
Some(v) => v.find_drop_in(path, hash),
None => None,
}
}
}
impl FindDropIn for DropIns {
fn find_drop_in(&self, path: &Path, hash: &[u8]) -> Option<PathBuf> {
for drop_in in &self.0 {
if match &drop_in.matcher {
Matcher::RecordedHash { hash: matcher_hash } => matcher_hash == hash,
Matcher::PathRegex {
regex: matcher_regex,
} => path
.to_str()
.is_some_and(|path| matcher_regex.is_match(path).unwrap_or(false)),
Matcher::Path { path: matcher_path } => path == matcher_path,
} {
return Some(drop_in.path.clone());
}
}
None
}
}
fn deserialize_regex<'de, D>(d: D) -> Result<Regex, D::Error>
where
D: serde::Deserializer<'de>,
{
struct RegexVisitor;
impl<'v> Visitor<'v> for RegexVisitor {
type Value = Regex;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, "a regex string")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
let regex = Regex::new(v);
regex.map_err(|err| serde::de::Error::custom(err))
}
}
d.deserialize_string(RegexVisitor)
}

View file

@ -2,23 +2,27 @@
mod args;
mod device_path;
mod drop_ins;
mod find_mount_point;
mod hash;
mod util;
use std::fs::OpenOptions;
use std::io;
use std::io::{self, BufReader};
use std::path::PathBuf;
use args::Args;
use clap::Parser;
use device_path::traverse_device_path;
use color_eyre::eyre::{self, Context};
use drop_ins::FindDropIn;
use fallible_iterator::FallibleIterator;
use thiserror::Error;
use typed_path::{Utf8UnixEncoding, Utf8WindowsPathBuf};
use uefi_eventlog::parsed::ParsedEventData;
use uefi_eventlog::EventType;
use crate::args::Args;
use crate::device_path::traverse_device_path;
use crate::drop_ins::DropIns;
use crate::hash::*;
#[derive(Error, Debug)]
@ -37,14 +41,32 @@ impl From<authenticode::PeOffsetError> for Error {
}
}
fn main() {
fn main() -> eyre::Result<()> {
color_eyre::install()?;
let args = Args::parse();
let hash_len = Hasher::from(args.algo).output_size();
let mut file = OpenOptions::new().read(true).open(args.event_log).unwrap();
let drop_ins: Option<DropIns> = match args.drop_ins {
Some(drop_ins_file) => Some(
serde_json::from_reader(BufReader::new(
OpenOptions::new()
.read(true)
.open(drop_ins_file)
.context("couldn't open drop-ins file")?,
))
.context("couldn't parse drop-ins JSON")?,
),
None => None,
};
let fucking_settings = uefi_eventlog::ParseSettings::new();
let mut events = uefi_eventlog::Parser::new(&mut file, &fucking_settings);
let mut file = OpenOptions::new()
.read(true)
.open(args.event_log)
.context("couldn't open event log")?;
let settings = uefi_eventlog::ParseSettings::new();
let mut events = uefi_eventlog::Parser::new(&mut file, &settings);
let size = Hasher::from(args.algo).output_size();
@ -70,10 +92,32 @@ fn main() {
continue;
}
let digest;
if let Some(event_digest) = event.digests.first() {
digest = event_digest.digest();
} else {
eprintln!("ignoring event with no digest");
continue;
}
'measure_file: {
match event.event {
EventType::EFIBootServicesApplication => {
let event_data = event.parsed_data.unwrap().unwrap();
let event_data = match event.parsed_data {
Some(event_data) => event_data,
None => {
eprintln!("no event data");
break 'measure_file;
}
};
let event_data = match event_data {
Ok(event_data) => event_data,
Err(err) => {
eprintln!("error while parsing event data: {err}");
break 'measure_file;
}
};
if let ParsedEventData::ImageLoadEvent { device_path, .. } = event_data
&& let Some(device_path) = device_path
{
@ -127,9 +171,15 @@ fn main() {
esp = PathBuf::from("/boot/efi");
}
let full_path = esp.join(unix_path.strip_prefix("/").unwrap_or(&unix_path));
let mut full_path =
esp.join(unix_path.strip_prefix("/").unwrap_or(&unix_path));
eprintln!("measuring file {full_path:?}");
if let Some(drop_in_path) = drop_ins.find_drop_in(&full_path, &digest) {
eprintln!("found drop in for file: {drop_in_path:?}");
full_path = drop_in_path;
};
let mut hasher = Hasher::from(args.algo);
let hash = match hash_by_path(&full_path, &mut hasher, args.bits) {
Ok(_) => {
@ -153,16 +203,15 @@ fn main() {
}
}
if let Some(digest) = event.digests.first() {
let digest = digest.digest();
let encoded = hex::encode(digest.as_slice());
eprintln!("applying digest: {encoded:0>len$}", len = hash_len * 2);
state.measure(&digest, args.algo.into());
}
let encoded = hex::encode(digest.as_slice());
eprintln!("applying digest: {encoded:0>len$}", len = hash_len * 2);
state.measure(&digest, args.algo.into());
}
let hash = state.as_slice();
let hex = hex::encode(hash);
println!("{hex:0>len$}", len = hash_len * 2);
Ok(())
}