Skip to content

Commit ecbf722

Browse files
authored
fix(events): fix hidden_kernel_module history scan for kernels >6.2 (#4422)
- also address potential slice out of bounds for name argument in hidden_kernel_module.go
1 parent 7ec7907 commit ecbf722

File tree

6 files changed

+88
-34
lines changed

6 files changed

+88
-34
lines changed

pkg/ebpf/c/maps.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ enum tail_call_id_e
2222
TAIL_HIDDEN_KERNEL_MODULE_KSET,
2323
TAIL_HIDDEN_KERNEL_MODULE_MOD_TREE,
2424
TAIL_HIDDEN_KERNEL_MODULE_NEW_MOD_ONLY,
25+
TAIL_HIDDEN_KERNEL_MODULE_MODTREE_LOOP,
2526
MAX_TAIL_CALL
2627
};
2728

pkg/ebpf/c/tracee.bpf.c

Lines changed: 80 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -726,10 +726,12 @@ int tracepoint__sched__sched_process_fork(struct bpf_raw_tracepoint_args *ctx)
726726
return 0;
727727
}
728728

729-
// number of iterations - value that the verifier was seen to cope with - the higher, the better
730-
#define MAX_NUM_MODULES 440
731-
#define HISTORY_SCAN_FAILURE 0
732-
#define HISTORY_SCAN_SUCCESSFUL 1
729+
#define MAX_NUM_MODULES 440
730+
#define MAX_MODULES_MAP_ENTRIES 2 * MAX_NUM_MODULES
731+
#define MOD_TREE_LOOP_ITERATIONS 240
732+
#define MOD_TREE_LOOP_DEPTH 14
733+
#define HISTORY_SCAN_FAILURE 0
734+
#define HISTORY_SCAN_SUCCESSFUL 1
733735

734736
enum
735737
{
@@ -747,7 +749,7 @@ enum
747749

748750
struct modules_map {
749751
__uint(type, BPF_MAP_TYPE_HASH);
750-
__uint(max_entries, MAX_NUM_MODULES);
752+
__uint(max_entries, MAX_MODULES_MAP_ENTRIES);
751753
__type(key, u64);
752754
__type(value, kernel_module_t);
753755
} modules_map SEC(".maps");
@@ -763,6 +765,21 @@ struct new_module_map {
763765

764766
typedef struct new_module_map new_module_map_t;
765767

768+
typedef struct module_context_args {
769+
struct rb_node *curr;
770+
int iteration_num;
771+
int idx;
772+
} module_context_args_t;
773+
774+
struct module_context_map {
775+
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
776+
__uint(max_entries, 1);
777+
__type(key, u32);
778+
__type(value, module_context_args_t);
779+
} module_context_map SEC(".maps");
780+
781+
typedef struct module_context_map module_context_map_t;
782+
766783
// We only care for modules that got deleted or inserted between our scan and if
767784
// we detected something suspicious. Since it's a very small time frame, it's
768785
// not likely that a large amount of modules will be deleted. Instead of saving
@@ -786,6 +803,7 @@ u64 last_module_insert_time = 0;
786803
bool hidden_old_mod_scan_done = false;
787804
static const int HID_MOD_RACE_CONDITION = -1;
788805
static const int HID_MOD_UNCOMPLETED_ITERATIONS = -2;
806+
static const int HID_MOD_COMPLETED_ITERATIONS = 0;
789807
static const int HID_MOD_MEM_ZEROED = -3;
790808
static const int MOD_HIDDEN = 1;
791809
static const int MOD_NOT_HIDDEN = 0;
@@ -841,7 +859,6 @@ statfunc int init_shown_modules()
841859
if (&pos->list == head) {
842860
return 0;
843861
}
844-
845862
bpf_map_update_elem(&modules_map, &pos, &ker_mod, BPF_ANY);
846863
}
847864

@@ -933,15 +950,34 @@ statfunc struct latch_tree_node *__lt_from_rb(struct rb_node *node, int idx)
933950
return container_of(node, struct latch_tree_node, node[idx]);
934951
}
935952

936-
statfunc int walk_mod_tree(program_data_t *p, struct rb_node *root, int idx)
953+
struct mod_tree_root {
954+
struct latch_tree_root root;
955+
};
956+
957+
SEC("uprobe/lkm_seeker_modtree_loop_tail")
958+
int lkm_seeker_modtree_loop(struct pt_regs *ctx)
937959
{
960+
program_data_t p = {};
961+
if (!init_tailcall_program_data(&p, ctx))
962+
return -1;
963+
938964
struct latch_tree_node *ltn;
939965
struct module *mod;
940-
struct rb_node *curr = root;
941966
u32 flags = MOD_TREE;
942967

968+
int key = 0;
969+
module_context_args_t *module_ctx_args = bpf_map_lookup_elem(&module_context_map, &key);
970+
if (module_ctx_args == NULL)
971+
return -1;
972+
973+
struct rb_node *curr = module_ctx_args->curr;
974+
int idx = module_ctx_args->idx;
975+
int iteration_num = module_ctx_args->iteration_num;
976+
977+
int loop_result = HID_MOD_UNCOMPLETED_ITERATIONS;
978+
943979
#pragma unroll
944-
for (int i = 0; i < MAX_NUM_MODULES; i++) {
980+
for (int i = 0; i < MOD_TREE_LOOP_ITERATIONS; i++) {
945981
if (curr != NULL) {
946982
rb_node_t rb_nod = {.node = curr};
947983
bpf_map_push_elem(&walk_mod_tree_queue, &rb_nod, BPF_EXIST);
@@ -950,17 +986,19 @@ statfunc int walk_mod_tree(program_data_t *p, struct rb_node *root, int idx)
950986
} else {
951987
rb_node_t rb_nod;
952988
if (bpf_map_pop_elem(&walk_mod_tree_queue, &rb_nod) != 0) {
953-
return 0; // Finished iterating
989+
loop_result = HID_MOD_COMPLETED_ITERATIONS;
990+
break;
954991
} else {
955992
curr = rb_nod.node;
956993
ltn = __lt_from_rb(curr, idx);
957994
mod = BPF_CORE_READ(container_of(ltn, struct mod_tree_node, node), mod);
958995

959996
int ret = is_hidden((u64) mod);
960997
if (ret == MOD_HIDDEN) {
961-
lkm_seeker_send_to_userspace(mod, &flags, p);
998+
lkm_seeker_send_to_userspace(mod, &flags, &p);
962999
} else if (ret == HID_MOD_RACE_CONDITION) {
963-
return ret;
1000+
loop_result = HID_MOD_RACE_CONDITION;
1001+
break;
9641002
}
9651003

9661004
/* We have visited the node and its left subtree.
@@ -970,12 +1008,27 @@ statfunc int walk_mod_tree(program_data_t *p, struct rb_node *root, int idx)
9701008
}
9711009
}
9721010

973-
return HID_MOD_UNCOMPLETED_ITERATIONS;
974-
}
1011+
iteration_num++;
9751012

976-
struct mod_tree_root {
977-
struct latch_tree_root root;
978-
};
1013+
if (loop_result == HID_MOD_COMPLETED_ITERATIONS) {
1014+
flags = HISTORY_SCAN_FINISHED;
1015+
lkm_seeker_send_to_userspace((struct module *) HISTORY_SCAN_SUCCESSFUL, &flags, &p);
1016+
bpf_tail_call(ctx, &prog_array, TAIL_HIDDEN_KERNEL_MODULE_PROC);
1017+
} else if (loop_result == HID_MOD_RACE_CONDITION || iteration_num == MOD_TREE_LOOP_DEPTH) {
1018+
flags = HISTORY_SCAN_FINISHED;
1019+
tracee_log(ctx, BPF_LOG_LVL_WARN, BPF_LOG_ID_HID_KER_MOD, loop_result ^ iteration_num);
1020+
lkm_seeker_send_to_userspace((struct module *) HISTORY_SCAN_FAILURE, &flags, &p);
1021+
bpf_tail_call(ctx, &prog_array, TAIL_HIDDEN_KERNEL_MODULE_PROC);
1022+
}
1023+
1024+
// Update context args for the next recursive call
1025+
module_ctx_args->iteration_num = iteration_num;
1026+
module_ctx_args->curr = curr;
1027+
1028+
bpf_tail_call(ctx, &prog_array, TAIL_HIDDEN_KERNEL_MODULE_MODTREE_LOOP);
1029+
1030+
return -1;
1031+
}
9791032

9801033
statfunc int find_modules_from_mod_tree(program_data_t *p)
9811034
{
@@ -989,9 +1042,16 @@ statfunc int find_modules_from_mod_tree(program_data_t *p)
9891042
seq = BPF_CORE_READ(m_tree, root.seq.seqcount.sequence); // version >= v5.10
9901043
}
9911044

992-
struct rb_node *node = BPF_CORE_READ(m_tree, root.tree[seq & 1].rb_node);
1045+
int idx = seq & 1;
1046+
struct rb_node *root = BPF_CORE_READ(m_tree, root.tree[idx].rb_node);
1047+
module_context_args_t module_ctx_args = {.idx = idx, .iteration_num = 0, .curr = root};
1048+
1049+
int key = 0;
1050+
bpf_map_update_elem(&module_context_map, &key, &module_ctx_args, BPF_ANY);
9931051

994-
return walk_mod_tree(p, node, seq & 1);
1052+
bpf_tail_call(p->ctx, &prog_array, TAIL_HIDDEN_KERNEL_MODULE_MODTREE_LOOP);
1053+
1054+
return -1;
9951055
}
9961056

9971057
static __always_inline u64 check_new_mods_only(program_data_t *p)
@@ -1221,19 +1281,9 @@ int lkm_seeker_mod_tree_tail(struct pt_regs *ctx)
12211281

12221282
// This method is efficient only when the kernel is compiled with
12231283
// CONFIG_MODULES_TREE_LOOKUP=y
1224-
int ret = find_modules_from_mod_tree(&p);
1225-
if (ret < 0) {
1226-
tracee_log(ctx, BPF_LOG_LVL_WARN, BPF_LOG_ID_HID_KER_MOD, ret);
1227-
lkm_seeker_send_to_userspace(
1228-
(struct module *) HISTORY_SCAN_FAILURE, &flags, &p); // Report failure of history scan
1229-
return -1;
1230-
}
1231-
1232-
// Report to userspace that the history scan finished successfully
1233-
lkm_seeker_send_to_userspace((struct module *) HISTORY_SCAN_SUCCESSFUL, &flags, &p);
1284+
find_modules_from_mod_tree(&p);
12341285

12351286
bpf_tail_call(ctx, &prog_array, TAIL_HIDDEN_KERNEL_MODULE_PROC);
1236-
12371287
return -1;
12381288
}
12391289

pkg/ebpf/c/tracee.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ statfunc int init_shown_modules();
3535
statfunc int is_hidden(u64);
3636
statfunc int find_modules_from_module_kset_list(program_data_t *);
3737
statfunc struct latch_tree_node *__lt_from_rb(struct rb_node *, int);
38-
statfunc int walk_mod_tree(program_data_t *p, struct rb_node *, int);
3938
statfunc int find_modules_from_mod_tree(program_data_t *);
4039
statfunc int check_is_proc_modules_hooked(program_data_t *);
4140

pkg/events/core.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12131,6 +12131,7 @@ var CoreEvents = map[ID]Definition{
1213112131
{"prog_array", "lkm_seeker_kset_tail", []uint32{TailHiddenKernelModuleKset}},
1213212132
{"prog_array", "lkm_seeker_mod_tree_tail", []uint32{TailHiddenKernelModuleModTree}},
1213312133
{"prog_array", "lkm_seeker_new_mod_only_tail", []uint32{TailHiddenKernelModuleNewModOnly}},
12134+
{"prog_array", "lkm_seeker_modtree_loop", []uint32{TailHiddenKernelModuleModTreeLoop}},
1213412135
},
1213512136
},
1213612137
sets: []string{},

pkg/events/definition_dependencies.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ const (
152152
TailHiddenKernelModuleKset
153153
TailHiddenKernelModuleModTree
154154
TailHiddenKernelModuleNewModOnly
155+
TailHiddenKernelModuleModTreeLoop
155156
MaxTail
156157
)
157158

pkg/events/derive/hidden_kernel_module.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,15 +165,17 @@ func handleHistoryScanFinished(scanStatus uint64) ([][]interface{}, []error) {
165165
// extractFromEvent extract arguments from the trace.Argument
166166
func extractFromEvent(args []trace.Argument, address uint64) []interface{} {
167167
// Parse module name if possible
168-
var name string
168+
name := ""
169169
nameBytes, err := parse.ArgVal[[]byte](args, "name")
170170
if err != nil {
171-
name = ""
172171
// Don't fail hard, submit it without a name!
173172
logger.Debugw("Failed extracting hidden module name")
174173
} else {
175174
// Remove the trailing terminating characters.
176-
name = string(nameBytes[:bytes.IndexByte(nameBytes[:], 0)])
175+
index := bytes.IndexByte(nameBytes[:], 0)
176+
if index > 0 {
177+
name = string(nameBytes[:index])
178+
}
177179
}
178180

179181
// Parse module srcversion if possible

0 commit comments

Comments
 (0)