2020-11-20 13:20:06

by KP Singh

[permalink] [raw]
Subject: [PATCH bpf-next 1/3] ima: Implement ima_inode_hash

From: KP Singh <[email protected]>

This is in preparation to add a helper for BPF LSM programs to use
IMA hashes when attached to LSM hooks. There are LSM hooks like
inode_unlink which do not have a struct file * argument and cannot
use the existing ima_file_hash API.

An inode based API is, therefore, useful in LSM based detections like an
executable trying to delete itself which rely on the inode_unlink LSM
hook.

Moreover, the ima_file_hash function does nothing with the struct file
pointer apart from calling file_inode on it and converting it to an
inode.

Signed-off-by: KP Singh <[email protected]>
---
include/linux/ima.h | 6 +++
scripts/bpf_helpers_doc.py | 1 +
security/integrity/ima/ima_main.c | 74 ++++++++++++++++++++++---------
3 files changed, 59 insertions(+), 22 deletions(-)

diff --git a/include/linux/ima.h b/include/linux/ima.h
index 8fa7bcfb2da2..7233a2751754 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -29,6 +29,7 @@ extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
enum kernel_read_file_id id);
extern void ima_post_path_mknod(struct dentry *dentry);
extern int ima_file_hash(struct file *file, char *buf, size_t buf_size);
+extern int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size);
extern void ima_kexec_cmdline(int kernel_fd, const void *buf, int size);

#ifdef CONFIG_IMA_KEXEC
@@ -115,6 +116,11 @@ static inline int ima_file_hash(struct file *file, char *buf, size_t buf_size)
return -EOPNOTSUPP;
}

+static inline int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size)
+{
+ return -EOPNOTSUPP;
+}
+
static inline void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) {}
#endif /* CONFIG_IMA */

diff --git a/scripts/bpf_helpers_doc.py b/scripts/bpf_helpers_doc.py
index c5bc947a70ad..add7fcb32dcd 100755
--- a/scripts/bpf_helpers_doc.py
+++ b/scripts/bpf_helpers_doc.py
@@ -478,6 +478,7 @@ class PrinterHelpers(Printer):
'struct tcp_request_sock',
'struct udp6_sock',
'struct task_struct',
+ 'struct inode',
'struct path',
'struct btf_ptr',
}
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 2d1af8899cab..1dd2123b5b43 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -501,37 +501,17 @@ int ima_file_check(struct file *file, int mask)
}
EXPORT_SYMBOL_GPL(ima_file_check);

-/**
- * ima_file_hash - return the stored measurement if a file has been hashed and
- * is in the iint cache.
- * @file: pointer to the file
- * @buf: buffer in which to store the hash
- * @buf_size: length of the buffer
- *
- * On success, return the hash algorithm (as defined in the enum hash_algo).
- * If buf is not NULL, this function also outputs the hash into buf.
- * If the hash is larger than buf_size, then only buf_size bytes will be copied.
- * It generally just makes sense to pass a buffer capable of holding the largest
- * possible hash: IMA_MAX_DIGEST_SIZE.
- * The file hash returned is based on the entire file, including the appended
- * signature.
- *
- * If IMA is disabled or if no measurement is available, return -EOPNOTSUPP.
- * If the parameters are incorrect, return -EINVAL.
- */
-int ima_file_hash(struct file *file, char *buf, size_t buf_size)
+static int __ima_inode_hash(struct inode *inode, char *buf, size_t buf_size)
{
- struct inode *inode;
struct integrity_iint_cache *iint;
int hash_algo;

- if (!file)
+ if (!inode)
return -EINVAL;

if (!ima_policy_flag)
return -EOPNOTSUPP;

- inode = file_inode(file);
iint = integrity_iint_find(inode);
if (!iint)
return -EOPNOTSUPP;
@@ -558,8 +538,58 @@ int ima_file_hash(struct file *file, char *buf, size_t buf_size)

return hash_algo;
}
+
+/**
+ * ima_file_hash - return the stored measurement if a file has been hashed and
+ * is in the iint cache.
+ * @file: pointer to the file
+ * @buf: buffer in which to store the hash
+ * @buf_size: length of the buffer
+ *
+ * On success, return the hash algorithm (as defined in the enum hash_algo).
+ * If buf is not NULL, this function also outputs the hash into buf.
+ * If the hash is larger than buf_size, then only buf_size bytes will be copied.
+ * It generally just makes sense to pass a buffer capable of holding the largest
+ * possible hash: IMA_MAX_DIGEST_SIZE.
+ * The file hash returned is based on the entire file, including the appended
+ * signature.
+ *
+ * If IMA is disabled or if no measurement is available, return -EOPNOTSUPP.
+ * If the parameters are incorrect, return -EINVAL.
+ */
+int ima_file_hash(struct file *file, char *buf, size_t buf_size)
+{
+ if (!file)
+ return -EINVAL;
+
+ return __ima_inode_hash(file_inode(file), buf, buf_size);
+}
EXPORT_SYMBOL_GPL(ima_file_hash);

+/**
+ * ima_inode_hash - return the stored measurement if the inode has been hashed
+ * and is in the iint cache.
+ * @inode: pointer to the inode
+ * @buf: buffer in which to store the hash
+ * @buf_size: length of the buffer
+ *
+ * On success, return the hash algorithm (as defined in the enum hash_algo).
+ * If buf is not NULL, this function also outputs the hash into buf.
+ * If the hash is larger than buf_size, then only buf_size bytes will be copied.
+ * It generally just makes sense to pass a buffer capable of holding the largest
+ * possible hash: IMA_MAX_DIGEST_SIZE.
+ * The hash returned is based on the entire contents, including the appended
+ * signature.
+ *
+ * If IMA is disabled or if no measurement is available, return -EOPNOTSUPP.
+ * If the parameters are incorrect, return -EINVAL.
+ */
+int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size)
+{
+ return __ima_inode_hash(inode, buf, buf_size);
+}
+EXPORT_SYMBOL_GPL(ima_inode_hash);
+
/**
* ima_post_create_tmpfile - mark newly created tmpfile as new
* @file : newly created tmpfile
--
2.29.2.454.gaff20da3a2-goog


2020-11-20 13:21:27

by KP Singh

[permalink] [raw]
Subject: [PATCH bpf-next 3/3] bpf: Update LSM selftests for bpf_ima_inode_hash

From: KP Singh <[email protected]>

- Update the IMA policy before executing the test binary (this is not an
override of the policy, just an append that ensures that hashes are
calculated on executions).

- Call the bpf_ima_inode_hash in the bprm_committed_creds hook and check
if the call succeeded and a hash was calculated.

Signed-off-by: KP Singh <[email protected]>
---
tools/testing/selftests/bpf/config | 3 ++
.../selftests/bpf/prog_tests/test_lsm.c | 32 +++++++++++++++++++
tools/testing/selftests/bpf/progs/lsm.c | 7 +++-
3 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config
index 2118e23ac07a..4b5764031368 100644
--- a/tools/testing/selftests/bpf/config
+++ b/tools/testing/selftests/bpf/config
@@ -39,3 +39,6 @@ CONFIG_BPF_JIT=y
CONFIG_BPF_LSM=y
CONFIG_SECURITY=y
CONFIG_LIRC=y
+CONFIG_IMA=y
+CONFIG_IMA_WRITE_POLICY=y
+CONFIG_IMA_READ_POLICY=y
diff --git a/tools/testing/selftests/bpf/prog_tests/test_lsm.c b/tools/testing/selftests/bpf/prog_tests/test_lsm.c
index 6ab29226c99b..3f5d64adb233 100644
--- a/tools/testing/selftests/bpf/prog_tests/test_lsm.c
+++ b/tools/testing/selftests/bpf/prog_tests/test_lsm.c
@@ -52,6 +52,28 @@ int exec_cmd(int *monitored_pid)
return -EINVAL;
}

+#define IMA_POLICY "measure func=BPRM_CHECK"
+
+/* This does not override the policy, IMA policy updates are
+ * append only, so this just ensures that "measure func=BPRM_CHECK"
+ * is in the policy. IMA does not allow us to remove this line once
+ * it is added.
+ */
+static int update_ima_policy(void)
+{
+ int fd, ret = 0;
+
+ fd = open("/sys/kernel/security/ima/policy", O_WRONLY);
+ if (fd < 0)
+ return -errno;
+
+ if (write(fd, IMA_POLICY, sizeof(IMA_POLICY)) == -1)
+ ret = -errno;
+
+ close(fd);
+ return ret;
+}
+
void test_test_lsm(void)
{
struct lsm *skel = NULL;
@@ -66,6 +88,10 @@ void test_test_lsm(void)
if (CHECK(err, "attach", "lsm attach failed: %d\n", err))
goto close_prog;

+ err = update_ima_policy();
+ if (CHECK(err != 0, "update_ima_policy", "error = %d\n", err))
+ goto close_prog;
+
err = exec_cmd(&skel->bss->monitored_pid);
if (CHECK(err < 0, "exec_cmd", "err %d errno %d\n", err, errno))
goto close_prog;
@@ -83,6 +109,12 @@ void test_test_lsm(void)
CHECK(skel->bss->mprotect_count != 1, "mprotect_count",
"mprotect_count = %d\n", skel->bss->mprotect_count);

+ CHECK(skel->data->ima_hash_ret < 0, "ima_hash_ret",
+ "ima_hash_ret = %d\n", skel->data->ima_hash_ret);
+
+ CHECK(skel->bss->ima_hash == 0, "ima_hash",
+ "ima_hash = %lu\n", skel->bss->ima_hash);
+
syscall(__NR_setdomainname, &buf, -2L);
syscall(__NR_setdomainname, 0, -3L);
syscall(__NR_setdomainname, ~0L, -4L);
diff --git a/tools/testing/selftests/bpf/progs/lsm.c b/tools/testing/selftests/bpf/progs/lsm.c
index ff4d343b94b5..b0f9639e4b0a 100644
--- a/tools/testing/selftests/bpf/progs/lsm.c
+++ b/tools/testing/selftests/bpf/progs/lsm.c
@@ -35,6 +35,8 @@ char _license[] SEC("license") = "GPL";
int monitored_pid = 0;
int mprotect_count = 0;
int bprm_count = 0;
+int ima_hash_ret = -1;
+u64 ima_hash = 0;

SEC("lsm/file_mprotect")
int BPF_PROG(test_int_hook, struct vm_area_struct *vma,
@@ -65,8 +67,11 @@ int BPF_PROG(test_void_hook, struct linux_binprm *bprm)
__u32 key = 0;
__u64 *value;

- if (monitored_pid == pid)
+ if (monitored_pid == pid) {
bprm_count++;
+ ima_hash_ret = bpf_ima_inode_hash(bprm->file->f_inode,
+ &ima_hash, sizeof(ima_hash));
+ }

bpf_copy_from_user(args, sizeof(args), (void *)bprm->vma->vm_mm->arg_start);
bpf_copy_from_user(args, sizeof(args), (void *)bprm->mm->arg_start);
--
2.29.2.454.gaff20da3a2-goog

2020-11-20 17:37:04

by Yonghong Song

[permalink] [raw]
Subject: Re: [PATCH bpf-next 1/3] ima: Implement ima_inode_hash



On 11/20/20 5:17 AM, KP Singh wrote:
> From: KP Singh <[email protected]>
>
> This is in preparation to add a helper for BPF LSM programs to use
> IMA hashes when attached to LSM hooks. There are LSM hooks like
> inode_unlink which do not have a struct file * argument and cannot
> use the existing ima_file_hash API.
>
> An inode based API is, therefore, useful in LSM based detections like an
> executable trying to delete itself which rely on the inode_unlink LSM
> hook.
>
> Moreover, the ima_file_hash function does nothing with the struct file
> pointer apart from calling file_inode on it and converting it to an
> inode.
>
> Signed-off-by: KP Singh <[email protected]>
> ---
> include/linux/ima.h | 6 +++
> scripts/bpf_helpers_doc.py | 1 +
> security/integrity/ima/ima_main.c | 74 ++++++++++++++++++++++---------
> 3 files changed, 59 insertions(+), 22 deletions(-)
>
> diff --git a/include/linux/ima.h b/include/linux/ima.h
> index 8fa7bcfb2da2..7233a2751754 100644
> --- a/include/linux/ima.h
> +++ b/include/linux/ima.h
> @@ -29,6 +29,7 @@ extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
> enum kernel_read_file_id id);
> extern void ima_post_path_mknod(struct dentry *dentry);
> extern int ima_file_hash(struct file *file, char *buf, size_t buf_size);
> +extern int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size);
> extern void ima_kexec_cmdline(int kernel_fd, const void *buf, int size);
>
> #ifdef CONFIG_IMA_KEXEC
> @@ -115,6 +116,11 @@ static inline int ima_file_hash(struct file *file, char *buf, size_t buf_size)
> return -EOPNOTSUPP;
> }
>
> +static inline int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size)
> +{
> + return -EOPNOTSUPP;
> +}
> +
> static inline void ima_kexec_cmdline(int kernel_fd, const void *buf, int size) {}
> #endif /* CONFIG_IMA */
>
> diff --git a/scripts/bpf_helpers_doc.py b/scripts/bpf_helpers_doc.py
> index c5bc947a70ad..add7fcb32dcd 100755
> --- a/scripts/bpf_helpers_doc.py
> +++ b/scripts/bpf_helpers_doc.py
> @@ -478,6 +478,7 @@ class PrinterHelpers(Printer):
> 'struct tcp_request_sock',
> 'struct udp6_sock',
> 'struct task_struct',
> + 'struct inode',

This change (bpf_helpers_doc.py) belongs to patch #2.

> 'struct path',
> 'struct btf_ptr',
> }
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index 2d1af8899cab..1dd2123b5b43 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -501,37 +501,17 @@ int ima_file_check(struct file *file, int mask)
> }
> EXPORT_SYMBOL_GPL(ima_file_check);
>
> -/**
> - * ima_file_hash - return the stored measurement if a file has been hashed and
> - * is in the iint cache.
> - * @file: pointer to the file
> - * @buf: buffer in which to store the hash
> - * @buf_size: length of the buffer
> - *
> - * On success, return the hash algorithm (as defined in the enum hash_algo).
> - * If buf is not NULL, this function also outputs the hash into buf.
> - * If the hash is larger than buf_size, then only buf_size bytes will be copied.
> - * It generally just makes sense to pass a buffer capable of holding the largest
> - * possible hash: IMA_MAX_DIGEST_SIZE.
> - * The file hash returned is based on the entire file, including the appended
> - * signature.
> - *
> - * If IMA is disabled or if no measurement is available, return -EOPNOTSUPP.
> - * If the parameters are incorrect, return -EINVAL.
> - */
> -int ima_file_hash(struct file *file, char *buf, size_t buf_size)
> +static int __ima_inode_hash(struct inode *inode, char *buf, size_t buf_size)
> {
> - struct inode *inode;
> struct integrity_iint_cache *iint;
> int hash_algo;
>
> - if (!file)
> + if (!inode)
> return -EINVAL;

Based on original code, for ima_file_hash(), inode cannot be NULL,
so I prefer to remove this change here and add !inode test in
ima_inode_hash.


>
> if (!ima_policy_flag)
> return -EOPNOTSUPP;
>
> - inode = file_inode(file);
> iint = integrity_iint_find(inode);
> if (!iint)
> return -EOPNOTSUPP;
> @@ -558,8 +538,58 @@ int ima_file_hash(struct file *file, char *buf, size_t buf_size)
>
> return hash_algo;
> }
> +
> +/**
> + * ima_file_hash - return the stored measurement if a file has been hashed and
> + * is in the iint cache.
> + * @file: pointer to the file
> + * @buf: buffer in which to store the hash
> + * @buf_size: length of the buffer
> + *
> + * On success, return the hash algorithm (as defined in the enum hash_algo).
> + * If buf is not NULL, this function also outputs the hash into buf.
> + * If the hash is larger than buf_size, then only buf_size bytes will be copied.
> + * It generally just makes sense to pass a buffer capable of holding the largest
> + * possible hash: IMA_MAX_DIGEST_SIZE.
> + * The file hash returned is based on the entire file, including the appended
> + * signature.
> + *
> + * If IMA is disabled or if no measurement is available, return -EOPNOTSUPP.
> + * If the parameters are incorrect, return -EINVAL.
> + */
> +int ima_file_hash(struct file *file, char *buf, size_t buf_size)
> +{
> + if (!file)
> + return -EINVAL;
> +
> + return __ima_inode_hash(file_inode(file), buf, buf_size);
> +}
> EXPORT_SYMBOL_GPL(ima_file_hash);
>
> +/**
> + * ima_inode_hash - return the stored measurement if the inode has been hashed
> + * and is in the iint cache.
> + * @inode: pointer to the inode
> + * @buf: buffer in which to store the hash
> + * @buf_size: length of the buffer
> + *
> + * On success, return the hash algorithm (as defined in the enum hash_algo).
> + * If buf is not NULL, this function also outputs the hash into buf.
> + * If the hash is larger than buf_size, then only buf_size bytes will be copied.
> + * It generally just makes sense to pass a buffer capable of holding the largest
> + * possible hash: IMA_MAX_DIGEST_SIZE.
> + * The hash returned is based on the entire contents, including the appended
> + * signature.
> + *
> + * If IMA is disabled or if no measurement is available, return -EOPNOTSUPP.
> + * If the parameters are incorrect, return -EINVAL.
> + */
> +int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size)
> +{

Add
if (!inode)
return -EINVAL;


> + return __ima_inode_hash(inode, buf, buf_size);
> +}
> +EXPORT_SYMBOL_GPL(ima_inode_hash);
> +
> /**
> * ima_post_create_tmpfile - mark newly created tmpfile as new
> * @file : newly created tmpfile
>

2020-11-20 18:16:17

by Yonghong Song

[permalink] [raw]
Subject: Re: [PATCH bpf-next 3/3] bpf: Update LSM selftests for bpf_ima_inode_hash



On 11/20/20 5:17 AM, KP Singh wrote:
> From: KP Singh <[email protected]>
>
> - Update the IMA policy before executing the test binary (this is not an
> override of the policy, just an append that ensures that hashes are
> calculated on executions).
>
> - Call the bpf_ima_inode_hash in the bprm_committed_creds hook and check
> if the call succeeded and a hash was calculated.
>
> Signed-off-by: KP Singh <[email protected]>

LGTM with a few nits below.

Acked-by: Yonghong Song <[email protected]>

> ---
> tools/testing/selftests/bpf/config | 3 ++
> .../selftests/bpf/prog_tests/test_lsm.c | 32 +++++++++++++++++++
> tools/testing/selftests/bpf/progs/lsm.c | 7 +++-
> 3 files changed, 41 insertions(+), 1 deletion(-)
>
> diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config
> index 2118e23ac07a..4b5764031368 100644
> --- a/tools/testing/selftests/bpf/config
> +++ b/tools/testing/selftests/bpf/config
> @@ -39,3 +39,6 @@ CONFIG_BPF_JIT=y
> CONFIG_BPF_LSM=y
> CONFIG_SECURITY=y
> CONFIG_LIRC=y
> +CONFIG_IMA=y
> +CONFIG_IMA_WRITE_POLICY=y
> +CONFIG_IMA_READ_POLICY=y
> diff --git a/tools/testing/selftests/bpf/prog_tests/test_lsm.c b/tools/testing/selftests/bpf/prog_tests/test_lsm.c
> index 6ab29226c99b..3f5d64adb233 100644
> --- a/tools/testing/selftests/bpf/prog_tests/test_lsm.c
> +++ b/tools/testing/selftests/bpf/prog_tests/test_lsm.c
> @@ -52,6 +52,28 @@ int exec_cmd(int *monitored_pid)
> return -EINVAL;
> }
>
[...]
> +
> void test_test_lsm(void)
> {
> struct lsm *skel = NULL;
> @@ -66,6 +88,10 @@ void test_test_lsm(void)
> if (CHECK(err, "attach", "lsm attach failed: %d\n", err))
> goto close_prog;
>
> + err = update_ima_policy();
> + if (CHECK(err != 0, "update_ima_policy", "error = %d\n", err))
> + goto close_prog;

"err != 0" => err?
"error = %d" => "err %d" for consistency with other usage in this function.

> +
> err = exec_cmd(&skel->bss->monitored_pid);
> if (CHECK(err < 0, "exec_cmd", "err %d errno %d\n", err, errno))
> goto close_prog;
> @@ -83,6 +109,12 @@ void test_test_lsm(void)
> CHECK(skel->bss->mprotect_count != 1, "mprotect_count",
> "mprotect_count = %d\n", skel->bss->mprotect_count);
>
> + CHECK(skel->data->ima_hash_ret < 0, "ima_hash_ret",
> + "ima_hash_ret = %d\n", skel->data->ima_hash_ret);
> +
> + CHECK(skel->bss->ima_hash == 0, "ima_hash",
> + "ima_hash = %lu\n", skel->bss->ima_hash);
> +
> syscall(__NR_setdomainname, &buf, -2L);
> syscall(__NR_setdomainname, 0, -3L);
> syscall(__NR_setdomainname, ~0L, -4L);
> diff --git a/tools/testing/selftests/bpf/progs/lsm.c b/tools/testing/selftests/bpf/progs/lsm.c
> index ff4d343b94b5..b0f9639e4b0a 100644
> --- a/tools/testing/selftests/bpf/progs/lsm.c
> +++ b/tools/testing/selftests/bpf/progs/lsm.c
> @@ -35,6 +35,8 @@ char _license[] SEC("license") = "GPL";
> int monitored_pid = 0;
> int mprotect_count = 0;
> int bprm_count = 0;
> +int ima_hash_ret = -1;

The helper returns type "long", but "int" type here should be fine too.

> +u64 ima_hash = 0;
>
> SEC("lsm/file_mprotect")
> int BPF_PROG(test_int_hook, struct vm_area_struct *vma,
> @@ -65,8 +67,11 @@ int BPF_PROG(test_void_hook, struct linux_binprm *bprm)
> __u32 key = 0;
> __u64 *value;
>
> - if (monitored_pid == pid)
> + if (monitored_pid == pid) {
> bprm_count++;
> + ima_hash_ret = bpf_ima_inode_hash(bprm->file->f_inode,
> + &ima_hash, sizeof(ima_hash));
> + }
>
> bpf_copy_from_user(args, sizeof(args), (void *)bprm->vma->vm_mm->arg_start);
> bpf_copy_from_user(args, sizeof(args), (void *)bprm->mm->arg_start);
>

2020-11-21 00:12:09

by KP Singh

[permalink] [raw]
Subject: Re: [PATCH bpf-next 1/3] ima: Implement ima_inode_hash

[...]

> >
> > diff --git a/scripts/bpf_helpers_doc.py b/scripts/bpf_helpers_doc.py
> > index c5bc947a70ad..add7fcb32dcd 100755
> > --- a/scripts/bpf_helpers_doc.py
> > +++ b/scripts/bpf_helpers_doc.py
> > @@ -478,6 +478,7 @@ class PrinterHelpers(Printer):
> > 'struct tcp_request_sock',
> > 'struct udp6_sock',
> > 'struct task_struct',
> > + 'struct inode',
>
> This change (bpf_helpers_doc.py) belongs to patch #2.

Indeed, I missed it during a rebase. Thanks!


>
> > 'struct path',
> > 'struct btf_ptr',
> > }
> > diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> > index 2d1af8899cab..1dd2123b5b43 100644
> > --- a/security/integrity/ima/ima_main.c
> > +++ b/security/integrity/ima/ima_main.c
> > @@ -501,37 +501,17 @@ int ima_file_check(struct file *file, int mask)
> > }
> > EXPORT_SYMBOL_GPL(ima_file_check);
> >
> > -/**
> > - * ima_file_hash - return the stored measurement if a file has been hashed and
> > - * is in the iint cache.
> > - * @file: pointer to the file
> > - * @buf: buffer in which to store the hash
> > - * @buf_size: length of the buffer
> > - *
> > - * On success, return the hash algorithm (as defined in the enum hash_algo).
> > - * If buf is not NULL, this function also outputs the hash into buf.
> > - * If the hash is larger than buf_size, then only buf_size bytes will be copied.
> > - * It generally just makes sense to pass a buffer capable of holding the largest
> > - * possible hash: IMA_MAX_DIGEST_SIZE.
> > - * The file hash returned is based on the entire file, including the appended
> > - * signature.
> > - *
> > - * If IMA is disabled or if no measurement is available, return -EOPNOTSUPP.
> > - * If the parameters are incorrect, return -EINVAL.
> > - */
> > -int ima_file_hash(struct file *file, char *buf, size_t buf_size)
> > +static int __ima_inode_hash(struct inode *inode, char *buf, size_t buf_size)
> > {
> > - struct inode *inode;
> > struct integrity_iint_cache *iint;
> > int hash_algo;
> >
> > - if (!file)
> > + if (!inode)
> > return -EINVAL;
>
> Based on original code, for ima_file_hash(), inode cannot be NULL,
> so I prefer to remove this change here and add !inode test in
> ima_inode_hash.

Makes sense. Thanks!

>
>
> >

[...]


> > + * If the parameters are incorrect, return -EINVAL.
> > + */
> > +int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size)
> > +{
>
> Add
> if (!inode)
> return -EINVAL;

Done.

>
>
> > + return __ima_inode_hash(inode, buf, buf_size);
> > +}
> > +EXPORT_SYMBOL_GPL(ima_inode_hash);
> > +
> > /**
> > * ima_post_create_tmpfile - mark newly created tmpfile as new
> > * @file : newly created tmpfile
> >

2020-11-21 00:25:00

by KP Singh

[permalink] [raw]
Subject: Re: [PATCH bpf-next 3/3] bpf: Update LSM selftests for bpf_ima_inode_hash

On Fri, Nov 20, 2020 at 7:11 PM Yonghong Song <[email protected]> wrote:
>
>
>
> On 11/20/20 5:17 AM, KP Singh wrote:
> > From: KP Singh <[email protected]>
> >
> > - Update the IMA policy before executing the test binary (this is not an
> > override of the policy, just an append that ensures that hashes are
> > calculated on executions).
> >
> > - Call the bpf_ima_inode_hash in the bprm_committed_creds hook and check
> > if the call succeeded and a hash was calculated.
> >
> > Signed-off-by: KP Singh <[email protected]>
>
> LGTM with a few nits below.
>
> Acked-by: Yonghong Song <[email protected]>
>
> > ---
> > tools/testing/selftests/bpf/config | 3 ++

[...]

> > }
> >
> [...]
> > +
> > void test_test_lsm(void)
> > {
> > struct lsm *skel = NULL;
> > @@ -66,6 +88,10 @@ void test_test_lsm(void)
> > if (CHECK(err, "attach", "lsm attach failed: %d\n", err))
> > goto close_prog;
> >
> > + err = update_ima_policy();
> > + if (CHECK(err != 0, "update_ima_policy", "error = %d\n", err))
> > + goto close_prog;
>
> "err != 0" => err?
> "error = %d" => "err %d" for consistency with other usage in this function.

Done.

>
> > +
> > err = exec_cmd(&skel->bss->monitored_pid);
> > if (CHECK(err < 0, "exec_cmd", "err %d errno %d\n", err, errno))
> > goto close_prog;
> > @@ -83,6 +109,12 @@ void test_test_lsm(void)

[...]

> > int mprotect_count = 0;
> > int bprm_count = 0;
> > +int ima_hash_ret = -1;
>
> The helper returns type "long", but "int" type here should be fine too.

Changed it to long for correctness.