Skip to content

Commit

Permalink
bpf: Add lsm.s/* bpf programs for IMA hash collection
Browse files Browse the repository at this point in the history
Due to restrictions of bpf sleepable programs (no tailcalls,
no perf buffer maps, etc.), we need to tail call to lsm.s
program and store hashes in separate bpf_map after event is posted.

Signed-off-by: Andrei Fedotov <[email protected]>
  • Loading branch information
anfedotoff committed Aug 27, 2024
1 parent 17c5346 commit e38e738
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 0 deletions.
4 changes: 4 additions & 0 deletions bpf/include/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,10 @@ static long BPF_FUNC(dynptr_read, void *dst, uint32_t len, const struct bpf_dynp
static long BPF_FUNC(dynptr_write, const struct bpf_dynptr *dst, uint32_t offset, void *src, uint32_t len, uint64_t flags);
static void BPF_FUNC(dynptr_data, const struct bpf_dynptr *ptr, uint32_t offset, uint32_t len);

/* LSM */
static long BPF_FUNC(ima_file_hash, struct file *file, void *dst, uint32_t size);
static long BPF_FUNC(ima_inode_hash, struct inode *inode, void *dst, uint32_t size);

/** LLVM built-ins, mem*() routines work for constant size */

#ifndef lock_xadd
Expand Down
1 change: 1 addition & 0 deletions bpf/lib/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#define MSG_COMMON_FLAG_RETURN BIT(0)
#define MSG_COMMON_FLAG_KERNEL_STACKTRACE BIT(1)
#define MSG_COMMON_FLAG_USER_STACKTRACE BIT(2)
#define MSG_COMMON_FLAG_IMA_HASH BIT(3)

/* Msg Layout */
struct msg_common {
Expand Down
83 changes: 83 additions & 0 deletions bpf/process/bpf_generic_lsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,20 @@ struct {
__type(value, struct event_config);
} config_map SEC(".maps");

#ifdef __LARGE_MAP_KEYS
struct ima_hash {
int algo;
char hash[64];
};

struct {
__uint(type, BPF_MAP_TYPE_LRU_HASH);
__uint(max_entries, 1024);
__type(key, struct msg_execve_key);
__type(value, struct ima_hash);
} ima_hash_map SEC(".maps");
#endif

#ifdef __LARGE_BPF_PROG
struct {
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
Expand Down Expand Up @@ -154,6 +168,75 @@ __attribute__((section("lsm/5"), used)) int
generic_lsm_output(void *ctx)
{
generic_output(ctx, (struct bpf_map_def *)&process_call_heap, MSG_OP_GENERIC_LSM);
#ifdef __LARGE_MAP_KEYS
struct msg_generic_kprobe *e;
int zero = 0;

e = map_lookup_elem(&process_call_heap, &zero);
if (e && e->common.flags & MSG_COMMON_FLAG_IMA_HASH)
tail_call(ctx, &lsm_calls, TAIL_CALL_IMA_HASH);
#endif
return try_override(ctx);
}

#ifdef __LARGE_MAP_KEYS
__attribute__((section("lsm.s/file_open"), used)) int
BPF_PROG(ima_file_open, struct file *file)
{
struct ima_hash hash;
struct msg_generic_kprobe *e;
int zero = 0;

e = map_lookup_elem(&process_call_heap, &zero);
if (!e)
return 0;
#ifdef __V61_BPF_PROG
hash.algo = ima_file_hash(file, &hash.hash, 64);
#else
hash.algo = ima_inode_hash(file->f_inode, &hash.hash, 64);
#endif
map_update_elem(&ima_hash_map, &e->current, &hash, BPF_ANY);

return try_override(ctx);
}

__attribute__((section("lsm.s/mmap_file"), used)) int
BPF_PROG(ima_mmap_file, struct file *file, unsigned long prot, unsigned long flags)
{
struct ima_hash hash;
struct msg_generic_kprobe *e;
int zero = 0;

e = map_lookup_elem(&process_call_heap, &zero);
if (!e)
return 0;
#ifdef __V61_BPF_PROG
hash.algo = ima_file_hash(file, &hash.hash, 64);
#else
hash.algo = ima_inode_hash(file->f_inode, &hash.hash, 64);
#endif
map_update_elem(&ima_hash_map, &e->current, &hash, BPF_ANY);

return try_override(ctx);
}

__attribute__((section("lsm.s/bprm_check_security"), used)) int
BPF_PROG(ima_bprm_check_security, struct linux_binprm *bprm)
{
struct ima_hash hash;
struct msg_generic_kprobe *e;
int zero = 0;

e = map_lookup_elem(&process_call_heap, &zero);
if (!e)
return 0;
#ifdef __V61_BPF_PROG
hash.algo = ima_file_hash(bprm->file, &hash.hash, 64);
#else
hash.algo = ima_inode_hash(bprm->file->f_inode, &hash.hash, 64);
#endif
map_update_elem(&ima_hash_map, &e->current, &hash, BPF_ANY);

return try_override(ctx);
}
#endif
7 changes: 7 additions & 0 deletions bpf/process/types/basic.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ enum {
TAIL_CALL_ARGS = 3,
TAIL_CALL_ACTIONS = 4,
TAIL_CALL_SEND = 5,
TAIL_CALL_IMA_HASH = 6,
};

struct generic_maps {
Expand Down Expand Up @@ -2211,6 +2212,12 @@ do_action(void *ctx, __u32 i, struct selector_action *actions,
e->common.flags |= MSG_COMMON_FLAG_USER_STACKTRACE;
e->user_stack_id = get_stackid(ctx, &stack_trace_map, BPF_F_USER_STACK);
}
#ifdef __LARGE_MAP_KEYS
__u32 ima_hash = actions->act[++i];

if (ima_hash)
e->common.flags |= MSG_COMMON_FLAG_IMA_HASH;
#endif
break;
}

Expand Down
3 changes: 3 additions & 0 deletions pkg/sensors/program/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,9 @@ func TracingAttach() AttachFunc {

func LSMOpen(load *Program) OpenFunc {
return func(coll *ebpf.CollectionSpec) error {
delete(coll.Programs, "ima_file_open")
delete(coll.Programs, "ima_mmap_file")
delete(coll.Programs, "ima_bprm_check_security")
for _, prog := range coll.Programs {
if prog.AttachType == ebpf.AttachLSMMac {
prog.AttachTo = load.Attach
Expand Down
4 changes: 4 additions & 0 deletions pkg/sensors/tracing/lsm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ func TestLSMObjectLoad(t *testing.T) {
// generic_lsm_process_event*,generic_lsm_output
tus.SensorMap{Name: "tcpmon_map", Progs: []uint{1, 2, 6}},
}
if kernels.MinKernelVersion("5.11") {
// all LSM programs
sensorMaps[1] = tus.SensorMap{Name: "lsm_calls", Progs: []uint{0, 1, 2, 3, 4, 5, 6}}
}

configHook := `
apiVersion: cilium.io/v1alpha1
Expand Down

0 comments on commit e38e738

Please sign in to comment.