Projects STRLCPY ebpfguard Commits 34630147
🤬
Revision indexing in progress... (symbol navigation in revisions will be accurate after indexed)
  • ■ ■ ■ ■ ■
    guardctl/Cargo.toml
    skipped 9 lines
    10 10  cli-table = "0.4"
    11 11  guardity = { path = "../guardity" }
    12 12  guardity-common = { path = "../guardity-common", features = ["user"] }
     13 +tokio = { version = "1.25", features = ["macros", "rt", "rt-multi-thread", "net", "signal", "sync"] }
    13 14   
  • ■ ■ ■ ■ ■ ■
    guardctl/src/main.rs
    1 1  use std::path::PathBuf;
    2 2   
    3  -use aya::{include_bytes_aligned, BpfLoader};
    4 3  use clap::{Parser, Subcommand};
     4 +use guardity::PolicyManager;
    5 5  use policy::{add_policies, list_policies};
    6 6   
    7 7  mod policy;
    skipped 28 lines
    36 36   List,
    37 37  }
    38 38   
    39  -fn main() -> anyhow::Result<()> {
     39 +#[tokio::main]
     40 +async fn main() -> anyhow::Result<()> {
    40 41   let args = Args::parse();
    41 42   
    42 43   let bpf_path = args.bpffs_path.join(args.bpffs_dir);
    43 44   
    44 45   match args.subcommand {
    45 46   Sub::Policy { policy } => {
    46  - #[cfg(debug_assertions)]
    47  - let mut bpf = BpfLoader::new()
    48  - .map_pin_path(bpf_path)
    49  - .load(include_bytes_aligned!(
    50  - "../../target/bpfel-unknown-none/debug/guardity"
    51  - ))?;
    52  - #[cfg(not(debug_assertions))]
    53  - let mut bpf = BpfLoader::new()
    54  - .map_pin_path(bpf_path)
    55  - .load(include_bytes_aligned!(
    56  - "../../target/bpfel-unknown-none/release/guardity"
    57  - ))?;
     47 + let mut policy_manager = PolicyManager::new(bpf_path)?;
     48 + 
    58 49   match policy {
    59 50   SubPolicy::Add { r#path } => {
    60  - add_policies(&mut bpf, path)?;
     51 + add_policies(&mut policy_manager, path).await?;
    61 52   }
    62 53   SubPolicy::List => {
    63  - list_policies(&mut bpf)?;
     54 + list_policies(&mut policy_manager).await?;
    64 55   }
    65 56   }
    66 57   }
    skipped 5 lines
  • ■ ■ ■ ■ ■ ■
    guardctl/src/policy/file_open.rs
    1  -use std::collections::HashSet;
    2  - 
    3  -use aya::{
    4  - maps::{HashMap, MapError},
    5  - Bpf,
    6  -};
    7 1  use cli_table::{Cell, Style, Table, TableStruct};
    8  -use guardity::policy::{engine::INODE_WILDCARD, Paths};
     2 +use guardity::{policy::Paths, PolicyManager};
    9 3   
    10  -pub(crate) fn list_file_open(bpf: &mut Bpf) -> anyhow::Result<TableStruct> {
     4 +pub(crate) async fn list_file_open(
     5 + policy_manager: &mut PolicyManager,
     6 +) -> anyhow::Result<TableStruct> {
    11 7   let mut table = Vec::new();
    12 8   
    13  - let allowed_file_open: HashMap<_, u64, guardity_common::Paths> =
    14  - bpf.map("ALLOWED_FILE_OPEN").unwrap().try_into()?;
    15  - let denied_file_open: HashMap<_, u64, guardity_common::Paths> =
    16  - bpf.map("DENIED_FILE_OPEN").unwrap().try_into()?;
     9 + let file_open = policy_manager.manage_file_open()?;
    17 10   
    18  - let mut subjects = HashSet::new();
    19  - for key in allowed_file_open.keys() {
    20  - let key = key?;
    21  - subjects.insert(key);
    22  - }
    23  - for key in denied_file_open.keys() {
    24  - let key = key?;
    25  - subjects.insert(key);
    26  - }
    27  - 
    28  - for subject in subjects {
    29  - let allowed = match allowed_file_open.get(&subject, 0) {
    30  - Ok(allowed) => {
    31  - let allowed = allowed.into();
    32  - match allowed {
    33  - Paths::All => "all".to_owned(),
    34  - Paths::Paths(paths) => paths
    35  - .iter()
    36  - .map(|p| p.to_string_lossy().to_string())
    37  - .collect::<Vec<_>>()
    38  - .join("\n"),
    39  - }
    40  - }
    41  - Err(MapError::KeyNotFound) => "-".to_owned(),
    42  - Err(e) => return Err(e.into()),
     11 + for policy in file_open.list_policies().await? {
     12 + let allow = match policy.allow {
     13 + Paths::All => "all".to_owned(),
     14 + Paths::Paths(paths) => paths
     15 + .iter()
     16 + .map(|p| p.to_string_lossy().to_string())
     17 + .collect::<Vec<_>>()
     18 + .join("\n"),
    43 19   };
    44  - let denied = match denied_file_open.get(&subject, 0) {
    45  - Ok(denied) => {
    46  - let denied = denied.into();
    47  - match denied {
    48  - Paths::All => "all".to_owned(),
    49  - Paths::Paths(paths) => paths
    50  - .iter()
    51  - .map(|p| p.to_string_lossy().to_string())
    52  - .collect::<Vec<_>>()
    53  - .join("\n"),
    54  - }
    55  - }
    56  - Err(MapError::KeyNotFound) => "-".to_owned(),
    57  - Err(e) => return Err(e.into()),
     20 + let deny = match policy.deny {
     21 + Paths::All => "all".to_owned(),
     22 + Paths::Paths(paths) => paths
     23 + .iter()
     24 + .map(|p| p.to_string_lossy().to_string())
     25 + .collect::<Vec<_>>()
     26 + .join("\n"),
    58 27   };
    59  - if subject == INODE_WILDCARD {
    60  - table.push(vec!["all".to_string(), allowed, denied]);
    61  - } else {
    62  - table.push(vec![subject.to_string(), allowed, denied]);
    63  - }
     28 + table.push(vec![policy.subject.to_string(), allow, deny]);
    64 29   }
    65 30   
    66 31   let table = table.table().title(vec![
    skipped 8 lines
  • ■ ■ ■ ■ ■ ■
    guardctl/src/policy/mod.rs
    1 1  use std::path::PathBuf;
    2 2   
    3  -use aya::Bpf;
    4 3  use cli_table::{print_stdout, Cell, Style, Table};
    5  -use guardity::policy::{engine, reader};
     4 +use guardity::{policy::reader, PolicyManager};
    6 5   
    7 6  use self::{
    8  - file_open::list_file_open, setuid::list_setuid, socket_bind::list_socket_bind,
    9  - socket_connect::list_socket_connect,
     7 + file_open::list_file_open, socket_bind::list_socket_bind, socket_connect::list_socket_connect,
     8 + task_fix_setuid::list_task_fix_setuid,
    10 9  };
    11 10   
    12 11  pub(crate) mod file_open;
    13  -pub(crate) mod setuid;
    14 12  pub(crate) mod socket_bind;
    15 13  pub(crate) mod socket_connect;
     14 +pub(crate) mod task_fix_setuid;
    16 15   
    17  -pub(crate) fn add_policies(bpf: &mut Bpf, r#path: PathBuf) -> anyhow::Result<()> {
     16 +pub(crate) async fn add_policies(
     17 + policy_manager: &mut PolicyManager,
     18 + r#path: PathBuf,
     19 +) -> anyhow::Result<()> {
     20 + let mut all = policy_manager.manage_all()?;
    18 21   let policies = reader::read_policies(r#path)?;
    19 22   for policy in policies {
    20  - engine::process_policy(bpf, policy)?;
     23 + all.add_policy(policy).await?;
    21 24   }
    22 25   Ok(())
    23 26  }
    24 27   
    25  -pub(crate) fn list_policies(bpf: &mut Bpf) -> anyhow::Result<()> {
    26  - let file_open = list_file_open(bpf)?;
    27  - let setuid = list_setuid(bpf)?;
    28  - let socket_bind = list_socket_bind(bpf)?;
    29  - let socket_connect = list_socket_connect(bpf)?;
     28 +pub(crate) async fn list_policies(policy_manager: &mut PolicyManager) -> anyhow::Result<()> {
     29 + let file_open = list_file_open(policy_manager).await?;
     30 + let setuid = list_task_fix_setuid(policy_manager).await?;
     31 + let socket_bind = list_socket_bind(policy_manager).await?;
     32 + let socket_connect = list_socket_connect(policy_manager).await?;
    30 33   
    31 34   let table = vec![
    32 35   vec!["file_open".cell()],
    skipped 16 lines
  • ■ ■ ■ ■ ■ ■
    guardctl/src/policy/setuid.rs
    1  -use aya::{maps::HashMap, Bpf};
    2  -use cli_table::{Cell, Style, Table, TableStruct};
    3  -use guardity::policy::engine::INODE_WILDCARD;
    4  - 
    5  -pub(crate) fn list_setuid(bpf: &mut Bpf) -> anyhow::Result<TableStruct> {
    6  - let mut table = Vec::new();
    7  - 
    8  - let allowed_setuid: HashMap<_, u64, u8> = bpf.map("ALLOWED_SETUID").unwrap().try_into()?;
    9  - for res in allowed_setuid.iter() {
    10  - let (inode, _) = res?;
    11  - if inode == INODE_WILDCARD {
    12  - table.push(vec!["allow".to_string(), "all".to_string()]);
    13  - } else {
    14  - table.push(vec!["allow".to_string(), inode.to_string()]);
    15  - }
    16  - }
    17  - 
    18  - let denied_setuid: HashMap<_, u64, u8> = bpf.map("DENIED_SETUID").unwrap().try_into()?;
    19  - for res in denied_setuid.iter() {
    20  - let (inode, _) = res?;
    21  - if inode == INODE_WILDCARD {
    22  - table.push(vec!["deny".to_string(), "all".to_string()]);
    23  - } else {
    24  - table.push(vec!["deny".to_string(), inode.to_string()]);
    25  - }
    26  - }
    27  - 
    28  - let table = table.table().title(vec![
    29  - "action".cell().bold(true),
    30  - "subject".cell().bold(true),
    31  - ]);
    32  - 
    33  - Ok(table)
    34  -}
    35  - 
  • ■ ■ ■ ■ ■ ■
    guardctl/src/policy/socket_bind.rs
    1  -use std::collections::HashSet;
    2  - 
    3  -use aya::{
    4  - maps::{HashMap, MapError},
    5  - Bpf,
    6  -};
    7 1  use cli_table::{Cell, Style, Table, TableStruct};
    8  -use guardity::policy::{engine::INODE_WILDCARD, Ports};
     2 +use guardity::{policy::Ports, PolicyManager};
    9 3   
    10  -pub(crate) fn list_socket_bind(bpf: &mut Bpf) -> anyhow::Result<TableStruct> {
     4 +pub(crate) async fn list_socket_bind(
     5 + policy_manager: &mut PolicyManager,
     6 +) -> anyhow::Result<TableStruct> {
    11 7   let mut table = Vec::new();
    12 8   
    13  - let allowed_socket_bind: HashMap<_, u64, guardity_common::Ports> =
    14  - bpf.map("ALLOWED_SOCKET_BIND").unwrap().try_into()?;
    15  - let denied_socket_bind: HashMap<_, u64, guardity_common::Ports> =
    16  - bpf.map("DENIED_SOCKET_BIND").unwrap().try_into()?;
     9 + let socket_bind = policy_manager.manage_socket_bind()?;
    17 10   
    18  - let mut subjects = HashSet::new();
    19  - for key in allowed_socket_bind.keys() {
    20  - let key = key?;
    21  - subjects.insert(key);
    22  - }
    23  - for key in denied_socket_bind.keys() {
    24  - let key = key?;
    25  - subjects.insert(key);
    26  - }
    27  - 
    28  - for subject in subjects {
    29  - let allowed = match allowed_socket_bind.get(&subject, 0) {
    30  - Ok(allowed) => {
    31  - let allowed = allowed.into();
    32  - match allowed {
    33  - Ports::All => "all".to_owned(),
    34  - Ports::Ports(ports) => ports
    35  - .iter()
    36  - .map(|p| p.to_string())
    37  - .collect::<Vec<_>>()
    38  - .join("\n"),
    39  - }
    40  - }
    41  - Err(MapError::KeyNotFound) => "-".to_owned(),
    42  - Err(e) => return Err(e.into()),
     11 + for policy in socket_bind.list_policies().await? {
     12 + let allow = match policy.allow {
     13 + Ports::All => "all".to_owned(),
     14 + Ports::Ports(ports) => ports
     15 + .iter()
     16 + .map(|p| p.to_string())
     17 + .collect::<Vec<_>>()
     18 + .join("\n"),
    43 19   };
    44  - let denied = match denied_socket_bind.get(&subject, 0) {
    45  - Ok(denied) => {
    46  - let denied = denied.into();
    47  - match denied {
    48  - Ports::All => "all".to_owned(),
    49  - Ports::Ports(ports) => ports
    50  - .iter()
    51  - .map(|p| p.to_string())
    52  - .collect::<Vec<_>>()
    53  - .join("\n"),
    54  - }
    55  - }
    56  - Err(MapError::KeyNotFound) => "-".to_owned(),
    57  - Err(e) => return Err(e.into()),
     20 + let deny = match policy.deny {
     21 + Ports::All => "all".to_owned(),
     22 + Ports::Ports(ports) => ports
     23 + .iter()
     24 + .map(|p| p.to_string())
     25 + .collect::<Vec<_>>()
     26 + .join("\n"),
    58 27   };
    59  - if subject == INODE_WILDCARD {
    60  - table.push(vec!["all".to_string(), allowed, denied]);
    61  - } else {
    62  - table.push(vec![subject.to_string(), allowed, denied]);
    63  - }
     28 + table.push(vec![policy.subject.to_string(), allow, deny]);
    64 29   }
    65 30   
    66 31   let table = table.table().title(vec![
    skipped 8 lines
  • ■ ■ ■ ■ ■
    guardctl/src/policy/socket_connect.rs
    1  -use std::{
    2  - collections::HashSet,
    3  - net::{IpAddr, Ipv4Addr, Ipv6Addr},
    4  -};
    5  - 
    6  -use aya::{maps::HashMap, Bpf};
    7 1  use cli_table::{Cell, Style, Table, TableStruct};
    8  -use guardity::policy::engine::INODE_WILDCARD;
    9  -use guardity_common::IpAddrs;
     2 +use guardity::{policy::Addresses, PolicyManager};
    10 3   
    11  -enum Addresses {
    12  - All,
    13  - Addresses(Vec<IpAddr>),
    14  -}
    15  - 
    16  -pub(crate) fn list_socket_connect(bpf: &mut Bpf) -> anyhow::Result<TableStruct> {
     4 +pub(crate) async fn list_socket_connect(
     5 + policy_manager: &mut PolicyManager,
     6 +) -> anyhow::Result<TableStruct> {
    17 7   let mut table = Vec::new();
    18 8   
    19  - let allowed_socket_connect_v4: HashMap<_, u64, guardity_common::Ipv4Addrs> =
    20  - bpf.map("ALLOWED_SOCKET_CONNECT_V4").unwrap().try_into()?;
    21  - let denied_socket_connect_v4: HashMap<_, u64, guardity_common::Ipv4Addrs> =
    22  - bpf.map("DENIED_SOCKET_CONNECT_V4").unwrap().try_into()?;
    23  - let allowed_socket_connect_v6: HashMap<_, u64, guardity_common::Ipv6Addrs> =
    24  - bpf.map("ALLOWED_SOCKET_CONNECT_V6").unwrap().try_into()?;
    25  - let denied_socket_connect_v6: HashMap<_, u64, guardity_common::Ipv6Addrs> =
    26  - bpf.map("DENIED_SOCKET_CONNECT_V6").unwrap().try_into()?;
    27  - 
    28  - let mut subjects = HashSet::new();
    29  - for key in allowed_socket_connect_v4.keys() {
    30  - let key = key?;
    31  - subjects.insert(key);
    32  - }
    33  - for key in denied_socket_connect_v4.keys() {
    34  - let key = key?;
    35  - subjects.insert(key);
    36  - }
    37  - for key in allowed_socket_connect_v6.keys() {
    38  - let key = key?;
    39  - subjects.insert(key);
    40  - }
    41  - for key in denied_socket_connect_v6.keys() {
    42  - let key = key?;
    43  - subjects.insert(key);
    44  - }
    45  - 
    46  - for subject in subjects {
    47  - let mut allowed = match allowed_socket_connect_v4.get(&subject, 0) {
    48  - Ok(allowed) => {
    49  - if allowed.all() {
    50  - Addresses::All
    51  - } else {
    52  - Addresses::Addresses(
    53  - allowed
    54  - .addrs
    55  - .iter()
    56  - .map(|a| IpAddr::V4(Ipv4Addr::from(*a)))
    57  - .collect(),
    58  - )
    59  - }
    60  - }
    61  - Err(aya::maps::MapError::KeyNotFound) => Addresses::Addresses(vec![]),
    62  - Err(e) => return Err(e.into()),
    63  - };
    64  - if let Addresses::Addresses(addrs) = &mut allowed {
    65  - match allowed_socket_connect_v6.get(&subject, 0) {
    66  - Ok(allowed) => {
    67  - if allowed.all() {
    68  - anyhow::bail!("Inconsistent policies: allowed all IPv6 addresses, but specified IPv4 addresses")
    69  - } else {
    70  - addrs.extend(allowed.addrs.iter().map(|a| IpAddr::V6(Ipv6Addr::from(*a))));
    71  - }
    72  - }
    73  - Err(aya::maps::MapError::KeyNotFound) => {}
    74  - Err(e) => return Err(e.into()),
    75  - }
    76  - }
    77  - 
    78  - let mut denied = match denied_socket_connect_v4.get(&subject, 0) {
    79  - Ok(denied) => {
    80  - if denied.all() {
    81  - Addresses::All
    82  - } else {
    83  - Addresses::Addresses(
    84  - denied
    85  - .addrs
    86  - .iter()
    87  - .map(|a| IpAddr::V4(Ipv4Addr::from(*a)))
    88  - .collect(),
    89  - )
    90  - }
    91  - }
    92  - Err(aya::maps::MapError::KeyNotFound) => Addresses::Addresses(vec![]),
    93  - Err(e) => return Err(e.into()),
    94  - };
    95  - if let Addresses::Addresses(addrs) = &mut denied {
    96  - match denied_socket_connect_v6.get(&subject, 0) {
    97  - Ok(denied) => {
    98  - if denied.all() {
    99  - anyhow::bail!("Inconsistent policies: denied all IPv6 addresses, but specified IPv4 addresses")
    100  - } else {
    101  - addrs.extend(denied.addrs.iter().map(|a| IpAddr::V6(Ipv6Addr::from(*a))));
    102  - }
    103  - }
    104  - Err(aya::maps::MapError::KeyNotFound) => {}
    105  - Err(e) => return Err(e.into()),
    106  - }
    107  - }
     9 + let socket_connect = policy_manager.manage_socket_connect()?;
    108 10   
    109  - let allowed = match allowed {
     11 + for policy in socket_connect.list_policies().await? {
     12 + let allow = match policy.allow {
    110 13   Addresses::All => "all".to_owned(),
    111  - Addresses::Addresses(addrs) => addrs
     14 + Addresses::Addresses(addresses) => addresses
    112 15   .iter()
    113 16   .map(|a| a.to_string())
    114 17   .collect::<Vec<_>>()
    115 18   .join("\n"),
    116 19   };
    117  - let denied = match denied {
     20 + let deny = match policy.deny {
    118 21   Addresses::All => "all".to_owned(),
    119  - Addresses::Addresses(addrs) => addrs
     22 + Addresses::Addresses(addresses) => addresses
    120 23   .iter()
    121 24   .map(|a| a.to_string())
    122 25   .collect::<Vec<_>>()
    123 26   .join("\n"),
    124 27   };
    125  - 
    126  - if subject == INODE_WILDCARD {
    127  - table.push(vec!["all".to_owned(), allowed, denied]);
    128  - } else {
    129  - table.push(vec![subject.to_string(), allowed, denied]);
    130  - }
     28 + table.push(vec![policy.subject.to_string(), allow, deny]);
    131 29   }
    132 30   
    133 31   let table = table.table().title(vec![
    skipped 7 lines
  • ■ ■ ■ ■ ■ ■
    guardctl/src/policy/task_fix_setuid.rs
     1 +use cli_table::{Cell, Style, Table, TableStruct};
     2 +use guardity::PolicyManager;
     3 + 
     4 +pub(crate) async fn list_task_fix_setuid(
     5 + policy_manager: &mut PolicyManager,
     6 +) -> anyhow::Result<TableStruct> {
     7 + let mut table = Vec::new();
     8 + 
     9 + let task_fix_setuid = policy_manager.manage_task_fix_setuid()?;
     10 + 
     11 + for policy in task_fix_setuid.list_policies().await? {
     12 + table.push(vec![policy.subject.to_string(), policy.allow.to_string()]);
     13 + }
     14 + 
     15 + let table = table.table().title(vec![
     16 + "action".cell().bold(true),
     17 + "subject".cell().bold(true),
     18 + ]);
     19 + 
     20 + Ok(table)
     21 +}
     22 + 
  • ■ ■ ■ ■ ■
    guardity/Cargo.toml
    skipped 8 lines
    9 9  bytes = "1.4"
    10 10  clap = { version = "4.2", features = ["derive"] }
    11 11  guardity-common = { path = "../guardity-common", features = ["user"] }
    12  -anyhow = "1"
     12 +anyhow = { version = "1", features = ["backtrace"] }
    13 13  env_logger = "0.10"
    14 14  log = "0.4"
     15 +once_cell = "1.17"
    15 16  serde = { version = "1.0", features = ["derive"] }
    16 17  serde_json = "1.0"
    17 18  serde_yaml = "0.9"
    skipped 7 lines
  • ■ ■ ■ ■ ■ ■
    guardity/src/alerts.rs
    skipped 19 lines
    20 20   fn from(alert: alerts::BprmCheckSecurity) -> Self {
    21 21   Self {
    22 22   pid: alert.pid,
    23  - subject: PolicySubject::Process(PathBuf::from(alert.binprm_inode.to_string())),
     23 + subject: PolicySubject::Binary(PathBuf::from(alert.binprm_inode.to_string())),
    24 24   }
    25 25   }
    26 26  }
    skipped 11 lines
    38 38   fn from(alert: alerts::FileOpen) -> Self {
    39 39   Self {
    40 40   pid: alert.pid,
    41  - subject: PolicySubject::Process(PathBuf::from(alert.binprm_inode.to_string())),
     41 + subject: PolicySubject::Binary(PathBuf::from(alert.binprm_inode.to_string())),
    42 42   path: PathBuf::from(alert.inode.to_string()),
    43 43   }
    44 44   }
    45 45  }
    46 46   
    47 47  #[derive(Debug)]
    48  -pub struct TaskFixSetUid {
     48 +pub struct TaskFixSetuid {
    49 49   pub pid: u32,
    50 50   pub subject: PolicySubject,
    51 51   pub old_uid: u32,
    skipped 2 lines
    54 54   pub new_gid: u32,
    55 55  }
    56 56   
    57  -impl Alert for TaskFixSetUid {}
     57 +impl Alert for TaskFixSetuid {}
    58 58   
    59  -impl From<alerts::TaskFixSetuid> for TaskFixSetUid {
     59 +impl From<alerts::TaskFixSetuid> for TaskFixSetuid {
    60 60   fn from(alert: alerts::TaskFixSetuid) -> Self {
    61 61   Self {
    62 62   pid: alert.pid,
    63  - subject: PolicySubject::Process(PathBuf::from(alert.binprm_inode.to_string())),
     63 + subject: PolicySubject::Binary(PathBuf::from(alert.binprm_inode.to_string())),
    64 64   old_uid: alert.old_uid,
    65 65   old_gid: alert.old_gid,
    66 66   new_uid: alert.new_uid,
    skipped 15 lines
    82 82   fn from(alert: alerts::SocketBind) -> Self {
    83 83   Self {
    84 84   pid: alert.pid,
    85  - subject: PolicySubject::Process(PathBuf::from(alert.binprm_inode.to_string())),
     85 + subject: PolicySubject::Binary(PathBuf::from(alert.binprm_inode.to_string())),
    86 86   port: alert.port,
    87 87   }
    88 88   }
    skipped 17 lines
    106 106   };
    107 107   Self {
    108 108   pid: alert.pid,
    109  - subject: PolicySubject::Process(PathBuf::from(alert.binprm_inode.to_string())),
     109 + subject: PolicySubject::Binary(PathBuf::from(alert.binprm_inode.to_string())),
    110 110   addr,
    111 111   }
    112 112   }
    skipped 2 lines
  • ■ ■ ■ ■ ■ ■
    guardity/src/error.rs
     1 +use thiserror::Error;
     2 + 
     3 +#[derive(Debug, Error)]
     4 +pub enum GuardityError {
     5 + #[error("Failed to find an inode for the given path")]
     6 + Inode(#[from] std::io::Error),
     7 +}
     8 + 
  • ■ ■ ■ ■ ■ ■
    guardity/src/hooks.rs
     1 +use std::{
     2 + fmt::Debug,
     3 + net::{IpAddr, Ipv4Addr, Ipv6Addr},
     4 +};
     5 + 
     6 +use aya::{
     7 + maps::{AsyncPerfEventArray, HashMap, MapData},
     8 + programs::lsm::LsmLink,
     9 + util::online_cpus,
     10 +};
     11 +use bytes::BytesMut;
     12 +use guardity_common::{
     13 + alerts as ebpf_alerts,
     14 + policy::{self as ebpf_policy, IpAddrs},
     15 +};
     16 +use once_cell::sync::Lazy;
     17 +use tokio::{
     18 + sync::{
     19 + mpsc::{self, Receiver},
     20 + Mutex,
     21 + },
     22 + task,
     23 +};
     24 + 
     25 +use crate::{alerts, policy, InodeSubjectMap};
     26 + 
     27 +static INODE_SUBJECT_MAP: Lazy<Mutex<InodeSubjectMap>> =
     28 + Lazy::new(|| Mutex::new(InodeSubjectMap::default()));
     29 + 
     30 +pub struct All {
     31 + pub bprm_check_security: BprmCheckSecurity,
     32 + pub file_open: FileOpen,
     33 + pub task_fix_setuid: TaskFixSetuid,
     34 + pub socket_bind: SocketBind,
     35 + pub socket_connect: SocketConnect,
     36 +}
     37 + 
     38 +impl All {
     39 + pub async fn add_policy(&mut self, policy: policy::Policy) -> anyhow::Result<()> {
     40 + match policy {
     41 + policy::Policy::FileOpen(policy) => self.file_open.add_policy(policy).await?,
     42 + policy::Policy::TaskFixSetuid(policy) => {
     43 + self.task_fix_setuid.add_policy(policy).await?
     44 + }
     45 + policy::Policy::SocketBind(policy) => self.socket_bind.add_policy(policy).await?,
     46 + policy::Policy::SocketConnect(policy) => self.socket_connect.add_policy(policy).await?,
     47 + }
     48 + 
     49 + Ok(())
     50 + }
     51 +}
     52 + 
     53 +pub struct BprmCheckSecurity {
     54 + #[allow(dead_code)]
     55 + pub(crate) program_link: Option<LsmLink>,
     56 + pub(crate) perf_array: AsyncPerfEventArray<MapData>,
     57 +}
     58 + 
     59 +impl BprmCheckSecurity {
     60 + pub async fn alerts(&mut self) -> anyhow::Result<Receiver<alerts::BprmCheckSecurity>> {
     61 + perf_array_alerts::<ebpf_alerts::BprmCheckSecurity, alerts::BprmCheckSecurity>(
     62 + &mut self.perf_array,
     63 + )
     64 + .await
     65 + }
     66 +}
     67 + 
     68 +pub struct FileOpen {
     69 + #[allow(dead_code)]
     70 + pub(crate) program_link: Option<LsmLink>,
     71 + pub(crate) allowed_map: HashMap<MapData, u64, ebpf_policy::Paths>,
     72 + pub(crate) denied_map: HashMap<MapData, u64, ebpf_policy::Paths>,
     73 + pub(crate) perf_array: AsyncPerfEventArray<MapData>,
     74 +}
     75 + 
     76 +impl FileOpen {
     77 + pub async fn add_policy(&mut self, policy: policy::FileOpen) -> anyhow::Result<()> {
     78 + let bin_inode = {
     79 + let mut map = INODE_SUBJECT_MAP.lock().await;
     80 + map.resolve_path(policy.subject)?
     81 + };
     82 + 
     83 + let allow: ebpf_policy::Paths = policy.allow.into();
     84 + let deny: ebpf_policy::Paths = policy.deny.into();
     85 + 
     86 + self.allowed_map.insert(bin_inode, allow, 0)?;
     87 + self.denied_map.insert(bin_inode, deny, 0)?;
     88 + 
     89 + Ok(())
     90 + }
     91 + 
     92 + pub async fn list_policies(&self) -> anyhow::Result<Vec<policy::FileOpen>> {
     93 + let mut policies = Vec::new();
     94 + 
     95 + for res in self.allowed_map.iter() {
     96 + let (bin_inode, allow) = res?;
     97 + let deny = self.denied_map.get(&bin_inode, 0)?;
     98 + 
     99 + let subject = {
     100 + let map = INODE_SUBJECT_MAP.lock().await;
     101 + map.resolve_inode(bin_inode)
     102 + };
     103 + 
     104 + policies.push(policy::FileOpen {
     105 + subject,
     106 + allow: allow.into(),
     107 + deny: deny.into(),
     108 + });
     109 + }
     110 + 
     111 + Ok(policies)
     112 + }
     113 + 
     114 + pub async fn alerts(&mut self) -> anyhow::Result<Receiver<alerts::FileOpen>> {
     115 + perf_array_alerts::<ebpf_alerts::FileOpen, alerts::FileOpen>(&mut self.perf_array).await
     116 + }
     117 +}
     118 + 
     119 +pub struct TaskFixSetuid {
     120 + #[allow(dead_code)]
     121 + pub(crate) program_link: Option<LsmLink>,
     122 + pub(crate) allowed_map: HashMap<MapData, u64, u8>,
     123 + pub(crate) denied_map: HashMap<MapData, u64, u8>,
     124 + pub(crate) perf_array: AsyncPerfEventArray<MapData>,
     125 +}
     126 + 
     127 +impl TaskFixSetuid {
     128 + pub async fn add_policy(&mut self, policy: policy::TaskFixSetuid) -> anyhow::Result<()> {
     129 + let bin_inode = {
     130 + let mut map = INODE_SUBJECT_MAP.lock().await;
     131 + map.resolve_path(policy.subject)?
     132 + };
     133 + 
     134 + if policy.allow {
     135 + self.allowed_map.insert(bin_inode, 0, 0)?;
     136 + } else {
     137 + self.denied_map.insert(bin_inode, 0, 0)?;
     138 + }
     139 + 
     140 + Ok(())
     141 + }
     142 + 
     143 + pub async fn list_policies(&self) -> anyhow::Result<Vec<policy::TaskFixSetuid>> {
     144 + let mut policies = Vec::new();
     145 + 
     146 + for res in self.allowed_map.iter() {
     147 + let (bin_inode, _) = res?;
     148 + 
     149 + let subject = {
     150 + let map = INODE_SUBJECT_MAP.lock().await;
     151 + map.resolve_inode(bin_inode)
     152 + };
     153 + 
     154 + policies.push(policy::TaskFixSetuid {
     155 + subject,
     156 + allow: true,
     157 + });
     158 + }
     159 + 
     160 + for res in self.denied_map.iter() {
     161 + let (bin_inode, _) = res?;
     162 + 
     163 + let subject = {
     164 + let map = INODE_SUBJECT_MAP.lock().await;
     165 + map.resolve_inode(bin_inode)
     166 + };
     167 + 
     168 + policies.push(policy::TaskFixSetuid {
     169 + subject,
     170 + allow: false,
     171 + });
     172 + }
     173 + 
     174 + Ok(policies)
     175 + }
     176 + 
     177 + pub async fn alerts(&mut self) -> anyhow::Result<Receiver<alerts::TaskFixSetuid>> {
     178 + perf_array_alerts::<ebpf_alerts::TaskFixSetuid, alerts::TaskFixSetuid>(&mut self.perf_array)
     179 + .await
     180 + }
     181 +}
     182 + 
     183 +pub struct SocketBind {
     184 + #[allow(dead_code)]
     185 + pub(crate) program_link: Option<LsmLink>,
     186 + pub(crate) allowed_map: HashMap<MapData, u64, ebpf_policy::Ports>,
     187 + pub(crate) denied_map: HashMap<MapData, u64, ebpf_policy::Ports>,
     188 + pub(crate) perf_array: AsyncPerfEventArray<MapData>,
     189 +}
     190 + 
     191 +impl SocketBind {
     192 + pub async fn add_policy(&mut self, policy: policy::SocketBind) -> anyhow::Result<()> {
     193 + let bin_inode = {
     194 + let mut map = INODE_SUBJECT_MAP.lock().await;
     195 + map.resolve_path(policy.subject)?
     196 + };
     197 + 
     198 + let allow: ebpf_policy::Ports = policy.allow.into();
     199 + let deny: ebpf_policy::Ports = policy.deny.into();
     200 + 
     201 + self.allowed_map.insert(bin_inode, allow, 0)?;
     202 + self.denied_map.insert(bin_inode, deny, 0)?;
     203 + 
     204 + Ok(())
     205 + }
     206 + 
     207 + pub async fn list_policies(&self) -> anyhow::Result<Vec<policy::SocketBind>> {
     208 + let mut policies = Vec::new();
     209 + 
     210 + for res in self.allowed_map.iter() {
     211 + let (bin_inode, allow) = res?;
     212 + let deny = self.denied_map.get(&bin_inode, 0)?;
     213 + 
     214 + let subject = {
     215 + let map = INODE_SUBJECT_MAP.lock().await;
     216 + map.resolve_inode(bin_inode)
     217 + };
     218 + 
     219 + policies.push(policy::SocketBind {
     220 + subject,
     221 + allow: allow.into(),
     222 + deny: deny.into(),
     223 + });
     224 + }
     225 + 
     226 + Ok(policies)
     227 + }
     228 + 
     229 + pub async fn alerts(&mut self) -> anyhow::Result<Receiver<alerts::SocketBind>> {
     230 + perf_array_alerts::<ebpf_alerts::SocketBind, alerts::SocketBind>(&mut self.perf_array).await
     231 + }
     232 +}
     233 + 
     234 +pub struct SocketConnect {
     235 + #[allow(dead_code)]
     236 + pub(crate) program_link: Option<LsmLink>,
     237 + pub(crate) allowed_map_v4: HashMap<MapData, u64, ebpf_policy::Ipv4Addrs>,
     238 + pub(crate) denied_map_v4: HashMap<MapData, u64, ebpf_policy::Ipv4Addrs>,
     239 + pub(crate) allowed_map_v6: HashMap<MapData, u64, ebpf_policy::Ipv6Addrs>,
     240 + pub(crate) denied_map_v6: HashMap<MapData, u64, ebpf_policy::Ipv6Addrs>,
     241 + pub(crate) perf_array: AsyncPerfEventArray<MapData>,
     242 +}
     243 + 
     244 +impl SocketConnect {
     245 + pub async fn add_policy(&mut self, policy: policy::SocketConnect) -> anyhow::Result<()> {
     246 + let bin_inode = {
     247 + let mut map = INODE_SUBJECT_MAP.lock().await;
     248 + map.resolve_path(policy.subject)?
     249 + };
     250 + 
     251 + let (allow_v4, allow_v6) = policy.allow.into_ebpf();
     252 + let (deny_v4, deny_v6) = policy.deny.into_ebpf();
     253 + 
     254 + self.allowed_map_v4.insert(bin_inode, allow_v4, 0)?;
     255 + self.denied_map_v4.insert(bin_inode, deny_v4, 0)?;
     256 + self.allowed_map_v6.insert(bin_inode, allow_v6, 0)?;
     257 + self.denied_map_v6.insert(bin_inode, deny_v6, 0)?;
     258 + 
     259 + Ok(())
     260 + }
     261 + 
     262 + pub async fn list_policies(&self) -> anyhow::Result<Vec<policy::SocketConnect>> {
     263 + let mut policies = Vec::new();
     264 + 
     265 + for res in self.allowed_map_v4.iter() {
     266 + let (bin_inode, allow_v4) = res?;
     267 + let deny_v4 = self.denied_map_v4.get(&bin_inode, 0)?;
     268 + let allow_v6 = self.allowed_map_v6.get(&bin_inode, 0)?;
     269 + let deny_v6 = self.denied_map_v6.get(&bin_inode, 0)?;
     270 + 
     271 + let subject = {
     272 + let map = INODE_SUBJECT_MAP.lock().await;
     273 + map.resolve_inode(bin_inode)
     274 + };
     275 + 
     276 + let allow = if allow_v4.all() {
     277 + if allow_v6.all() {
     278 + policy::Addresses::All
     279 + } else {
     280 + return Err(anyhow::anyhow!("Inconsistent policy state"));
     281 + }
     282 + } else {
     283 + if allow_v4.all() {
     284 + return Err(anyhow::anyhow!("Inconsistent policy state"));
     285 + }
     286 + let mut addrs = Vec::new();
     287 + for addr in allow_v4.addrs.iter() {
     288 + addrs.push(IpAddr::V4(Ipv4Addr::from(addr.to_owned())));
     289 + }
     290 + for addr in allow_v6.addrs.iter() {
     291 + addrs.push(IpAddr::V6(Ipv6Addr::from(addr.to_owned())));
     292 + }
     293 + policy::Addresses::Addresses(addrs)
     294 + };
     295 + let deny = if deny_v4.all() {
     296 + if deny_v6.all() {
     297 + policy::Addresses::All
     298 + } else {
     299 + return Err(anyhow::anyhow!("Inconsistent policy state"));
     300 + }
     301 + } else {
     302 + if deny_v4.all() {
     303 + return Err(anyhow::anyhow!("Inconsistent policy state"));
     304 + }
     305 + let mut addrs = Vec::new();
     306 + for addr in deny_v4.addrs.iter() {
     307 + addrs.push(IpAddr::V4(Ipv4Addr::from(addr.to_owned())));
     308 + }
     309 + for addr in deny_v6.addrs.iter() {
     310 + addrs.push(IpAddr::V6(Ipv6Addr::from(addr.to_owned())));
     311 + }
     312 + policy::Addresses::Addresses(addrs)
     313 + };
     314 + 
     315 + policies.push(policy::SocketConnect {
     316 + subject,
     317 + allow,
     318 + deny,
     319 + });
     320 + }
     321 + 
     322 + Ok(policies)
     323 + }
     324 + 
     325 + pub async fn alerts(&mut self) -> anyhow::Result<Receiver<alerts::SocketConnect>> {
     326 + perf_array_alerts::<ebpf_alerts::SocketConnect, alerts::SocketConnect>(&mut self.perf_array)
     327 + .await
     328 + }
     329 +}
     330 + 
     331 +pub async fn perf_array_alerts<E, U>(
     332 + perf_array: &mut AsyncPerfEventArray<MapData>,
     333 +) -> anyhow::Result<Receiver<U>>
     334 +where
     335 + E: ebpf_alerts::Alert,
     336 + U: alerts::Alert + Debug + Send + From<E> + 'static,
     337 +{
     338 + let (tx, rx) = mpsc::channel(32);
     339 + 
     340 + let cpus = online_cpus()?;
     341 + for cpu_id in cpus {
     342 + let tx = tx.clone();
     343 + let mut buf = perf_array.open(cpu_id, None)?;
     344 + 
     345 + task::spawn(async move {
     346 + let mut buffers = (0..10)
     347 + .map(|_| BytesMut::with_capacity(1024))
     348 + .collect::<Vec<_>>();
     349 + loop {
     350 + let events = buf.read_events(&mut buffers).await.unwrap();
     351 + for buf in buffers.iter_mut().take(events.read) {
     352 + let alert: U = {
     353 + let ptr = buf.as_ptr() as *const E;
     354 + let alert = unsafe { ptr.read_unaligned() };
     355 + alert.into()
     356 + };
     357 + tx.send(alert).await.unwrap();
     358 + }
     359 + }
     360 + });
     361 + }
     362 + 
     363 + Ok(rx)
     364 +}
     365 + 
  • ■ ■ ■ ■ ■ ■
    guardity/src/lib.rs
    1  -use std::{fmt::Debug, marker::PhantomData, path::Path};
     1 +use std::path::Path;
    2 2   
    3 3  use aya::{
    4 4   include_bytes_aligned,
    5  - maps::{AsyncPerfEventArray, MapData},
    6 5   programs::{lsm::LsmLink, Lsm},
    7  - util::online_cpus,
    8 6   Bpf, BpfLoader, Btf,
    9 7  };
    10  -use bytes::BytesMut;
    11  -use guardity_common::alerts as ebpf_alerts;
    12  -use tokio::{
    13  - sync::mpsc::{self, Receiver},
    14  - task,
    15  -};
     8 +use hooks::{All, BprmCheckSecurity, FileOpen, SocketBind, SocketConnect, TaskFixSetuid};
     9 +use policy::inode::InodeSubjectMap;
    16 10   
    17 11  pub mod alerts;
     12 +pub mod error;
    18 13  pub mod fs;
     14 +pub mod hooks;
    19 15  pub mod policy;
    20 16   
    21 17  pub struct PolicyManager {
    22 18   bpf: Bpf,
    23  - bprm_check_security: Option<BprmCheckSecurityHook>,
    24  - file_open: Option<FileOpenHook>,
    25  - task_fix_setuid: Option<TaskFixSetuidHook>,
    26  - socket_bind: Option<SocketBindHook>,
    27  - socket_connect: Option<SocketConnectHook>,
    28 19  }
    29 20   
    30 21  impl PolicyManager {
    skipped 11 lines
    42 33   "../../target/bpfel-unknown-none/release/guardity"
    43 34   ))?;
    44 35   
    45  - Ok(Self {
    46  - bpf,
    47  - bprm_check_security: None,
    48  - file_open: None,
    49  - task_fix_setuid: None,
    50  - socket_bind: None,
    51  - socket_connect: None,
    52  - })
     36 + Ok(Self { bpf })
    53 37   }
    54 38   
    55  - pub fn attach_bprm_check_security(&mut self) -> anyhow::Result<()> {
    56  - let link = attach_program(&mut self.bpf, "bprm_check_security")?;
    57  - let perf_array = perf_array(&mut self.bpf, "ALERT_BPRM_CHECK_SECURITY")?;
    58  - let bprm_check_security = Hook::new(link, perf_array)?;
    59  - self.bprm_check_security = Some(bprm_check_security);
     39 + pub fn attach_all(&mut self) -> anyhow::Result<All> {
     40 + let bprm_check_security = self.attach_bprm_check_security()?;
     41 + let file_open = self.attach_file_open()?;
     42 + let task_fix_setuid = self.attach_task_fix_setuid()?;
     43 + let socket_bind = self.attach_socket_bind()?;
     44 + let socket_connect = self.attach_socket_connect()?;
    60 45   
    61  - Ok(())
     46 + Ok(All {
     47 + bprm_check_security,
     48 + file_open,
     49 + task_fix_setuid,
     50 + socket_bind,
     51 + socket_connect,
     52 + })
    62 53   }
    63 54   
    64  - pub fn bprm_check_security(&mut self) -> anyhow::Result<&mut BprmCheckSecurityHook> {
    65  - match self.bprm_check_security {
    66  - Some(ref mut bprm_check_security) => Ok(bprm_check_security),
    67  - None => Err(anyhow::anyhow!("bprm_check_security is not attached")),
    68  - }
     55 + pub fn manage_all(&mut self) -> anyhow::Result<All> {
     56 + let bprm_check_security = self.manage_bprm_check_security()?;
     57 + let file_open = self.manage_file_open()?;
     58 + let task_fix_setuid = self.manage_task_fix_setuid()?;
     59 + let socket_bind = self.manage_socket_bind()?;
     60 + let socket_connect = self.manage_socket_connect()?;
     61 + 
     62 + Ok(All {
     63 + bprm_check_security,
     64 + file_open,
     65 + task_fix_setuid,
     66 + socket_bind,
     67 + socket_connect,
     68 + })
    69 69   }
    70 70   
    71  - pub fn attach_file_open(&mut self) -> anyhow::Result<()> {
    72  - let link = attach_program(&mut self.bpf, "file_open")?;
    73  - let perf_array = perf_array(&mut self.bpf, "ALERT_FILE_OPEN")?;
    74  - let file_open = Hook::new(link, perf_array)?;
    75  - self.file_open = Some(file_open);
     71 + pub fn attach_bprm_check_security(&mut self) -> anyhow::Result<BprmCheckSecurity> {
     72 + let mut bprm_check_security = self.manage_bprm_check_security()?;
     73 + let program_link = self.attach_program("bprm_check_security")?;
     74 + bprm_check_security.program_link = Some(program_link);
    76 75   
    77  - Ok(())
     76 + Ok(bprm_check_security)
    78 77   }
    79 78   
    80  - pub fn file_open(&mut self) -> anyhow::Result<&mut FileOpenHook> {
    81  - match self.file_open {
    82  - Some(ref mut file_open) => Ok(file_open),
    83  - None => Err(anyhow::anyhow!("file_open is not attached")),
    84  - }
     79 + pub fn manage_bprm_check_security(&mut self) -> anyhow::Result<BprmCheckSecurity> {
     80 + let perf_array = self
     81 + .bpf
     82 + .take_map("ALERT_BPRM_CHECK_SECURITY")
     83 + .unwrap()
     84 + .try_into()?;
     85 + 
     86 + Ok(BprmCheckSecurity {
     87 + program_link: None,
     88 + perf_array,
     89 + })
    85 90   }
    86 91   
    87  - pub fn attach_task_fix_setuid(&mut self) -> anyhow::Result<()> {
    88  - let link = attach_program(&mut self.bpf, "task_fix_setuid")?;
    89  - let perf_array = perf_array(&mut self.bpf, "ALERT_SETUID")?;
    90  - let setuid = Hook::new(link, perf_array)?;
    91  - self.task_fix_setuid = Some(setuid);
     92 + pub fn attach_file_open(&mut self) -> anyhow::Result<FileOpen> {
     93 + let mut file_open = self.manage_file_open()?;
     94 + let program_link = self.attach_program("file_open")?;
     95 + file_open.program_link = Some(program_link);
    92 96   
    93  - Ok(())
     97 + Ok(file_open)
    94 98   }
    95 99   
    96  - pub fn task_fix_setuid(&mut self) -> anyhow::Result<&mut TaskFixSetuidHook> {
    97  - match self.task_fix_setuid {
    98  - Some(ref mut setuid) => Ok(setuid),
    99  - None => Err(anyhow::anyhow!("setuid is not attached")),
    100  - }
     100 + pub fn manage_file_open(&mut self) -> anyhow::Result<FileOpen> {
     101 + let allowed_map = self.bpf.take_map("ALLOWED_FILE_OPEN").unwrap().try_into()?;
     102 + let denied_map = self.bpf.take_map("DENIED_FILE_OPEN").unwrap().try_into()?;
     103 + let perf_array = self.bpf.take_map("ALERT_FILE_OPEN").unwrap().try_into()?;
     104 + 
     105 + Ok(FileOpen {
     106 + program_link: None,
     107 + allowed_map,
     108 + denied_map,
     109 + perf_array,
     110 + })
    101 111   }
    102 112   
    103  - pub fn attach_socket_bind(&mut self) -> anyhow::Result<()> {
    104  - let link = attach_program(&mut self.bpf, "socket_bind")?;
    105  - let perf_array = perf_array(&mut self.bpf, "ALERT_SOCKET_BIND")?;
    106  - let socket_bind = Hook::new(link, perf_array)?;
    107  - self.socket_bind = Some(socket_bind);
     113 + pub fn attach_task_fix_setuid(&mut self) -> anyhow::Result<TaskFixSetuid> {
     114 + let mut task_fix_setuid = self.manage_task_fix_setuid()?;
     115 + let program_link = self.attach_program("task_fix_setuid")?;
     116 + task_fix_setuid.program_link = Some(program_link);
    108 117   
    109  - Ok(())
     118 + Ok(task_fix_setuid)
    110 119   }
    111 120   
    112  - pub fn socket_bind(&mut self) -> anyhow::Result<&mut SocketBindHook> {
    113  - match self.socket_bind {
    114  - Some(ref mut socket_bind) => Ok(socket_bind),
    115  - None => Err(anyhow::anyhow!("socket_bind is not attached")),
    116  - }
     121 + pub fn manage_task_fix_setuid(&mut self) -> anyhow::Result<TaskFixSetuid> {
     122 + let allowed_map = self
     123 + .bpf
     124 + .take_map("ALLOWED_TASK_FIX_SETUID")
     125 + .unwrap()
     126 + .try_into()?;
     127 + let denied_map = self
     128 + .bpf
     129 + .take_map("DENIED_TASK_FIX_SETUID")
     130 + .unwrap()
     131 + .try_into()?;
     132 + let perf_array = self
     133 + .bpf
     134 + .take_map("ALERT_TASK_FIX_SETUID")
     135 + .unwrap()
     136 + .try_into()?;
     137 + 
     138 + Ok(TaskFixSetuid {
     139 + program_link: None,
     140 + allowed_map,
     141 + denied_map,
     142 + perf_array,
     143 + })
    117 144   }
    118 145   
    119  - pub fn attach_socket_connect(&mut self) -> anyhow::Result<()> {
    120  - let link = attach_program(&mut self.bpf, "socket_connect")?;
    121  - let perf_array = perf_array(&mut self.bpf, "ALERT_SOCKET_CONNECT")?;
    122  - let socket_connect = Hook::new(link, perf_array)?;
    123  - self.socket_connect = Some(socket_connect);
     146 + pub fn attach_socket_bind(&mut self) -> anyhow::Result<SocketBind> {
     147 + let mut socket_bind = self.manage_socket_bind()?;
     148 + let program_link = self.attach_program("socket_bind")?;
     149 + socket_bind.program_link = Some(program_link);
    124 150   
    125  - Ok(())
     151 + Ok(socket_bind)
    126 152   }
    127 153   
    128  - pub fn socket_connect(&mut self) -> anyhow::Result<&mut SocketConnectHook> {
    129  - match self.socket_connect {
    130  - Some(ref mut socket_connect) => Ok(socket_connect),
    131  - None => Err(anyhow::anyhow!("socket_connect is not attached")),
    132  - }
     154 + pub fn manage_socket_bind(&mut self) -> anyhow::Result<SocketBind> {
     155 + let allowed_map = self
     156 + .bpf
     157 + .take_map("ALLOWED_SOCKET_BIND")
     158 + .unwrap()
     159 + .try_into()?;
     160 + let denied_map = self
     161 + .bpf
     162 + .take_map("DENIED_SOCKET_BIND")
     163 + .unwrap()
     164 + .try_into()?;
     165 + let perf_array = self.bpf.take_map("ALERT_SOCKET_BIND").unwrap().try_into()?;
     166 + 
     167 + Ok(SocketBind {
     168 + program_link: None,
     169 + allowed_map,
     170 + denied_map,
     171 + perf_array,
     172 + })
    133 173   }
    134  -}
    135 174   
    136  -fn attach_program(bpf: &mut Bpf, name: &str) -> anyhow::Result<LsmLink> {
    137  - let btf = Btf::from_sys_fs()?;
    138  - let program: &mut Lsm = bpf.program_mut(name).unwrap().try_into()?;
    139  - program.load(name, &btf)?;
    140  - let link_id = program.attach()?;
    141  - let link = program.take_link(link_id)?;
     175 + pub fn attach_socket_connect(&mut self) -> anyhow::Result<SocketConnect> {
     176 + let mut socket_connect = self.manage_socket_connect()?;
     177 + let program_link = self.attach_program("socket_connect")?;
     178 + socket_connect.program_link = Some(program_link);
    142 179   
    143  - Ok(link)
    144  -}
    145  - 
    146  -fn perf_array(bpf: &mut Bpf, name: &str) -> anyhow::Result<AsyncPerfEventArray<MapData>> {
    147  - let perf_array = bpf.take_map(name).unwrap().try_into()?;
    148  - Ok(perf_array)
    149  -}
     180 + Ok(socket_connect)
     181 + }
    150 182   
    151  -pub struct Hook<T, U>
    152  -where
    153  - T: ebpf_alerts::Alert,
    154  - U: alerts::Alert,
    155  -{
    156  - #[allow(dead_code)]
    157  - program_link: LsmLink,
    158  - perf_array: AsyncPerfEventArray<MapData>,
    159  - phantom_t: PhantomData<T>,
    160  - phantom_u: PhantomData<U>,
    161  -}
     183 + pub fn manage_socket_connect(&mut self) -> anyhow::Result<SocketConnect> {
     184 + let allowed_map_v4 = self
     185 + .bpf
     186 + .take_map("ALLOWED_SOCKET_CONNECT_V4")
     187 + .unwrap()
     188 + .try_into()?;
     189 + let denied_map_v4 = self
     190 + .bpf
     191 + .take_map("DENIED_SOCKET_CONNECT_V4")
     192 + .unwrap()
     193 + .try_into()?;
     194 + let allowed_map_v6 = self
     195 + .bpf
     196 + .take_map("ALLOWED_SOCKET_CONNECT_V6")
     197 + .unwrap()
     198 + .try_into()?;
     199 + let denied_map_v6 = self
     200 + .bpf
     201 + .take_map("DENIED_SOCKET_CONNECT_V6")
     202 + .unwrap()
     203 + .try_into()?;
     204 + let perf_array = self
     205 + .bpf
     206 + .take_map("ALERT_SOCKET_CONNECT")
     207 + .unwrap()
     208 + .try_into()?;
    162 209   
    163  -impl<T, U> Hook<T, U>
    164  -where
    165  - T: ebpf_alerts::Alert,
    166  - U: alerts::Alert + Debug + Send + From<T> + 'static,
    167  -{
    168  - fn new(
    169  - program_link: LsmLink,
    170  - perf_array: AsyncPerfEventArray<MapData>,
    171  - ) -> anyhow::Result<Self> {
    172  - Ok(Self {
    173  - program_link,
     210 + Ok(SocketConnect {
     211 + program_link: None,
     212 + allowed_map_v4,
     213 + denied_map_v4,
     214 + allowed_map_v6,
     215 + denied_map_v6,
    174 216   perf_array,
    175  - phantom_t: PhantomData,
    176  - phantom_u: PhantomData,
    177 217   })
    178 218   }
    179 219   
    180  - pub async fn alerts(&mut self) -> anyhow::Result<Receiver<U>> {
    181  - let (tx, rx) = mpsc::channel(32);
    182  - 
    183  - let cpus = online_cpus()?;
    184  - for cpu_id in cpus {
    185  - let tx = tx.clone();
    186  - let mut buf = self.perf_array.open(cpu_id, None)?;
    187  - 
    188  - task::spawn(async move {
    189  - let mut buffers = (0..10)
    190  - .map(|_| BytesMut::with_capacity(1024))
    191  - .collect::<Vec<_>>();
    192  - loop {
    193  - let events = buf.read_events(&mut buffers).await.unwrap();
    194  - for buf in buffers.iter_mut().take(events.read) {
    195  - let alert: U = {
    196  - let ptr = buf.as_ptr() as *const T;
    197  - let alert = unsafe { ptr.read_unaligned() };
    198  - alert.into()
    199  - };
    200  - tx.send(alert).await.unwrap();
    201  - }
    202  - }
    203  - });
    204  - }
     220 + fn attach_program(&mut self, name: &str) -> anyhow::Result<LsmLink> {
     221 + let btf = Btf::from_sys_fs()?;
     222 + let program: &mut Lsm = self.bpf.program_mut(name).unwrap().try_into()?;
     223 + program.load(name, &btf)?;
     224 + let link_id = program.attach()?;
     225 + let link = program.take_link(link_id)?;
    205 226   
    206  - Ok(rx)
     227 + Ok(link)
    207 228   }
    208 229  }
    209 230   
    210  -pub type BprmCheckSecurityHook = Hook<ebpf_alerts::BprmCheckSecurity, alerts::BprmCheckSecurity>;
    211  -pub type FileOpenHook = Hook<ebpf_alerts::FileOpen, alerts::FileOpen>;
    212  -pub type TaskFixSetuidHook = Hook<ebpf_alerts::TaskFixSetuid, alerts::TaskFixSetUid>;
    213  -pub type SocketBindHook = Hook<ebpf_alerts::SocketBind, alerts::SocketBind>;
    214  -pub type SocketConnectHook = Hook<ebpf_alerts::SocketConnect, alerts::SocketConnect>;
    215  - 
  • ■ ■ ■ ■ ■ ■
    guardity/src/main.rs
    skipped 26 lines
    27 27   
    28 28   let mut policy_manager = PolicyManager::new(bpf_path)?;
    29 29   
    30  - policy_manager.attach_bprm_check_security()?;
    31  - policy_manager.attach_file_open()?;
    32  - policy_manager.attach_task_fix_setuid()?;
    33  - policy_manager.attach_socket_bind()?;
    34  - policy_manager.attach_socket_connect()?;
     30 + let mut bprm_check_security = policy_manager.attach_bprm_check_security()?;
     31 + let mut file_open = policy_manager.attach_file_open()?;
     32 + let mut task_fix_setuid = policy_manager.attach_task_fix_setuid()?;
     33 + let mut socket_bind = policy_manager.attach_socket_bind()?;
     34 + let mut socket_connect = policy_manager.attach_socket_connect()?;
    35 35   
    36  - let mut rx_bprm_check_security = policy_manager.bprm_check_security()?.alerts().await?;
    37  - let mut rx_file_open = policy_manager.file_open()?.alerts().await?;
    38  - let mut rx_task_fix_setuid = policy_manager.task_fix_setuid()?.alerts().await?;
    39  - let mut rx_socket_bind = policy_manager.socket_bind()?.alerts().await?;
    40  - let mut rx_socket_connect = policy_manager.socket_connect()?.alerts().await?;
     36 + let mut rx_bprm_check_security = bprm_check_security.alerts().await?;
     37 + let mut rx_file_open = file_open.alerts().await?;
     38 + let mut rx_task_fix_setuid = task_fix_setuid.alerts().await?;
     39 + let mut rx_socket_bind = socket_bind.alerts().await?;
     40 + let mut rx_socket_connect = socket_connect.alerts().await?;
    41 41   
    42 42   info!("Waiting for Ctrl-C...");
    43 43   
    skipped 33 lines
  • ■ ■ ■ ■ ■ ■
    guardity/src/policy/engine.rs
    1  -use aya::{maps::HashMap, Bpf};
    2  -use guardity_common::{Ipv4Addrs, Ipv6Addrs, Paths, Ports};
    3  - 
    4  -use super::{Policy, PolicySubject};
    5  -use crate::fs;
    6  - 
    7  -pub const INODE_WILDCARD: u64 = 0;
    8  - 
    9  -pub fn process_policy(bpf: &mut Bpf, policy: Policy) -> anyhow::Result<()> {
    10  - match policy {
    11  - Policy::FileOpen {
    12  - subject,
    13  - allow,
    14  - deny,
    15  - } => {
    16  - let allow: Paths = allow.into();
    17  - let deny: Paths = deny.into();
    18  - match subject {
    19  - PolicySubject::Process(path) => {
    20  - let bin_inode = fs::inode(path)?;
    21  - 
    22  - let mut allowed_file_open: HashMap<_, u64, Paths> =
    23  - bpf.map_mut("ALLOWED_FILE_OPEN").unwrap().try_into()?;
    24  - allowed_file_open.insert(bin_inode, allow, 0)?;
    25  - 
    26  - let mut denied_file_open: HashMap<_, u64, Paths> =
    27  - bpf.map_mut("DENIED_FILE_OPEN").unwrap().try_into()?;
    28  - denied_file_open.insert(bin_inode, deny, 0)?;
    29  - }
    30  - PolicySubject::All => {
    31  - let mut allowed_file_open: HashMap<_, u64, Paths> =
    32  - bpf.map_mut("ALLOWED_FILE_OPEN").unwrap().try_into()?;
    33  - allowed_file_open.insert(INODE_WILDCARD, allow, 0)?;
    34  - 
    35  - let mut denied_file_open: HashMap<_, u64, Paths> =
    36  - bpf.map_mut("DENIED_FILE_OPEN").unwrap().try_into()?;
    37  - denied_file_open.insert(INODE_WILDCARD, deny, 0)?;
    38  - }
    39  - }
    40  - }
    41  - Policy::SetUid { subject, allow } => {
    42  - match subject {
    43  - PolicySubject::Process(path) => {
    44  - let inode = fs::inode(path)?;
    45  - if allow {
    46  - let mut allowed_setuid: HashMap<_, u64, u8> =
    47  - bpf.map_mut("ALLOWED_SETUID").unwrap().try_into()?;
    48  - allowed_setuid.insert(inode, 0, 0)?;
    49  - } else {
    50  - let mut denied_setuid: HashMap<_, u64, u8> =
    51  - bpf.map_mut("DENIED_SETUID").unwrap().try_into()?;
    52  - denied_setuid.insert(inode, 0, 0)?;
    53  - }
    54  - }
    55  - PolicySubject::All => {
    56  - if allow {
    57  - let mut allowed_setuid: HashMap<_, u64, u8> =
    58  - bpf.map_mut("ALLOWED_SETUID").unwrap().try_into()?;
    59  - allowed_setuid.insert(INODE_WILDCARD, 0, 0)?;
    60  - } else {
    61  - let mut denied_setuid: HashMap<_, u64, u8> =
    62  - bpf.map_mut("DENIED_SETUID").unwrap().try_into()?;
    63  - denied_setuid.insert(INODE_WILDCARD, 0, 0)?;
    64  - }
    65  - }
    66  - };
    67  - }
    68  - Policy::SocketBind {
    69  - subject,
    70  - allow,
    71  - deny,
    72  - } => {
    73  - let allow: Ports = allow.into();
    74  - let deny: Ports = deny.into();
    75  - match subject {
    76  - PolicySubject::Process(path) => {
    77  - let inode = fs::inode(path)?;
    78  - let mut allowed_socket_bind: HashMap<_, u64, Ports> =
    79  - bpf.map_mut("ALLOWED_SOCKET_BIND").unwrap().try_into()?;
    80  - allowed_socket_bind.insert(inode, allow, 0)?;
    81  - 
    82  - let mut denied_socket_bind: HashMap<_, u64, Ports> =
    83  - bpf.map_mut("DENIED_SOCKET_BIND").unwrap().try_into()?;
    84  - denied_socket_bind.insert(inode, deny, 0)?;
    85  - }
    86  - PolicySubject::All => {
    87  - let mut allowed_socket_bind: HashMap<_, u64, Ports> =
    88  - bpf.map_mut("ALLOWED_SOCKET_BIND").unwrap().try_into()?;
    89  - allowed_socket_bind.insert(INODE_WILDCARD, allow, 0)?;
    90  - 
    91  - let mut denied_socket_bind: HashMap<_, u64, Ports> =
    92  - bpf.map_mut("DENIED_SOCKET_BIND").unwrap().try_into()?;
    93  - denied_socket_bind.insert(INODE_WILDCARD, deny, 0)?;
    94  - }
    95  - }
    96  - }
    97  - Policy::SocketConnect {
    98  - subject,
    99  - allow,
    100  - deny,
    101  - } => {
    102  - let (allow_v4, allow_v6) = allow.into_ebpf();
    103  - let (deny_v4, deny_v6) = deny.into_ebpf();
    104  - match subject {
    105  - PolicySubject::Process(bin_path) => {
    106  - let bin_inode = fs::inode(bin_path)?;
    107  - 
    108  - let mut allowed_socket_connect_v4: HashMap<_, u64, Ipv4Addrs> = bpf
    109  - .map_mut("ALLOWED_SOCKET_CONNECT_V4")
    110  - .unwrap()
    111  - .try_into()?;
    112  - allowed_socket_connect_v4.insert(bin_inode, allow_v4, 0)?;
    113  - 
    114  - let mut denied_socket_connect_v4: HashMap<_, u64, Ipv4Addrs> = bpf
    115  - .map_mut("DENIED_SOCKET_CONNECT_V4")
    116  - .unwrap()
    117  - .try_into()?;
    118  - denied_socket_connect_v4.insert(bin_inode, deny_v4, 0)?;
    119  - 
    120  - let mut allowed_socket_connect_v6: HashMap<_, u64, Ipv6Addrs> = bpf
    121  - .map_mut("ALLOWED_SOCKET_CONNECT_V6")
    122  - .unwrap()
    123  - .try_into()?;
    124  - allowed_socket_connect_v6.insert(bin_inode, allow_v6, 0)?;
    125  - 
    126  - let mut denied_socket_connect_v6: HashMap<_, u64, Ipv6Addrs> = bpf
    127  - .map_mut("DENIED_SOCKET_CONNECT_V6")
    128  - .unwrap()
    129  - .try_into()?;
    130  - denied_socket_connect_v6.insert(bin_inode, deny_v6, 0)?;
    131  - }
    132  - PolicySubject::All => {
    133  - let mut allowed_socket_connect_v4: HashMap<_, u64, Ipv4Addrs> = bpf
    134  - .map_mut("ALLOWED_SOCKET_CONNECT_V4")
    135  - .unwrap()
    136  - .try_into()?;
    137  - allowed_socket_connect_v4.insert(INODE_WILDCARD, allow_v4, 0)?;
    138  - 
    139  - let mut denied_socket_connect_v4: HashMap<_, u64, Ipv4Addrs> = bpf
    140  - .map_mut("DENIED_SOCKET_CONNECT_V4")
    141  - .unwrap()
    142  - .try_into()?;
    143  - denied_socket_connect_v4.insert(INODE_WILDCARD, deny_v4, 0)?;
    144  - 
    145  - let mut allowed_socket_connect_v6: HashMap<_, u64, Ipv6Addrs> = bpf
    146  - .map_mut("ALLOWED_SOCKET_CONNECT_V6")
    147  - .unwrap()
    148  - .try_into()?;
    149  - allowed_socket_connect_v6.insert(INODE_WILDCARD, allow_v6, 0)?;
    150  - 
    151  - let mut denied_socket_connect_v6: HashMap<_, u64, Ipv6Addrs> = bpf
    152  - .map_mut("DENIED_SOCKET_CONNECT_V6")
    153  - .unwrap()
    154  - .try_into()?;
    155  - denied_socket_connect_v6.insert(INODE_WILDCARD, deny_v6, 0)?;
    156  - }
    157  - }
    158  - }
    159  - }
    160  - Ok(())
    161  -}
    162  - 
  • ■ ■ ■ ■ ■ ■
    guardity/src/policy/inode.rs
     1 +use std::{collections::HashMap, path::PathBuf};
     2 + 
     3 +use crate::fs;
     4 + 
     5 +use super::PolicySubject;
     6 + 
     7 +#[derive(Default)]
     8 +pub struct InodeSubjectMap {
     9 + map: HashMap<u64, PathBuf>,
     10 +}
     11 + 
     12 +impl InodeSubjectMap {
     13 + pub fn resolve_path(&mut self, subject: PolicySubject) -> anyhow::Result<u64> {
     14 + match subject {
     15 + PolicySubject::Binary(path) => {
     16 + let inode = fs::inode(&path)?;
     17 + self.map.insert(inode, path);
     18 + Ok(inode)
     19 + }
     20 + PolicySubject::All => Ok(0),
     21 + }
     22 + }
     23 + 
     24 + pub fn resolve_inode(&self, inode: u64) -> PolicySubject {
     25 + match inode {
     26 + 0 => PolicySubject::All,
     27 + _ => self
     28 + .map
     29 + .get(&inode)
     30 + .map(|p| PolicySubject::Binary(p.to_owned()))
     31 + .unwrap_or(PolicySubject::Binary(PathBuf::from(inode.to_string()))),
     32 + }
     33 + }
     34 +}
     35 + 
  • ■ ■ ■ ■ ■ ■
    guardity/src/policy/mod.rs
    skipped 3 lines
    4 4   path::PathBuf,
    5 5  };
    6 6   
     7 +use guardity_common::policy as ebpf_policy;
    7 8  use serde::{Deserialize, Serialize};
    8 9   
    9 10  use crate::fs;
    10 11   
    11  -pub mod engine;
     12 +pub mod inode;
    12 13  pub mod reader;
    13 14   
    14 15  #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
    15 16  pub enum PolicySubject {
    16  - #[serde(rename = "process")]
    17  - Process(PathBuf),
     17 + #[serde(rename = "binary")]
     18 + Binary(PathBuf),
    18 19   #[serde(rename = "all")]
    19 20   All,
    20 21  }
    skipped 1 lines
    22 23  impl Display for PolicySubject {
    23 24   fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
    24 25   match self {
    25  - PolicySubject::Process(path) => write!(f, "{}", path.display()),
     26 + PolicySubject::Binary(path) => write!(f, "{}", path.display()),
    26 27   PolicySubject::All => write!(f, "all"),
    27 28   }
    28 29   }
    skipped 14 lines
    43 44  // operations). Therefore, `Into` and `From` traits have to be implemented
    44 45  // separately.
    45 46  #[allow(clippy::from_over_into)]
    46  -impl Into<guardity_common::Paths> for Paths {
    47  - fn into(self) -> guardity_common::Paths {
     47 +impl Into<ebpf_policy::Paths> for Paths {
     48 + fn into(self) -> ebpf_policy::Paths {
    48 49   match self {
    49  - Paths::All => guardity_common::Paths {
    50  - paths: [0; guardity_common::MAX_PATHS],
     50 + Paths::All => ebpf_policy::Paths {
     51 + paths: [0; ebpf_policy::MAX_PATHS],
    51 52   },
    52 53   Paths::Paths(paths) => {
    53  - let mut ebpf_paths = [0; guardity_common::MAX_PATHS];
     54 + let mut ebpf_paths = [0; ebpf_policy::MAX_PATHS];
    54 55   for (i, path) in paths.iter().enumerate() {
    55 56   ebpf_paths[i] = fs::inode(path).unwrap();
    56 57   }
    57  - guardity_common::Paths { paths: ebpf_paths }
     58 + ebpf_policy::Paths { paths: ebpf_paths }
    58 59   }
    59 60   }
    60 61   }
    61 62  }
    62 63   
    63  -impl From<guardity_common::Paths> for Paths {
    64  - fn from(paths: guardity_common::Paths) -> Self {
     64 +impl From<ebpf_policy::Paths> for Paths {
     65 + fn from(paths: ebpf_policy::Paths) -> Self {
    65 66   if paths.paths[0] == 0 {
    66 67   Paths::All
    67 68   } else {
    skipped 19 lines
    87 88  }
    88 89   
    89 90  #[allow(clippy::from_over_into)]
    90  -impl Into<guardity_common::Ports> for Ports {
    91  - fn into(self) -> guardity_common::Ports {
     91 +impl Into<ebpf_policy::Ports> for Ports {
     92 + fn into(self) -> ebpf_policy::Ports {
    92 93   match self {
    93  - Ports::All => guardity_common::Ports::new(true, 0, [0; guardity_common::MAX_PORTS]),
     94 + Ports::All => ebpf_policy::Ports::new(true, 0, [0; ebpf_policy::MAX_PORTS]),
    94 95   Ports::Ports(ports) => {
    95  - let mut ebpf_ports = [0; guardity_common::MAX_PORTS];
     96 + let mut ebpf_ports = [0; ebpf_policy::MAX_PORTS];
    96 97   for (i, port) in ports.iter().enumerate() {
    97 98   ebpf_ports[i] = *port;
    98 99   }
    99  - guardity_common::Ports::new(false, ports.len(), ebpf_ports)
     100 + ebpf_policy::Ports::new(false, ports.len(), ebpf_ports)
    100 101   }
    101 102   }
    102 103   }
    103 104  }
    104 105   
    105  -impl From<guardity_common::Ports> for Ports {
    106  - fn from(ports: guardity_common::Ports) -> Self {
     106 +impl From<ebpf_policy::Ports> for Ports {
     107 + fn from(ports: ebpf_policy::Ports) -> Self {
    107 108   if ports.all {
    108 109   Ports::All
    109 110   } else {
    skipped 11 lines
    121 122  }
    122 123   
    123 124  impl Addresses {
    124  - pub fn into_ebpf(self) -> (guardity_common::Ipv4Addrs, guardity_common::Ipv6Addrs) {
     125 + pub fn into_ebpf(self) -> (ebpf_policy::Ipv4Addrs, ebpf_policy::Ipv6Addrs) {
    125 126   match self {
    126 127   Addresses::All => (
    127  - guardity_common::Ipv4Addrs::new_all(),
    128  - guardity_common::Ipv6Addrs::new_all(),
     128 + ebpf_policy::Ipv4Addrs::new_all(),
     129 + ebpf_policy::Ipv6Addrs::new_all(),
    129 130   ),
    130 131   Addresses::Addresses(addrs) => {
    131  - let mut ebpf_addrs_v4 = [0; guardity_common::MAX_IPV4ADDRS];
    132  - let mut ebpf_addrs_v6 = [[0u8; 16]; guardity_common::MAX_IPV6ADDRS];
     132 + let mut ebpf_addrs_v4 = [0; ebpf_policy::MAX_IPV4ADDRS];
     133 + let mut ebpf_addrs_v6 = [[0u8; 16]; ebpf_policy::MAX_IPV6ADDRS];
    133 134   let mut i_v4 = 0;
    134 135   let mut i_v6 = 0;
    135 136   for addr in addrs.iter() {
    skipped 9 lines
    145 146   }
    146 147   }
    147 148   (
    148  - guardity_common::Ipv4Addrs::new(ebpf_addrs_v4),
    149  - guardity_common::Ipv6Addrs::new(ebpf_addrs_v6),
     149 + ebpf_policy::Ipv4Addrs::new(ebpf_addrs_v4),
     150 + ebpf_policy::Ipv6Addrs::new(ebpf_addrs_v6),
    150 151   )
    151 152   }
    152 153   }
    skipped 3 lines
    156 157  #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
    157 158  pub enum Policy {
    158 159   #[serde(rename = "file_open")]
    159  - FileOpen {
    160  - subject: PolicySubject,
    161  - allow: Paths,
    162  - deny: Paths,
    163  - },
     160 + FileOpen(FileOpen),
    164 161   #[serde(rename = "setuid")]
    165  - SetUid { subject: PolicySubject, allow: bool },
     162 + TaskFixSetuid(TaskFixSetuid),
    166 163   #[serde(rename = "socket_bind")]
    167  - SocketBind {
    168  - subject: PolicySubject,
    169  - allow: Ports,
    170  - deny: Ports,
    171  - },
     164 + SocketBind(SocketBind),
    172 165   #[serde(rename = "socket_connect")]
    173  - SocketConnect {
    174  - subject: PolicySubject,
    175  - allow: Addresses,
    176  - deny: Addresses,
    177  - },
     166 + SocketConnect(SocketConnect),
     167 +}
     168 + 
     169 +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
     170 +pub struct FileOpen {
     171 + pub subject: PolicySubject,
     172 + pub allow: Paths,
     173 + pub deny: Paths,
     174 +}
     175 + 
     176 +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
     177 +pub struct TaskFixSetuid {
     178 + pub subject: PolicySubject,
     179 + pub allow: bool,
     180 +}
     181 + 
     182 +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
     183 +pub struct SocketBind {
     184 + pub subject: PolicySubject,
     185 + pub allow: Ports,
     186 + pub deny: Ports,
     187 +}
     188 + 
     189 +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
     190 +pub struct SocketConnect {
     191 + pub subject: PolicySubject,
     192 + pub allow: Addresses,
     193 + pub deny: Addresses,
    178 194  }
    179 195   
    180 196  #[cfg(test)]
    skipped 11 lines
    192 208   deny: !paths
    193 209   - /root/s3cr3tdir
    194 210  - !file_open
    195  - subject: !process /usr/bin/myapp
     211 + subject: !binary /usr/bin/myapp
    196 212   allow: !paths
    197 213   - /etc/myapp
    198 214   deny: all
    skipped 2 lines
    201 217   assert_eq!(policy.len(), 2);
    202 218   assert_eq!(
    203 219   policy[0],
    204  - Policy::FileOpen {
     220 + Policy::FileOpen(FileOpen {
    205 221   subject: PolicySubject::All,
    206 222   allow: Paths::All,
    207 223   deny: Paths::Paths(vec![PathBuf::from("/root/s3cr3tdir")])
    208  - }
     224 + })
    209 225   );
    210 226   assert_eq!(
    211 227   policy[1],
    212  - Policy::FileOpen {
    213  - subject: PolicySubject::Process(PathBuf::from("/usr/bin/myapp")),
     228 + Policy::FileOpen(FileOpen {
     229 + subject: PolicySubject::Binary(PathBuf::from("/usr/bin/myapp")),
    214 230   allow: Paths::Paths(vec![PathBuf::from("/etc/myapp")]),
    215 231   deny: Paths::All
    216  - }
     232 + })
    217 233   );
    218 234   }
    219 235   
    skipped 4 lines
    224 240   subject: all
    225 241   allow: false
    226 242  - !setuid
    227  - subject: !process /usr/bin/sudo
     243 + subject: !binary /usr/bin/sudo
    228 244   allow: true
    229 245  ";
    230 246   let policy = serde_yaml::from_str::<Vec<Policy>>(yaml).unwrap();
    231 247   assert_eq!(policy.len(), 2);
    232 248   assert_eq!(
    233 249   policy[0],
    234  - Policy::SetUid {
     250 + Policy::TaskFixSetuid(TaskFixSetuid {
    235 251   subject: PolicySubject::All,
    236 252   allow: false
    237  - }
     253 + })
    238 254   );
    239 255   assert_eq!(
    240 256   policy[1],
    241  - Policy::SetUid {
    242  - subject: PolicySubject::Process(PathBuf::from("/usr/bin/sudo")),
     257 + Policy::TaskFixSetuid(TaskFixSetuid {
     258 + subject: PolicySubject::Binary(PathBuf::from("/usr/bin/sudo")),
    243 259   allow: true
    244  - }
     260 + })
    245 261   );
    246 262   }
    247 263   
    skipped 1 lines
    249 265   fn test_socket_bind() {
    250 266   let yaml = "
    251 267  - !socket_bind
    252  - subject: !process /usr/bin/nginx
     268 + subject: !binary /usr/bin/nginx
    253 269   allow: !ports
    254 270   - 80
    255 271   - 443
    256 272   deny: all
    257 273  - !socket_bind
    258  - subject: !process /usr/bin/python
     274 + subject: !binary /usr/bin/python
    259 275   allow: !ports
    260 276   - 8080
    261 277   deny: all
    skipped 2 lines
    264 280   assert_eq!(policy.len(), 2);
    265 281   assert_eq!(
    266 282   policy[0],
    267  - Policy::SocketBind {
    268  - subject: PolicySubject::Process(PathBuf::from("/usr/bin/nginx")),
     283 + Policy::SocketBind(SocketBind {
     284 + subject: PolicySubject::Binary(PathBuf::from("/usr/bin/nginx")),
    269 285   allow: Ports::Ports(vec![80, 443]),
    270 286   deny: Ports::All
    271  - }
     287 + })
    272 288   );
    273 289   assert_eq!(
    274 290   policy[1],
    275  - Policy::SocketBind {
    276  - subject: PolicySubject::Process(PathBuf::from("/usr/bin/python")),
     291 + Policy::SocketBind(SocketBind {
     292 + subject: PolicySubject::Binary(PathBuf::from("/usr/bin/python")),
    277 293   allow: Ports::Ports(vec![8080]),
    278 294   deny: Ports::All
    279  - }
     295 + })
    280 296   );
    281 297   }
    282 298   
    skipped 1 lines
    284 300   fn test_socket_connect() {
    285 301   let yaml = "
    286 302  - !socket_connect
    287  - subject: !process /usr/bin/nginx
     303 + subject: !binary /usr/bin/nginx
    288 304   allow: !addresses
    289 305   - 10.0.0.1
    290 306   - 2001:db8:3333:4444:5555:6666:7777:8888
    291 307   deny: all
    292 308  - !socket_connect
    293  - subject: !process /usr/bin/tomcat
     309 + subject: !binary /usr/bin/tomcat
    294 310   allow: all
    295 311   deny: !addresses
    296 312   - 172.16.0.1
    skipped 3 lines
    300 316   assert_eq!(policy.len(), 2);
    301 317   assert_eq!(
    302 318   policy[0],
    303  - Policy::SocketConnect {
    304  - subject: PolicySubject::Process(PathBuf::from("/usr/bin/nginx")),
     319 + Policy::SocketConnect(SocketConnect {
     320 + subject: PolicySubject::Binary(PathBuf::from("/usr/bin/nginx")),
    305 321   allow: Addresses::Addresses(vec![
    306 322   IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
    307 323   IpAddr::V6(Ipv6Addr::new(
    skipped 1 lines
    309 325   ))
    310 326   ]),
    311 327   deny: Addresses::All
    312  - }
     328 + })
    313 329   );
    314 330   assert_eq!(
    315 331   policy[1],
    316  - Policy::SocketConnect {
    317  - subject: PolicySubject::Process(PathBuf::from("/usr/bin/tomcat")),
     332 + Policy::SocketConnect(SocketConnect {
     333 + subject: PolicySubject::Binary(PathBuf::from("/usr/bin/tomcat")),
    318 334   allow: Addresses::All,
    319 335   deny: Addresses::Addresses(vec![
    320 336   IpAddr::V4(Ipv4Addr::new(172, 16, 0, 1)),
    skipped 1 lines
    322 338   0x2001, 0x0db8, 0x3333, 0x4444, 0xCCCC, 0xDDDD, 0xEEEE, 0xFFFF
    323 339   )),
    324 340   ]),
    325  - }
     341 + })
    326 342   );
    327 343   }
    328 344  }
    skipped 1 lines
  • ■ ■ ■ ■ ■ ■
    guardity-common/src/consts.rs
     1 +/// Wildcard for the inode.
     2 +pub const INODE_WILDCARD: u64 = 0;
     3 + 
  • ■ ■ ■ ■ ■
    guardity-common/src/lib.rs
    1 1  #![cfg_attr(not(feature = "user"), no_std)]
    2 2   
    3 3  pub mod alerts;
    4  - 
    5  -pub const MAX_PATHS: usize = 4;
    6  -pub const MAX_PORTS: usize = 1;
    7  -pub const MAX_IPV4ADDRS: usize = 1;
    8  -pub const MAX_IPV6ADDRS: usize = 1;
    9  - 
    10  -#[repr(C)]
    11  -#[derive(Copy, Clone)]
    12  -pub struct Paths {
    13  - pub paths: [u64; MAX_PATHS],
    14  -}
    15  - 
    16  -#[repr(C)]
    17  -#[derive(Copy, Clone)]
    18  -pub struct Ports {
    19  - pub all: bool,
    20  - _padding1: [u8; 7],
    21  - pub len: usize,
    22  - pub ports: [u16; MAX_PORTS],
    23  - _padding2: [u16; 3 * MAX_PORTS],
    24  -}
    25  - 
    26  -impl Ports {
    27  - pub fn new(all: bool, len: usize, ports: [u16; MAX_PORTS]) -> Self {
    28  - Self {
    29  - all,
    30  - _padding1: [0; 7],
    31  - len,
    32  - ports,
    33  - _padding2: [0; 3 * MAX_PORTS],
    34  - }
    35  - }
    36  -}
    37  - 
    38  -pub trait IpAddrs<T, const U: usize> {
    39  - fn all(&self) -> bool;
    40  - fn addrs(&self) -> [T; U];
    41  -}
    42  - 
    43  -#[repr(C)]
    44  -#[derive(Copy, Clone)]
    45  -pub struct Ipv4Addrs {
    46  - pub addrs: [u32; MAX_IPV4ADDRS],
    47  -}
    48  - 
    49  -impl Ipv4Addrs {
    50  - pub fn new(addrs: [u32; MAX_IPV4ADDRS]) -> Self {
    51  - Self { addrs }
    52  - }
    53  - 
    54  - pub fn new_all() -> Self {
    55  - Self {
    56  - addrs: [0; MAX_IPV4ADDRS],
    57  - }
    58  - }
    59  -}
    60  - 
    61  -impl IpAddrs<u32, MAX_IPV4ADDRS> for Ipv4Addrs {
    62  - #[inline(always)]
    63  - fn all(&self) -> bool {
    64  - self.addrs[0] == 0
    65  - }
    66  - 
    67  - #[inline(always)]
    68  - fn addrs(&self) -> [u32; MAX_IPV4ADDRS] {
    69  - self.addrs
    70  - }
    71  -}
    72  - 
    73  -#[repr(C)]
    74  -#[derive(Copy, Clone)]
    75  -pub struct Ipv6Addrs {
    76  - pub addrs: [[u8; 16]; MAX_IPV4ADDRS],
    77  -}
    78  - 
    79  -impl Ipv6Addrs {
    80  - pub fn new(addrs: [[u8; 16]; MAX_IPV4ADDRS]) -> Self {
    81  - Self { addrs }
    82  - }
    83  - 
    84  - pub fn new_all() -> Self {
    85  - Self {
    86  - addrs: [[0; 16]; MAX_IPV4ADDRS],
    87  - }
    88  - }
    89  -}
    90  - 
    91  -impl IpAddrs<[u8; 16], MAX_IPV6ADDRS> for Ipv6Addrs {
    92  - #[inline(always)]
    93  - fn all(&self) -> bool {
    94  - self.addrs[0] == [0; 16]
    95  - }
    96  - 
    97  - #[inline(always)]
    98  - fn addrs(&self) -> [[u8; 16]; MAX_IPV6ADDRS] {
    99  - self.addrs
    100  - }
    101  -}
    102  - 
    103  -#[cfg(feature = "user")]
    104  -pub mod user {
    105  - use super::*;
    106  - 
    107  - use aya::Pod;
    108  - 
    109  - unsafe impl Pod for Paths {}
    110  - unsafe impl Pod for Ports {}
    111  - unsafe impl Pod for Ipv4Addrs {}
    112  - unsafe impl Pod for Ipv6Addrs {}
    113  -}
     4 +pub mod consts;
     5 +pub mod policy;
    114 6   
  • ■ ■ ■ ■ ■ ■
    guardity-common/src/policy.rs
     1 +pub const MAX_PATHS: usize = 4;
     2 +pub const MAX_PORTS: usize = 1;
     3 +pub const MAX_IPV4ADDRS: usize = 1;
     4 +pub const MAX_IPV6ADDRS: usize = 1;
     5 + 
     6 +#[repr(C)]
     7 +#[derive(Copy, Clone)]
     8 +pub struct Paths {
     9 + pub paths: [u64; MAX_PATHS],
     10 +}
     11 + 
     12 +#[repr(C)]
     13 +#[derive(Copy, Clone)]
     14 +pub struct Ports {
     15 + pub all: bool,
     16 + _padding1: [u8; 7],
     17 + pub len: usize,
     18 + pub ports: [u16; MAX_PORTS],
     19 + _padding2: [u16; 3 * MAX_PORTS],
     20 +}
     21 + 
     22 +impl Ports {
     23 + pub fn new(all: bool, len: usize, ports: [u16; MAX_PORTS]) -> Self {
     24 + Self {
     25 + all,
     26 + _padding1: [0; 7],
     27 + len,
     28 + ports,
     29 + _padding2: [0; 3 * MAX_PORTS],
     30 + }
     31 + }
     32 +}
     33 + 
     34 +pub trait IpAddrs<T, const U: usize> {
     35 + fn all(&self) -> bool;
     36 + fn addrs(&self) -> [T; U];
     37 +}
     38 + 
     39 +#[repr(C)]
     40 +#[derive(Copy, Clone)]
     41 +pub struct Ipv4Addrs {
     42 + pub addrs: [u32; MAX_IPV4ADDRS],
     43 +}
     44 + 
     45 +impl Ipv4Addrs {
     46 + pub fn new(addrs: [u32; MAX_IPV4ADDRS]) -> Self {
     47 + Self { addrs }
     48 + }
     49 + 
     50 + pub fn new_all() -> Self {
     51 + Self {
     52 + addrs: [0; MAX_IPV4ADDRS],
     53 + }
     54 + }
     55 +}
     56 + 
     57 +impl IpAddrs<u32, MAX_IPV4ADDRS> for Ipv4Addrs {
     58 + #[inline(always)]
     59 + fn all(&self) -> bool {
     60 + self.addrs[0] == 0
     61 + }
     62 + 
     63 + #[inline(always)]
     64 + fn addrs(&self) -> [u32; MAX_IPV4ADDRS] {
     65 + self.addrs
     66 + }
     67 +}
     68 + 
     69 +#[repr(C)]
     70 +#[derive(Copy, Clone)]
     71 +pub struct Ipv6Addrs {
     72 + pub addrs: [[u8; 16]; MAX_IPV4ADDRS],
     73 +}
     74 + 
     75 +impl Ipv6Addrs {
     76 + pub fn new(addrs: [[u8; 16]; MAX_IPV4ADDRS]) -> Self {
     77 + Self { addrs }
     78 + }
     79 + 
     80 + pub fn new_all() -> Self {
     81 + Self {
     82 + addrs: [[0; 16]; MAX_IPV4ADDRS],
     83 + }
     84 + }
     85 +}
     86 + 
     87 +impl IpAddrs<[u8; 16], MAX_IPV6ADDRS> for Ipv6Addrs {
     88 + #[inline(always)]
     89 + fn all(&self) -> bool {
     90 + self.addrs[0] == [0; 16]
     91 + }
     92 + 
     93 + #[inline(always)]
     94 + fn addrs(&self) -> [[u8; 16]; MAX_IPV6ADDRS] {
     95 + self.addrs
     96 + }
     97 +}
     98 + 
     99 +#[cfg(feature = "user")]
     100 +pub mod user {
     101 + use super::*;
     102 + 
     103 + use aya::Pod;
     104 + 
     105 + unsafe impl Pod for Paths {}
     106 + unsafe impl Pod for Ports {}
     107 + unsafe impl Pod for Ipv4Addrs {}
     108 + unsafe impl Pod for Ipv6Addrs {}
     109 +}
     110 + 
  • ■ ■ ■ ■ ■ ■
    guardity-ebpf/src/consts.rs
    1  -/// Wildcard for the inode.
    2  -pub const INODE_WILDCARD: u64 = 0;
    3  - 
    4 1  /// IPv4 family.
    5 2  pub const AF_INET: u16 = 2;
    6 3  /// IPv6 family.
    skipped 2 lines
  • ■ ■ ■ ■ ■
    guardity-ebpf/src/file_open.rs
    1 1  use aya_bpf::{maps::HashMap, programs::LsmContext, BpfContext};
    2  -use guardity_common::{alerts, Paths, MAX_PATHS};
     2 +use guardity_common::{
     3 + alerts,
     4 + consts::INODE_WILDCARD,
     5 + policy::{Paths, MAX_PATHS},
     6 +};
    3 7   
    4 8  use crate::{
    5 9   binprm::current_binprm_inode,
    6  - consts::INODE_WILDCARD,
    7 10   maps::{ALERT_FILE_OPEN, ALLOWED_FILE_OPEN, DENIED_FILE_OPEN},
    8 11   vmlinux::file,
    9 12   Action, Mode,
    skipped 65 lines
    75 78   match check_conditions(map, file, inode, binprm_inode, mode) {
    76 79   Action::Allow => Action::Allow,
    77 80   Action::Deny => {
    78  - ALERT_FILE_OPEN.output(ctx, &alerts::FileOpen::new(ctx.pid(), binprm_inode, inode), 0);
     81 + ALERT_FILE_OPEN.output(
     82 + ctx,
     83 + &alerts::FileOpen::new(ctx.pid(), binprm_inode, inode),
     84 + 0,
     85 + );
    79 86   Action::Deny
    80 87   }
    81 88   }
    skipped 81 lines
  • ■ ■ ■ ■ ■ ■
    guardity-ebpf/src/maps.rs
    skipped 1 lines
    2 2   macros::map,
    3 3   maps::{HashMap, PerfEventArray},
    4 4  };
    5  -use guardity_common::{alerts, Ipv4Addrs, Ipv6Addrs, Paths, Ports};
     5 +use guardity_common::{alerts, policy};
    6 6   
    7 7  #[map]
    8 8  pub static ALERT_BPRM_CHECK_SECURITY: PerfEventArray<alerts::BprmCheckSecurity> =
    skipped 1 lines
    10 10   
    11 11  /// Map of allowed file open paths for each binary.
    12 12  #[map]
    13  -pub static ALLOWED_FILE_OPEN: HashMap<u64, Paths> = HashMap::pinned(1024, 0);
     13 +pub static ALLOWED_FILE_OPEN: HashMap<u64, policy::Paths> = HashMap::pinned(1024, 0);
    14 14   
    15 15  /// Map of denied file open paths for each binary.
    16 16  #[map]
    17  -pub static DENIED_FILE_OPEN: HashMap<u64, Paths> = HashMap::pinned(1024, 0);
     17 +pub static DENIED_FILE_OPEN: HashMap<u64, policy::Paths> = HashMap::pinned(1024, 0);
    18 18   
    19 19  /// Map of alerts for `file_open` LSM hook inspection.
    20 20  #[map]
    skipped 1 lines
    22 22   
    23 23  /// Map indicating which binaries are allowed to use `setuid`.
    24 24  #[map]
    25  -pub static ALLOWED_SETUID: HashMap<u64, u8> = HashMap::pinned(1024, 0);
     25 +pub static ALLOWED_TASK_FIX_SETUID: HashMap<u64, u8> = HashMap::pinned(1024, 0);
    26 26   
    27 27  /// Map indicating which binaries are denied to use `setuid`.
    28 28  #[map]
    29  -pub static DENIED_SETUID: HashMap<u64, u8> = HashMap::pinned(1024, 0);
     29 +pub static DENIED_TASK_FIX_SETUID: HashMap<u64, u8> = HashMap::pinned(1024, 0);
    30 30   
    31 31  /// Map of alerts for `setuid` LSM hook inspection.
    32 32  #[map]
    33  -pub static ALERT_SETUID: PerfEventArray<alerts::TaskFixSetuid> = PerfEventArray::pinned(1024, 0);
     33 +pub static ALERT_TASK_FIX_SETUID: PerfEventArray<alerts::TaskFixSetuid> =
     34 + PerfEventArray::pinned(1024, 0);
    34 35   
    35 36  /// Map of allowed socket bind ports for each binary.
    36 37  #[map]
    37  -pub static ALLOWED_SOCKET_BIND: HashMap<u64, Ports> = HashMap::pinned(1024, 0);
     38 +pub static ALLOWED_SOCKET_BIND: HashMap<u64, policy::Ports> = HashMap::pinned(1024, 0);
    38 39   
    39 40  /// Map of denied socket bind ports for each binary.
    40 41  #[map]
    41  -pub static DENIED_SOCKET_BIND: HashMap<u64, Ports> = HashMap::pinned(1024, 0);
     42 +pub static DENIED_SOCKET_BIND: HashMap<u64, policy::Ports> = HashMap::pinned(1024, 0);
    42 43   
    43 44  /// Map of alerts for `socket_bind` LSM hook inspection.
    44 45  #[map]
    skipped 1 lines
    46 47   
    47 48  /// Map of allowed socket connect IPv4 addresses for each binary.
    48 49  #[map]
    49  -pub static ALLOWED_SOCKET_CONNECT_V4: HashMap<u64, Ipv4Addrs> = HashMap::pinned(1024, 0);
     50 +pub static ALLOWED_SOCKET_CONNECT_V4: HashMap<u64, policy::Ipv4Addrs> = HashMap::pinned(1024, 0);
    50 51   
    51 52  /// Map of denied socket connect IPv4 addresses for each binary.
    52 53  #[map]
    53  -pub static DENIED_SOCKET_CONNECT_V4: HashMap<u64, Ipv4Addrs> = HashMap::pinned(1024, 0);
     54 +pub static DENIED_SOCKET_CONNECT_V4: HashMap<u64, policy::Ipv4Addrs> = HashMap::pinned(1024, 0);
    54 55   
    55 56  /// Map of allowed socket connect IPv6 addresses for each binary.
    56 57  #[map]
    57  -pub static ALLOWED_SOCKET_CONNECT_V6: HashMap<u64, Ipv6Addrs> = HashMap::pinned(1024, 0);
     58 +pub static ALLOWED_SOCKET_CONNECT_V6: HashMap<u64, policy::Ipv6Addrs> = HashMap::pinned(1024, 0);
    58 59   
    59 60  /// Map of denied socket connect IPv6 addresses for each binary.
    60 61  #[map]
    61  -pub static DENIED_SOCKET_CONNECT_V6: HashMap<u64, Ipv6Addrs> = HashMap::pinned(1024, 0);
     62 +pub static DENIED_SOCKET_CONNECT_V6: HashMap<u64, policy::Ipv6Addrs> = HashMap::pinned(1024, 0);
    62 63   
    63 64  /// Map of alerts for `socket_connect` LSM hook inspection.
    64 65  #[map]
    skipped 3 lines
  • ■ ■ ■ ■ ■ ■
    guardity-ebpf/src/setuid.rs
    1 1  use aya_bpf::{cty::c_long, programs::LsmContext, BpfContext};
    2  -use guardity_common::alerts;
     2 +use guardity_common::{alerts, consts::INODE_WILDCARD};
    3 3   
    4 4  use crate::{
    5 5   binprm::current_binprm_inode,
    6  - consts::INODE_WILDCARD,
    7  - maps::{ALERT_SETUID, ALLOWED_SETUID, DENIED_SETUID},
     6 + maps::{ALERT_TASK_FIX_SETUID, ALLOWED_TASK_FIX_SETUID, DENIED_TASK_FIX_SETUID},
    8 7   vmlinux::cred,
    9 8  };
    10 9   
    skipped 27 lines
    38 37   
    39 38   let binprm_inode = current_binprm_inode();
    40 39   
    41  - if unsafe { ALLOWED_SETUID.get(&INODE_WILDCARD) }.is_some() {
    42  - if unsafe { DENIED_SETUID.get(&binprm_inode).is_some() } {
    43  - ALERT_SETUID.output(
     40 + if unsafe { ALLOWED_TASK_FIX_SETUID.get(&INODE_WILDCARD) }.is_some() {
     41 + if unsafe { DENIED_TASK_FIX_SETUID.get(&binprm_inode).is_some() } {
     42 + ALERT_TASK_FIX_SETUID.output(
    44 43   &ctx,
    45 44   &alerts::TaskFixSetuid::new(
    46 45   ctx.pid(),
    skipped 10 lines
    57 56   return Ok(0);
    58 57   }
    59 58   
    60  - if unsafe { DENIED_SETUID.get(&INODE_WILDCARD) }.is_some() {
    61  - if unsafe { ALLOWED_SETUID.get(&binprm_inode).is_some() } {
     59 + if unsafe { DENIED_TASK_FIX_SETUID.get(&INODE_WILDCARD) }.is_some() {
     60 + if unsafe { ALLOWED_TASK_FIX_SETUID.get(&binprm_inode).is_some() } {
    62 61   return Ok(0);
    63 62   }
    64  - ALERT_SETUID.output(
     63 + ALERT_TASK_FIX_SETUID.output(
    65 64   &ctx,
    66 65   &alerts::TaskFixSetuid::new(
    67 66   ctx.pid(),
    skipped 14 lines
  • ■ ■ ■ ■ ■ ■
    guardity-ebpf/src/socket_bind.rs
    1 1  use core::cmp;
    2 2   
    3 3  use aya_bpf::{cty::c_long, programs::LsmContext, BpfContext};
    4  -use guardity_common::{alerts, MAX_PORTS};
     4 +use guardity_common::{alerts, consts::INODE_WILDCARD, policy::MAX_PORTS};
    5 5   
    6 6  use crate::{
    7 7   binprm::current_binprm_inode,
    8  - consts::{AF_INET, INODE_WILDCARD},
     8 + consts::AF_INET,
    9 9   maps::{ALERT_SOCKET_BIND, ALLOWED_SOCKET_BIND, DENIED_SOCKET_BIND},
    10 10   vmlinux::{sockaddr, sockaddr_in},
    11 11  };
    skipped 131 lines
  • ■ ■ ■ ■ ■
    guardity-ebpf/src/socket_connect.rs
    1 1  use aya_bpf::{
    2 2   cty::c_long, helpers::bpf_probe_read_kernel, maps::HashMap, programs::LsmContext, BpfContext,
    3 3  };
    4  -use guardity_common::{alerts, IpAddrs, Ipv4Addrs, Ipv6Addrs};
     4 +use guardity_common::{
     5 + alerts,
     6 + consts::INODE_WILDCARD,
     7 + policy::{IpAddrs, Ipv4Addrs, Ipv6Addrs},
     8 +};
    5 9   
    6 10  use crate::{
    7 11   binprm::current_binprm_inode,
    8  - consts::{AF_INET, AF_INET6, INODE_WILDCARD},
     12 + consts::{AF_INET, AF_INET6},
    9 13   maps::{
    10 14   ALERT_SOCKET_CONNECT, ALLOWED_SOCKET_CONNECT_V4, ALLOWED_SOCKET_CONNECT_V6,
    11 15   DENIED_SOCKET_CONNECT_V4, DENIED_SOCKET_CONNECT_V6,
    skipped 199 lines
  • ■ ■ ■ ■
    policy.yaml
    skipped 1 lines
    2 2   subject: all
    3 3   allow: false
    4 4  - !setuid
    5  - subject: !process /usr/bin/sudo
     5 + subject: !binary /usr/bin/sudo
    6 6   allow: true
    7 7  - !file_open
    8 8   subject: all
    skipped 15 lines
Please wait...
Page is in error, reload to recover