Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[workspace]
members = [".", "xtask", "ssh-monitor-ebpf"]
resolver = "2"

[package]
name = "ssh-monitor"
version = "0.1.0"
edition = "2021"

[dependencies]
aya = "0.1.1"
anyhow = "1.0"
clap = { version = "4.4", features = ["derive"] }
tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros", "signal"] }
libc = "0.2"
Binary file modified bin/ssh_monitor.o
Binary file not shown.
11 changes: 1 addition & 10 deletions core/ssh_session_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"github.com/cilium/ebpf/ringbuf"
)

// Match Rust layout (repr(C))
type SshSessionEvent struct {
Pid uint32
Uid uint32
Expand All @@ -29,43 +28,35 @@ func RunSSHSessionMonitor() error {
return fmt.Errorf("load spec: %w", err)
}

// Load with no pinning or options
coll, err := ebpf.NewCollectionWithOptions(spec, ebpf.CollectionOptions{})
if err != nil {
return fmt.Errorf("create collection: %w", err)
}
defer coll.Close()

// Get maps

ringbufMap := coll.Maps["SSH_SESSION_RINGBUF"]
if ringbufMap == nil {
return fmt.Errorf("map SSH_SESSION_RINGBUF not found")
}

// Attach kprobe to track shell exec
kp, err := link.Kprobe("do_execveat_common", coll.Programs["track_shell_start"], nil)
if err != nil {
return fmt.Errorf("attach kprobe: %w", err)
}
defer kp.Close()

// Attach tracepoint to track process exit
tp, err := link.Tracepoint("sched", "sched_process_exit", coll.Programs["sched_process_exit"], nil)
if err != nil {
return fmt.Errorf("attach tracepoint: %w", err)
}
defer tp.Close()

log.Println("SSH Session Monitor started. Waiting for events...")

// Set up ring buffer reader
reader, err := ringbuf.NewReader(ringbufMap)
if err != nil {
return fmt.Errorf("open ringbuf: %w", err)
}
defer reader.Close()

// Graceful shutdown on Ctrl+C
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt)

Expand Down
23 changes: 6 additions & 17 deletions ebpf-programs/connect_count/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,6 @@
[package]
name = "connect_count"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["staticlib"]

[dependencies]
aya-ebpf = { version = "0.1.1", default-features = false }

[profile.release]
opt-level = "z"
lto = true
panic = "abort"
codegen-units = 1
strip = "debuginfo"
[workspace]
resolver = "2"
members = [
"program",
"xtask"
]
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
[package]
name = "ebpf_test"
name = "connect_count"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["staticlib"]

[dependencies]
aya-ebpf = { version = "0.1.1", default-features = false }

[profile.release]
opt-level = "z"
lto = false
lto = true
panic = "abort"
strip = "debuginfo"
codegen-units = 1
strip = "debuginfo"
8 changes: 8 additions & 0 deletions ebpf-programs/connect_count/xtask/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "xtask"
version = "0.1.0"
edition = "2021"

[dependencies]
anyhow = "1"
clap = { version = "4.5", features = ["derive"] }
103 changes: 103 additions & 0 deletions ebpf-programs/connect_count/xtask/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
use std::{
fs,
path::{Path, PathBuf},
process::{Command, Stdio},
};

use anyhow::{bail, Context, Result};
use clap::Parser;

#[derive(Parser)]
enum Args {
BuildEbpf,
}

fn main() -> Result<()> {
match Args::parse() {
Args::BuildEbpf => build_ssh_session_monitor(),
}
}

fn build_ssh_session_monitor() -> Result<()> {
let crate_name = "connect_count";
let target = "bpfel-unknown-none";
let deps_dir = Path::new("target").join(target).join("release").join("deps");

let output_bitcode: PathBuf;
let final_output = Path::new("../../bin/connect_count.o");

println!("[1/3] Building {crate_name} with `cargo rustc`...");

let status = Command::new("cargo")
.args([
"+nightly",
"rustc",
"--release",
"--target",
target,
"-Z",
"build-std=core",
"-p",
crate_name,
"--",
"--emit=obj",
])
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.status()
.context("Failed to run cargo rustc")?;

if !status.success() {
bail!("Build failed for {crate_name}");
}

println!("\nSearching for LLVM bitcode .o in {}", deps_dir.display());

let candidates: Vec<_> = fs::read_dir(&deps_dir)?
.filter_map(Result::ok)
.map(|entry| entry.path())
.filter(|path| {
path.extension().map(|ext| ext == "o").unwrap_or(false)
&& path.file_name()
.map(|name| name.to_string_lossy().contains("connect_count"))
.unwrap_or(false)
})
.collect();

if candidates.is_empty() {
bail!(
"No matching .o files found for crate in {}",
deps_dir.display()
);
}

output_bitcode = candidates[0].clone();

println!("Found: {}", output_bitcode.display());

println!("\n[2/3] Compiling bitcode to BPF ELF with llc-20...");

let status = Command::new("llc-20")
.args([
"-march=bpf",
"-filetype=obj",
"-o",
final_output.to_str().unwrap(),
output_bitcode.to_str().unwrap(),
])
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.status()
.context("Failed to execute llc-20")?;

if !status.success() {
bail!("llc-20 failed to generate final ELF file.");
}

println!(
"Done: Final ELF written to {}",
final_output.display()
);

Ok(())
}
24 changes: 6 additions & 18 deletions ebpf-programs/ssh_fail_monitor/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,18 +1,6 @@
[package]
name = "ssh_fail_monitor"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["staticlib"]
name = "ssh_fail_monitor"

[dependencies]
aya-ebpf = { version = "0.1.1", default-features = false }

[profile.release]
opt-level = "z"
lto = true
panic = "abort"
codegen-units = 1
strip = "debuginfo"
[workspace]
resolver = "2"
members = [
"program",
"xtask"
]
18 changes: 18 additions & 0 deletions ebpf-programs/ssh_fail_monitor/program/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "ssh_fail_monitor"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["staticlib"]
name = "ssh_fail_monitor"

[dependencies]
aya-ebpf = { version = "0.1.1", default-features = false }

[profile.release]
opt-level = "z"
lto = true
panic = "abort"
codegen-units = 1
strip = "debuginfo"
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
#![no_std]
#![no_main]

use aya_ebpf::bpf_printk;
use aya_ebpf::{
cty::c_int,
helpers::{
bpf_get_current_comm, bpf_get_current_pid_tgid, bpf_get_current_uid_gid, bpf_ktime_get_ns,
},
macros::map,
maps::{HashMap, RingBuf},
programs::ProbeContext,
helpers::{
bpf_get_current_pid_tgid,
bpf_get_current_uid_gid,
bpf_get_current_comm,
bpf_ktime_get_ns,
},
EbpfContext,
cty::c_int,
};
use aya_ebpf::bpf_printk;

#[repr(C)]
#[derive(Clone, Copy)]
Expand All @@ -31,8 +28,7 @@ pub struct SshFailEvent {
static mut SSH_FAIL_RINGBUF: RingBuf = RingBuf::with_byte_size(4096, 0);

#[map(name = "SSH_FAIL_COUNTS")]
static mut SSH_FAIL_COUNTS: HashMap<u32, u32> =
HashMap::<u32, u32>::with_max_entries(1024, 0);
static mut SSH_FAIL_COUNTS: HashMap<u32, u32> = HashMap::<u32, u32>::with_max_entries(1024, 0);

#[no_mangle]
#[link_section = "uretprobe/pam_authenticate"]
Expand All @@ -43,19 +39,18 @@ pub fn ssh_fail_monitor(ctx: ProbeContext) -> u32 {

fn try_monitor(ctx: ProbeContext) -> Result<(), ()> {
// SAFELY extract return value from `ctx`

let ret_val = unsafe { *(ctx.as_ptr() as *const c_int) };
unsafe {
bpf_printk!(b"ssh_fail_monitor: ret_val seen\n");
}
unsafe {
let _ = bpf_printk!(b"ssh_fail_monitor: ret_val seen\n");
}
if ret_val == 0 {
return Ok(());
}

let pid = (bpf_get_current_pid_tgid() >> 32) as u32;
let uid = (bpf_get_current_uid_gid() >> 32) as u32;


unsafe {
bpf_printk!(b"[ssh_fail] processing event\n");
}
Expand All @@ -77,10 +72,14 @@ fn try_monitor(ctx: ProbeContext) -> Result<(), ()> {
};

unsafe {
let count = SSH_FAIL_COUNTS.get(&pid).copied().unwrap_or(0);
SSH_FAIL_COUNTS.insert(&pid, &(count + 1), 0).ok();
SSH_FAIL_RINGBUF.output(&event, 0);
bpf_printk!(b"[ssh_fail] event emitted\n");
let map_ptr = core::ptr::addr_of_mut!(SSH_FAIL_COUNTS);
let ringbuf_ptr = core::ptr::addr_of_mut!(SSH_FAIL_RINGBUF);

let count = (*map_ptr).get(&pid).copied().unwrap_or(0);
(*map_ptr).insert(&pid, &(count + 1), 0).ok();

let _ = (*ringbuf_ptr).output(&event, 0);
bpf_printk!(b"[ssh_fail] event emitted\n");
}

Ok(())
Expand Down
8 changes: 8 additions & 0 deletions ebpf-programs/ssh_fail_monitor/xtask/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "xtask"
version = "0.1.0"
edition = "2021"

[dependencies]
anyhow = "1"
clap = { version = "4.5", features = ["derive"] }
Loading