Skip to content

Commit 45b5680

Browse files
dwindsorKernel Patches Daemon
authored andcommitted
kernel/bpf: Add BPF_MAP_TYPE_CRED_STORAGE map type and kfuncs
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 <[email protected]>
1 parent c32e265 commit 45b5680

File tree

8 files changed

+228
-3
lines changed

8 files changed

+228
-3
lines changed

include/linux/bpf_lsm.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,27 @@ static inline struct bpf_storage_blob *bpf_inode(
4040
return inode->i_security + bpf_lsm_blob_sizes.lbs_inode;
4141
}
4242

43+
static inline struct bpf_storage_blob *bpf_cred(
44+
const struct cred *cred)
45+
{
46+
if (unlikely(!cred->security))
47+
return NULL;
48+
49+
return cred->security + bpf_lsm_blob_sizes.lbs_cred;
50+
}
51+
4352
extern const struct bpf_func_proto bpf_inode_storage_get_proto;
4453
extern const struct bpf_func_proto bpf_inode_storage_delete_proto;
4554
void bpf_inode_storage_free(struct inode *inode);
4655

56+
void bpf_cred_storage_free(struct cred *cred);
57+
struct bpf_local_storage_data *bpf_cred_storage_get(struct bpf_map *map,
58+
struct cred *cred,
59+
void *init,
60+
int init__sz,
61+
u64 flags);
62+
int bpf_cred_storage_delete(struct bpf_map *map, struct cred *cred);
63+
4764
void bpf_lsm_find_cgroup_shim(const struct bpf_prog *prog, bpf_func_t *bpf_func);
4865

4966
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)
8198
{
8299
}
83100

101+
static inline void bpf_cred_storage_free(struct cred *cred)
102+
{
103+
}
104+
105+
static inline struct bpf_local_storage_data *bpf_cred_storage_get(struct bpf_map *map,
106+
struct cred *cred,
107+
void *init,
108+
int init__sz,
109+
u64 flags)
110+
{
111+
return NULL;
112+
}
113+
114+
static inline int bpf_cred_storage_delete(struct bpf_map *map, struct cred *cred)
115+
{
116+
return -EOPNOTSUPP;
117+
}
118+
84119
static inline void bpf_lsm_find_cgroup_shim(const struct bpf_prog *prog,
85120
bpf_func_t *bpf_func)
86121
{

include/linux/bpf_types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ BPF_MAP_TYPE(BPF_MAP_TYPE_HASH_OF_MAPS, htab_of_maps_map_ops)
110110
BPF_MAP_TYPE(BPF_MAP_TYPE_INODE_STORAGE, inode_storage_map_ops)
111111
#endif
112112
BPF_MAP_TYPE(BPF_MAP_TYPE_TASK_STORAGE, task_storage_map_ops)
113+
BPF_MAP_TYPE(BPF_MAP_TYPE_CRED_STORAGE, cred_storage_map_ops)
113114
#ifdef CONFIG_NET
114115
BPF_MAP_TYPE(BPF_MAP_TYPE_DEVMAP, dev_map_ops)
115116
BPF_MAP_TYPE(BPF_MAP_TYPE_DEVMAP_HASH, dev_map_hash_ops)

include/uapi/linux/bpf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,7 @@ enum bpf_map_type {
10261026
BPF_MAP_TYPE_USER_RINGBUF,
10271027
BPF_MAP_TYPE_CGRP_STORAGE,
10281028
BPF_MAP_TYPE_ARENA,
1029+
BPF_MAP_TYPE_CRED_STORAGE,
10291030
__MAX_BPF_MAP_TYPE
10301031
};
10311032

kernel/bpf/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o bpf_lru_list
1212
obj-$(CONFIG_BPF_SYSCALL) += local_storage.o queue_stack_maps.o ringbuf.o
1313
obj-$(CONFIG_BPF_SYSCALL) += bpf_local_storage.o bpf_task_storage.o
1414
obj-${CONFIG_BPF_LSM} += bpf_inode_storage.o
15+
obj-${CONFIG_BPF_LSM} += bpf_cred_storage.o
1516
obj-$(CONFIG_BPF_SYSCALL) += disasm.o mprog.o
1617
obj-$(CONFIG_BPF_JIT) += trampoline.o
1718
obj-$(CONFIG_BPF_SYSCALL) += btf.o memalloc.o rqspinlock.o stream.o

kernel/bpf/bpf_cred_storage.c

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <linux/rculist.h>
4+
#include <linux/list.h>
5+
#include <linux/hash.h>
6+
#include <linux/types.h>
7+
#include <linux/spinlock.h>
8+
#include <linux/bpf.h>
9+
#include <linux/bpf_local_storage.h>
10+
#include <linux/bpf_lsm.h>
11+
#include <linux/cred.h>
12+
#include <linux/btf_ids.h>
13+
#include <linux/rcupdate_trace.h>
14+
15+
DEFINE_BPF_STORAGE_CACHE(cred_cache);
16+
17+
static struct bpf_local_storage __rcu **cred_storage_ptr(void *owner)
18+
{
19+
struct cred *cred = owner;
20+
struct bpf_storage_blob *bsb;
21+
22+
bsb = bpf_cred(cred);
23+
if (!bsb)
24+
return NULL;
25+
return &bsb->storage;
26+
}
27+
28+
static struct bpf_local_storage_data *cred_storage_lookup(struct cred *cred,
29+
struct bpf_map *map,
30+
bool cacheit_lockit)
31+
{
32+
struct bpf_local_storage *cred_storage;
33+
struct bpf_local_storage_map *smap;
34+
struct bpf_storage_blob *bsb;
35+
36+
bsb = bpf_cred(cred);
37+
if (!bsb)
38+
return NULL;
39+
40+
cred_storage = rcu_dereference_check(bsb->storage, bpf_rcu_lock_held());
41+
if (!cred_storage)
42+
return NULL;
43+
44+
smap = (struct bpf_local_storage_map *)map;
45+
return bpf_local_storage_lookup(cred_storage, smap, cacheit_lockit);
46+
}
47+
48+
void bpf_cred_storage_free(struct cred *cred)
49+
{
50+
struct bpf_local_storage *local_storage;
51+
struct bpf_storage_blob *bsb;
52+
53+
bsb = bpf_cred(cred);
54+
if (!bsb)
55+
return;
56+
57+
migrate_disable();
58+
rcu_read_lock();
59+
60+
local_storage = rcu_dereference(bsb->storage);
61+
if (!local_storage)
62+
goto out;
63+
64+
bpf_local_storage_destroy(local_storage);
65+
out:
66+
rcu_read_unlock();
67+
migrate_enable();
68+
}
69+
70+
static int cred_storage_delete(struct cred *cred, struct bpf_map *map)
71+
{
72+
struct bpf_local_storage_data *sdata;
73+
74+
sdata = cred_storage_lookup(cred, map, false);
75+
if (!sdata)
76+
return -ENOENT;
77+
78+
bpf_selem_unlink(SELEM(sdata), false);
79+
80+
return 0;
81+
}
82+
83+
static struct bpf_map *cred_storage_map_alloc(union bpf_attr *attr)
84+
{
85+
return bpf_local_storage_map_alloc(attr, &cred_cache, false);
86+
}
87+
88+
static void cred_storage_map_free(struct bpf_map *map)
89+
{
90+
bpf_local_storage_map_free(map, &cred_cache, NULL);
91+
}
92+
93+
static int notsupp_get_next_key(struct bpf_map *map, void *key,
94+
void *next_key)
95+
{
96+
return -ENOTSUPP;
97+
}
98+
99+
const struct bpf_map_ops cred_storage_map_ops = {
100+
.map_meta_equal = bpf_map_meta_equal,
101+
.map_alloc_check = bpf_local_storage_map_alloc_check,
102+
.map_alloc = cred_storage_map_alloc,
103+
.map_free = cred_storage_map_free,
104+
.map_get_next_key = notsupp_get_next_key,
105+
.map_check_btf = bpf_local_storage_map_check_btf,
106+
.map_mem_usage = bpf_local_storage_map_mem_usage,
107+
.map_btf_id = &bpf_local_storage_map_btf_id[0],
108+
.map_owner_storage_ptr = cred_storage_ptr,
109+
};
110+
111+
BTF_ID_LIST_SINGLE(bpf_cred_storage_btf_ids, struct, cred)
112+
113+
__bpf_kfunc struct bpf_local_storage_data *bpf_cred_storage_get(struct bpf_map *map,
114+
struct cred *cred,
115+
void *init,
116+
int init__sz,
117+
u64 flags)
118+
{
119+
struct bpf_local_storage_data *sdata;
120+
121+
WARN_ON_ONCE(!bpf_rcu_lock_held());
122+
if (flags & ~(BPF_LOCAL_STORAGE_GET_F_CREATE))
123+
return NULL;
124+
125+
if (!cred || !cred_storage_ptr(cred))
126+
return NULL;
127+
128+
sdata = cred_storage_lookup(cred, map, true);
129+
if (sdata)
130+
return sdata;
131+
132+
/* This helper must only called from where the cred is guaranteed
133+
* to have a refcount and cannot be freed.
134+
*/
135+
if (flags & BPF_LOCAL_STORAGE_GET_F_CREATE) {
136+
sdata = bpf_local_storage_update(
137+
cred, (struct bpf_local_storage_map *)map, init,
138+
BPF_NOEXIST, false, GFP_ATOMIC);
139+
return IS_ERR(sdata) ? NULL : sdata;
140+
}
141+
142+
return NULL;
143+
}
144+
145+
__bpf_kfunc int bpf_cred_storage_delete(struct bpf_map *map, struct cred *cred)
146+
{
147+
if (!cred)
148+
return -EINVAL;
149+
150+
return cred_storage_delete(cred, map);
151+
}
152+
153+
BTF_KFUNCS_START(bpf_cred_storage_kfunc_ids)
154+
BTF_ID_FLAGS(func, bpf_cred_storage_delete, 0)
155+
BTF_ID_FLAGS(func, bpf_cred_storage_get, KF_RET_NULL)
156+
BTF_KFUNCS_END(bpf_cred_storage_kfunc_ids)
157+
158+
static const struct btf_kfunc_id_set bpf_cred_storage_kfunc_set = {
159+
.owner = THIS_MODULE,
160+
.set = &bpf_cred_storage_kfunc_ids,
161+
};
162+
163+
static int __init bpf_cred_storage_init(void)
164+
{
165+
int err;
166+
err = register_btf_kfunc_id_set(BPF_PROG_TYPE_LSM, &bpf_cred_storage_kfunc_set);
167+
if (err) {
168+
pr_err("bpf_cred_storage: failed to register kfuncs: %d\n", err);
169+
return err;
170+
}
171+
172+
pr_info("bpf_cred_storage: kfuncs registered successfully\n");
173+
return 0;
174+
}
175+
late_initcall(bpf_cred_storage_init);

kernel/bpf/syscall.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,7 +1262,8 @@ static int map_check_btf(struct bpf_map *map, struct bpf_token *token,
12621262
map->map_type != BPF_MAP_TYPE_SK_STORAGE &&
12631263
map->map_type != BPF_MAP_TYPE_INODE_STORAGE &&
12641264
map->map_type != BPF_MAP_TYPE_TASK_STORAGE &&
1265-
map->map_type != BPF_MAP_TYPE_CGRP_STORAGE) {
1265+
map->map_type != BPF_MAP_TYPE_CGRP_STORAGE &&
1266+
map->map_type != BPF_MAP_TYPE_CRED_STORAGE) {
12661267
ret = -EOPNOTSUPP;
12671268
goto free_map_tab;
12681269
}
@@ -1289,13 +1290,15 @@ static int map_check_btf(struct bpf_map *map, struct bpf_token *token,
12891290
map->map_type != BPF_MAP_TYPE_SK_STORAGE &&
12901291
map->map_type != BPF_MAP_TYPE_INODE_STORAGE &&
12911292
map->map_type != BPF_MAP_TYPE_TASK_STORAGE &&
1292-
map->map_type != BPF_MAP_TYPE_CGRP_STORAGE) {
1293+
map->map_type != BPF_MAP_TYPE_CGRP_STORAGE &&
1294+
map->map_type != BPF_MAP_TYPE_CRED_STORAGE) {
12931295
ret = -EOPNOTSUPP;
12941296
goto free_map_tab;
12951297
}
12961298
break;
12971299
case BPF_UPTR:
1298-
if (map->map_type != BPF_MAP_TYPE_TASK_STORAGE) {
1300+
if (map->map_type != BPF_MAP_TYPE_TASK_STORAGE &&
1301+
map->map_type != BPF_MAP_TYPE_CRED_STORAGE) {
12991302
ret = -EOPNOTSUPP;
13001303
goto free_map_tab;
13011304
}
@@ -1449,6 +1452,7 @@ static int map_create(union bpf_attr *attr, bool kernel)
14491452
case BPF_MAP_TYPE_SK_STORAGE:
14501453
case BPF_MAP_TYPE_INODE_STORAGE:
14511454
case BPF_MAP_TYPE_TASK_STORAGE:
1455+
case BPF_MAP_TYPE_CRED_STORAGE:
14521456
case BPF_MAP_TYPE_CGRP_STORAGE:
14531457
case BPF_MAP_TYPE_BLOOM_FILTER:
14541458
case BPF_MAP_TYPE_LPM_TRIE:

kernel/cred.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ static struct kmem_cache *cred_jar;
3838
/* init to 2 - one for init_task, one to ensure it is never freed */
3939
static struct group_info init_groups = { .usage = REFCOUNT_INIT(2) };
4040

41+
#ifdef CONFIG_BPF_LSM
42+
#include <linux/bpf_lsm.h>
43+
#endif
44+
4145
/*
4246
* The initial credentials for the initial task
4347
*/
@@ -76,6 +80,9 @@ static void put_cred_rcu(struct rcu_head *rcu)
7680
cred, atomic_long_read(&cred->usage));
7781

7882
security_cred_free(cred);
83+
#ifdef CONFIG_BPF_LSM
84+
bpf_cred_storage_free(cred);
85+
#endif
7986
key_put(cred->session_keyring);
8087
key_put(cred->process_keyring);
8188
key_put(cred->thread_keyring);

security/bpf/hooks.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ static int __init bpf_lsm_init(void)
3030

3131
struct lsm_blob_sizes bpf_lsm_blob_sizes __ro_after_init = {
3232
.lbs_inode = sizeof(struct bpf_storage_blob),
33+
.lbs_cred = sizeof(struct bpf_storage_blob),
3334
};
3435

3536
DEFINE_LSM(bpf) = {

0 commit comments

Comments
 (0)