Skip to content

Commit

Permalink
bpf: Add IMA hash collection for file and linux_binprm args
Browse files Browse the repository at this point in the history
Storing hash in msg_generic_kprobe args after path object.
Hash information format is:
----------------------
| 4 bytes | 64 bytes |
| algo    |  hash    |
----------------------

Signed-off-by: Andrei Fedotov <[email protected]>
  • Loading branch information
anfedotoff committed Aug 16, 2024
1 parent ecdb38f commit 15d918b
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 2 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
73 changes: 71 additions & 2 deletions bpf/process/types/basic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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: {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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__ */
23 changes: 23 additions & 0 deletions pkg/sensors/tracing/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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")
Expand Down

0 comments on commit 15d918b

Please sign in to comment.