Skip to content

Commit

Permalink
Add additional dropped binary detection based on magic write
Browse files Browse the repository at this point in the history
It sometimes is usefull to distinguish between changes to just file
metadata and file modifications. Even though OverlayFS would offer
a flag that indicates that only metadata has changed and not all of the
data was copied to the upper layer, this functionality is disabled by
default by quite a few kernels.

Instead, we now keep track of MAGIC_WRITE related inodes and probe on
exec if the executed file was dropped or not.
  • Loading branch information
patrickpichler committed Jul 11, 2024
1 parent 0a090cf commit eb0ff68
Show file tree
Hide file tree
Showing 9 changed files with 35 additions and 7 deletions.
15 changes: 12 additions & 3 deletions e2e/e2e.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,15 +394,17 @@ func (t *testCASTAIServer) KubernetesDeltaBatchIngest(server castaipb.RuntimeSec
}

const (
ExecUpperLayer uint32 = 1 << 0
ExecMemfd uint32 = 1 << 1
ExecTmpfs uint32 = 1 << 2
ExecUpperLayer uint32 = 1 << 0
ExecMemfd uint32 = 1 << 1
ExecTmpfs uint32 = 1 << 2
ExecDroppedBinary uint32 = 1 << 3
)

func (t *testCASTAIServer) validateExecEvents() error {
var foundExecWithHash bool
var foundExecFromUpperLayer bool
var foundExecTmpfs bool
var foundExecDroppedBinary bool

for _, e := range t.events {
if e.EventType == castaipb.EventType_EVENT_EXEC {
Expand All @@ -420,6 +422,10 @@ func (t *testCASTAIServer) validateExecEvents() error {
if (originalFileFlags | ExecTmpfs) > 0 {
foundExecTmpfs = true
}

if (originalFileFlags | ExecDroppedBinary) > 0 {
foundExecDroppedBinary = true
}
}
}

Expand All @@ -432,6 +438,9 @@ func (t *testCASTAIServer) validateExecEvents() error {
if !foundExecTmpfs {
return errors.New("expected at least one exec event from tmpfs")
}
if !foundExecDroppedBinary {
return errors.New("expected at least one exec event from dropped binary")
}

return nil
}
Expand Down
7 changes: 4 additions & 3 deletions pkg/ebpftracer/c/headers/common/filesystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@

#define UID_GID_MAP_MAX_BASE_EXTENTS 5

#define FS_EXE_UPPER_LAYER (1 << 0)
#define FS_EXE_FROM_MEMFD (1 << 1)
#define FS_EXE_FROM_TMPFS (1 << 2)
#define FS_EXE_UPPER_LAYER (1 << 0)
#define FS_EXE_FROM_MEMFD (1 << 1)
#define FS_EXE_FROM_TMPFS (1 << 2)
#define FS_EXE_DROPPED_BINARY (1 << 3)
// TODO: Implement these flags.
//#define FS_EXE_WRITABLE (1 << 3)

Expand Down
2 changes: 2 additions & 0 deletions pkg/ebpftracer/c/headers/maps.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ BPF_HASH(process_tree_map, u32, eq_t, 10240);
BPF_HASH(events_map, u32, event_config_t, MAX_EVENT_ID); // map to persist event configuration data
BPF_LRU_HASH(syscall_stats_map, syscall_stats_key_t, u64, 65536); // holds syscalls stats per cgroup

BPF_LRU_HASH(dropped_binary_inodes, u64, u32, 8192); // holds inodes of binaries that have been identified as dropped

BPF_HASH(oom_info, __u32, __u32, 1024); // marks PIDs as OOM
BPF_HASH(ignored_cgroups_map, u64, u64, 10240); // marks cgroup ids as ignored, causing no more events to be emited for actions in those cgroups
//
Expand Down
9 changes: 9 additions & 0 deletions pkg/ebpftracer/c/tracee.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1364,6 +1364,11 @@ int tracepoint__sched__sched_process_exec(struct bpf_raw_tracepoint_args *ctx)
}
}

// If there is a dummy element in the map, we know the binary was dropped.
if (bpf_map_lookup_elem(&dropped_binary_inodes, &inode_nr)){
flags |= FS_EXE_DROPPED_BINARY;
}

pid_t pid = p.event->context.task.host_pid;
u16 *original_flags = bpf_map_lookup_elem(&pid_original_file_flags, &pid);
if (original_flags != NULL) {
Expand Down Expand Up @@ -3428,6 +3433,10 @@ statfunc int do_vfs_write_magic_return(struct pt_regs *ctx, bool is_buf)
return 0;
}

u32 one = 1;
// We just need a dummy value in the map for now.
bpf_map_update_elem(&dropped_binary_inodes, &file_info.id.inode, &one, BPF_ANY);

save_bytes_to_buf(&(p.event->args_buf), header, header_bytes, 1);
save_to_submit_buf(&(p.event->args_buf), &file_info.id.device, sizeof(dev_t), 2);
save_to_submit_buf(&(p.event->args_buf), &file_info.id.inode, sizeof(unsigned long), 3);
Expand Down
3 changes: 3 additions & 0 deletions pkg/ebpftracer/tracer_arm64_bpfel.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified pkg/ebpftracer/tracer_arm64_bpfel.o
Binary file not shown.
3 changes: 2 additions & 1 deletion pkg/ebpftracer/tracer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ func TestTracer(t *testing.T) {
Events: []*ebpftracer.EventPolicy{
// {ID: events.NetFlowBase},
//{ID: events.NetPacketTCPBase},
// {ID: events.SchedProcessExec},
{ID: events.SchedProcessExec},
{ID: events.MagicWrite},
//{ID: events.SecuritySocketConnect},
// {ID: events.SockSetState},
//{ID: events.NetPacketDNSBase},
Expand Down
3 changes: 3 additions & 0 deletions pkg/ebpftracer/tracer_x86_bpfel.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified pkg/ebpftracer/tracer_x86_bpfel.o
Binary file not shown.

0 comments on commit eb0ff68

Please sign in to comment.