Type definitions and parsers for the Linux Integrity Measurement Architecture (IMA), based on the upstream specification at https://ima-doc.readthedocs.io/.
Two artefacts produced by IMA are supported:
-
The event log (measurement list / integrity log) exposed by the kernel via
securityfs:/sys/kernel/security/ima/binary_runtime_measurements/sys/kernel/security/ima/ascii_runtime_measurements
Both binary and ASCII representations can be parsed, and the
template_hashof every event can be recomputed and verified using the built-inHasherimplementations. -
The policy file (
/etc/ima/ima-policy,/sys/kernel/security/ima/policy, …): an ordered list of rules composed of an action, conditions and options.
use ima_parser::policy::{parse_policy, Action}; let text = concat!( "# measure all executables run\n", "measure func=BPRM_CHECK\n", "dont_measure fsmagic=0x9fa0\n", ); let policy = parse_policy(text).unwrap(); assert_eq!(policy.rules.len(), 2); assert_eq!(policy.rules[0].action, Action::Measure);
use ima_parser::log::{EventLogParser, ParseOptions}; use ima_parser::hash::HashAlgorithm; let bytes = std::fs::read("/sys/kernel/security/ima/binary_runtime_measurements")?; // The default file is hashed with SHA-1; for the SHA-256 variant use // `with_template_hash_algorithm`. let opts = ParseOptions::default() .with_template_hash_algorithm(HashAlgorithm::Sha1); for event in EventLogParser::new(bytes.as_slice(), opts) { let event = event?; println!("PCR {} {}", event.pcr_index, event.template); }
use ima_parser::log::parse_ascii_log; let line = "10 91f34b5c671d73504b274a919661cf80dab1e127 ima-ng sha1:1801e1be3e65ef1eaa5c16617bec8f1274eaf6b3 boot_aggregate\n"; let events = parse_ascii_log(line).unwrap(); assert_eq!(events.len(), 1); assert_eq!(events[0].template.as_str(), "ima-ng");
use ima_parser::hash::HashAlgorithm; use ima_parser::log::parse_ascii_log; // Build a self-consistent synthetic event by first computing the // template hash for a known (digest, filename) pair, then feeding the // result back through the ASCII parser. use sha1::{Digest, Sha1}; let filedata_hex = "cd".repeat(20); let filename = "/etc/hosts"; let mut d_ng = Vec::new(); d_ng.extend_from_slice(b"sha1"); d_ng.push(b':'); d_ng.push(0); d_ng.extend_from_slice(&[0xcd; 20]); let mut n_ng = Vec::new(); n_ng.extend_from_slice(filename.as_bytes()); n_ng.push(0); let mut h = Sha1::new(); h.update((d_ng.len() as u32).to_le_bytes()); h.update(&d_ng); h.update((n_ng.len() as u32).to_le_bytes()); h.update(&n_ng); let th_hex: String = h.finalize().iter().map(|b| format!("{:02x}", b)).collect(); let line = format!("10 {} ima-ng sha1:{} {}\n", th_hex, filedata_hex, filename); let events = parse_ascii_log(&line).unwrap(); assert_eq!(events[0].verify_template_hash(HashAlgorithm::Sha1), Some(true));
hash(default) — enables built-in template-hash computation via thesha1andsha2crates from RustCrypto. Disabling it removes both dependencies; you can still implement theHashertrait against your own crypto stack.