mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-06 00:47:56 -04:00
Merge branch 'bpf-lsm: Extend interoperability with IMA'
Roberto Sassu says: ==================== Extend the interoperability with IMA, to give wider flexibility for the implementation of integrity-focused LSMs based on eBPF. Patch 1 fixes some style issues. Patches 2-6 give the ability to eBPF-based LSMs to take advantage of the measurement capability of IMA without needing to setup a policy in IMA (those LSMs might implement the policy capability themselves). Patches 7-9 allow eBPF-based LSMs to evaluate files read by the kernel. Changelog v2: - Add better description to patch 1 (suggested by Shuah) - Recalculate digest if it is not fresh (when IMA_COLLECTED flag not set) - Move declaration of bpf_ima_file_hash() at the end (suggested by Yonghong) - Add tests to check if the digest has been recalculated - Add deny test for bpf_kernel_read_file() - Add description to tests v1: - Modify ima_file_hash() only and allow the usage of the function with the modified behavior by eBPF-based LSMs through the new function bpf_ima_file_hash() (suggested by Mimi) - Make bpf_lsm_kernel_read_file() sleepable so that bpf_ima_inode_hash() and bpf_ima_file_hash() can be called inside the implementation of eBPF-based LSMs for this hook ==================== Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
@@ -5119,6 +5119,16 @@ union bpf_attr {
|
||||
* 0 on success.
|
||||
* **-EINVAL** for invalid input
|
||||
* **-EOPNOTSUPP** for unsupported protocol
|
||||
*
|
||||
* long bpf_ima_file_hash(struct file *file, void *dst, u32 size)
|
||||
* Description
|
||||
* Returns a calculated IMA hash of the *file*.
|
||||
* 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 the hash calculation failed or **-EINVAL** if
|
||||
* invalid arguments are passed.
|
||||
*/
|
||||
#define __BPF_FUNC_MAPPER(FN) \
|
||||
FN(unspec), \
|
||||
@@ -5314,6 +5324,7 @@ union bpf_attr {
|
||||
FN(xdp_store_bytes), \
|
||||
FN(copy_from_user_task), \
|
||||
FN(skb_set_tstamp), \
|
||||
FN(ima_file_hash), \
|
||||
/* */
|
||||
|
||||
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
|
||||
|
||||
@@ -99,6 +99,24 @@ static const struct bpf_func_proto bpf_ima_inode_hash_proto = {
|
||||
.allowed = bpf_ima_inode_hash_allowed,
|
||||
};
|
||||
|
||||
BPF_CALL_3(bpf_ima_file_hash, struct file *, file, void *, dst, u32, size)
|
||||
{
|
||||
return ima_file_hash(file, dst, size);
|
||||
}
|
||||
|
||||
BTF_ID_LIST_SINGLE(bpf_ima_file_hash_btf_ids, struct, file)
|
||||
|
||||
static const struct bpf_func_proto bpf_ima_file_hash_proto = {
|
||||
.func = bpf_ima_file_hash,
|
||||
.gpl_only = false,
|
||||
.ret_type = RET_INTEGER,
|
||||
.arg1_type = ARG_PTR_TO_BTF_ID,
|
||||
.arg1_btf_id = &bpf_ima_file_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)
|
||||
{
|
||||
@@ -121,6 +139,8 @@ bpf_lsm_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
||||
return &bpf_bprm_opts_set_proto;
|
||||
case BPF_FUNC_ima_inode_hash:
|
||||
return prog->aux->sleepable ? &bpf_ima_inode_hash_proto : NULL;
|
||||
case BPF_FUNC_ima_file_hash:
|
||||
return prog->aux->sleepable ? &bpf_ima_file_hash_proto : NULL;
|
||||
default:
|
||||
return tracing_prog_func_proto(func_id, prog);
|
||||
}
|
||||
@@ -167,6 +187,7 @@ BTF_ID(func, bpf_lsm_inode_setxattr)
|
||||
BTF_ID(func, bpf_lsm_inode_symlink)
|
||||
BTF_ID(func, bpf_lsm_inode_unlink)
|
||||
BTF_ID(func, bpf_lsm_kernel_module_request)
|
||||
BTF_ID(func, bpf_lsm_kernel_read_file)
|
||||
BTF_ID(func, bpf_lsm_kernfs_init_security)
|
||||
|
||||
#ifdef CONFIG_KEYS
|
||||
|
||||
@@ -418,6 +418,7 @@ int ima_file_mmap(struct file *file, unsigned long prot)
|
||||
|
||||
/**
|
||||
* ima_file_mprotect - based on policy, limit mprotect change
|
||||
* @vma: vm_area_struct protection is set to
|
||||
* @prot: contains the protection that will be applied by the kernel.
|
||||
*
|
||||
* Files can be mmap'ed read/write and later changed to execute to circumvent
|
||||
@@ -519,20 +520,38 @@ int ima_file_check(struct file *file, int mask)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ima_file_check);
|
||||
|
||||
static int __ima_inode_hash(struct inode *inode, char *buf, size_t buf_size)
|
||||
static int __ima_inode_hash(struct inode *inode, struct file *file, char *buf,
|
||||
size_t buf_size)
|
||||
{
|
||||
struct integrity_iint_cache *iint;
|
||||
int hash_algo;
|
||||
struct integrity_iint_cache *iint = NULL, tmp_iint;
|
||||
int rc, hash_algo;
|
||||
|
||||
if (!ima_policy_flag)
|
||||
return -EOPNOTSUPP;
|
||||
if (ima_policy_flag) {
|
||||
iint = integrity_iint_find(inode);
|
||||
if (iint)
|
||||
mutex_lock(&iint->mutex);
|
||||
}
|
||||
|
||||
if ((!iint || !(iint->flags & IMA_COLLECTED)) && file) {
|
||||
if (iint)
|
||||
mutex_unlock(&iint->mutex);
|
||||
|
||||
memset(&tmp_iint, 0, sizeof(tmp_iint));
|
||||
tmp_iint.inode = inode;
|
||||
mutex_init(&tmp_iint.mutex);
|
||||
|
||||
rc = ima_collect_measurement(&tmp_iint, file, NULL, 0,
|
||||
ima_hash_algo, NULL);
|
||||
if (rc < 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
iint = &tmp_iint;
|
||||
mutex_lock(&iint->mutex);
|
||||
}
|
||||
|
||||
iint = integrity_iint_find(inode);
|
||||
if (!iint)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
mutex_lock(&iint->mutex);
|
||||
|
||||
/*
|
||||
* ima_file_hash can be called when ima_collect_measurement has still
|
||||
* not been called, we might not always have a hash.
|
||||
@@ -551,12 +570,14 @@ static int __ima_inode_hash(struct inode *inode, char *buf, size_t buf_size)
|
||||
hash_algo = iint->ima_hash->algo;
|
||||
mutex_unlock(&iint->mutex);
|
||||
|
||||
if (iint == &tmp_iint)
|
||||
kfree(iint->ima_hash);
|
||||
|
||||
return hash_algo;
|
||||
}
|
||||
|
||||
/**
|
||||
* ima_file_hash - return the stored measurement if a file has been hashed and
|
||||
* is in the iint cache.
|
||||
* ima_file_hash - return a measurement of the file
|
||||
* @file: pointer to the file
|
||||
* @buf: buffer in which to store the hash
|
||||
* @buf_size: length of the buffer
|
||||
@@ -569,7 +590,7 @@ static int __ima_inode_hash(struct inode *inode, char *buf, size_t buf_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 measurement cannot be performed, return -EOPNOTSUPP.
|
||||
* If the parameters are incorrect, return -EINVAL.
|
||||
*/
|
||||
int ima_file_hash(struct file *file, char *buf, size_t buf_size)
|
||||
@@ -577,7 +598,7 @@ 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);
|
||||
return __ima_inode_hash(file_inode(file), file, buf, buf_size);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ima_file_hash);
|
||||
|
||||
@@ -604,14 +625,14 @@ int ima_inode_hash(struct inode *inode, char *buf, size_t buf_size)
|
||||
if (!inode)
|
||||
return -EINVAL;
|
||||
|
||||
return __ima_inode_hash(inode, buf, buf_size);
|
||||
return __ima_inode_hash(inode, NULL, buf, buf_size);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ima_inode_hash);
|
||||
|
||||
/**
|
||||
* ima_post_create_tmpfile - mark newly created tmpfile as new
|
||||
* @mnt_userns: user namespace of the mount the inode was found from
|
||||
* @file : newly created tmpfile
|
||||
* @mnt_userns: user namespace of the mount the inode was found from
|
||||
* @inode: inode of the newly created tmpfile
|
||||
*
|
||||
* No measuring, appraising or auditing of newly created tmpfiles is needed.
|
||||
* Skip calling process_measurement(), but indicate which newly, created
|
||||
@@ -643,7 +664,7 @@ void ima_post_create_tmpfile(struct user_namespace *mnt_userns,
|
||||
|
||||
/**
|
||||
* ima_post_path_mknod - mark as a new inode
|
||||
* @mnt_userns: user namespace of the mount the inode was found from
|
||||
* @mnt_userns: user namespace of the mount the inode was found from
|
||||
* @dentry: newly created dentry
|
||||
*
|
||||
* Mark files created via the mknodat syscall as new, so that the
|
||||
@@ -814,8 +835,8 @@ int ima_load_data(enum kernel_load_data_id id, bool contents)
|
||||
* ima_post_load_data - appraise decision based on policy
|
||||
* @buf: pointer to in memory file contents
|
||||
* @size: size of in memory file contents
|
||||
* @id: kernel load data caller identifier
|
||||
* @description: @id-specific description of contents
|
||||
* @load_id: kernel load data caller identifier
|
||||
* @description: @load_id-specific description of contents
|
||||
*
|
||||
* Measure/appraise/audit in memory buffer based on policy. Policy rules
|
||||
* are written in terms of a policy identifier.
|
||||
|
||||
@@ -5119,6 +5119,16 @@ union bpf_attr {
|
||||
* 0 on success.
|
||||
* **-EINVAL** for invalid input
|
||||
* **-EOPNOTSUPP** for unsupported protocol
|
||||
*
|
||||
* long bpf_ima_file_hash(struct file *file, void *dst, u32 size)
|
||||
* Description
|
||||
* Returns a calculated IMA hash of the *file*.
|
||||
* 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 the hash calculation failed or **-EINVAL** if
|
||||
* invalid arguments are passed.
|
||||
*/
|
||||
#define __BPF_FUNC_MAPPER(FN) \
|
||||
FN(unspec), \
|
||||
@@ -5314,6 +5324,7 @@ union bpf_attr {
|
||||
FN(xdp_store_bytes), \
|
||||
FN(copy_from_user_task), \
|
||||
FN(skb_set_tstamp), \
|
||||
FN(ima_file_hash), \
|
||||
/* */
|
||||
|
||||
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
|
||||
|
||||
@@ -12,7 +12,7 @@ LOG_FILE="$(mktemp /tmp/ima_setup.XXXX.log)"
|
||||
|
||||
usage()
|
||||
{
|
||||
echo "Usage: $0 <setup|cleanup|run> <existing_tmp_dir>"
|
||||
echo "Usage: $0 <setup|cleanup|run|modify-bin|restore-bin|load-policy> <existing_tmp_dir>"
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ setup()
|
||||
|
||||
ensure_mount_securityfs
|
||||
echo "measure func=BPRM_CHECK fsuuid=${mount_uuid}" > ${IMA_POLICY_FILE}
|
||||
echo "measure func=BPRM_CHECK fsuuid=${mount_uuid}" > ${mount_dir}/policy_test
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
@@ -77,6 +78,32 @@ run()
|
||||
exec "${copied_bin_path}"
|
||||
}
|
||||
|
||||
modify_bin()
|
||||
{
|
||||
local tmp_dir="$1"
|
||||
local mount_dir="${tmp_dir}/mnt"
|
||||
local copied_bin_path="${mount_dir}/$(basename ${TEST_BINARY})"
|
||||
|
||||
echo "mod" >> "${copied_bin_path}"
|
||||
}
|
||||
|
||||
restore_bin()
|
||||
{
|
||||
local tmp_dir="$1"
|
||||
local mount_dir="${tmp_dir}/mnt"
|
||||
local copied_bin_path="${mount_dir}/$(basename ${TEST_BINARY})"
|
||||
|
||||
truncate -s -4 "${copied_bin_path}"
|
||||
}
|
||||
|
||||
load_policy()
|
||||
{
|
||||
local tmp_dir="$1"
|
||||
local mount_dir="${tmp_dir}/mnt"
|
||||
|
||||
echo ${mount_dir}/policy_test > ${IMA_POLICY_FILE} 2> /dev/null
|
||||
}
|
||||
|
||||
catch()
|
||||
{
|
||||
local exit_code="$1"
|
||||
@@ -105,6 +132,12 @@ main()
|
||||
cleanup "${tmp_dir}"
|
||||
elif [[ "${action}" == "run" ]]; then
|
||||
run "${tmp_dir}"
|
||||
elif [[ "${action}" == "modify-bin" ]]; then
|
||||
modify_bin "${tmp_dir}"
|
||||
elif [[ "${action}" == "restore-bin" ]]; then
|
||||
restore_bin "${tmp_dir}"
|
||||
elif [[ "${action}" == "load-policy" ]]; then
|
||||
load_policy "${tmp_dir}"
|
||||
else
|
||||
echo "Unknown action: ${action}"
|
||||
exit 1
|
||||
|
||||
@@ -13,14 +13,17 @@
|
||||
|
||||
#include "ima.skel.h"
|
||||
|
||||
static int run_measured_process(const char *measured_dir, u32 *monitored_pid)
|
||||
#define MAX_SAMPLES 4
|
||||
|
||||
static int _run_measured_process(const char *measured_dir, u32 *monitored_pid,
|
||||
const char *cmd)
|
||||
{
|
||||
int child_pid, child_status;
|
||||
|
||||
child_pid = fork();
|
||||
if (child_pid == 0) {
|
||||
*monitored_pid = getpid();
|
||||
execlp("./ima_setup.sh", "./ima_setup.sh", "run", measured_dir,
|
||||
execlp("./ima_setup.sh", "./ima_setup.sh", cmd, measured_dir,
|
||||
NULL);
|
||||
exit(errno);
|
||||
|
||||
@@ -32,19 +35,39 @@ static int run_measured_process(const char *measured_dir, u32 *monitored_pid)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static u64 ima_hash_from_bpf;
|
||||
static int run_measured_process(const char *measured_dir, u32 *monitored_pid)
|
||||
{
|
||||
return _run_measured_process(measured_dir, monitored_pid, "run");
|
||||
}
|
||||
|
||||
static u64 ima_hash_from_bpf[MAX_SAMPLES];
|
||||
static int ima_hash_from_bpf_idx;
|
||||
|
||||
static int process_sample(void *ctx, void *data, size_t len)
|
||||
{
|
||||
ima_hash_from_bpf = *((u64 *)data);
|
||||
if (ima_hash_from_bpf_idx >= MAX_SAMPLES)
|
||||
return -ENOSPC;
|
||||
|
||||
ima_hash_from_bpf[ima_hash_from_bpf_idx++] = *((u64 *)data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_init(struct ima__bss *bss)
|
||||
{
|
||||
ima_hash_from_bpf_idx = 0;
|
||||
|
||||
bss->use_ima_file_hash = false;
|
||||
bss->enable_bprm_creds_for_exec = false;
|
||||
bss->enable_kernel_read_file = false;
|
||||
bss->test_deny = false;
|
||||
}
|
||||
|
||||
void test_test_ima(void)
|
||||
{
|
||||
char measured_dir_template[] = "/tmp/ima_measuredXXXXXX";
|
||||
struct ring_buffer *ringbuf = NULL;
|
||||
const char *measured_dir;
|
||||
u64 bin_true_sample;
|
||||
char cmd[256];
|
||||
|
||||
int err, duration = 0;
|
||||
@@ -72,13 +95,127 @@ void test_test_ima(void)
|
||||
if (CHECK(err, "failed to run command", "%s, errno = %d\n", cmd, errno))
|
||||
goto close_clean;
|
||||
|
||||
/*
|
||||
* Test #1
|
||||
* - Goal: obtain a sample with the bpf_ima_inode_hash() helper
|
||||
* - Expected result: 1 sample (/bin/true)
|
||||
*/
|
||||
test_init(skel->bss);
|
||||
err = run_measured_process(measured_dir, &skel->bss->monitored_pid);
|
||||
if (CHECK(err, "run_measured_process", "err = %d\n", err))
|
||||
if (CHECK(err, "run_measured_process #1", "err = %d\n", err))
|
||||
goto close_clean;
|
||||
|
||||
err = ring_buffer__consume(ringbuf);
|
||||
ASSERT_EQ(err, 1, "num_samples_or_err");
|
||||
ASSERT_NEQ(ima_hash_from_bpf, 0, "ima_hash");
|
||||
ASSERT_NEQ(ima_hash_from_bpf[0], 0, "ima_hash");
|
||||
|
||||
/*
|
||||
* Test #2
|
||||
* - Goal: obtain samples with the bpf_ima_file_hash() helper
|
||||
* - Expected result: 2 samples (./ima_setup.sh, /bin/true)
|
||||
*/
|
||||
test_init(skel->bss);
|
||||
skel->bss->use_ima_file_hash = true;
|
||||
err = run_measured_process(measured_dir, &skel->bss->monitored_pid);
|
||||
if (CHECK(err, "run_measured_process #2", "err = %d\n", err))
|
||||
goto close_clean;
|
||||
|
||||
err = ring_buffer__consume(ringbuf);
|
||||
ASSERT_EQ(err, 2, "num_samples_or_err");
|
||||
ASSERT_NEQ(ima_hash_from_bpf[0], 0, "ima_hash");
|
||||
ASSERT_NEQ(ima_hash_from_bpf[1], 0, "ima_hash");
|
||||
bin_true_sample = ima_hash_from_bpf[1];
|
||||
|
||||
/*
|
||||
* Test #3
|
||||
* - Goal: confirm that bpf_ima_inode_hash() returns a non-fresh digest
|
||||
* - Expected result: 2 samples (/bin/true: non-fresh, fresh)
|
||||
*/
|
||||
test_init(skel->bss);
|
||||
|
||||
err = _run_measured_process(measured_dir, &skel->bss->monitored_pid,
|
||||
"modify-bin");
|
||||
if (CHECK(err, "modify-bin #3", "err = %d\n", err))
|
||||
goto close_clean;
|
||||
|
||||
skel->bss->enable_bprm_creds_for_exec = true;
|
||||
err = run_measured_process(measured_dir, &skel->bss->monitored_pid);
|
||||
if (CHECK(err, "run_measured_process #3", "err = %d\n", err))
|
||||
goto close_clean;
|
||||
|
||||
err = ring_buffer__consume(ringbuf);
|
||||
ASSERT_EQ(err, 2, "num_samples_or_err");
|
||||
ASSERT_NEQ(ima_hash_from_bpf[0], 0, "ima_hash");
|
||||
ASSERT_NEQ(ima_hash_from_bpf[1], 0, "ima_hash");
|
||||
ASSERT_EQ(ima_hash_from_bpf[0], bin_true_sample, "sample_equal_or_err");
|
||||
/* IMA refreshed the digest. */
|
||||
ASSERT_NEQ(ima_hash_from_bpf[1], bin_true_sample,
|
||||
"sample_different_or_err");
|
||||
|
||||
/*
|
||||
* Test #4
|
||||
* - Goal: verify that bpf_ima_file_hash() returns a fresh digest
|
||||
* - Expected result: 4 samples (./ima_setup.sh: fresh, fresh;
|
||||
* /bin/true: fresh, fresh)
|
||||
*/
|
||||
test_init(skel->bss);
|
||||
skel->bss->use_ima_file_hash = true;
|
||||
skel->bss->enable_bprm_creds_for_exec = true;
|
||||
err = run_measured_process(measured_dir, &skel->bss->monitored_pid);
|
||||
if (CHECK(err, "run_measured_process #4", "err = %d\n", err))
|
||||
goto close_clean;
|
||||
|
||||
err = ring_buffer__consume(ringbuf);
|
||||
ASSERT_EQ(err, 4, "num_samples_or_err");
|
||||
ASSERT_NEQ(ima_hash_from_bpf[0], 0, "ima_hash");
|
||||
ASSERT_NEQ(ima_hash_from_bpf[1], 0, "ima_hash");
|
||||
ASSERT_NEQ(ima_hash_from_bpf[2], 0, "ima_hash");
|
||||
ASSERT_NEQ(ima_hash_from_bpf[3], 0, "ima_hash");
|
||||
ASSERT_NEQ(ima_hash_from_bpf[2], bin_true_sample,
|
||||
"sample_different_or_err");
|
||||
ASSERT_EQ(ima_hash_from_bpf[3], ima_hash_from_bpf[2],
|
||||
"sample_equal_or_err");
|
||||
|
||||
skel->bss->use_ima_file_hash = false;
|
||||
skel->bss->enable_bprm_creds_for_exec = false;
|
||||
err = _run_measured_process(measured_dir, &skel->bss->monitored_pid,
|
||||
"restore-bin");
|
||||
if (CHECK(err, "restore-bin #3", "err = %d\n", err))
|
||||
goto close_clean;
|
||||
|
||||
/*
|
||||
* Test #5
|
||||
* - Goal: obtain a sample from the kernel_read_file hook
|
||||
* - Expected result: 2 samples (./ima_setup.sh, policy_test)
|
||||
*/
|
||||
test_init(skel->bss);
|
||||
skel->bss->use_ima_file_hash = true;
|
||||
skel->bss->enable_kernel_read_file = true;
|
||||
err = _run_measured_process(measured_dir, &skel->bss->monitored_pid,
|
||||
"load-policy");
|
||||
if (CHECK(err, "run_measured_process #5", "err = %d\n", err))
|
||||
goto close_clean;
|
||||
|
||||
err = ring_buffer__consume(ringbuf);
|
||||
ASSERT_EQ(err, 2, "num_samples_or_err");
|
||||
ASSERT_NEQ(ima_hash_from_bpf[0], 0, "ima_hash");
|
||||
ASSERT_NEQ(ima_hash_from_bpf[1], 0, "ima_hash");
|
||||
|
||||
/*
|
||||
* Test #6
|
||||
* - Goal: ensure that the kernel_read_file hook denies an operation
|
||||
* - Expected result: 0 samples
|
||||
*/
|
||||
test_init(skel->bss);
|
||||
skel->bss->enable_kernel_read_file = true;
|
||||
skel->bss->test_deny = true;
|
||||
err = _run_measured_process(measured_dir, &skel->bss->monitored_pid,
|
||||
"load-policy");
|
||||
if (CHECK(!err, "run_measured_process #6", "err = %d\n", err))
|
||||
goto close_clean;
|
||||
|
||||
err = ring_buffer__consume(ringbuf);
|
||||
ASSERT_EQ(err, 0, "num_samples_or_err");
|
||||
|
||||
close_clean:
|
||||
snprintf(cmd, sizeof(cmd), "./ima_setup.sh cleanup %s", measured_dir);
|
||||
|
||||
@@ -18,8 +18,12 @@ struct {
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
SEC("lsm.s/bprm_committed_creds")
|
||||
void BPF_PROG(ima, struct linux_binprm *bprm)
|
||||
bool use_ima_file_hash;
|
||||
bool enable_bprm_creds_for_exec;
|
||||
bool enable_kernel_read_file;
|
||||
bool test_deny;
|
||||
|
||||
static void ima_test_common(struct file *file)
|
||||
{
|
||||
u64 ima_hash = 0;
|
||||
u64 *sample;
|
||||
@@ -28,8 +32,12 @@ void BPF_PROG(ima, struct linux_binprm *bprm)
|
||||
|
||||
pid = bpf_get_current_pid_tgid() >> 32;
|
||||
if (pid == monitored_pid) {
|
||||
ret = bpf_ima_inode_hash(bprm->file->f_inode, &ima_hash,
|
||||
sizeof(ima_hash));
|
||||
if (!use_ima_file_hash)
|
||||
ret = bpf_ima_inode_hash(file->f_inode, &ima_hash,
|
||||
sizeof(ima_hash));
|
||||
else
|
||||
ret = bpf_ima_file_hash(file, &ima_hash,
|
||||
sizeof(ima_hash));
|
||||
if (ret < 0 || ima_hash == 0)
|
||||
return;
|
||||
|
||||
@@ -43,3 +51,53 @@ void BPF_PROG(ima, struct linux_binprm *bprm)
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int ima_test_deny(void)
|
||||
{
|
||||
u32 pid;
|
||||
|
||||
pid = bpf_get_current_pid_tgid() >> 32;
|
||||
if (pid == monitored_pid && test_deny)
|
||||
return -EPERM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("lsm.s/bprm_committed_creds")
|
||||
void BPF_PROG(bprm_committed_creds, struct linux_binprm *bprm)
|
||||
{
|
||||
ima_test_common(bprm->file);
|
||||
}
|
||||
|
||||
SEC("lsm.s/bprm_creds_for_exec")
|
||||
int BPF_PROG(bprm_creds_for_exec, struct linux_binprm *bprm)
|
||||
{
|
||||
if (!enable_bprm_creds_for_exec)
|
||||
return 0;
|
||||
|
||||
ima_test_common(bprm->file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("lsm.s/kernel_read_file")
|
||||
int BPF_PROG(kernel_read_file, struct file *file, enum kernel_read_file_id id,
|
||||
bool contents)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!enable_kernel_read_file)
|
||||
return 0;
|
||||
|
||||
if (!contents)
|
||||
return 0;
|
||||
|
||||
if (id != READING_POLICY)
|
||||
return 0;
|
||||
|
||||
ret = ima_test_deny();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ima_test_common(file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user