1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
|
#![no_std]
#![no_main]
use core::{ffi::c_void, any::Any};
use core::{str, ptr};
use aya_bpf::helpers::gen::bpf_probe_read;
use aya_bpf::helpers::{bpf_get_current_comm, bpf_probe_read_buf, bpf_probe_read_user, bpf_probe_read_user_str, bpf_probe_read_user_str_bytes};
use aya_bpf::maps::HashMap;
//use aya_bpf::helpers::gen::bpf_probe_read;
use aya_bpf::{
macros::{tracepoint, map},
programs::TracePointContext, BpfContext, helpers::{gen::{self, bpf_probe_read_kernel_str}, bpf_probe_read_kernel_str_bytes}, maps::{PerfEventArray, PerCpuArray},
};
use aya_log_ebpf::info;
use fs_tracer_common::WriteSyscallBPF;
#[map]
static EVENTS: PerfEventArray<WriteSyscallBPF> = PerfEventArray::with_max_entries(1024, 0);
#[map]
static SYSCALLENTERS: HashMap<u32, WriteSyscallBPF> = HashMap::with_max_entries(1024, 0);
//TODO: Clean up code. Generics. Arbitrary length buffer? https://github.com/elbaro/mybee/blob/fe037927b848cdbe399c0b0730ae79400cf95279/mybee-ebpf/src/main.rs#L29
enum SyscallType {
ENTER,
EXIT,
}
//#[map]
//static mut READ_FROM_USERSPACE_BUFFER: PerCpuArray<[u8;2048]> = PerCpuArray::with_max_entries(1, 0);
#[tracepoint]
pub fn fs_tracer_enter(ctx: TracePointContext) -> u32 {
match try_fs_tracer(ctx, SyscallType::ENTER) {
Ok(ret) => ret,
Err(ret) => ret,
}
}
#[tracepoint]
pub fn fs_tracer_exit(ctx: TracePointContext) -> u32 {
match try_fs_tracer(ctx, SyscallType::EXIT) {
Ok(ret) => ret,
Err(ret) => ret,
}
}
#[inline(always)]
fn ptr_at<T>(ctx: &TracePointContext, offset: usize) -> Option<*const T> {
let start = ctx.as_ptr(); //maybe try using the bpf_probe_read here to see if we can use result of that to know the type of the syscall
Some(unsafe { start.add(offset) } as *const T)
}
fn try_fs_tracer(ctx: TracePointContext, syscall_type: SyscallType) -> Result<u32, u32> {
let syscall_nr = unsafe { * ptr_at::<i32>(&ctx, 8).unwrap() };
//info!( &ctx, "syscall_nr: {}", syscall_nr);
//let typee = unsafe { *(cmd.as_ptr().add(0) as *const u16)};
//let typee = ctx.read_at(0)
/* let a: [u64; 1] = [0u64; 1];
let ret = unsafe { bpf_probe_read(a.as_ptr() as *mut c_void, 8, ctx.as_ptr().add(0) as *const c_void)}; //TODO: Maybe we can try reading some high btis to get the type of the syscall exit or enter
info!(&ctx, "ret: {}", ret);
info!(&ctx, "x: {}", unsafe {a[0]});
info!(&ctx, "syscall_nr: {}", syscall_nr);*/
//info!(&ctx, "type: {}", typee);
//return Ok(1);
return handle_syscall(ctx, syscall_nr, syscall_type);
}
fn handle_syscall(ctx: TracePointContext, syscall_nr: i32, syscall_type: SyscallType) -> Result<u32, u32> {
match syscall_nr {
1 => {
return handle_sys_write(ctx, syscall_type);
},
2 => {
return Ok(0)
//handle_sys_open(ctx);
},
8 => {
return Ok(0)
//handle_sys_lseek(ctx);
},
3 => {
return Ok(0)
//handle_sys_close(ctx);
},
_ => {
info!(&ctx, "unhandled syscall: {}", syscall_nr);
return Err(1)
}
}
}
/*static mut read_from_userspace_buffer: [u8; 2048] = [0u8; 2048];
static mut write_to_userspace_buffer: [u8; 2048] = [0u8; 2048];
static mut write_syscall_bpf: WriteSyscallBPF = WriteSyscallBPF {
fd: 0,
buf: [0u8; 2048],
count: 0,
};*/
#[derive(Clone, Copy)]
struct WriteSyscallArgs {
fd: u64,
buf: *const u8,
count: u64,
}
fn handle_sys_write(ctx: TracePointContext, syscall_type: SyscallType) -> Result<u32, u32> {
match syscall_type {
SyscallType::ENTER => {
return handle_sys_write_enter(ctx);
},
SyscallType::EXIT => {
return handle_sys_write_exit(ctx);
},
}
}
fn handle_sys_write_enter(ctx: TracePointContext) -> Result<u32, u32> {
// info!(&ctx, "handle_sys_write start");
let args = unsafe { *ptr_at::<WriteSyscallArgs>(&ctx, 16).unwrap() };
// if fd is stdout, stderr or stdin, ignore
if args.fd <= 2 {
return Ok(0)
}
// info!(&ctx, "argfs fd: {}", args.fd);
let mut buf = [0u8; 96]; //we need to make this muuuuuch bigger
//get_string_from_userspace(args.buf, unsafe { &mut *READ_FROM_USERSPACE_BUFFER.get_ptr_mut(0).unwrap() });
//get_string_from_userspace(args.buf, &mut buf);
let _ = unsafe { bpf_probe_read_user_str_bytes(args.buf, &mut buf) };
let buf_ref = &buf;
// info!(&ctx, "buf: {}", unsafe { str::from_utf8_unchecked(buf_ref) });
//info!(&ctx, "count: {}", args.count); ";
let mut anotherbuf = [0u8; 96];
unsafe { bpf_probe_read_kernel_str(anotherbuf.as_mut_ptr() as *mut c_void, 96, buf_ref.as_ptr() as *const c_void) };
let tgid: u32 = ctx.tgid();
let _ = SYSCALLENTERS.insert(&tgid, &WriteSyscallBPF {
pid: ctx.pid(),
fd: args.fd,
buf: anotherbuf,
count: args.count,
ret: -9999,
}, 0);
return Ok(0)
}
fn handle_sys_write_exit(ctx: TracePointContext) -> Result<u32, u32> {
//info!(&ctx, "handle_sys_write_exit start");
let ret = unsafe { *ptr_at::<i64>(&ctx, 16).unwrap() }; //TODO: We cant use unwrap, thats why we couldnt use the aya helper fns
let tgid = ctx.tgid();
if let Some(& syscall) = unsafe { SYSCALLENTERS.get(&tgid) } {
let mut newsyscall = syscall.clone();
newsyscall.ret = ret;
EVENTS.output(&ctx, &newsyscall, 0);
}
//syscall_enter.ret = ret;
//EVENTS.output(&ctx, &syscall_enter, 0);
return Ok(0)
}
// thread can only execute 1 syscall at a time <-
//TODO: How are we going to correlate. We have open of a filename, we need to insert that into (pid, fd) -> filename. on close we remove from map. we need some timeout to remove stale entries
//TODO: to get the fd from open, we need to know the return value of the syscall. for that we need a tracepoint on end and keep a map of (tgid, pid) -> WriteSyscallBPF). we need to differenciate the syscalls by id
//TODO: Maybe we can use git itself for the diffs etc.
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
unsafe { core::hint::unreachable_unchecked() }
}
|