■ ■ ■ ■ ■ ■
examples/file_open/examples/file_open.rs
| 1 | + | use std::{fs::create_dir_all, path::PathBuf}; |
| 2 | + | |
| 3 | + | use clap::Parser; |
| 4 | + | use guardity::{ |
| 5 | + | policy::{FileOpen, Paths, PolicySubject}, |
| 6 | + | PolicyManager, |
| 7 | + | }; |
| 8 | + | use log::info; |
| 9 | + | |
| 10 | + | #[derive(Debug, Parser)] |
| 11 | + | struct Opt { |
| 12 | + | #[clap(long, default_value = "/sys/fs/bpf")] |
| 13 | + | bpffs_path: PathBuf, |
| 14 | + | #[clap(long, default_value = "example_file_open")] |
| 15 | + | bpffs_dir: PathBuf, |
| 16 | + | /// Binary which should be the subject of the policy. If empty, all |
| 17 | + | /// processes are subject. |
| 18 | + | #[clap(long)] |
| 19 | + | subject: Option<PathBuf>, |
| 20 | + | /// Path to which the open access should be denied. |
| 21 | + | #[clap(long)] |
| 22 | + | path_to_deny: PathBuf, |
| 23 | + | } |
| 24 | + | |
| 25 | + | #[tokio::main] |
| 26 | + | async fn main() -> anyhow::Result<()> { |
| 27 | + | let opt = Opt::parse(); |
| 28 | + | |
| 29 | + | env_logger::init(); |
| 30 | + | |
| 31 | + | // Create a directory where guardity policy manager can store its BPF |
| 32 | + | // objects (maps). |
| 33 | + | let bpf_path = opt.bpffs_path.join(opt.bpffs_dir); |
| 34 | + | create_dir_all(&bpf_path)?; |
| 35 | + | |
| 36 | + | // Create a policy manager. |
| 37 | + | let mut policy_manager = PolicyManager::new(bpf_path)?; |
| 38 | + | |
| 39 | + | // Attach the policy manager to the `file_open` LSM hook. |
| 40 | + | let mut file_open = policy_manager.attach_file_open()?; |
| 41 | + | |
| 42 | + | // Get the receiver end of the alerts channel (for the `file_open` LSM |
| 43 | + | // hook). |
| 44 | + | let mut rx = file_open.alerts().await?; |
| 45 | + | |
| 46 | + | // Based on input from CLI, decide whether the policy subject is a certain |
| 47 | + | // binary or all processes. |
| 48 | + | let subject = match opt.subject { |
| 49 | + | Some(subject) => PolicySubject::Binary(subject), |
| 50 | + | None => PolicySubject::All, |
| 51 | + | }; |
| 52 | + | |
| 53 | + | // Define a policy which blocks access to a provided path. |
| 54 | + | let policy = FileOpen { |
| 55 | + | subject, |
| 56 | + | allow: Paths::All, |
| 57 | + | deny: Paths::Paths(vec![opt.path_to_deny]), |
| 58 | + | }; |
| 59 | + | |
| 60 | + | // Add the policy to the policy manager. |
| 61 | + | file_open.add_policy(policy).await?; |
| 62 | + | |
| 63 | + | info!("Waiting for Ctrl-C..."); |
| 64 | + | |
| 65 | + | // Wait for policy violation alerts (or for CTRL+C). |
| 66 | + | loop { |
| 67 | + | tokio::select! { |
| 68 | + | Some(alert) = rx.recv() => { |
| 69 | + | info!("file_open: pid={} subject={} path={}", alert.pid, alert.subject, alert.path.display()); |
| 70 | + | } |
| 71 | + | _ = tokio::signal::ctrl_c() => { |
| 72 | + | break; |
| 73 | + | } |
| 74 | + | } |
| 75 | + | } |
| 76 | + | |
| 77 | + | Ok(()) |
| 78 | + | } |
| 79 | + | |