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
86 changes: 11 additions & 75 deletions crates/cardwire-daemon/src/analyzer/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,6 @@ pub struct ExecEvent {
pub pid: u32,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct CloseEvent {
pub pid: u32,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct ReportEvent {
Expand All @@ -46,7 +40,6 @@ enum PidType {
#[derive(Clone)]
pub struct CardwireAnalyzer {
exec_ring: Arc<Mutex<AsyncFd<RingBuf<aya::maps::MapData>>>>,
close_ring: Arc<Mutex<AsyncFd<RingBuf<aya::maps::MapData>>>>,
report_ring: Arc<Mutex<AsyncFd<RingBuf<aya::maps::MapData>>>>,
pid_map: Arc<RwLock<AyaHashMap<aya::maps::MapData, u32, u32>>>,
forced_map: Arc<RwLock<AyaHashMap<aya::maps::MapData, u32, u32>>>,
Expand All @@ -73,19 +66,16 @@ impl CardwireAnalyzer {
) -> anyhow::Result<CardwireAnalyzer> {
let mut blocker = blocker.write().await;
let exec_ring = blocker.get_exec_ring()?;
let close_ring = blocker.get_close_ring()?;
let report_ring = blocker.get_report_ring()?;
let pid_map = Arc::clone(&blocker.pid_map);
let forced_map = Arc::clone(&blocker.forced_map);
let ebpf_logger = blocker.get_ebpf_logger()?;

let exec_ring = AsyncFd::new(exec_ring)?;
let close_ring = AsyncFd::new(close_ring)?;
let report_ring = AsyncFd::new(report_ring)?;

// Now Rwlock -> Arc
let exec_ring = Arc::new(Mutex::new(exec_ring));
let close_ring = Arc::new(Mutex::new(close_ring));
let report_ring = Arc::new(Mutex::new(report_ring));
let ebpf_logger: Arc<Mutex<AsyncFd<EbpfLogger<&'static dyn Log>>>> =
Arc::new(Mutex::new(ebpf_logger));
Expand All @@ -95,7 +85,6 @@ impl CardwireAnalyzer {
let xdg_folders: Vec<PathBuf> = xdg_result.1;
Ok(CardwireAnalyzer {
exec_ring,
close_ring,
report_ring,
pid_map,
forced_map,
Expand All @@ -111,12 +100,10 @@ impl CardwireAnalyzer {
pub async fn run(self) -> anyhow::Result<()> {
// Clone the Arcs and Sender to move into the background task
let exec_arc = self.exec_ring.clone();
let close_arc = self.close_ring.clone();
let logger_arc = self.ebpf_logger.clone();

// Lock the buffers once
let mut exec_ring = exec_arc.lock().await;
let mut close_ring = close_arc.lock().await;

let shared_self = Arc::new(self);

Expand All @@ -141,40 +128,19 @@ impl CardwireAnalyzer {
task::spawn(async move { shared_self_report.report_logger().await });

loop {
tokio::select! {
Ok(mut guard) = exec_ring.ready_mut(Interest::READABLE) => {
if guard.ready().is_readable() {
while let Some(item) = guard.get_inner_mut().next() {
if item.len() < std::mem::size_of::<ExecEvent>() {
debug!("Skipping malformed exec event. Size: {}", item.len());
continue;
}
let event = unsafe { ptr::read_unaligned(item.as_ptr() as *const ExecEvent) };
let this = Arc::clone(&shared_self);
task::spawn(async move {
this.spawn_exec_analyzer(event).await
});
}
guard.clear_ready();
}
}

Ok(mut guard) = close_ring.ready_mut(Interest::READABLE) => {
if guard.ready().is_readable() {
while let Some(item) = guard.get_inner_mut().next() {
if item.len() < std::mem::size_of::<CloseEvent>() {
debug!("Skipping malformed close event. Size: {}", item.len());
continue;
}
let event = unsafe { ptr::read_unaligned(item.as_ptr() as *const CloseEvent) };
let this = Arc::clone(&shared_self);
task::spawn(async move {
this.spawn_remove_analyzer(event).await
});
}
guard.clear_ready();
if let Ok(mut guard) = exec_ring.ready_mut(Interest::READABLE).await
&& guard.ready().is_readable()
{
while let Some(item) = guard.get_inner_mut().next() {
if item.len() < std::mem::size_of::<ExecEvent>() {
debug!("Skipping malformed exec event. Size: {}", item.len());
continue;
}
let event = unsafe { ptr::read_unaligned(item.as_ptr() as *const ExecEvent) };
let this = Arc::clone(&shared_self);
task::spawn(async move { this.spawn_exec_analyzer(event).await });
}
guard.clear_ready();
Comment thread
luytan marked this conversation as resolved.
}
}
}
Expand Down Expand Up @@ -216,26 +182,6 @@ impl CardwireAnalyzer {
}
}
}
async fn spawn_remove_analyzer(&self, event: CloseEvent) -> () {
{
let mut pid_map = self.pid_map.write().await;
if pid_map.remove(&event.pid).is_ok() {
debug!("REMOVE: pid: {}", event.pid);
}
}
{
let mut forced_map = self.forced_map.write().await;
if forced_map.remove(&event.pid).is_ok() {
debug!("REMOVE FORCED: pid: {}", event.pid);
}
}
{
let mut reported_pid_map = self.reported_pids.write().await;
if reported_pid_map.remove(&event.pid) {
debug!("REMOVE REPORTED: pid: {}", event.pid);
}
}
}

async fn report_logger(&self) -> () {
let report_arc = self.report_ring.clone();
Expand Down Expand Up @@ -492,16 +438,6 @@ mod tests {
assert_eq!(event.pid, u32::MAX);
}

#[test]
fn test_close_event_deserialization() {
let item: Vec<u8> = vec![
0x2A, 0x00, 0x00, 0x00, // pid = 42
];
assert!(item.len() >= std::mem::size_of::<CloseEvent>());
let event = unsafe { ptr::read_unaligned(item.as_ptr() as *const CloseEvent) };
assert_eq!(event.pid, 42);
}

#[test]
fn test_get_real_process_name_returns_exe_for_wine_proton_cmdline() {
let cmdline_bytes =
Expand Down
22 changes: 0 additions & 22 deletions crates/cardwire-ebpf-userspace/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,28 +292,6 @@ impl EbpfBlocker {
Ok(ring_buf)
}

/// take the CW_CLOSE_EVENTS RingBuf map from the blocker
pub fn get_close_ring(&mut self) -> CardwireEbpfResult<RingBuf<aya::maps::MapData>> {
let map_str = "CW_CLOSE_EVENTS";
let map = match self.ebpf.take_map(map_str) {
Some(map) => map,
None => {
error!("error while trying to take map {}", map_str);
return Err(CardwireEbpfError::MissingMap {
name: map_str.to_string(),
});
}
};
let ring_buf: RingBuf<aya::maps::MapData> = match RingBuf::try_from(map) {
Ok(ringbuf) => ringbuf,
Err(err) => {
error!("error while trying to get the close ring_buf");
return Err(CardwireEbpfError::aya(err));
}
};
Ok(ring_buf)
}

/// take the CW_REPORT_EVENTS RingBuf map from the blocker
pub fn get_report_ring(&mut self) -> CardwireEbpfResult<RingBuf<aya::maps::MapData>> {
let map_str = "CW_REPORT_EVENTS";
Expand Down
47 changes: 15 additions & 32 deletions crates/cardwire-ebpf/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use aya_ebpf::{
use aya_log_ebpf::{error, warn};

use crate::{
helpers::{is_cardwired, is_comm_whitelisted, is_hybrid, is_inode_blocked, is_smart}, maps::{CW_CLOSE_EVENTS, CW_DIRENT, CW_EXEC_EVENTS, CloseEvent, ExecEvent}, vmlinux::{dentry, file, inode, linux_dirent64, path}
helpers::{is_cardwired, is_comm_whitelisted, is_hybrid, is_inode_blocked, is_smart}, maps::{CW_ALLOWED_PID, CW_DIRENT, CW_EXEC_EVENTS, CW_FORCED_PID, ExecEvent}, vmlinux::{dentry, file, inode, linux_dirent64, path}
};

#[allow(
Expand Down Expand Up @@ -424,6 +424,10 @@ pub fn tracepoint_sched_process_exec(ctx: TracePointContext) -> u32 {
}

unsafe fn try_tracepoint_sched_process_exec(ctx: TracePointContext) -> Result<i32, i32> {
// First we clean the MAP
let pid = (bpf_get_current_pid_tgid() >> 32) as u32;
let _ = CW_ALLOWED_PID.remove(&pid);
let _ = CW_FORCED_PID.remove(&pid);
// If it's the daemon, we must exit
match is_cardwired() {
Some(res) => {
Expand Down Expand Up @@ -459,7 +463,6 @@ unsafe fn try_tracepoint_sched_process_exec(ctx: TracePointContext) -> Result<i3
return ReturnCode::SUCCESS;
}
};
let pid = (bpf_get_current_pid_tgid() >> 32) as u32;

// We just send the event to userspace
let event: ExecEvent = ExecEvent { pid };
Expand All @@ -480,38 +483,18 @@ pub fn tracepoint_sched_process_exit(ctx: TracePointContext) -> u32 {
}
}

unsafe fn try_tracepoint_sched_process_exit(ctx: TracePointContext) -> Result<i32, i32> {
// Only proceed if we are in smart mode, events are not used when not in smart mode and it would
// slow down the system for no reason
if let Some(res) = unsafe { is_smart() }
&& res
{
let pid_tgid: u64 = bpf_get_current_pid_tgid();
let tgid = pid_tgid as u32;
let pid = (pid_tgid >> 32) as u32;

// Only send close event if the main thread is exiting
if pid != tgid {
return ReturnCode::SUCCESS;
}

let event: CloseEvent = CloseEvent { pid };
unsafe fn try_tracepoint_sched_process_exit(_ctx: TracePointContext) -> Result<i32, i32> {
let pid_tgid: u64 = bpf_get_current_pid_tgid();
let tgid = pid_tgid as u32;
let pid = (pid_tgid >> 32) as u32;

let mut ring_buf = match CW_CLOSE_EVENTS.reserve(0) {
Some(ring_buf) => ring_buf,
// Reservation fail, warn and leave
None => {
warn!(
&ctx,
"failed to reserve bytes for ring_buf: CW_CLOSE_EVENTS"
);
return ReturnCode::SUCCESS;
}
};

ring_buf.write(event);
ring_buf.submit(0);
// Only process the exit if the main thread is exiting
if pid != tgid {
return ReturnCode::SUCCESS;
}
// Remove PID from the maps
let _ = CW_ALLOWED_PID.remove(&pid);
let _ = CW_FORCED_PID.remove(&pid);

ReturnCode::SUCCESS
}
Expand Down
9 changes: 0 additions & 9 deletions crates/cardwire-ebpf/src/maps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,6 @@ pub struct ExecEvent {
#[btf_map]
pub static CW_EXEC_EVENTS: RingBuf<ExecEvent, 262144> = RingBuf::new();

#[repr(align(8))]
#[allow(dead_code)]
pub struct CloseEvent {
pub pid: u32,
}

#[btf_map]
pub static CW_CLOSE_EVENTS: RingBuf<CloseEvent, 262144> = RingBuf::new();

#[repr(C)]
#[repr(align(8))]
#[allow(dead_code)]
Expand Down