Skip to content

Commit

Permalink
fix(events): fix hidden_kernel_module history scan for kernels >6.2
Browse files Browse the repository at this point in the history
- also address potential slice out of bounds for name argument in
  hidden_kernel_module.go
  • Loading branch information
OriGlassman authored and randomname21 committed Nov 25, 2024
1 parent aa615f3 commit 30f9723
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 21 deletions.
4 changes: 4 additions & 0 deletions pkg/ebpf/c/maps.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ enum tail_call_id_e
TAIL_HIDDEN_KERNEL_MODULE_KSET,
TAIL_HIDDEN_KERNEL_MODULE_MOD_TREE,
TAIL_HIDDEN_KERNEL_MODULE_NEW_MOD_ONLY,
TAIL_HIDDEN_KERNEL_MODULE_MODTREE_1,
TAIL_HIDDEN_KERNEL_MODULE_MODTREE_2,
TAIL_HIDDEN_KERNEL_MODULE_MODTREE_3,
TAIL_HIDDEN_KERNEL_MODULE_MODTREE_4,
MAX_TAIL_CALL
};

Expand Down
188 changes: 171 additions & 17 deletions pkg/ebpf/c/tracee.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,8 @@ enum

struct modules_map {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, MAX_NUM_MODULES);
__uint(max_entries, 2 * MAX_NUM_MODULES); // Do not decrease as it won't be big enough to hold
// all loaded modules
__type(key, u64);
__type(value, kernel_module_t);
} modules_map SEC(".maps");
Expand All @@ -763,6 +764,15 @@ struct new_module_map {

typedef struct new_module_map new_module_map_t;

struct module_context_map {
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__uint(max_entries, 2);
__type(key, u32);
__type(value, u64);
} module_context_map SEC(".maps");

typedef struct module_context_map module_context_map_t;

// We only care for modules that got deleted or inserted between our scan and if
// we detected something suspicious. Since it's a very small time frame, it's
// not likely that a large amount of modules will be deleted. Instead of saving
Expand Down Expand Up @@ -841,7 +851,6 @@ statfunc int init_shown_modules()
if (&pos->list == head) {
return 0;
}

bpf_map_update_elem(&modules_map, &pos, &ker_mod, BPF_ANY);
}

Expand Down Expand Up @@ -933,11 +942,15 @@ statfunc struct latch_tree_node *__lt_from_rb(struct rb_node *node, int idx)
return container_of(node, struct latch_tree_node, node[idx]);
}

statfunc int walk_mod_tree(program_data_t *p, struct rb_node *root, int idx)
struct mod_tree_root {
struct latch_tree_root root;
};

statfunc int mod_tree_loop(program_data_t *p, struct rb_node *addr, int idx)
{
struct latch_tree_node *ltn;
struct module *mod;
struct rb_node *curr = root;
struct rb_node *curr = addr;
u32 flags = MOD_TREE;

#pragma unroll
Expand Down Expand Up @@ -970,12 +983,152 @@ statfunc int walk_mod_tree(program_data_t *p, struct rb_node *root, int idx)
}
}

int key = 0;
bpf_map_update_elem(
&module_context_map, &key, &curr, BPF_ANY); // To be able to continue in the tailcall
return HID_MOD_UNCOMPLETED_ITERATIONS;
}

struct mod_tree_root {
struct latch_tree_root root;
};
statfunc int get_mod_tree_rb_idx()
{
int k = 1;
int *idx = (int *) bpf_map_lookup_elem(&module_context_map, &k);
if (idx == NULL)
return -1;
return *idx;
}

statfunc struct rb_node *get_mod_tree_rb_node()
{
int key = 0;
u64 *addr = (u64 *) bpf_map_lookup_elem(&module_context_map, &key);
if (addr == NULL)
return NULL;

return (struct rb_node *) *addr;
}

SEC("uprobe/lkm_seeker_modtree_1_tail")
int lkm_seeker_modtree_1_tail(struct pt_regs *ctx)
{
program_data_t p = {};
if (!init_tailcall_program_data(&p, ctx))
return -1;

struct rb_node *curr = get_mod_tree_rb_node();
if (curr == NULL)
return -1;

int idx = get_mod_tree_rb_idx();
if (idx == -1)
return -1;

u32 flags = HISTORY_SCAN_FINISHED;
int ret = mod_tree_loop(&p, curr, idx);
if (ret == 0) {
lkm_seeker_send_to_userspace((struct module *) HISTORY_SCAN_SUCCESSFUL, &flags, &p);
} else if (ret == HID_MOD_UNCOMPLETED_ITERATIONS) { // Continue doing more iterations
bpf_tail_call(ctx, &prog_array, TAIL_HIDDEN_KERNEL_MODULE_MODTREE_2);
} else {
tracee_log(ctx, BPF_LOG_LVL_WARN, BPF_LOG_ID_HID_KER_MOD, ret);
lkm_seeker_send_to_userspace((struct module *) HISTORY_SCAN_FAILURE, &flags, &p);
}

bpf_tail_call(ctx, &prog_array, TAIL_HIDDEN_KERNEL_MODULE_PROC);

return 0;
}

SEC("uprobe/lkm_seeker_modtree_2_tail")
int lkm_seeker_modtree_2_tail(struct pt_regs *ctx)
{
program_data_t p = {};
if (!init_tailcall_program_data(&p, ctx))
return -1;

struct rb_node *curr = get_mod_tree_rb_node();
if (curr == NULL)
return -1;

int idx = get_mod_tree_rb_idx();
if (idx == -1)
return -1;

u32 flags = HISTORY_SCAN_FINISHED;
int ret = mod_tree_loop(&p, curr, idx);
if (ret == 0) {
lkm_seeker_send_to_userspace((struct module *) HISTORY_SCAN_SUCCESSFUL, &flags, &p);
} else if (ret == HID_MOD_UNCOMPLETED_ITERATIONS) { // Continue doing more iterations
bpf_tail_call(ctx, &prog_array, TAIL_HIDDEN_KERNEL_MODULE_MODTREE_3);
} else {
tracee_log(ctx, BPF_LOG_LVL_WARN, BPF_LOG_ID_HID_KER_MOD, ret);
lkm_seeker_send_to_userspace((struct module *) HISTORY_SCAN_FAILURE, &flags, &p);
}

bpf_tail_call(ctx, &prog_array, TAIL_HIDDEN_KERNEL_MODULE_PROC);

return -1;
}

SEC("uprobe/lkm_seeker_modtree_3_tail")
int lkm_seeker_modtree_3_tail(struct pt_regs *ctx)
{
program_data_t p = {};
if (!init_tailcall_program_data(&p, ctx))
return -1;

struct rb_node *curr = get_mod_tree_rb_node();
if (curr == NULL)
return -1;

int idx = get_mod_tree_rb_idx();
if (idx == -1)
return -1;

u32 flags = HISTORY_SCAN_FINISHED;
int ret = mod_tree_loop(&p, curr, idx);
if (ret == 0) {
lkm_seeker_send_to_userspace((struct module *) HISTORY_SCAN_SUCCESSFUL, &flags, &p);
} else if (ret == HID_MOD_UNCOMPLETED_ITERATIONS) { // Continue doing more iterations
bpf_tail_call(ctx, &prog_array, TAIL_HIDDEN_KERNEL_MODULE_MODTREE_4);
} else {
tracee_log(ctx, BPF_LOG_LVL_WARN, BPF_LOG_ID_HID_KER_MOD, ret);
lkm_seeker_send_to_userspace((struct module *) HISTORY_SCAN_FAILURE, &flags, &p);
}

bpf_tail_call(ctx, &prog_array, TAIL_HIDDEN_KERNEL_MODULE_PROC);

return -1;
}

SEC("uprobe/lkm_seeker_modtree_4_tail")
int lkm_seeker_modtree_4_tail(struct pt_regs *ctx)
{
program_data_t p = {};
if (!init_tailcall_program_data(&p, ctx))
return -1;

struct rb_node *curr = get_mod_tree_rb_node();
if (curr == NULL)
return -1;

int idx = get_mod_tree_rb_idx();
if (idx == -1)
return -1;

u32 flags = HISTORY_SCAN_FINISHED;
int ret = mod_tree_loop(&p, curr, idx);
if (ret == 0) {
lkm_seeker_send_to_userspace((struct module *) HISTORY_SCAN_SUCCESSFUL, &flags, &p);
} else {
tracee_log(ctx, BPF_LOG_LVL_WARN, BPF_LOG_ID_HID_KER_MOD, ret);
lkm_seeker_send_to_userspace((struct module *) HISTORY_SCAN_FAILURE, &flags, &p);
}

bpf_tail_call(ctx, &prog_array, TAIL_HIDDEN_KERNEL_MODULE_PROC);

return -1;
}

statfunc int find_modules_from_mod_tree(program_data_t *p)
{
Expand All @@ -989,9 +1142,12 @@ statfunc int find_modules_from_mod_tree(program_data_t *p)
seq = BPF_CORE_READ(m_tree, root.seq.seqcount.sequence); // version >= v5.10
}

struct rb_node *node = BPF_CORE_READ(m_tree, root.tree[seq & 1].rb_node);
int key = 1;
int idx = seq & 1;
bpf_map_update_elem(&module_context_map, &key, &idx, BPF_ANY);

return walk_mod_tree(p, node, seq & 1);
struct rb_node *node = BPF_CORE_READ(m_tree, root.tree[idx].rb_node);
return mod_tree_loop(p, node, idx);
}

static __always_inline u64 check_new_mods_only(program_data_t *p)
Expand Down Expand Up @@ -1222,18 +1378,16 @@ int lkm_seeker_mod_tree_tail(struct pt_regs *ctx)
// This method is efficient only when the kernel is compiled with
// CONFIG_MODULES_TREE_LOOKUP=y
int ret = find_modules_from_mod_tree(&p);
if (ret < 0) {
if (ret == 0) {
lkm_seeker_send_to_userspace((struct module *) HISTORY_SCAN_SUCCESSFUL, &flags, &p);
} else if (ret == HID_MOD_UNCOMPLETED_ITERATIONS) { // Continue doing more iterations
bpf_tail_call(ctx, &prog_array, TAIL_HIDDEN_KERNEL_MODULE_MODTREE_1);
} else {
tracee_log(ctx, BPF_LOG_LVL_WARN, BPF_LOG_ID_HID_KER_MOD, ret);
lkm_seeker_send_to_userspace(
(struct module *) HISTORY_SCAN_FAILURE, &flags, &p); // Report failure of history scan
return -1;
lkm_seeker_send_to_userspace((struct module *) HISTORY_SCAN_FAILURE, &flags, &p);
}

// Report to userspace that the history scan finished successfully
lkm_seeker_send_to_userspace((struct module *) HISTORY_SCAN_SUCCESSFUL, &flags, &p);

bpf_tail_call(ctx, &prog_array, TAIL_HIDDEN_KERNEL_MODULE_PROC);

return -1;
}

Expand Down
1 change: 0 additions & 1 deletion pkg/ebpf/c/tracee.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ statfunc int init_shown_modules();
statfunc int is_hidden(u64);
statfunc int find_modules_from_module_kset_list(program_data_t *);
statfunc struct latch_tree_node *__lt_from_rb(struct rb_node *, int);
statfunc int walk_mod_tree(program_data_t *p, struct rb_node *, int);
statfunc int find_modules_from_mod_tree(program_data_t *);
statfunc int check_is_proc_modules_hooked(program_data_t *);

Expand Down
4 changes: 4 additions & 0 deletions pkg/events/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -12132,6 +12132,10 @@ var CoreEvents = map[ID]Definition{
{"prog_array", "lkm_seeker_kset_tail", []uint32{TailHiddenKernelModuleKset}},
{"prog_array", "lkm_seeker_mod_tree_tail", []uint32{TailHiddenKernelModuleModTree}},
{"prog_array", "lkm_seeker_new_mod_only_tail", []uint32{TailHiddenKernelModuleNewModOnly}},
{"prog_array", "lkm_seeker_modtree_1_tail", []uint32{TailHiddenKernelModuleModTree1}},
{"prog_array", "lkm_seeker_modtree_2_tail", []uint32{TailHiddenKernelModuleModTree2}},
{"prog_array", "lkm_seeker_modtree_3_tail", []uint32{TailHiddenKernelModuleModTree3}},
{"prog_array", "lkm_seeker_modtree_4_tail", []uint32{TailHiddenKernelModuleModTree4}},
},
},
sets: []string{},
Expand Down
4 changes: 4 additions & 0 deletions pkg/events/definition_dependencies.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ const (
TailHiddenKernelModuleKset
TailHiddenKernelModuleModTree
TailHiddenKernelModuleNewModOnly
TailHiddenKernelModuleModTree1
TailHiddenKernelModuleModTree2
TailHiddenKernelModuleModTree3
TailHiddenKernelModuleModTree4
MaxTail
)

Expand Down
8 changes: 5 additions & 3 deletions pkg/events/derive/hidden_kernel_module.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,15 +165,17 @@ func handleHistoryScanFinished(scanStatus uint64) ([][]interface{}, []error) {
// extractFromEvent extract arguments from the trace.Argument
func extractFromEvent(args []trace.Argument, address uint64) []interface{} {
// Parse module name if possible
var name string
name := ""
nameBytes, err := parse.ArgVal[[]byte](args, "name")
if err != nil {
name = ""
// Don't fail hard, submit it without a name!
logger.Debugw("Failed extracting hidden module name")
} else {
// Remove the trailing terminating characters.
name = string(nameBytes[:bytes.IndexByte(nameBytes[:], 0)])
index := bytes.IndexByte(nameBytes[:], 0)
if index > 0 {
name = string(nameBytes[:index])
}
}

// Parse module srcversion if possible
Expand Down

0 comments on commit 30f9723

Please sign in to comment.