mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
selftests/bpf: Add tests for BPF LSM inode init labelling
Exercise bpf_inode_init_xattr() in combination with a policy example via BPF LSM. A program on the inode_init_security hook labels new files and directories, inherits a zone label from the parent directory, and has claims refused for names outside the security.bpf. prefix and for a name that would exceed XATTR_NAME_MAX once the prefix is put back as well as other corner case tests that should get rejected. # LDLIBS=-static PKG_CONFIG='pkg-config --static' ./vmtest.sh -- ./test_progs -t lsm_inode_init_xattr [...] #226/1 lsm_inode_init_xattr/init_labels:OK #226/2 lsm_inode_init_xattr/inherit_from_parent:OK #226/3 lsm_inode_init_xattr/refused_claims:OK #226/4 lsm_inode_init_xattr/null_xattrs:OK #226/5 lsm_inode_init_xattr/shared_budget:OK #226/6 lsm_inode_init_xattr/value_shapes:OK #226 lsm_inode_init_xattr:OK Summary: 1/6 PASSED, 0 SKIPPED, 0/0 FAILED Co-developed-by: David Windsor <dwindsor@gmail.com> Signed-off-by: David Windsor <dwindsor@gmail.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://patch.msgid.link/20260915150739.284189-9-daniel@iogearbox.net
This commit is contained in:
parent
2757e9e539
commit
90dd01b6c1
|
|
@ -124,6 +124,8 @@ CONFIG_SECURITY=y
|
|||
CONFIG_SECURITYFS=y
|
||||
CONFIG_SYN_COOKIES=y
|
||||
CONFIG_TEST_BPF=m
|
||||
CONFIG_TMPFS=y
|
||||
CONFIG_TMPFS_XATTR=y
|
||||
CONFIG_UDMABUF=y
|
||||
CONFIG_USERFAULTFD=y
|
||||
CONFIG_VSOCKETS=y
|
||||
|
|
|
|||
399
tools/testing/selftests/bpf/prog_tests/lsm_inode_init_xattr.c
Normal file
399
tools/testing/selftests/bpf/prog_tests/lsm_inode_init_xattr.c
Normal file
|
|
@ -0,0 +1,399 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/xattr.h>
|
||||
#include <test_progs.h>
|
||||
|
||||
#include "lsm_inode_init_xattr.skel.h"
|
||||
#include "lsm_inode_init_xattr_budget.skel.h"
|
||||
#include "lsm_inode_init_xattr_value.skel.h"
|
||||
|
||||
#define INIT_XATTRS_MAX 2
|
||||
#define VALUE_SIZE_MAX (64 * 1024)
|
||||
#define TESTDIR "/tmp/test_progs_lsm_init_xattr"
|
||||
#define RAMFSDIR "/tmp/test_progs_lsm_init_xattr_ramfs"
|
||||
|
||||
static bool testdir_mounted;
|
||||
static bool ramfsdir_mounted;
|
||||
|
||||
static int testdir_setup(void)
|
||||
{
|
||||
if (mkdir(TESTDIR, 0755) && errno != EEXIST)
|
||||
return -errno;
|
||||
if (mount("tmpfs", TESTDIR, "tmpfs", 0, NULL))
|
||||
return -errno;
|
||||
testdir_mounted = true;
|
||||
if (mkdir(RAMFSDIR, 0755) && errno != EEXIST)
|
||||
return -errno;
|
||||
if (mount("ramfs", RAMFSDIR, "ramfs", 0, NULL))
|
||||
return -errno;
|
||||
ramfsdir_mounted = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void testdir_cleanup(void)
|
||||
{
|
||||
if (ramfsdir_mounted)
|
||||
umount(RAMFSDIR);
|
||||
rmdir(RAMFSDIR);
|
||||
if (testdir_mounted)
|
||||
umount(TESTDIR);
|
||||
rmdir(TESTDIR);
|
||||
}
|
||||
|
||||
static bool lsm_is_active(const char *name)
|
||||
{
|
||||
char buf[512], *tok;
|
||||
int fd, len;
|
||||
|
||||
fd = open("/sys/kernel/security/lsm", O_RDONLY);
|
||||
if (fd < 0)
|
||||
return true;
|
||||
len = read(fd, buf, sizeof(buf) - 1);
|
||||
close(fd);
|
||||
if (len <= 0)
|
||||
return true;
|
||||
buf[len] = '\0';
|
||||
for (tok = strtok(buf, ",\n"); tok; tok = strtok(NULL, ",\n"))
|
||||
if (!strcmp(tok, name))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int read_label(const char *path, const char *name, char *buf, size_t sz)
|
||||
{
|
||||
int ret = getxattr(path, name, buf, sz);
|
||||
|
||||
return ret < 0 ? -errno : ret;
|
||||
}
|
||||
|
||||
static void assert_label(const char *path, const char *name, const char *want)
|
||||
{
|
||||
char buf[64] = {};
|
||||
int ret;
|
||||
|
||||
ret = read_label(path, name, buf, sizeof(buf));
|
||||
if (!ASSERT_EQ(ret, (int)strlen(want) + 1, name))
|
||||
return;
|
||||
ASSERT_STREQ(buf, want, name);
|
||||
}
|
||||
|
||||
static struct lsm_inode_init_xattr *policy_attach(void)
|
||||
{
|
||||
struct lsm_inode_init_xattr *skel;
|
||||
|
||||
skel = lsm_inode_init_xattr__open_and_load();
|
||||
if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
|
||||
return NULL;
|
||||
|
||||
skel->bss->monitored_pid = getpid();
|
||||
if (!ASSERT_OK(lsm_inode_init_xattr__attach(skel), "skel_attach")) {
|
||||
lsm_inode_init_xattr__destroy(skel);
|
||||
return NULL;
|
||||
}
|
||||
return skel;
|
||||
}
|
||||
|
||||
static void test_init_labels(void)
|
||||
{
|
||||
struct lsm_inode_init_xattr *skel;
|
||||
const char *file = TESTDIR "/file";
|
||||
const char *subdir = TESTDIR "/subdir";
|
||||
int fd = -1;
|
||||
|
||||
skel = policy_attach();
|
||||
if (!skel)
|
||||
return;
|
||||
|
||||
fd = open(file, O_CREAT | O_RDWR, 0644);
|
||||
if (!ASSERT_GE(fd, 0, "create_file"))
|
||||
goto out;
|
||||
|
||||
if (!ASSERT_TRUE(skel->bss->hook_ran, "hook_ran"))
|
||||
goto out;
|
||||
|
||||
ASSERT_OK(skel->data->zone_err, "zone_err");
|
||||
ASSERT_OK(skel->data->origin_err, "origin_err");
|
||||
assert_label(file, "security.bpf.zone", "default");
|
||||
assert_label(file, "security.bpf.origin", "created");
|
||||
|
||||
if (!ASSERT_OK(mkdir(subdir, 0755), "mkdir"))
|
||||
goto out;
|
||||
assert_label(subdir, "security.bpf.zone", "default");
|
||||
assert_label(subdir, "security.bpf.origin", "created");
|
||||
rmdir(subdir);
|
||||
out:
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
remove(file);
|
||||
lsm_inode_init_xattr__destroy(skel);
|
||||
}
|
||||
|
||||
static void test_inherit_from_parent(void)
|
||||
{
|
||||
const char *zonedir = TESTDIR "/zoned";
|
||||
const char *file = TESTDIR "/zoned/file";
|
||||
struct lsm_inode_init_xattr *skel;
|
||||
int dirfd = -1, fd = -1, err;
|
||||
struct {
|
||||
char v[32];
|
||||
__u32 len;
|
||||
} label = {};
|
||||
|
||||
if (!ASSERT_OK(mkdir(zonedir, 0755), "mkdir_zoned"))
|
||||
return;
|
||||
|
||||
skel = policy_attach();
|
||||
if (!skel)
|
||||
goto out_dir;
|
||||
|
||||
dirfd = open(zonedir, O_RDONLY | O_DIRECTORY);
|
||||
if (!ASSERT_GE(dirfd, 0, "open_zoned"))
|
||||
goto out;
|
||||
|
||||
strncpy(label.v, "restricted", sizeof(label.v) - 1);
|
||||
label.len = strlen("restricted") + 1;
|
||||
|
||||
err = bpf_map_update_elem(bpf_map__fd(skel->maps.inode_zone), &dirfd,
|
||||
&label, BPF_ANY);
|
||||
if (!ASSERT_OK(err, "seed_parent_zone"))
|
||||
goto out;
|
||||
|
||||
fd = open(file, O_CREAT | O_RDWR, 0644);
|
||||
if (!ASSERT_GE(fd, 0, "create_file"))
|
||||
goto out;
|
||||
|
||||
if (!ASSERT_TRUE(skel->bss->hook_ran, "hook_ran"))
|
||||
goto out;
|
||||
|
||||
ASSERT_EQ(skel->bss->inherited, 1, "inherited");
|
||||
ASSERT_OK(skel->data->zone_err, "zone_err");
|
||||
assert_label(file, "security.bpf.zone", "restricted");
|
||||
assert_label(file, "security.bpf.origin", "created");
|
||||
out:
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
if (dirfd >= 0)
|
||||
close(dirfd);
|
||||
remove(file);
|
||||
lsm_inode_init_xattr__destroy(skel);
|
||||
out_dir:
|
||||
rmdir(zonedir);
|
||||
}
|
||||
|
||||
static void test_refused_claims(void)
|
||||
{
|
||||
const char *file = TESTDIR "/refused";
|
||||
struct lsm_inode_init_xattr *skel;
|
||||
char buf[64];
|
||||
int fd = -1;
|
||||
|
||||
skel = policy_attach();
|
||||
if (!skel)
|
||||
return;
|
||||
|
||||
fd = open(file, O_CREAT | O_RDWR, 0644);
|
||||
if (!ASSERT_GE(fd, 0, "create_file"))
|
||||
goto out;
|
||||
|
||||
if (!ASSERT_TRUE(skel->bss->hook_ran, "hook_ran"))
|
||||
goto out;
|
||||
|
||||
ASSERT_EQ(skel->data->overflow_err, -ENOSPC, "overflow_err");
|
||||
ASSERT_EQ(read_label(file, "security.bpf.overflow", buf, sizeof(buf)),
|
||||
-ENODATA, "overflow_absent");
|
||||
|
||||
ASSERT_EQ(skel->data->toolong_err, -EINVAL, "toolong_err");
|
||||
|
||||
ASSERT_EQ(skel->data->selinux_err, -EPERM, "selinux_err");
|
||||
ASSERT_EQ(skel->data->user_err, -EPERM, "user_err");
|
||||
|
||||
if (!lsm_is_active("selinux"))
|
||||
ASSERT_EQ(read_label(file, "security.selinux", buf, sizeof(buf)),
|
||||
-ENODATA, "selinux_absent");
|
||||
ASSERT_EQ(read_label(file, "user.zone", buf, sizeof(buf)),
|
||||
-ENODATA, "user_absent");
|
||||
out:
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
remove(file);
|
||||
lsm_inode_init_xattr__destroy(skel);
|
||||
}
|
||||
|
||||
static void test_null_xattrs(void)
|
||||
{
|
||||
const char *file = RAMFSDIR "/file";
|
||||
struct lsm_inode_init_xattr *skel;
|
||||
int fd = -1;
|
||||
|
||||
skel = policy_attach();
|
||||
if (!skel)
|
||||
return;
|
||||
|
||||
fd = open(file, O_CREAT | O_RDWR, 0644);
|
||||
if (!ASSERT_GE(fd, 0, "create_file"))
|
||||
goto out;
|
||||
|
||||
if (!ASSERT_TRUE(skel->bss->hook_ran, "hook_ran"))
|
||||
goto out;
|
||||
ASSERT_EQ(skel->data->zone_err, -EOPNOTSUPP, "zone_err");
|
||||
out:
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
remove(file);
|
||||
lsm_inode_init_xattr__destroy(skel);
|
||||
}
|
||||
|
||||
static void test_shared_budget(void)
|
||||
{
|
||||
struct lsm_inode_init_xattr_budget *skel[INIT_XATTRS_MAX + 1] = {};
|
||||
struct bpf_link *link[INIT_XATTRS_MAX + 1] = {};
|
||||
const char *file = TESTDIR "/budget";
|
||||
int claimed = 0, refused = 0;
|
||||
int i, fd = -1;
|
||||
|
||||
for (i = 0; i <= INIT_XATTRS_MAX; i++) {
|
||||
skel[i] = lsm_inode_init_xattr_budget__open();
|
||||
if (!ASSERT_OK_PTR(skel[i], "skel_open"))
|
||||
goto out;
|
||||
|
||||
snprintf(skel[i]->rodata->xattr_name,
|
||||
sizeof(skel[i]->rodata->xattr_name),
|
||||
"security.bpf.slot%d", i);
|
||||
|
||||
if (!ASSERT_OK(lsm_inode_init_xattr_budget__load(skel[i]),
|
||||
"skel_load"))
|
||||
goto out;
|
||||
|
||||
skel[i]->bss->monitored_pid = getpid();
|
||||
|
||||
link[i] = bpf_program__attach_lsm(skel[i]->progs.claim_one);
|
||||
if (!ASSERT_OK_PTR(link[i], "attach"))
|
||||
goto out;
|
||||
}
|
||||
|
||||
fd = open(file, O_CREAT | O_RDWR, 0644);
|
||||
if (!ASSERT_GE(fd, 0, "create_file"))
|
||||
goto out;
|
||||
|
||||
for (i = 0; i <= INIT_XATTRS_MAX; i++) {
|
||||
int err = skel[i]->data->claim_err;
|
||||
|
||||
ASSERT_TRUE(skel[i]->bss->hook_ran, "hook_ran");
|
||||
if (!err)
|
||||
claimed++;
|
||||
else if (ASSERT_EQ(err, -ENOSPC, "claim_err"))
|
||||
refused++;
|
||||
}
|
||||
|
||||
ASSERT_EQ(claimed, INIT_XATTRS_MAX, "claimed");
|
||||
ASSERT_EQ(refused, 1, "refused");
|
||||
out:
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
remove(file);
|
||||
for (i = 0; i <= INIT_XATTRS_MAX; i++) {
|
||||
bpf_link__destroy(link[i]);
|
||||
lsm_inode_init_xattr_budget__destroy(skel[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int claim_value(const char *file, __u32 len, __u64 flags,
|
||||
int hook_retval, int *open_errno)
|
||||
{
|
||||
struct lsm_inode_init_xattr_value *skel;
|
||||
struct bpf_link *link = NULL;
|
||||
int err = 1, fd;
|
||||
|
||||
skel = lsm_inode_init_xattr_value__open();
|
||||
if (!ASSERT_OK_PTR(skel, "skel_open"))
|
||||
return 1;
|
||||
|
||||
skel->rodata->value_len = len;
|
||||
skel->rodata->dynptr_flags = flags;
|
||||
skel->rodata->hook_retval = hook_retval;
|
||||
|
||||
if (!ASSERT_OK(lsm_inode_init_xattr_value__load(skel), "skel_load"))
|
||||
goto out;
|
||||
|
||||
skel->bss->monitored_pid = getpid();
|
||||
|
||||
link = bpf_program__attach_lsm(skel->progs.claim_value);
|
||||
if (!ASSERT_OK_PTR(link, "attach"))
|
||||
goto out;
|
||||
|
||||
fd = open(file, O_CREAT | O_RDWR | O_EXCL, 0644);
|
||||
*open_errno = fd < 0 ? errno : 0;
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
|
||||
if (ASSERT_TRUE(skel->bss->hook_ran, "hook_ran"))
|
||||
err = skel->data->claim_err;
|
||||
out:
|
||||
bpf_link__destroy(link);
|
||||
lsm_inode_init_xattr_value__destroy(skel);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void test_value_shapes(void)
|
||||
{
|
||||
const char *file = TESTDIR "/value";
|
||||
char buf[64];
|
||||
int err, open_errno;
|
||||
|
||||
remove(file);
|
||||
|
||||
err = claim_value(file, 0, 0, 0, &open_errno);
|
||||
ASSERT_OK(err, "empty_value_err");
|
||||
ASSERT_OK(open_errno, "empty_value_open");
|
||||
ASSERT_EQ(read_label(file, "security.bpf.value", buf, sizeof(buf)),
|
||||
0, "empty_value_len");
|
||||
remove(file);
|
||||
|
||||
err = claim_value(file, sizeof(buf), 1, 0, &open_errno);
|
||||
ASSERT_EQ(err, -EINVAL, "bad_dynptr_err");
|
||||
ASSERT_EQ(read_label(file, "security.bpf.value", buf, sizeof(buf)),
|
||||
-ENODATA, "bad_dynptr_absent");
|
||||
remove(file);
|
||||
|
||||
err = claim_value(file, VALUE_SIZE_MAX + 1, 0, 0, &open_errno);
|
||||
ASSERT_EQ(err, -E2BIG, "oversized_err");
|
||||
ASSERT_EQ(read_label(file, "security.bpf.value", buf, sizeof(buf)),
|
||||
-ENODATA, "oversized_absent");
|
||||
remove(file);
|
||||
|
||||
err = claim_value(file, 8, 0, -EPERM, &open_errno);
|
||||
ASSERT_OK(err, "denied_claim_err");
|
||||
ASSERT_EQ(open_errno, EPERM, "denied_open");
|
||||
ASSERT_EQ(read_label(file, "security.bpf.value", buf, sizeof(buf)),
|
||||
-ENOENT, "denied_absent");
|
||||
remove(file);
|
||||
}
|
||||
|
||||
void test_lsm_inode_init_xattr(void)
|
||||
{
|
||||
if (!ASSERT_OK(testdir_setup(), "testdir_setup"))
|
||||
goto out;
|
||||
|
||||
if (test__start_subtest("init_labels"))
|
||||
test_init_labels();
|
||||
if (test__start_subtest("inherit_from_parent"))
|
||||
test_inherit_from_parent();
|
||||
if (test__start_subtest("refused_claims"))
|
||||
test_refused_claims();
|
||||
if (test__start_subtest("null_xattrs"))
|
||||
test_null_xattrs();
|
||||
if (test__start_subtest("shared_budget"))
|
||||
test_shared_budget();
|
||||
if (test__start_subtest("value_shapes"))
|
||||
test_value_shapes();
|
||||
out:
|
||||
testdir_cleanup();
|
||||
}
|
||||
98
tools/testing/selftests/bpf/progs/lsm_inode_init_xattr.c
Normal file
98
tools/testing/selftests/bpf/progs/lsm_inode_init_xattr.c
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include "vmlinux.h"
|
||||
#include <errno.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include "bpf_kfuncs.h"
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
#define LABEL_MAX 32
|
||||
|
||||
struct label {
|
||||
char v[LABEL_MAX];
|
||||
__u32 len;
|
||||
};
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_INODE_STORAGE);
|
||||
__uint(map_flags, BPF_F_NO_PREALLOC);
|
||||
__type(key, int);
|
||||
__type(value, struct label);
|
||||
} inode_zone SEC(".maps");
|
||||
|
||||
__u32 monitored_pid;
|
||||
|
||||
const char xattr_zone[] = "security.bpf.zone";
|
||||
const char xattr_origin[] = "security.bpf.origin";
|
||||
const char xattr_overflow[] = "security.bpf.overflow";
|
||||
/* One byte over XATTR_NAME_MAX once "security." is prepended again. */
|
||||
const char xattr_toolong[] = "security.bpf." "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
|
||||
const char xattr_selinux[] = "security.selinux";
|
||||
const char xattr_user[] = "user.zone";
|
||||
|
||||
char zone_scratch[LABEL_MAX];
|
||||
char origin_value[] = "created";
|
||||
|
||||
__u32 hook_ran;
|
||||
__s32 zone_err = 1;
|
||||
__s32 origin_err = 1;
|
||||
__s32 overflow_err = 1;
|
||||
__s32 toolong_err = 1;
|
||||
__s32 selinux_err = 1;
|
||||
__s32 user_err = 1;
|
||||
__u32 inherited;
|
||||
|
||||
SEC("lsm/inode_init_security")
|
||||
int BPF_PROG(init_label, struct inode *inode, struct inode *dir,
|
||||
const struct qstr *qstr, struct xattr *xattrs, int *xattr_count)
|
||||
{
|
||||
struct bpf_dynptr value;
|
||||
struct label *parent;
|
||||
int len = 0;
|
||||
|
||||
if ((bpf_get_current_pid_tgid() >> 32) != monitored_pid)
|
||||
return 0;
|
||||
|
||||
hook_ran = 1;
|
||||
if (!xattrs) {
|
||||
/* The filesystem takes no xattrs at inode creation. */
|
||||
zone_err = -EOPNOTSUPP;
|
||||
return 0;
|
||||
}
|
||||
__builtin_memset(zone_scratch, 0, LABEL_MAX);
|
||||
|
||||
if (dir) {
|
||||
parent = bpf_inode_storage_get(&inode_zone, dir, 0, 0);
|
||||
if (parent && parent->len > 0 && parent->len <= LABEL_MAX) {
|
||||
len = parent->len;
|
||||
__builtin_memcpy(zone_scratch, parent->v, LABEL_MAX);
|
||||
inherited = 1;
|
||||
}
|
||||
}
|
||||
if (!len) {
|
||||
__builtin_memcpy(zone_scratch, "default", sizeof("default"));
|
||||
len = sizeof("default");
|
||||
}
|
||||
|
||||
bpf_dynptr_from_mem(zone_scratch, len, 0, &value);
|
||||
/* Refused before a slot is claimed, so the budget below is intact. */
|
||||
toolong_err = bpf_inode_init_xattr(xattrs, xattr_count, xattr_toolong,
|
||||
&value);
|
||||
zone_err = bpf_inode_init_xattr(xattrs, xattr_count, xattr_zone,
|
||||
&value);
|
||||
|
||||
bpf_dynptr_from_mem(origin_value, sizeof(origin_value), 0, &value);
|
||||
origin_err = bpf_inode_init_xattr(xattrs, xattr_count, xattr_origin,
|
||||
&value);
|
||||
|
||||
overflow_err = bpf_inode_init_xattr(xattrs, xattr_count,
|
||||
xattr_overflow, &value);
|
||||
|
||||
selinux_err = bpf_inode_init_xattr(xattrs, xattr_count, xattr_selinux,
|
||||
&value);
|
||||
user_err = bpf_inode_init_xattr(xattrs, xattr_count, xattr_user,
|
||||
&value);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include "vmlinux.h"
|
||||
#include <errno.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include "bpf_kfuncs.h"
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
const char xattr_name[32] = "security.bpf.slot";
|
||||
|
||||
__u32 monitored_pid;
|
||||
__u32 hook_ran;
|
||||
__s32 claim_err = 1;
|
||||
|
||||
char claim_value[] = "v";
|
||||
|
||||
SEC("lsm/inode_init_security")
|
||||
int BPF_PROG(claim_one, struct inode *inode, struct inode *dir,
|
||||
const struct qstr *qstr, struct xattr *xattrs, int *xattr_count)
|
||||
{
|
||||
struct bpf_dynptr value;
|
||||
|
||||
if ((bpf_get_current_pid_tgid() >> 32) != monitored_pid)
|
||||
return 0;
|
||||
|
||||
hook_ran = 1;
|
||||
if (!xattrs) {
|
||||
claim_err = -EOPNOTSUPP;
|
||||
return 0;
|
||||
}
|
||||
bpf_dynptr_from_mem(claim_value, sizeof(claim_value), 0, &value);
|
||||
claim_err = bpf_inode_init_xattr(xattrs, xattr_count, xattr_name,
|
||||
&value);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include "vmlinux.h"
|
||||
#include <errno.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include "bpf_kfuncs.h"
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
#define VALUE_MAX (64 * 1024 + 1)
|
||||
|
||||
const char xattr_value[] = "security.bpf.value";
|
||||
|
||||
/* Shape of the value handed to the kfunc, and what the hook returns after. */
|
||||
const volatile __u32 value_len;
|
||||
const volatile __u64 dynptr_flags;
|
||||
const volatile __s32 hook_retval;
|
||||
|
||||
char value_src[VALUE_MAX];
|
||||
|
||||
__u32 monitored_pid;
|
||||
__u32 hook_ran;
|
||||
__s32 claim_err = 1;
|
||||
|
||||
SEC("lsm/inode_init_security")
|
||||
int BPF_PROG(claim_value, struct inode *inode, struct inode *dir,
|
||||
const struct qstr *qstr, struct xattr *xattrs, int *xattr_count)
|
||||
{
|
||||
struct bpf_dynptr value;
|
||||
__u32 len = value_len;
|
||||
|
||||
if ((bpf_get_current_pid_tgid() >> 32) != monitored_pid)
|
||||
return 0;
|
||||
if (len > VALUE_MAX)
|
||||
return 0;
|
||||
|
||||
hook_ran = 1;
|
||||
if (!xattrs) {
|
||||
claim_err = -EOPNOTSUPP;
|
||||
return 0;
|
||||
}
|
||||
bpf_dynptr_from_mem(value_src, len, dynptr_flags, &value);
|
||||
claim_err = bpf_inode_init_xattr(xattrs, xattr_count, xattr_value,
|
||||
&value);
|
||||
return hook_retval;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user