From 2d738b4d618031608433e39822f734483fb3c2b5 Mon Sep 17 00:00:00 2001 From: Benjamin Kay Date: Wed, 31 Jul 2019 20:37:37 -0500 Subject: [PATCH] Added support for parsing THP_enabled and Speculation_Store_Bypass in Linux 5.0 and 4.17, respectively. --- Cargo.toml | 2 +- src/lib.rs | 2 +- src/pid/status.rs | 40 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0e1227b..b41816c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "procinfo" # NB: When modifying, also modify html_root_url in lib.rs. -version = "0.4.2" +version = "0.4.3" authors = ["Dan Burkert "] license = "MIT/Apache-2.0" repository = "https://github.com/danburkert/procinfo-rs" diff --git a/src/lib.rs b/src/lib.rs index 24cc2ba..d054046 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ #![recursion_limit = "1000"] #![cfg_attr(rustc_nightly, feature(test))] -#![doc(html_root_url = "https://docs.rs/procinfo/0.4.2")] +#![doc(html_root_url = "https://docs.rs/procinfo/0.4.3")] #![allow(dead_code)] // TODO: remove diff --git a/src/pid/status.rs b/src/pid/status.rs index a8cc3ad..474118b 100644 --- a/src/pid/status.rs +++ b/src/pid/status.rs @@ -42,6 +42,31 @@ named!(parse_seccomp_mode, | tag!("1") => { |_| SeccompMode::Strict } | tag!("2") => { |_| SeccompMode::Filter })); +/// The Speculation Store Bypass of a process +#[derive(Debug, PartialEq, Eq, Hash)] +pub enum SpeculationStoreBypass { + Vulnerable, + NotVulnerable, + ThreadForceMitigated, + ThreadMitigated, + ThreadVulnerable, + GloballyMitigated, +} + +impl Default for SpeculationStoreBypass { + fn default() -> SpeculationStoreBypass { + SpeculationStoreBypass::Vulnerable + } +} + +named!(parse_speculation_store_bypass_mode, + alt!(tag!("vulnerable") => { |_| SpeculationStoreBypass::Vulnerable } + | tag!("not vulnerable") => { |_| SpeculationStoreBypass::NotVulnerable } + | tag!("thread force mitigated") => { |_| SpeculationStoreBypass::ThreadForceMitigated } + | tag!("thread mitigated") => { |_| SpeculationStoreBypass::ThreadMitigated } + | tag!("thread vulnerable") => { |_| SpeculationStoreBypass::ThreadVulnerable } + | tag!("globally mitigated") => { |_| SpeculationStoreBypass::GloballyMitigated })); + /// Process status information. /// /// See `man 5 proc` and `Linux/fs/proc/array.c`. @@ -130,6 +155,8 @@ pub struct Status { pub hugetlb_pages: usize, /// Process's memory is currently being dumped (since Linux 4.15). pub core_dumping: bool, + /// THP (transparent huge pages) enabled (since Linux 5.0). + pub thp_enabled: bool, /// Number of threads in process containing this thread. pub threads: u32, /// The number of currently queued signals for this real user ID @@ -163,6 +190,8 @@ pub struct Status { /// This field is provided only if the kernel was built with the /// `CONFIG_SECCOMP` kernel configuration option enabled. pub seccomp: SeccompMode, + /// Speculation Store Bypass (since Linux 4.17) + pub speculation_store_bypass: SpeculationStoreBypass, /// CPUs on which this process may run (since Linux 2.6.24, see cpuset(7)). /// /// The slice represents a bitmask in the same format as `BitVec`. @@ -230,6 +259,7 @@ named!(parse_vm_swap, delimited!(tag!("VmSwap:"), parse_kb, named!(parse_hugetlb_pages, delimited!(tag!("HugetlbPages:"), parse_kb, line_ending)); named!(parse_core_dumping, delimited!(tag!("CoreDumping:\t"), parse_bit, line_ending)); +named!(parse_thp_enabled, delimited!(tag!("THP_enabled:\t"), parse_bit, line_ending)); named!(parse_threads, delimited!(tag!("Threads:\t"), parse_u32, line_ending)); @@ -249,6 +279,7 @@ named!(parse_cap_ambient, delimited!(tag!("CapAmb:\t"), parse_u64_hex, lin named!(parse_no_new_privs, delimited!(tag!("NoNewPrivs:\t"), parse_bit, line_ending)); named!(parse_seccomp, delimited!(tag!("Seccomp:\t"), parse_seccomp_mode, line_ending)); +named!(parse_speculation_store_bypass, delimited!(tag!("Speculation_Store_Bypass:\t"), parse_speculation_store_bypass_mode, line_ending)); named!(parse_cpus_allowed >, delimited!(tag!("Cpus_allowed:\t"), parse_u32_mask_list, line_ending)); named!(parse_mems_allowed >, delimited!(tag!("Mems_allowed:\t"), parse_u32_mask_list, line_ending)); @@ -303,6 +334,7 @@ fn parse_status(i: &[u8]) -> IResult<&[u8], Status> { | parse_vm_swap => { |value| status.vm_swap = value } | parse_hugetlb_pages => { |value| status.hugetlb_pages = value } | parse_core_dumping => { |value| status.core_dumping = value } + | parse_thp_enabled => { |value| status.thp_enabled = value } | parse_threads => { |value| status.threads = value } | parse_sig_queued => { |(count, max)| { status.sig_queued = count; @@ -321,6 +353,7 @@ fn parse_status(i: &[u8]) -> IResult<&[u8], Status> { | parse_no_new_privs => { |value| status.no_new_privs = value } | parse_seccomp => { |value| status.seccomp = value } + | parse_speculation_store_bypass => { |value| status.speculation_store_bypass = value } | parse_cpus_allowed => { |value| status.cpus_allowed = value } | parse_cpus_allowed_list | parse_mems_allowed => { |value| status.mems_allowed = value } @@ -356,7 +389,8 @@ pub fn status_task(process_id: pid_t, thread_id: pid_t) -> Result { #[cfg(test)] mod tests { use parsers::tests::unwrap; - use super::{SeccompMode, parse_status, status, status_self}; + use super::{SeccompMode, SpeculationStoreBypass, parse_status, status, status_self}; + use pid::State; /// Test that the system status files can be parsed. @@ -402,6 +436,7 @@ mod tests { VmSwap:\t 0 kB\n\ HugetlbPages:\t 0 kB\n\ CoreDumping:\t0\n\ + THP_enabled:\t1\n\ Threads:\t1\n\ SigQ:\t0/257232\n\ SigPnd:\t0000000000000000\n\ @@ -416,6 +451,7 @@ mod tests { CapAmb:\t0000000000000000\n\ NoNewPrivs:\t0\n\ Seccomp:\t0\n\ + Speculation_Store_Bypass:\tthread vulnerable\n\ Cpus_allowed:\tffff\n\ Cpus_allowed_list:\t0-15\n\ Mems_allowed:\t00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001\n\ @@ -464,6 +500,7 @@ mod tests { assert_eq!(0, status.vm_swap); assert_eq!(0, status.hugetlb_pages); assert_eq!(false, status.core_dumping); + assert_eq!(true, status.thp_enabled); assert_eq!(1, status.threads); assert_eq!(0, status.sig_queued); assert_eq!(257232, status.sig_queued_max); @@ -479,6 +516,7 @@ mod tests { assert_eq!(0x0000000000000000, status.cap_ambient); assert_eq!(false, status.no_new_privs); assert_eq!(SeccompMode::Disabled, status.seccomp); + assert_eq!(SpeculationStoreBypass::ThreadVulnerable, status.speculation_store_bypass); assert_eq!(&[0xff, 0xff, 0x00, 0x00], &*status.cpus_allowed); let mems_allowed: &mut [u8] = &mut [0; 64]; mems_allowed[0] = 0x80;