diff --git a/bpf/include/api.h b/bpf/include/api.h index 9a83dbdd68e..4994824e9d4 100644 --- a/bpf/include/api.h +++ b/bpf/include/api.h @@ -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 diff --git a/bpf/lib/common.h b/bpf/lib/common.h index acd23496346..48a9b5718a4 100644 --- a/bpf/lib/common.h +++ b/bpf/lib/common.h @@ -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 { diff --git a/bpf/process/types/basic.h b/bpf/process/types/basic.h index 06de0defca1..b2fbb5dd818 100644 --- a/bpf/process/types/basic.h +++ b/bpf/process/types/basic.h @@ -335,7 +335,7 @@ parse_iovec_array(long off, unsigned long arg, int i, unsigned long max, #define MAX_STRING_FILTER 32 #endif -FUNC_INLINE long copy_path(char *args, const struct path *arg) +FUNC_INLINE long copy_path(char *args, const struct path *arg, bool reserve) { int *s = (int *)args; int size = 0, flags = 0; @@ -380,6 +380,17 @@ FUNC_INLINE long copy_path(char *args, const struct path *arg) a: size += sizeof(u32) + sizeof(u16); // for the flags + i_mode + /* + * hash information format is: + * ---------------------- + * | 4 bytes | 64 bytes | + * | algo | hash | + * ---------------------- + * Reserve a place for IMA hash information. + */ + if (reserve) + size += sizeof(u32) + 64; + return size; } @@ -2160,6 +2171,52 @@ FUNC_INLINE void do_action_notify_enforcer(int error, int signal) #define do_action_notify_enforcer(error, signal) #endif +#if defined GENERIC_LSM && defined __LARGE_MAP_KEYS +FUNC_INLINE bool +get_ima_hash(struct bpf_map_def *config_map, struct msg_generic_kprobe *e, __u32 idx) +{ + unsigned long a; + struct event_config *config; + long ty; + int pathlen, hash_algo = -95; // EOPNOTSUPP + char *args = e->args; + + config = map_lookup_elem(config_map, &e->idx); + if (!config) + return false; + a = (&e->a0)[idx]; + ty = (&config->arg0)[idx]; + args = args_off(e, e->argsoff[idx & MAX_SELECTORS_MASK]); + pathlen = *(int *)args; + args += pathlen + 6; + if (ty == file_ty) { + struct file *file = (struct file *)a; +#ifdef __V61_BPF_PROG + hash_algo = ima_file_hash(file, args + 4, 64); +#else + hash_algo = ima_inode_hash(file->f_inode, args + 4, 64); +#endif /* __V61_BPF_PROG */ + *(int *)args = hash_algo; + return true; + } + if (ty == linux_binprm_type) { + struct linux_binprm *bprm = (struct linux_binprm *)a; +#ifdef __V61_BPF_PROG + hash_algo = ima_file_hash(bprm->file, args + 4, 64); +#else + struct file *file; + + a = (unsigned long)_(&bprm->file); + probe_read(&file, sizeof(file), (const void *)a); + hash_algo = ima_inode_hash(file->f_inode, args + 4, 64); +#endif /* __V61_BPF_PROG */ + *(int *)args = hash_algo; + return true; + } + return false; +} +#endif /* GENERIC_LSM */ + FUNC_LOCAL __u32 do_action(void *ctx, __u32 i, struct selector_action *actions, struct generic_maps *maps, bool *post) @@ -2211,6 +2268,15 @@ 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); } + +#if defined GENERIC_LSM && defined __LARGE_MAP_KEYS + __u32 ima_arg_idx = actions->act[++i]; + + if (ima_arg_idx >= 0 && ima_arg_idx < 5) { + e->common.flags |= MSG_COMMON_FLAG_IMA_HASH; + get_ima_hash(maps->config, e, ima_arg_idx); + } +#endif /* GENERIC_LSM */ break; } @@ -2443,6 +2509,7 @@ read_call_arg(void *ctx, struct msg_generic_kprobe *e, int index, int type, char *args = e->args; long size = -1; const struct path *path_arg = 0; + bool reserve = false; if (orig_off >= 16383 - min_size) { return 0; @@ -2470,6 +2537,7 @@ read_call_arg(void *ctx, struct msg_generic_kprobe *e, int index, int type, struct file *file; probe_read(&file, sizeof(file), &arg); path_arg = _(&file->f_path); + reserve = true; goto do_copy_path; } case path_ty: { @@ -2516,6 +2584,7 @@ read_call_arg(void *ctx, struct msg_generic_kprobe *e, int index, int type, arg = (unsigned long)_(&bprm->file); probe_read(&file, sizeof(file), (const void *)arg); path_arg = _(&file->f_path); + reserve = true; goto do_copy_path; } break; #endif @@ -2631,7 +2700,7 @@ read_call_arg(void *ctx, struct msg_generic_kprobe *e, int index, int type, return size; do_copy_path: - return copy_path(args, path_arg); + return copy_path(args, path_arg, reserve); } #endif /* __BASIC_H__ */ diff --git a/pkg/sensors/tracing/args.go b/pkg/sensors/tracing/args.go index f9a673cf596..0aabcf39e2f 100644 --- a/pkg/sensors/tracing/args.go +++ b/pkg/sensors/tracing/args.go @@ -74,6 +74,25 @@ func getTracepointMetaValue(arg *v1alpha1.KProbeArg) int { return 0 } +// getImaHash parses hash information encoded from BPF copy_strings in the form: +// *---------*----------* +// | 4 bytes | 64 bytes | +// | algo | hash | +// *---------*----------* +func getImaHash(r *bytes.Reader) (int32, []byte) { + var hashAlgo int32 + err := binary.Read(r, binary.LittleEndian, &hashAlgo) + if err != nil { + return -1, nil + } + hash := make([]byte, 64) + err = binary.Read(r, binary.LittleEndian, hash) + if err != nil { + return -1, nil + } + return hashAlgo, hash +} + func getArg(r *bytes.Reader, a argPrinter) api.MsgGenericKprobeArg { var err error @@ -133,6 +152,9 @@ func getArg(r *bytes.Reader, a argPrinter) api.MsgGenericKprobeArg { arg.Flags = flags arg.Label = a.label + if a.ty == gt.GenericFileType { + getImaHash(r) + } return arg case gt.GenericPathType: var arg api.MsgGenericKprobeArgPath @@ -539,6 +561,7 @@ func getArg(r *bytes.Reader, a argPrinter) api.MsgGenericKprobeArg { arg.Flags = flags arg.Permission = mode arg.Label = a.label + getImaHash(r) return arg default: logger.GetLogger().WithError(err).WithField("event-type", a.ty).Warnf("Unknown event type")