Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf: minimize number of allocated lsm slots per program

Previous patch adds 1:1 mapping between all 211 LSM hooks
and bpf_cgroup program array. Instead of reserving a slot per
possible hook, reserve 10 slots per cgroup for lsm programs.
Those slots are dynamically allocated on demand and reclaimed.

struct cgroup_bpf {
struct bpf_prog_array * effective[33]; /* 0 264 */
/* --- cacheline 4 boundary (256 bytes) was 8 bytes ago --- */
struct hlist_head progs[33]; /* 264 264 */
/* --- cacheline 8 boundary (512 bytes) was 16 bytes ago --- */
u8 flags[33]; /* 528 33 */

/* XXX 7 bytes hole, try to pack */

struct list_head storages; /* 568 16 */
/* --- cacheline 9 boundary (576 bytes) was 8 bytes ago --- */
struct bpf_prog_array * inactive; /* 584 8 */
struct percpu_ref refcnt; /* 592 16 */
struct work_struct release_work; /* 608 72 */

/* size: 680, cachelines: 11, members: 7 */
/* sum members: 673, holes: 1, sum holes: 7 */
/* last cacheline: 40 bytes */
};

Reviewed-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Stanislav Fomichev <sdf@google.com>
Link: https://lore.kernel.org/r/20220628174314.1216643-5-sdf@google.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Stanislav Fomichev and committed by
Alexei Starovoitov
c0e19f2c 69fd337a

+64 -24
+2 -1
include/linux/bpf-cgroup-defs.h
··· 11 11 struct bpf_prog_array; 12 12 13 13 #ifdef CONFIG_BPF_LSM 14 - #define CGROUP_LSM_NUM 211 /* will be addressed in the next patch */ 14 + /* Maximum number of concurrently attachable per-cgroup LSM hooks. */ 15 + #define CGROUP_LSM_NUM 10 15 16 #else 16 17 #define CGROUP_LSM_NUM 0 17 18 #endif
+8 -1
include/linux/bpf.h
··· 2508 2508 2509 2509 struct btf_id_set; 2510 2510 bool btf_id_set_contains(const struct btf_id_set *set, u32 id); 2511 - int btf_id_set_index(const struct btf_id_set *set, u32 id); 2512 2511 2513 2512 #define MAX_BPRINTF_VARARGS 12 2514 2513 ··· 2543 2544 enum bpf_dynptr_type type, u32 offset, u32 size); 2544 2545 void bpf_dynptr_set_null(struct bpf_dynptr_kern *ptr); 2545 2546 int bpf_dynptr_check_size(u32 size); 2547 + 2548 + #ifdef CONFIG_BPF_LSM 2549 + void bpf_cgroup_atype_get(u32 attach_btf_id, int cgroup_atype); 2550 + void bpf_cgroup_atype_put(int cgroup_atype); 2551 + #else 2552 + static inline void bpf_cgroup_atype_get(u32 attach_btf_id, int cgroup_atype) {} 2553 + static inline void bpf_cgroup_atype_put(int cgroup_atype) {} 2554 + #endif /* CONFIG_BPF_LSM */ 2546 2555 2547 2556 #endif /* _LINUX_BPF_H */
-6
include/linux/bpf_lsm.h
··· 42 42 extern const struct bpf_func_proto bpf_inode_storage_delete_proto; 43 43 void bpf_inode_storage_free(struct inode *inode); 44 44 45 - int bpf_lsm_hook_idx(u32 btf_id); 46 45 void bpf_lsm_find_cgroup_shim(const struct bpf_prog *prog, bpf_func_t *bpf_func); 47 46 48 47 #else /* !CONFIG_BPF_LSM */ ··· 70 71 static inline void bpf_lsm_find_cgroup_shim(const struct bpf_prog *prog, 71 72 bpf_func_t *bpf_func) 72 73 { 73 - } 74 - 75 - static inline int bpf_lsm_hook_idx(u32 btf_id) 76 - { 77 - return -EINVAL; 78 74 } 79 75 80 76 #endif /* CONFIG_BPF_LSM */
-5
kernel/bpf/bpf_lsm.c
··· 69 69 *bpf_func = __cgroup_bpf_run_lsm_current; 70 70 } 71 71 72 - int bpf_lsm_hook_idx(u32 btf_id) 73 - { 74 - return btf_id_set_index(&bpf_lsm_hooks, btf_id); 75 - } 76 - 77 72 int bpf_lsm_verify_prog(struct bpf_verifier_log *vlog, 78 73 const struct bpf_prog *prog) 79 74 {
-10
kernel/bpf/btf.c
··· 6843 6843 return *pa - *pb; 6844 6844 } 6845 6845 6846 - int btf_id_set_index(const struct btf_id_set *set, u32 id) 6847 - { 6848 - const u32 *p; 6849 - 6850 - p = bsearch(&id, set->ids, set->cnt, sizeof(u32), btf_id_cmp_func); 6851 - if (!p) 6852 - return -1; 6853 - return p - set->ids; 6854 - } 6855 - 6856 6846 bool btf_id_set_contains(const struct btf_id_set *set, u32 id) 6857 6847 { 6858 6848 return bsearch(&id, set->ids, set->cnt, sizeof(u32), btf_id_cmp_func) != NULL;
+46 -1
kernel/bpf/cgroup.c
··· 127 127 } 128 128 129 129 #ifdef CONFIG_BPF_LSM 130 + struct cgroup_lsm_atype { 131 + u32 attach_btf_id; 132 + int refcnt; 133 + }; 134 + 135 + static struct cgroup_lsm_atype cgroup_lsm_atype[CGROUP_LSM_NUM]; 136 + 130 137 static enum cgroup_bpf_attach_type 131 138 bpf_cgroup_atype_find(enum bpf_attach_type attach_type, u32 attach_btf_id) 132 139 { 140 + int i; 141 + 142 + lockdep_assert_held(&cgroup_mutex); 143 + 133 144 if (attach_type != BPF_LSM_CGROUP) 134 145 return to_cgroup_bpf_attach_type(attach_type); 135 - return CGROUP_LSM_START + bpf_lsm_hook_idx(attach_btf_id); 146 + 147 + for (i = 0; i < ARRAY_SIZE(cgroup_lsm_atype); i++) 148 + if (cgroup_lsm_atype[i].attach_btf_id == attach_btf_id) 149 + return CGROUP_LSM_START + i; 150 + 151 + for (i = 0; i < ARRAY_SIZE(cgroup_lsm_atype); i++) 152 + if (cgroup_lsm_atype[i].attach_btf_id == 0) 153 + return CGROUP_LSM_START + i; 154 + 155 + return -E2BIG; 156 + 157 + } 158 + 159 + void bpf_cgroup_atype_get(u32 attach_btf_id, int cgroup_atype) 160 + { 161 + int i = cgroup_atype - CGROUP_LSM_START; 162 + 163 + lockdep_assert_held(&cgroup_mutex); 164 + 165 + WARN_ON_ONCE(cgroup_lsm_atype[i].attach_btf_id && 166 + cgroup_lsm_atype[i].attach_btf_id != attach_btf_id); 167 + 168 + cgroup_lsm_atype[i].attach_btf_id = attach_btf_id; 169 + cgroup_lsm_atype[i].refcnt++; 170 + } 171 + 172 + void bpf_cgroup_atype_put(int cgroup_atype) 173 + { 174 + int i = cgroup_atype - CGROUP_LSM_START; 175 + 176 + mutex_lock(&cgroup_mutex); 177 + if (--cgroup_lsm_atype[i].refcnt <= 0) 178 + cgroup_lsm_atype[i].attach_btf_id = 0; 179 + WARN_ON_ONCE(cgroup_lsm_atype[i].refcnt < 0); 180 + mutex_unlock(&cgroup_mutex); 136 181 } 137 182 #else 138 183 static enum cgroup_bpf_attach_type
+7
kernel/bpf/core.c
··· 107 107 fp->aux->prog = fp; 108 108 fp->jit_requested = ebpf_jit_enabled(); 109 109 fp->blinding_requested = bpf_jit_blinding_enabled(fp); 110 + #ifdef CONFIG_CGROUP_BPF 111 + aux->cgroup_atype = CGROUP_BPF_ATTACH_TYPE_INVALID; 112 + #endif 110 113 111 114 INIT_LIST_HEAD_RCU(&fp->aux->ksym.lnode); 112 115 mutex_init(&fp->aux->used_maps_mutex); ··· 2572 2569 aux = container_of(work, struct bpf_prog_aux, work); 2573 2570 #ifdef CONFIG_BPF_SYSCALL 2574 2571 bpf_free_kfunc_btf_tab(aux->kfunc_btf_tab); 2572 + #endif 2573 + #ifdef CONFIG_CGROUP_BPF 2574 + if (aux->cgroup_atype != CGROUP_BPF_ATTACH_TYPE_INVALID) 2575 + bpf_cgroup_atype_put(aux->cgroup_atype); 2575 2576 #endif 2576 2577 bpf_free_used_maps(aux); 2577 2578 bpf_free_used_btfs(aux);
+1
kernel/bpf/trampoline.c
··· 555 555 bpf_prog_inc(p); 556 556 bpf_link_init(&shim_link->link.link, BPF_LINK_TYPE_UNSPEC, 557 557 &bpf_shim_tramp_link_lops, p); 558 + bpf_cgroup_atype_get(p->aux->attach_btf_id, cgroup_atype); 558 559 559 560 return shim_link; 560 561 }