bpf: Add a BPF helper for getting the IMA hash of an inode
authorKP Singh <kpsingh@google.com>
Tue, 24 Nov 2020 15:12:09 +0000 (15:12 +0000)
committerDaniel Borkmann <daniel@iogearbox.net>
Wed, 25 Nov 2020 23:04:04 +0000 (00:04 +0100)
Provide a wrapper function to get the IMA hash of an inode. This helper
is useful in fingerprinting files (e.g executables on execution) and
using these fingerprints in detections like an executable unlinking
itself.

Since the ima_inode_hash can sleep, it's only allowed for sleepable
LSM hooks.

Signed-off-by: KP Singh <kpsingh@google.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/bpf/20201124151210.1081188-3-kpsingh@chromium.org
include/uapi/linux/bpf.h
kernel/bpf/bpf_lsm.c
scripts/bpf_helpers_doc.py
tools/include/uapi/linux/bpf.h

index 3ca6146f001ae1694ca3301111259c118b5afada..c3458ec1f30a4ae59ad78e9548601d66168d0dba 100644 (file)
@@ -3807,6 +3807,16 @@ union bpf_attr {
  *             See: **clock_gettime**\ (**CLOCK_MONOTONIC_COARSE**)
  *     Return
  *             Current *ktime*.
+ *
+ * long bpf_ima_inode_hash(struct inode *inode, void *dst, u32 size)
+ *     Description
+ *             Returns the stored IMA hash of the *inode* (if it's avaialable).
+ *             If the hash is larger than *size*, then only *size*
+ *             bytes will be copied to *dst*
+ *     Return
+ *             The **hash_algo** is returned on success,
+ *             **-EOPNOTSUP** if IMA is disabled or **-EINVAL** if
+ *             invalid arguments are passed.
  */
 #define __BPF_FUNC_MAPPER(FN)          \
        FN(unspec),                     \
@@ -3970,6 +3980,7 @@ union bpf_attr {
        FN(get_current_task_btf),       \
        FN(bprm_opts_set),              \
        FN(ktime_get_coarse_ns),        \
+       FN(ima_inode_hash),             \
        /* */
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
index b4f27a87409211dc1308de1a3f615b9d1f2a88f1..70e5e0b6d69d0d591b1cfd9c7ff516bc927c0fcf 100644 (file)
@@ -15,6 +15,7 @@
 #include <net/bpf_sk_storage.h>
 #include <linux/bpf_local_storage.h>
 #include <linux/btf_ids.h>
+#include <linux/ima.h>
 
 /* For every LSM hook that allows attachment of BPF programs, declare a nop
  * function where a BPF program can be attached.
@@ -75,6 +76,29 @@ const static struct bpf_func_proto bpf_bprm_opts_set_proto = {
        .arg2_type      = ARG_ANYTHING,
 };
 
+BPF_CALL_3(bpf_ima_inode_hash, struct inode *, inode, void *, dst, u32, size)
+{
+       return ima_inode_hash(inode, dst, size);
+}
+
+static bool bpf_ima_inode_hash_allowed(const struct bpf_prog *prog)
+{
+       return bpf_lsm_is_sleepable_hook(prog->aux->attach_btf_id);
+}
+
+BTF_ID_LIST_SINGLE(bpf_ima_inode_hash_btf_ids, struct, inode)
+
+const static struct bpf_func_proto bpf_ima_inode_hash_proto = {
+       .func           = bpf_ima_inode_hash,
+       .gpl_only       = false,
+       .ret_type       = RET_INTEGER,
+       .arg1_type      = ARG_PTR_TO_BTF_ID,
+       .arg1_btf_id    = &bpf_ima_inode_hash_btf_ids[0],
+       .arg2_type      = ARG_PTR_TO_UNINIT_MEM,
+       .arg3_type      = ARG_CONST_SIZE,
+       .allowed        = bpf_ima_inode_hash_allowed,
+};
+
 static const struct bpf_func_proto *
 bpf_lsm_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
 {
@@ -97,6 +121,8 @@ bpf_lsm_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
                return &bpf_task_storage_delete_proto;
        case BPF_FUNC_bprm_opts_set:
                return &bpf_bprm_opts_set_proto;
+       case BPF_FUNC_ima_inode_hash:
+               return prog->aux->sleepable ? &bpf_ima_inode_hash_proto : NULL;
        default:
                return tracing_prog_func_proto(func_id, prog);
        }
index c5bc947a70ada9115599a61d81b644ab892acc7d..8b829748d4887e3c4eb3def30bf83ba264eb5d4d 100755 (executable)
@@ -436,6 +436,7 @@ class PrinterHelpers(Printer):
             'struct xdp_md',
             'struct path',
             'struct btf_ptr',
+            'struct inode',
     ]
     known_types = {
             '...',
@@ -480,6 +481,7 @@ class PrinterHelpers(Printer):
             'struct task_struct',
             'struct path',
             'struct btf_ptr',
+            'struct inode',
     }
     mapped_types = {
             'u8': '__u8',
index 3ca6146f001ae1694ca3301111259c118b5afada..c3458ec1f30a4ae59ad78e9548601d66168d0dba 100644 (file)
@@ -3807,6 +3807,16 @@ union bpf_attr {
  *             See: **clock_gettime**\ (**CLOCK_MONOTONIC_COARSE**)
  *     Return
  *             Current *ktime*.
+ *
+ * long bpf_ima_inode_hash(struct inode *inode, void *dst, u32 size)
+ *     Description
+ *             Returns the stored IMA hash of the *inode* (if it's avaialable).
+ *             If the hash is larger than *size*, then only *size*
+ *             bytes will be copied to *dst*
+ *     Return
+ *             The **hash_algo** is returned on success,
+ *             **-EOPNOTSUP** if IMA is disabled or **-EINVAL** if
+ *             invalid arguments are passed.
  */
 #define __BPF_FUNC_MAPPER(FN)          \
        FN(unspec),                     \
@@ -3970,6 +3980,7 @@ union bpf_attr {
        FN(get_current_task_btf),       \
        FN(bprm_opts_set),              \
        FN(ktime_get_coarse_ns),        \
+       FN(ima_inode_hash),             \
        /* */
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper