* [PATCH 1/2] kernel/bpf: Add BPF_MAP_TYPE_CRED_STORAGE map type and kfuncs
@ 2025-09-03 17:58 David Windsor
2025-09-03 17:58 ` [PATCH 2/2] selftests/bpf: Add cred local storage tests David Windsor
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: David Windsor @ 2025-09-03 17:58 UTC (permalink / raw)
To: bpf
Cc: linux-kernel, martin.lau, ast, daniel, andrii, eddyz87, song,
yonghong.song, john.fastabend, kpsingh, sdf, haoluo, jolsa,
dwindsor
All other bpf local storage is obtained using helpers which benefit from
RET_PTR_TO_MAP_VALUE_OR_NULL, so can return void * pointers directly to
map values. kfuncs don't have that, so return struct
bpf_local_storage_data * and access map values through sdata->data.
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
include/linux/bpf_lsm.h | 35 +++++++
include/linux/bpf_types.h | 1 +
include/uapi/linux/bpf.h | 1 +
kernel/bpf/Makefile | 1 +
kernel/bpf/bpf_cred_storage.c | 175 ++++++++++++++++++++++++++++++++++
kernel/bpf/syscall.c | 10 +-
kernel/cred.c | 7 ++
security/bpf/hooks.c | 1 +
8 files changed, 228 insertions(+), 3 deletions(-)
create mode 100644 kernel/bpf/bpf_cred_storage.c
diff --git a/include/linux/bpf_lsm.h b/include/linux/bpf_lsm.h
index 643809cc78c3..b0e2e5f2a2b8 100644
--- a/include/linux/bpf_lsm.h
+++ b/include/linux/bpf_lsm.h
@@ -40,10 +40,27 @@ static inline struct bpf_storage_blob *bpf_inode(
return inode->i_security + bpf_lsm_blob_sizes.lbs_inode;
}
+static inline struct bpf_storage_blob *bpf_cred(
+ const struct cred *cred)
+{
+ if (unlikely(!cred->security))
+ return NULL;
+
+ return cred->security + bpf_lsm_blob_sizes.lbs_cred;
+}
+
extern const struct bpf_func_proto bpf_inode_storage_get_proto;
extern const struct bpf_func_proto bpf_inode_storage_delete_proto;
void bpf_inode_storage_free(struct inode *inode);
+void bpf_cred_storage_free(struct cred *cred);
+struct bpf_local_storage_data *bpf_cred_storage_get(struct bpf_map *map,
+ struct cred *cred,
+ void *init,
+ int init__sz,
+ u64 flags);
+int bpf_cred_storage_delete(struct bpf_map *map, struct cred *cred);
+
void bpf_lsm_find_cgroup_shim(const struct bpf_prog *prog, bpf_func_t *bpf_func);
int bpf_lsm_get_retval_range(const struct bpf_prog *prog,
@@ -81,6 +98,24 @@ static inline void bpf_inode_storage_free(struct inode *inode)
{
}
+static inline void bpf_cred_storage_free(struct cred *cred)
+{
+}
+
+static inline struct bpf_local_storage_data *bpf_cred_storage_get(struct bpf_map *map,
+ struct cred *cred,
+ void *init,
+ int init__sz,
+ u64 flags)
+{
+ return NULL;
+}
+
+static inline int bpf_cred_storage_delete(struct bpf_map *map, struct cred *cred)
+{
+ return -EOPNOTSUPP;
+}
+
static inline void bpf_lsm_find_cgroup_shim(const struct bpf_prog *prog,
bpf_func_t *bpf_func)
{
diff --git a/include/linux/bpf_types.h b/include/linux/bpf_types.h
index fa78f49d4a9a..109404ff6f08 100644
--- a/include/linux/bpf_types.h
+++ b/include/linux/bpf_types.h
@@ -110,6 +110,7 @@ BPF_MAP_TYPE(BPF_MAP_TYPE_HASH_OF_MAPS, htab_of_maps_map_ops)
BPF_MAP_TYPE(BPF_MAP_TYPE_INODE_STORAGE, inode_storage_map_ops)
#endif
BPF_MAP_TYPE(BPF_MAP_TYPE_TASK_STORAGE, task_storage_map_ops)
+BPF_MAP_TYPE(BPF_MAP_TYPE_CRED_STORAGE, cred_storage_map_ops)
#ifdef CONFIG_NET
BPF_MAP_TYPE(BPF_MAP_TYPE_DEVMAP, dev_map_ops)
BPF_MAP_TYPE(BPF_MAP_TYPE_DEVMAP_HASH, dev_map_hash_ops)
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 233de8677382..8ce34453b907 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -1026,6 +1026,7 @@ enum bpf_map_type {
BPF_MAP_TYPE_USER_RINGBUF,
BPF_MAP_TYPE_CGRP_STORAGE,
BPF_MAP_TYPE_ARENA,
+ BPF_MAP_TYPE_CRED_STORAGE,
__MAX_BPF_MAP_TYPE
};
diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile
index 269c04a24664..a9e97cca162e 100644
--- a/kernel/bpf/Makefile
+++ b/kernel/bpf/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o bpf_lru_list
obj-$(CONFIG_BPF_SYSCALL) += local_storage.o queue_stack_maps.o ringbuf.o
obj-$(CONFIG_BPF_SYSCALL) += bpf_local_storage.o bpf_task_storage.o
obj-${CONFIG_BPF_LSM} += bpf_inode_storage.o
+obj-${CONFIG_BPF_LSM} += bpf_cred_storage.o
obj-$(CONFIG_BPF_SYSCALL) += disasm.o mprog.o
obj-$(CONFIG_BPF_JIT) += trampoline.o
obj-$(CONFIG_BPF_SYSCALL) += btf.o memalloc.o rqspinlock.o stream.o
diff --git a/kernel/bpf/bpf_cred_storage.c b/kernel/bpf/bpf_cred_storage.c
new file mode 100644
index 000000000000..3202bb95830e
--- /dev/null
+++ b/kernel/bpf/bpf_cred_storage.c
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/rculist.h>
+#include <linux/list.h>
+#include <linux/hash.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/bpf.h>
+#include <linux/bpf_local_storage.h>
+#include <linux/bpf_lsm.h>
+#include <linux/cred.h>
+#include <linux/btf_ids.h>
+#include <linux/rcupdate_trace.h>
+
+DEFINE_BPF_STORAGE_CACHE(cred_cache);
+
+static struct bpf_local_storage __rcu **cred_storage_ptr(void *owner)
+{
+ struct cred *cred = owner;
+ struct bpf_storage_blob *bsb;
+
+ bsb = bpf_cred(cred);
+ if (!bsb)
+ return NULL;
+ return &bsb->storage;
+}
+
+static struct bpf_local_storage_data *cred_storage_lookup(struct cred *cred,
+ struct bpf_map *map,
+ bool cacheit_lockit)
+{
+ struct bpf_local_storage *cred_storage;
+ struct bpf_local_storage_map *smap;
+ struct bpf_storage_blob *bsb;
+
+ bsb = bpf_cred(cred);
+ if (!bsb)
+ return NULL;
+
+ cred_storage = rcu_dereference_check(bsb->storage, bpf_rcu_lock_held());
+ if (!cred_storage)
+ return NULL;
+
+ smap = (struct bpf_local_storage_map *)map;
+ return bpf_local_storage_lookup(cred_storage, smap, cacheit_lockit);
+}
+
+void bpf_cred_storage_free(struct cred *cred)
+{
+ struct bpf_local_storage *local_storage;
+ struct bpf_storage_blob *bsb;
+
+ bsb = bpf_cred(cred);
+ if (!bsb)
+ return;
+
+ migrate_disable();
+ rcu_read_lock();
+
+ local_storage = rcu_dereference(bsb->storage);
+ if (!local_storage)
+ goto out;
+
+ bpf_local_storage_destroy(local_storage);
+out:
+ rcu_read_unlock();
+ migrate_enable();
+}
+
+static int cred_storage_delete(struct cred *cred, struct bpf_map *map)
+{
+ struct bpf_local_storage_data *sdata;
+
+ sdata = cred_storage_lookup(cred, map, false);
+ if (!sdata)
+ return -ENOENT;
+
+ bpf_selem_unlink(SELEM(sdata), false);
+
+ return 0;
+}
+
+static struct bpf_map *cred_storage_map_alloc(union bpf_attr *attr)
+{
+ return bpf_local_storage_map_alloc(attr, &cred_cache, false);
+}
+
+static void cred_storage_map_free(struct bpf_map *map)
+{
+ bpf_local_storage_map_free(map, &cred_cache, NULL);
+}
+
+static int notsupp_get_next_key(struct bpf_map *map, void *key,
+ void *next_key)
+{
+ return -ENOTSUPP;
+}
+
+const struct bpf_map_ops cred_storage_map_ops = {
+ .map_meta_equal = bpf_map_meta_equal,
+ .map_alloc_check = bpf_local_storage_map_alloc_check,
+ .map_alloc = cred_storage_map_alloc,
+ .map_free = cred_storage_map_free,
+ .map_get_next_key = notsupp_get_next_key,
+ .map_check_btf = bpf_local_storage_map_check_btf,
+ .map_mem_usage = bpf_local_storage_map_mem_usage,
+ .map_btf_id = &bpf_local_storage_map_btf_id[0],
+ .map_owner_storage_ptr = cred_storage_ptr,
+};
+
+BTF_ID_LIST_SINGLE(bpf_cred_storage_btf_ids, struct, cred)
+
+__bpf_kfunc struct bpf_local_storage_data *bpf_cred_storage_get(struct bpf_map *map,
+ struct cred *cred,
+ void *init,
+ int init__sz,
+ u64 flags)
+{
+ struct bpf_local_storage_data *sdata;
+
+ WARN_ON_ONCE(!bpf_rcu_lock_held());
+ if (flags & ~(BPF_LOCAL_STORAGE_GET_F_CREATE))
+ return NULL;
+
+ if (!cred || !cred_storage_ptr(cred))
+ return NULL;
+
+ sdata = cred_storage_lookup(cred, map, true);
+ if (sdata)
+ return sdata;
+
+ /* This helper must only called from where the cred is guaranteed
+ * to have a refcount and cannot be freed.
+ */
+ if (flags & BPF_LOCAL_STORAGE_GET_F_CREATE) {
+ sdata = bpf_local_storage_update(
+ cred, (struct bpf_local_storage_map *)map, init,
+ BPF_NOEXIST, false, GFP_ATOMIC);
+ return IS_ERR(sdata) ? NULL : sdata;
+ }
+
+ return NULL;
+}
+
+__bpf_kfunc int bpf_cred_storage_delete(struct bpf_map *map, struct cred *cred)
+{
+ if (!cred)
+ return -EINVAL;
+
+ return cred_storage_delete(cred, map);
+}
+
+BTF_KFUNCS_START(bpf_cred_storage_kfunc_ids)
+BTF_ID_FLAGS(func, bpf_cred_storage_delete, 0)
+BTF_ID_FLAGS(func, bpf_cred_storage_get, KF_RET_NULL)
+BTF_KFUNCS_END(bpf_cred_storage_kfunc_ids)
+
+static const struct btf_kfunc_id_set bpf_cred_storage_kfunc_set = {
+ .owner = THIS_MODULE,
+ .set = &bpf_cred_storage_kfunc_ids,
+};
+
+static int __init bpf_cred_storage_init(void)
+{
+ int err;
+ err = register_btf_kfunc_id_set(BPF_PROG_TYPE_LSM, &bpf_cred_storage_kfunc_set);
+ if (err) {
+ pr_err("bpf_cred_storage: failed to register kfuncs: %d\n", err);
+ return err;
+ }
+
+ pr_info("bpf_cred_storage: kfuncs registered successfully\n");
+ return 0;
+}
+late_initcall(bpf_cred_storage_init);
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 0fbfa8532c39..b44e7f243e10 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -1262,7 +1262,8 @@ static int map_check_btf(struct bpf_map *map, struct bpf_token *token,
map->map_type != BPF_MAP_TYPE_SK_STORAGE &&
map->map_type != BPF_MAP_TYPE_INODE_STORAGE &&
map->map_type != BPF_MAP_TYPE_TASK_STORAGE &&
- map->map_type != BPF_MAP_TYPE_CGRP_STORAGE) {
+ map->map_type != BPF_MAP_TYPE_CGRP_STORAGE &&
+ map->map_type != BPF_MAP_TYPE_CRED_STORAGE) {
ret = -EOPNOTSUPP;
goto free_map_tab;
}
@@ -1289,13 +1290,15 @@ static int map_check_btf(struct bpf_map *map, struct bpf_token *token,
map->map_type != BPF_MAP_TYPE_SK_STORAGE &&
map->map_type != BPF_MAP_TYPE_INODE_STORAGE &&
map->map_type != BPF_MAP_TYPE_TASK_STORAGE &&
- map->map_type != BPF_MAP_TYPE_CGRP_STORAGE) {
+ map->map_type != BPF_MAP_TYPE_CGRP_STORAGE &&
+ map->map_type != BPF_MAP_TYPE_CRED_STORAGE) {
ret = -EOPNOTSUPP;
goto free_map_tab;
}
break;
case BPF_UPTR:
- if (map->map_type != BPF_MAP_TYPE_TASK_STORAGE) {
+ if (map->map_type != BPF_MAP_TYPE_TASK_STORAGE &&
+ map->map_type != BPF_MAP_TYPE_CRED_STORAGE) {
ret = -EOPNOTSUPP;
goto free_map_tab;
}
@@ -1449,6 +1452,7 @@ static int map_create(union bpf_attr *attr, bool kernel)
case BPF_MAP_TYPE_SK_STORAGE:
case BPF_MAP_TYPE_INODE_STORAGE:
case BPF_MAP_TYPE_TASK_STORAGE:
+ case BPF_MAP_TYPE_CRED_STORAGE:
case BPF_MAP_TYPE_CGRP_STORAGE:
case BPF_MAP_TYPE_BLOOM_FILTER:
case BPF_MAP_TYPE_LPM_TRIE:
diff --git a/kernel/cred.c b/kernel/cred.c
index 9676965c0981..a1be27fe5f4c 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -38,6 +38,10 @@ static struct kmem_cache *cred_jar;
/* init to 2 - one for init_task, one to ensure it is never freed */
static struct group_info init_groups = { .usage = REFCOUNT_INIT(2) };
+#ifdef CONFIG_BPF_LSM
+#include <linux/bpf_lsm.h>
+#endif
+
/*
* The initial credentials for the initial task
*/
@@ -76,6 +80,9 @@ static void put_cred_rcu(struct rcu_head *rcu)
cred, atomic_long_read(&cred->usage));
security_cred_free(cred);
+#ifdef CONFIG_BPF_LSM
+ bpf_cred_storage_free(cred);
+#endif
key_put(cred->session_keyring);
key_put(cred->process_keyring);
key_put(cred->thread_keyring);
diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c
index db759025abe1..d42badc18eb6 100644
--- a/security/bpf/hooks.c
+++ b/security/bpf/hooks.c
@@ -30,6 +30,7 @@ static int __init bpf_lsm_init(void)
struct lsm_blob_sizes bpf_lsm_blob_sizes __ro_after_init = {
.lbs_inode = sizeof(struct bpf_storage_blob),
+ .lbs_cred = sizeof(struct bpf_storage_blob),
};
DEFINE_LSM(bpf) = {
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 2/2] selftests/bpf: Add cred local storage tests
2025-09-03 17:58 [PATCH 1/2] kernel/bpf: Add BPF_MAP_TYPE_CRED_STORAGE map type and kfuncs David Windsor
@ 2025-09-03 17:58 ` David Windsor
2025-09-03 23:29 ` [PATCH 1/2] kernel/bpf: Add BPF_MAP_TYPE_CRED_STORAGE map type and kfuncs Alexei Starovoitov
2025-09-04 13:00 ` kernel test robot
2 siblings, 0 replies; 6+ messages in thread
From: David Windsor @ 2025-09-03 17:58 UTC (permalink / raw)
To: bpf
Cc: linux-kernel, martin.lau, ast, daniel, andrii, eddyz87, song,
yonghong.song, john.fastabend, kpsingh, sdf, haoluo, jolsa,
dwindsor
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
.../selftests/bpf/prog_tests/cred_storage.c | 52 +++++++++++
.../selftests/bpf/progs/cred_storage.c | 87 +++++++++++++++++++
2 files changed, 139 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/cred_storage.c
create mode 100644 tools/testing/selftests/bpf/progs/cred_storage.c
diff --git a/tools/testing/selftests/bpf/prog_tests/cred_storage.c b/tools/testing/selftests/bpf/prog_tests/cred_storage.c
new file mode 100644
index 000000000000..1a99f6453a0f
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/cred_storage.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <test_progs.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include "cred_storage.skel.h"
+
+static void test_cred_lifecycle(void)
+{
+ struct cred_storage *skel;
+ pid_t child;
+ int status, err;
+
+ skel = cred_storage__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "skel_load"))
+ return;
+
+ err = cred_storage__attach(skel);
+ if (!ASSERT_OK(err, "attach"))
+ goto cleanup;
+
+ skel->data->cred_storage_result = -1;
+
+ skel->bss->monitored_pid = getpid();
+
+ child = fork();
+ if (child == 0) {
+ /* forces cred_prepare with new credentials */
+ exit(0);
+ } else if (child > 0) {
+ waitpid(child, &status, 0);
+
+ /* give time for cred_free hook to run */
+ usleep(10000);
+
+ /* verify that the dummy value was stored and persisted */
+ ASSERT_EQ(skel->data->cred_storage_result, 0,
+ "cred_storage_dummy_value");
+ } else {
+ ASSERT_TRUE(false, "fork failed");
+ }
+
+cleanup:
+ cred_storage__destroy(skel);
+}
+
+void test_cred_storage(void)
+{
+ if (test__start_subtest("lifecycle"))
+ test_cred_lifecycle();
+}
diff --git a/tools/testing/selftests/bpf/progs/cred_storage.c b/tools/testing/selftests/bpf/progs/cred_storage.c
new file mode 100644
index 000000000000..ae66d3b00d2e
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/cred_storage.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (C) 2025 David Windsor.
+ */
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+
+char _license[] SEC("license") = "GPL";
+
+#define DUMMY_STORAGE_VALUE 0xdeadbeef
+
+extern struct bpf_local_storage_data *bpf_cred_storage_get(struct bpf_map *map,
+ struct cred *cred,
+ void *init, int init__sz, __u64 flags) __ksym;
+
+__u32 monitored_pid = 0;
+int cred_storage_result = -1;
+
+struct cred_storage {
+ __u32 value;
+};
+
+struct {
+ __uint(type, BPF_MAP_TYPE_CRED_STORAGE);
+ __uint(map_flags, BPF_F_NO_PREALLOC);
+ __type(key, int);
+ __type(value, struct cred_storage);
+} cred_storage_map SEC(".maps");
+
+SEC("lsm/cred_prepare")
+int BPF_PROG(cred_prepare, struct cred *new, const struct cred *old, gfp_t gfp)
+{
+ __u32 pid = bpf_get_current_pid_tgid() >> 32;
+ struct cred_storage init_storage = {
+ .value = DUMMY_STORAGE_VALUE,
+ };
+ struct bpf_local_storage_data *sdata;
+ struct cred_storage *storage;
+
+ if (pid != monitored_pid)
+ return 0;
+
+ sdata = bpf_cred_storage_get((struct bpf_map *)&cred_storage_map, new, &init_storage,
+ sizeof(init_storage), BPF_LOCAL_STORAGE_GET_F_CREATE);
+ if (!sdata)
+ return 0;
+
+ storage = (struct cred_storage *)sdata->data;
+ if (!storage)
+ return 0;
+
+ /* Verify the storage was initialized correctly */
+ if (storage->value == DUMMY_STORAGE_VALUE)
+ cred_storage_result = 0;
+
+ return 0;
+}
+
+SEC("lsm/cred_free")
+int BPF_PROG(cred_free, struct cred *cred)
+{
+ __u32 pid = bpf_get_current_pid_tgid() >> 32;
+ struct bpf_local_storage_data *sdata;
+ struct cred_storage *storage;
+
+ if (pid != monitored_pid)
+ return 0;
+
+ /* Try to retrieve the storage that should have been created in prepare */
+ sdata = bpf_cred_storage_get((struct bpf_map *)&cred_storage_map, cred,
+ NULL, 0, 0);
+ if (!sdata)
+ return 0;
+
+ storage = (struct cred_storage *)sdata->data;
+ if (!storage)
+ return 0;
+
+ /* Verify the dummy value is still there during free */
+ if (storage->value == DUMMY_STORAGE_VALUE)
+ cred_storage_result = 0;
+
+ return 0;
+}
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH 1/2] kernel/bpf: Add BPF_MAP_TYPE_CRED_STORAGE map type and kfuncs
2025-09-03 17:58 [PATCH 1/2] kernel/bpf: Add BPF_MAP_TYPE_CRED_STORAGE map type and kfuncs David Windsor
2025-09-03 17:58 ` [PATCH 2/2] selftests/bpf: Add cred local storage tests David Windsor
@ 2025-09-03 23:29 ` Alexei Starovoitov
2025-09-03 23:49 ` David Windsor
2025-09-04 13:00 ` kernel test robot
2 siblings, 1 reply; 6+ messages in thread
From: Alexei Starovoitov @ 2025-09-03 23:29 UTC (permalink / raw)
To: David Windsor
Cc: bpf, LKML, Martin KaFai Lau, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Eduard, Song Liu, Yonghong Song, John Fastabend,
KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa
On Wed, Sep 3, 2025 at 10:58 AM David Windsor <dwindsor@gmail.com> wrote:
>
> All other bpf local storage is obtained using helpers which benefit from
> RET_PTR_TO_MAP_VALUE_OR_NULL, so can return void * pointers directly to
> map values. kfuncs don't have that, so return struct
> bpf_local_storage_data * and access map values through sdata->data.
The commit log tells nothing about motivation for such "cred local storage".
Technically it's doable, but sorry not going to.
cred is not something that needs fast access and automatic lifetime
management. Use hash map with 'struct cred *' as a key.
pw-bot: cr
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] kernel/bpf: Add BPF_MAP_TYPE_CRED_STORAGE map type and kfuncs
2025-09-03 23:29 ` [PATCH 1/2] kernel/bpf: Add BPF_MAP_TYPE_CRED_STORAGE map type and kfuncs Alexei Starovoitov
@ 2025-09-03 23:49 ` David Windsor
0 siblings, 0 replies; 6+ messages in thread
From: David Windsor @ 2025-09-03 23:49 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: bpf, LKML, Martin KaFai Lau, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Eduard, Song Liu, Yonghong Song, John Fastabend,
KP Singh, Stanislav Fomichev, Hao Luo, Jiri Olsa
> cred is not something that needs fast access and automatic lifetime
management.
Use case is for eg KRSI to be able to track credential leakage.
Lifetime management absolutely helps there. Also, the use case is
"whatever the bpf-lsm maintainers had in mind in their presentation,"
right?
Also, this entire presentation says otherwise:
https://lpc.events/event/18/contributions/1940/attachments/1438/3389/kfuncs%20for%20BPF%20LSM%20Use%20Cases.v4.pdf
From that:
"Still missing storage for following types:
struct file
struct cred
struct ipc
struct msg_msg
struct superblock"
> Technically it's doable, but sorry not going to.
Sweet I'll do it
On Wed, Sep 3, 2025 at 7:30 PM Alexei Starovoitov
<alexei.starovoitov@gmail.com> wrote:
>
> On Wed, Sep 3, 2025 at 10:58 AM David Windsor <dwindsor@gmail.com> wrote:
> >
> > All other bpf local storage is obtained using helpers which benefit from
> > RET_PTR_TO_MAP_VALUE_OR_NULL, so can return void * pointers directly to
> > map values. kfuncs don't have that, so return struct
> > bpf_local_storage_data * and access map values through sdata->data.
>
> The commit log tells nothing about motivation for such "cred local storage".
> Technically it's doable, but sorry not going to.
> cred is not something that needs fast access and automatic lifetime
> management. Use hash map with 'struct cred *' as a key.
>
> pw-bot: cr
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] kernel/bpf: Add BPF_MAP_TYPE_CRED_STORAGE map type and kfuncs
2025-09-03 17:58 [PATCH 1/2] kernel/bpf: Add BPF_MAP_TYPE_CRED_STORAGE map type and kfuncs David Windsor
2025-09-03 17:58 ` [PATCH 2/2] selftests/bpf: Add cred local storage tests David Windsor
2025-09-03 23:29 ` [PATCH 1/2] kernel/bpf: Add BPF_MAP_TYPE_CRED_STORAGE map type and kfuncs Alexei Starovoitov
@ 2025-09-04 13:00 ` kernel test robot
2 siblings, 0 replies; 6+ messages in thread
From: kernel test robot @ 2025-09-04 13:00 UTC (permalink / raw)
To: David Windsor, bpf
Cc: oe-kbuild-all, linux-kernel, martin.lau, ast, daniel, andrii,
eddyz87, song, yonghong.song, john.fastabend, kpsingh, sdf,
haoluo, jolsa, dwindsor
Hi David,
kernel test robot noticed the following build errors:
[auto build test ERROR on bpf-next/net]
[also build test ERROR on bpf-next/master bpf/master linus/master v6.17-rc4]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/David-Windsor/selftests-bpf-Add-cred-local-storage-tests/20250904-015935
base: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git net
patch link: https://lore.kernel.org/r/20250903175841.232537-1-dwindsor%40gmail.com
patch subject: [PATCH 1/2] kernel/bpf: Add BPF_MAP_TYPE_CRED_STORAGE map type and kfuncs
config: nios2-randconfig-001-20250904 (https://download.01.org/0day-ci/archive/20250904/202509042029.W1pcuqjU-lkp@intel.com/config)
compiler: nios2-linux-gcc (GCC) 11.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250904/202509042029.W1pcuqjU-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202509042029.W1pcuqjU-lkp@intel.com/
All errors (new ones prefixed by >>):
>> nios2-linux-ld: kernel/bpf/syscall.o:(.rodata+0x734): undefined reference to `cred_storage_map_ops'
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 0/2] bpf: Add BPF_MAP_TYPE_CRED_STORAGE support
@ 2025-09-12 22:25 David Windsor
2025-09-12 22:25 ` [PATCH 2/2] selftests/bpf: Add cred local storage tests David Windsor
0 siblings, 1 reply; 6+ messages in thread
From: David Windsor @ 2025-09-12 22:25 UTC (permalink / raw)
To: bpf
Cc: linux-kernel, martin.lau, ast, daniel, andrii, eddyz87, song,
yonghong.song, john.fastabend, kpsingh, sdf, haoluo, jolsa,
dwindsor
This series adds BPF_MAP_TYPE_CRED_STORAGE, enabling BPF programs to
associate data with credential structures (struct cred).
Like other local storage types (task, inode, sk), this provides automatic
lifecycle management and is useful for LSM programs tracking credential
state across LSM calls. Lifetime management is necessary for detecting
credential leaks and enforcing time-based security policies.
The implementation uses kfuncs (bpf_cred_storage_get/delete) that return
bpf_local_storage_data pointers, with map values accessible via the data
field.
v2:
- fix kernel ci build error
David Windsor (2):
bpf: Add BPF_MAP_TYPE_CRED_STORAGE map type and kfuncs
selftests/bpf: Add cred local storage tests
include/linux/bpf_lsm.h | 35 ++++
include/linux/bpf_types.h | 1 +
include/uapi/linux/bpf.h | 1 +
kernel/bpf/Makefile | 1 +
kernel/bpf/bpf_cred_storage.c | 175 ++++++++++++++++++
kernel/bpf/syscall.c | 10 +-
kernel/cred.c | 7 +
security/bpf/hooks.c | 1 +
.../selftests/bpf/prog_tests/cred_storage.c | 52 ++++++
.../selftests/bpf/progs/cred_storage.c | 87 +++++++++
10 files changed, 367 insertions(+), 3 deletions(-)
create mode 100644 kernel/bpf/bpf_cred_storage.c
create mode 100644 tools/testing/selftests/bpf/prog_tests/cred_storage.c
create mode 100644 tools/testing/selftests/bpf/progs/cred_storage.c
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/2] selftests/bpf: Add cred local storage tests
2025-09-12 22:25 [PATCH v2 0/2] bpf: Add BPF_MAP_TYPE_CRED_STORAGE support David Windsor
@ 2025-09-12 22:25 ` David Windsor
0 siblings, 0 replies; 6+ messages in thread
From: David Windsor @ 2025-09-12 22:25 UTC (permalink / raw)
To: bpf
Cc: linux-kernel, martin.lau, ast, daniel, andrii, eddyz87, song,
yonghong.song, john.fastabend, kpsingh, sdf, haoluo, jolsa,
dwindsor
Add test coverage for the new BPF_MAP_TYPE_CRED_STORAGE map type.
The test verifies that credential storage can be created, accessed,
and persists across credential lifecycle events.
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
.../selftests/bpf/prog_tests/cred_storage.c | 52 +++++++++++
.../selftests/bpf/progs/cred_storage.c | 87 +++++++++++++++++++
2 files changed, 139 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/cred_storage.c
create mode 100644 tools/testing/selftests/bpf/progs/cred_storage.c
diff --git a/tools/testing/selftests/bpf/prog_tests/cred_storage.c b/tools/testing/selftests/bpf/prog_tests/cred_storage.c
new file mode 100644
index 000000000000..1a99f6453a0f
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/cred_storage.c
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <test_progs.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include "cred_storage.skel.h"
+
+static void test_cred_lifecycle(void)
+{
+ struct cred_storage *skel;
+ pid_t child;
+ int status, err;
+
+ skel = cred_storage__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "skel_load"))
+ return;
+
+ err = cred_storage__attach(skel);
+ if (!ASSERT_OK(err, "attach"))
+ goto cleanup;
+
+ skel->data->cred_storage_result = -1;
+
+ skel->bss->monitored_pid = getpid();
+
+ child = fork();
+ if (child == 0) {
+ /* forces cred_prepare with new credentials */
+ exit(0);
+ } else if (child > 0) {
+ waitpid(child, &status, 0);
+
+ /* give time for cred_free hook to run */
+ usleep(10000);
+
+ /* verify that the dummy value was stored and persisted */
+ ASSERT_EQ(skel->data->cred_storage_result, 0,
+ "cred_storage_dummy_value");
+ } else {
+ ASSERT_TRUE(false, "fork failed");
+ }
+
+cleanup:
+ cred_storage__destroy(skel);
+}
+
+void test_cred_storage(void)
+{
+ if (test__start_subtest("lifecycle"))
+ test_cred_lifecycle();
+}
diff --git a/tools/testing/selftests/bpf/progs/cred_storage.c b/tools/testing/selftests/bpf/progs/cred_storage.c
new file mode 100644
index 000000000000..ae66d3b00d2e
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/cred_storage.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (C) 2025 David Windsor.
+ */
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+
+char _license[] SEC("license") = "GPL";
+
+#define DUMMY_STORAGE_VALUE 0xdeadbeef
+
+extern struct bpf_local_storage_data *bpf_cred_storage_get(struct bpf_map *map,
+ struct cred *cred,
+ void *init, int init__sz, __u64 flags) __ksym;
+
+__u32 monitored_pid = 0;
+int cred_storage_result = -1;
+
+struct cred_storage {
+ __u32 value;
+};
+
+struct {
+ __uint(type, BPF_MAP_TYPE_CRED_STORAGE);
+ __uint(map_flags, BPF_F_NO_PREALLOC);
+ __type(key, int);
+ __type(value, struct cred_storage);
+} cred_storage_map SEC(".maps");
+
+SEC("lsm/cred_prepare")
+int BPF_PROG(cred_prepare, struct cred *new, const struct cred *old, gfp_t gfp)
+{
+ __u32 pid = bpf_get_current_pid_tgid() >> 32;
+ struct cred_storage init_storage = {
+ .value = DUMMY_STORAGE_VALUE,
+ };
+ struct bpf_local_storage_data *sdata;
+ struct cred_storage *storage;
+
+ if (pid != monitored_pid)
+ return 0;
+
+ sdata = bpf_cred_storage_get((struct bpf_map *)&cred_storage_map, new, &init_storage,
+ sizeof(init_storage), BPF_LOCAL_STORAGE_GET_F_CREATE);
+ if (!sdata)
+ return 0;
+
+ storage = (struct cred_storage *)sdata->data;
+ if (!storage)
+ return 0;
+
+ /* Verify the storage was initialized correctly */
+ if (storage->value == DUMMY_STORAGE_VALUE)
+ cred_storage_result = 0;
+
+ return 0;
+}
+
+SEC("lsm/cred_free")
+int BPF_PROG(cred_free, struct cred *cred)
+{
+ __u32 pid = bpf_get_current_pid_tgid() >> 32;
+ struct bpf_local_storage_data *sdata;
+ struct cred_storage *storage;
+
+ if (pid != monitored_pid)
+ return 0;
+
+ /* Try to retrieve the storage that should have been created in prepare */
+ sdata = bpf_cred_storage_get((struct bpf_map *)&cred_storage_map, cred,
+ NULL, 0, 0);
+ if (!sdata)
+ return 0;
+
+ storage = (struct cred_storage *)sdata->data;
+ if (!storage)
+ return 0;
+
+ /* Verify the dummy value is still there during free */
+ if (storage->value == DUMMY_STORAGE_VALUE)
+ cred_storage_result = 0;
+
+ return 0;
+}
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-09-12 22:25 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-03 17:58 [PATCH 1/2] kernel/bpf: Add BPF_MAP_TYPE_CRED_STORAGE map type and kfuncs David Windsor
2025-09-03 17:58 ` [PATCH 2/2] selftests/bpf: Add cred local storage tests David Windsor
2025-09-03 23:29 ` [PATCH 1/2] kernel/bpf: Add BPF_MAP_TYPE_CRED_STORAGE map type and kfuncs Alexei Starovoitov
2025-09-03 23:49 ` David Windsor
2025-09-04 13:00 ` kernel test robot
-- strict thread matches above, loose matches on Subject: below --
2025-09-12 22:25 [PATCH v2 0/2] bpf: Add BPF_MAP_TYPE_CRED_STORAGE support David Windsor
2025-09-12 22:25 ` [PATCH 2/2] selftests/bpf: Add cred local storage tests David Windsor
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.