mirror of https://gitee.com/openkylin/linux.git
Merge branch 'BPF ring buffer + sleepable programs'
KP Singh says: ==================== - Use ring_buffer__consume without BPF_RB_FORCE_WAKEUP as suggested by Andrii - Use ASSERT_OK_PTR macro Sleepable programs currently do not have access to any ringbuffer and since the perf ring buffer is a per-cpu map, it would not be trivial to enable for sleepable programs. Our specific use-case is to use the bpf_ima_inode_hash helper and write the hash to a ring buffer from a sleepable LSM hook. This series allows the BPF ringbuffer to be used in sleepable programs (tracing and lsm). Since the helper prototypes were already exposed the only change required was have the verifier allow BPF_MAP_TYPE_RINGBUF for sleepable programs. The ima test is also modified to use the ringbuffer instead of global variables. Based on dicussions we had over the BPF office hours and enabling all the possible debug options, I could not find any issues or warnings when using the ring buffer from sleepable programs. ==================== Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
This commit is contained in:
commit
ecda49c522
|
@ -10024,9 +10024,11 @@ static int check_map_prog_compatibility(struct bpf_verifier_env *env,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case BPF_MAP_TYPE_RINGBUF:
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
verbose(env,
|
verbose(env,
|
||||||
"Sleepable programs can only use array and hash maps\n");
|
"Sleepable programs can only use array, hash, and ringbuf maps\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <test_progs.h>
|
#include <test_progs.h>
|
||||||
|
#include <linux/ring_buffer.h>
|
||||||
|
|
||||||
#include "ima.skel.h"
|
#include "ima.skel.h"
|
||||||
|
|
||||||
|
@ -31,9 +32,18 @@ static int run_measured_process(const char *measured_dir, u32 *monitored_pid)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u64 ima_hash_from_bpf;
|
||||||
|
|
||||||
|
static int process_sample(void *ctx, void *data, size_t len)
|
||||||
|
{
|
||||||
|
ima_hash_from_bpf = *((u64 *)data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void test_test_ima(void)
|
void test_test_ima(void)
|
||||||
{
|
{
|
||||||
char measured_dir_template[] = "/tmp/ima_measuredXXXXXX";
|
char measured_dir_template[] = "/tmp/ima_measuredXXXXXX";
|
||||||
|
struct ring_buffer *ringbuf;
|
||||||
const char *measured_dir;
|
const char *measured_dir;
|
||||||
char cmd[256];
|
char cmd[256];
|
||||||
|
|
||||||
|
@ -44,6 +54,11 @@ void test_test_ima(void)
|
||||||
if (CHECK(!skel, "skel_load", "skeleton failed\n"))
|
if (CHECK(!skel, "skel_load", "skeleton failed\n"))
|
||||||
goto close_prog;
|
goto close_prog;
|
||||||
|
|
||||||
|
ringbuf = ring_buffer__new(bpf_map__fd(skel->maps.ringbuf),
|
||||||
|
process_sample, NULL, NULL);
|
||||||
|
if (!ASSERT_OK_PTR(ringbuf, "ringbuf"))
|
||||||
|
goto close_prog;
|
||||||
|
|
||||||
err = ima__attach(skel);
|
err = ima__attach(skel);
|
||||||
if (CHECK(err, "attach", "attach failed: %d\n", err))
|
if (CHECK(err, "attach", "attach failed: %d\n", err))
|
||||||
goto close_prog;
|
goto close_prog;
|
||||||
|
@ -60,11 +75,9 @@ void test_test_ima(void)
|
||||||
if (CHECK(err, "run_measured_process", "err = %d\n", err))
|
if (CHECK(err, "run_measured_process", "err = %d\n", err))
|
||||||
goto close_clean;
|
goto close_clean;
|
||||||
|
|
||||||
CHECK(skel->data->ima_hash_ret < 0, "ima_hash_ret",
|
err = ring_buffer__consume(ringbuf);
|
||||||
"ima_hash_ret = %ld\n", skel->data->ima_hash_ret);
|
ASSERT_EQ(err, 1, "num_samples_or_err");
|
||||||
|
ASSERT_NEQ(ima_hash_from_bpf, 0, "ima_hash");
|
||||||
CHECK(skel->bss->ima_hash == 0, "ima_hash",
|
|
||||||
"ima_hash = %lu\n", skel->bss->ima_hash);
|
|
||||||
|
|
||||||
close_clean:
|
close_clean:
|
||||||
snprintf(cmd, sizeof(cmd), "./ima_setup.sh cleanup %s", measured_dir);
|
snprintf(cmd, sizeof(cmd), "./ima_setup.sh cleanup %s", measured_dir);
|
||||||
|
|
|
@ -9,20 +9,37 @@
|
||||||
#include <bpf/bpf_helpers.h>
|
#include <bpf/bpf_helpers.h>
|
||||||
#include <bpf/bpf_tracing.h>
|
#include <bpf/bpf_tracing.h>
|
||||||
|
|
||||||
long ima_hash_ret = -1;
|
|
||||||
u64 ima_hash = 0;
|
|
||||||
u32 monitored_pid = 0;
|
u32 monitored_pid = 0;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
__uint(type, BPF_MAP_TYPE_RINGBUF);
|
||||||
|
__uint(max_entries, 1 << 12);
|
||||||
|
} ringbuf SEC(".maps");
|
||||||
|
|
||||||
char _license[] SEC("license") = "GPL";
|
char _license[] SEC("license") = "GPL";
|
||||||
|
|
||||||
SEC("lsm.s/bprm_committed_creds")
|
SEC("lsm.s/bprm_committed_creds")
|
||||||
int BPF_PROG(ima, struct linux_binprm *bprm)
|
void BPF_PROG(ima, struct linux_binprm *bprm)
|
||||||
{
|
{
|
||||||
u32 pid = bpf_get_current_pid_tgid() >> 32;
|
u64 ima_hash = 0;
|
||||||
|
u64 *sample;
|
||||||
|
int ret;
|
||||||
|
u32 pid;
|
||||||
|
|
||||||
if (pid == monitored_pid)
|
pid = bpf_get_current_pid_tgid() >> 32;
|
||||||
ima_hash_ret = bpf_ima_inode_hash(bprm->file->f_inode,
|
if (pid == monitored_pid) {
|
||||||
&ima_hash, sizeof(ima_hash));
|
ret = bpf_ima_inode_hash(bprm->file->f_inode, &ima_hash,
|
||||||
|
sizeof(ima_hash));
|
||||||
|
if (ret < 0 || ima_hash == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
return 0;
|
sample = bpf_ringbuf_reserve(&ringbuf, sizeof(u64), 0);
|
||||||
|
if (!sample)
|
||||||
|
return;
|
||||||
|
|
||||||
|
*sample = ima_hash;
|
||||||
|
bpf_ringbuf_submit(sample, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue