mirror of
https://github.com/evilsocket/opensnitch.git
synced 2025-03-04 08:34:40 +01:00
ebpf: fixed getting ppid, skip failed execve's
- Fixed getting ppid (precompiled .o won't probably work).
- Skip failed execve* calls.
(cherry picked from commit 68c2c8ae1a
)
This commit is contained in:
parent
eafb70fb55
commit
1ae20c3aa3
5 changed files with 119 additions and 50 deletions
|
@ -8,7 +8,7 @@ import (
|
|||
)
|
||||
|
||||
// NewExecEvent constructs a new execEvent from the arguments.
|
||||
func NewExecEvent(pid, ppid, uid uint64, path string, comm [16]byte) *execEvent {
|
||||
func NewExecEvent(pid, ppid, uid uint32, path string, comm [16]byte) *execEvent {
|
||||
ev := &execEvent{
|
||||
Type: EV_TYPE_EXEC,
|
||||
PID: pid,
|
||||
|
@ -31,18 +31,18 @@ type execEventItem struct {
|
|||
}
|
||||
|
||||
type eventsStore struct {
|
||||
execEvents map[uint64]*execEventItem
|
||||
execEvents map[uint32]*execEventItem
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
// NewEventsStore creates a new store of events.
|
||||
func NewEventsStore() *eventsStore {
|
||||
return &eventsStore{
|
||||
execEvents: make(map[uint64]*execEventItem),
|
||||
execEvents: make(map[uint32]*execEventItem),
|
||||
}
|
||||
}
|
||||
|
||||
func (e *eventsStore) add(key uint64, event execEvent, proc procmon.Process) {
|
||||
func (e *eventsStore) add(key uint32, event execEvent, proc procmon.Process) {
|
||||
e.Lock()
|
||||
defer e.Unlock()
|
||||
e.execEvents[key] = &execEventItem{
|
||||
|
@ -51,14 +51,14 @@ func (e *eventsStore) add(key uint64, event execEvent, proc procmon.Process) {
|
|||
}
|
||||
}
|
||||
|
||||
func (e *eventsStore) isInStore(key uint64) (item *execEventItem, found bool) {
|
||||
func (e *eventsStore) isInStore(key uint32) (item *execEventItem, found bool) {
|
||||
e.RLock()
|
||||
defer e.RUnlock()
|
||||
item, found = e.execEvents[key]
|
||||
return
|
||||
}
|
||||
|
||||
func (e *eventsStore) delete(key uint64) {
|
||||
func (e *eventsStore) delete(key uint32) {
|
||||
e.Lock()
|
||||
defer e.Unlock()
|
||||
delete(e.execEvents, key)
|
||||
|
|
|
@ -30,14 +30,17 @@ const TaskCommLen = 16
|
|||
|
||||
type execEvent struct {
|
||||
Type uint64
|
||||
PID uint64
|
||||
PPID uint64
|
||||
UID uint64
|
||||
ArgsCount uint64
|
||||
ArgsPartial uint64
|
||||
PID uint32
|
||||
UID uint32
|
||||
PPID uint32
|
||||
RetCode uint32
|
||||
ArgsCount uint8
|
||||
ArgsPartial uint8
|
||||
Filename [MaxPathLen]byte
|
||||
Args [MaxArgs][MaxArgLen]byte
|
||||
Comm [TaskCommLen]byte
|
||||
Pad1 uint16
|
||||
Pad2 uint32
|
||||
}
|
||||
|
||||
// Struct that holds the metadata of a connection.
|
||||
|
@ -91,6 +94,8 @@ func initEventsStreamer() {
|
|||
"tracepoint/sched/sched_process_exit",
|
||||
"tracepoint/syscalls/sys_enter_execve",
|
||||
"tracepoint/syscalls/sys_enter_execveat",
|
||||
"tracepoint/syscalls/sys_exit_execve",
|
||||
"tracepoint/syscalls/sys_exit_execveat",
|
||||
//"tracepoint/sched/sched_process_exec",
|
||||
//"tracepoint/sched/sched_process_fork",
|
||||
}
|
||||
|
@ -198,6 +203,7 @@ func event2process(event *execEvent) (proc *procmon.Process) {
|
|||
proc.ReadCwd()
|
||||
proc.ReadEnv()
|
||||
proc.UID = int(event.UID)
|
||||
proc.PPID = int(event.PPID)
|
||||
|
||||
if event.ArgsPartial == 0 {
|
||||
for i := 0; i < int(event.ArgsCount); i++ {
|
||||
|
|
|
@ -165,7 +165,7 @@ func findConnProcess(value *networkEventT, connKey string) (proc *procmon.Proces
|
|||
proc.UID = int(value.UID)
|
||||
|
||||
err := proc.ReadPath()
|
||||
if ev, found := execEvents.isInStore(value.Pid); found {
|
||||
if ev, found := execEvents.isInStore(uint32(value.Pid)); found {
|
||||
// use socket's UID. See above why ^
|
||||
ev.Proc.UID = proc.UID
|
||||
ev.Proc.ReadCmdline()
|
||||
|
@ -186,8 +186,8 @@ func findConnProcess(value *networkEventT, connKey string) (proc *procmon.Proces
|
|||
log.Debug("[ebpf conn] not in cache, NOR in execEvents: %s, %d -> %s", connKey, proc.ID, proc.Path)
|
||||
// We'll end here if the events module has not been loaded, or if the process is not in cache.
|
||||
proc.GetInfo()
|
||||
execEvents.add(value.Pid,
|
||||
*NewExecEvent(value.Pid, 0, value.UID, proc.Path, value.Comm),
|
||||
execEvents.add(uint32(value.Pid),
|
||||
*NewExecEvent(uint32(value.Pid), 0, uint32(value.UID), proc.Path, value.Comm),
|
||||
*proc)
|
||||
}
|
||||
|
||||
|
|
|
@ -34,18 +34,55 @@ enum events_type {
|
|||
EVENT_SCHED_EXIT,
|
||||
};
|
||||
|
||||
struct trace_ev_common {
|
||||
short common_type;
|
||||
char common_flags;
|
||||
char common_preempt_count;
|
||||
int common_pid;
|
||||
};
|
||||
|
||||
struct trace_sys_enter_execve {
|
||||
struct trace_ev_common ext;
|
||||
|
||||
int __syscall_nr;
|
||||
char *filename;
|
||||
const char *const *argv;
|
||||
const char *const *envp;
|
||||
};
|
||||
|
||||
struct trace_sys_enter_execveat {
|
||||
struct trace_ev_common ext;
|
||||
|
||||
int __syscall_nr;
|
||||
char *filename;
|
||||
const char *const *argv;
|
||||
const char *const *envp;
|
||||
int flags;
|
||||
};
|
||||
|
||||
struct trace_sys_exit_execve {
|
||||
struct trace_ev_common ext;
|
||||
|
||||
int __syscall_nr;
|
||||
long ret;
|
||||
};
|
||||
|
||||
|
||||
struct data_t {
|
||||
u64 type;
|
||||
u64 pid; // PID as in the userspace term (i.e. task->tgid in kernel)
|
||||
u64 ppid; // Parent PID as in the userspace term (i.e task->real_parent->tgid in kernel)
|
||||
u64 uid;
|
||||
u64 args_count;
|
||||
u64 args_partial;
|
||||
u32 pid; // PID as in the userspace term (i.e. task->tgid in kernel)
|
||||
u32 uid;
|
||||
// Parent PID as in the userspace term (i.e task->real_parent->tgid in kernel)
|
||||
u32 ppid;
|
||||
u32 ret_code;
|
||||
u8 args_count;
|
||||
u8 args_partial;
|
||||
char filename[MAX_PATH_LEN];
|
||||
char args[MAX_ARGS][MAX_ARG_SIZE];
|
||||
char comm[TASK_COMM_LEN];
|
||||
}__attribute__((packed));
|
||||
u16 pad1;
|
||||
u32 pad2;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// maps
|
||||
|
|
|
@ -10,6 +10,14 @@ struct bpf_map_def SEC("maps/proc-events") events = {
|
|||
.max_entries = 256, // max cpus
|
||||
};
|
||||
|
||||
struct bpf_map_def SEC("maps/execMap") execMap = {
|
||||
.type = BPF_MAP_TYPE_HASH,
|
||||
.key_size = sizeof(u32),
|
||||
.value_size = sizeof(struct data_t),
|
||||
.max_entries = 256,
|
||||
};
|
||||
|
||||
|
||||
static __always_inline void new_event(struct data_t* data)
|
||||
{
|
||||
// initializing variables with __builtin_memset() is required
|
||||
|
@ -23,15 +31,28 @@ static __always_inline void new_event(struct data_t* data)
|
|||
bpf_probe_read(&parent, sizeof(parent), &task->real_parent);
|
||||
data->pid = bpf_get_current_pid_tgid() >> 32;
|
||||
|
||||
// FIXME: always 0?
|
||||
#if !defined(__arm__) && !defined(__i386__)
|
||||
// on i686 -> invalid read from stack
|
||||
bpf_probe_read(&data->ppid, sizeof(data->ppid), &parent->tgid);
|
||||
bpf_probe_read(&data->ppid, sizeof(u32), &parent->tgid);
|
||||
#endif
|
||||
data->uid = bpf_get_current_uid_gid() & 0xffffffff;
|
||||
bpf_get_current_comm(&data->comm, sizeof(data->comm));
|
||||
};
|
||||
|
||||
static __always_inline void __handle_exit_execve(struct trace_sys_exit_execve *ctx)
|
||||
{
|
||||
u64 pid_tgid = bpf_get_current_pid_tgid();
|
||||
struct data_t *proc = bpf_map_lookup_elem(&execMap, &pid_tgid);
|
||||
if (proc == NULL) { return; }
|
||||
if (ctx->ret != 0) { goto out; }
|
||||
proc->ret_code = ctx->ret;
|
||||
|
||||
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, proc, sizeof(*proc));
|
||||
|
||||
out:
|
||||
bpf_map_delete_elem(&execMap, &pid_tgid);
|
||||
}
|
||||
|
||||
// https://0xax.gitbooks.io/linux-insides/content/SysCall/linux-syscall-4.html
|
||||
// bprm_execve REGS_PARM3
|
||||
// https://elixir.bootlin.com/linux/latest/source/fs/exec.c#L1796
|
||||
|
@ -50,16 +71,20 @@ int tracepoint__sched_sched_process_exit(struct pt_regs *ctx)
|
|||
return 0;
|
||||
};
|
||||
|
||||
struct trace_sys_enter_execve {
|
||||
short common_type;
|
||||
char common_flags;
|
||||
char common_preempt_count;
|
||||
int common_pid;
|
||||
int __syscall_nr;
|
||||
char *filename;
|
||||
const char *const *argv;
|
||||
const char *const *envp;
|
||||
SEC("tracepoint/syscalls/sys_exit_execve")
|
||||
int tracepoint__syscalls_sys_exit_execve(struct trace_sys_exit_execve *ctx)
|
||||
{
|
||||
__handle_exit_execve(ctx);
|
||||
return 0;
|
||||
};
|
||||
|
||||
SEC("tracepoint/syscalls/sys_exit_execveat")
|
||||
int tracepoint__syscalls_sys_exit_execveat(struct trace_sys_exit_execve *ctx)
|
||||
{
|
||||
__handle_exit_execve(ctx);
|
||||
return 0;
|
||||
};
|
||||
|
||||
SEC("tracepoint/syscalls/sys_enter_execve")
|
||||
int tracepoint__syscalls_sys_enter_execve(struct trace_sys_enter_execve* ctx)
|
||||
{
|
||||
|
@ -93,24 +118,19 @@ int tracepoint__syscalls_sys_enter_execve(struct trace_sys_enter_execve* ctx)
|
|||
}
|
||||
#endif
|
||||
|
||||
// With some commands, this helper fails with error -28 (ENOSPC). Misleading error? cmd failed maybe?
|
||||
// BUG: after coming back from suspend state, this helper fails with error -95 (EOPNOTSUPP)
|
||||
// Possible workaround: count -95 errors, and from userspace reinitialize the streamer if errors >= n-errors
|
||||
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, data, sizeof(*data));
|
||||
// in case of failure adding the item to the map, send it directly
|
||||
u64 pid_tgid = bpf_get_current_pid_tgid();
|
||||
if (bpf_map_update_elem(&execMap, &pid_tgid, data, BPF_ANY) != 0) {
|
||||
|
||||
// With some commands, this helper fails with error -28 (ENOSPC). Misleading error? cmd failed maybe?
|
||||
// BUG: after coming back from suspend state, this helper fails with error -95 (EOPNOTSUPP)
|
||||
// Possible workaround: count -95 errors, and from userspace reinitialize the streamer if errors >= n-errors
|
||||
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, data, sizeof(*data));
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
struct trace_sys_enter_execveat {
|
||||
short common_type;
|
||||
char common_flags;
|
||||
char common_preempt_count;
|
||||
int common_pid;
|
||||
int __syscall_nr;
|
||||
char *filename;
|
||||
const char *const *argv;
|
||||
const char *const *envp;
|
||||
int flags;
|
||||
};
|
||||
SEC("tracepoint/syscalls/sys_enter_execveat")
|
||||
int tracepoint__syscalls_sys_enter_execveat(struct trace_sys_enter_execveat* ctx)
|
||||
{
|
||||
|
@ -140,10 +160,16 @@ int tracepoint__syscalls_sys_enter_execveat(struct trace_sys_enter_execveat* ctx
|
|||
data->args_count++;
|
||||
}
|
||||
|
||||
// With some commands, this helper fails with error -28 (ENOSPC). Misleading error? cmd failed maybe?
|
||||
// BUG: after coming back from suspend state, this helper fails with error -95 (EOPNOTSUPP)
|
||||
// Possible workaround: count -95 errors, and from userspace reinitialize the streamer if errors >= n-errors
|
||||
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, data, sizeof(*data));
|
||||
// in case of failure adding the item to the map, send it directly
|
||||
u64 pid_tgid = bpf_get_current_pid_tgid();
|
||||
if (bpf_map_update_elem(&execMap, &pid_tgid, data, BPF_ANY) != 0) {
|
||||
|
||||
// With some commands, this helper fails with error -28 (ENOSPC). Misleading error? cmd failed maybe?
|
||||
// BUG: after coming back from suspend state, this helper fails with error -95 (EOPNOTSUPP)
|
||||
// Possible workaround: count -95 errors, and from userspace reinitialize the streamer if errors >= n-errors
|
||||
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, data, sizeof(*data));
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue