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

bpf: Add kfunc filter function to 'struct btf_kfunc_id_set'

This commit adds the ability to filter kfuncs to certain BPF program
types. This is required to limit bpf_sock_destroy kfunc implemented in
follow-up commits to programs with attach type 'BPF_TRACE_ITER'.

The commit adds a callback filter to 'struct btf_kfunc_id_set'. The
filter has access to the `bpf_prog` construct including its properties
such as `expected_attached_type`.

Signed-off-by: Aditi Ghag <aditi.ghag@isovalent.com>
Link: https://lore.kernel.org/r/20230519225157.760788-7-aditi.ghag@isovalent.com
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>

authored by

Aditi Ghag and committed by
Martin KaFai Lau
e924e80e c96dac8d

+69 -21
+11 -7
include/linux/btf.h
··· 98 98 union bpf_attr; 99 99 struct btf_show; 100 100 struct btf_id_set; 101 + struct bpf_prog; 102 + 103 + typedef int (*btf_kfunc_filter_t)(const struct bpf_prog *prog, u32 kfunc_id); 101 104 102 105 struct btf_kfunc_id_set { 103 106 struct module *owner; 104 107 struct btf_id_set8 *set; 108 + btf_kfunc_filter_t filter; 105 109 }; 106 110 107 111 struct btf_id_dtor_kfunc { ··· 483 479 return bsearch(&id, set->pairs, set->cnt, sizeof(set->pairs[0]), btf_id_cmp_func); 484 480 } 485 481 486 - struct bpf_prog; 487 482 struct bpf_verifier_log; 488 483 489 484 #ifdef CONFIG_BPF_SYSCALL ··· 490 487 const char *btf_name_by_offset(const struct btf *btf, u32 offset); 491 488 struct btf *btf_parse_vmlinux(void); 492 489 struct btf *bpf_prog_get_target_btf(const struct bpf_prog *prog); 493 - u32 *btf_kfunc_id_set_contains(const struct btf *btf, 494 - enum bpf_prog_type prog_type, 495 - u32 kfunc_btf_id); 496 - u32 *btf_kfunc_is_modify_return(const struct btf *btf, u32 kfunc_btf_id); 490 + u32 *btf_kfunc_id_set_contains(const struct btf *btf, u32 kfunc_btf_id, 491 + const struct bpf_prog *prog); 492 + u32 *btf_kfunc_is_modify_return(const struct btf *btf, u32 kfunc_btf_id, 493 + const struct bpf_prog *prog); 497 494 int register_btf_kfunc_id_set(enum bpf_prog_type prog_type, 498 495 const struct btf_kfunc_id_set *s); 499 496 int register_btf_fmodret_id_set(const struct btf_kfunc_id_set *kset); ··· 520 517 return NULL; 521 518 } 522 519 static inline u32 *btf_kfunc_id_set_contains(const struct btf *btf, 523 - enum bpf_prog_type prog_type, 524 - u32 kfunc_btf_id) 520 + u32 kfunc_btf_id, 521 + struct bpf_prog *prog) 522 + 525 523 { 526 524 return NULL; 527 525 }
+54 -11
kernel/bpf/btf.c
··· 222 222 enum { 223 223 BTF_KFUNC_SET_MAX_CNT = 256, 224 224 BTF_DTOR_KFUNC_MAX_CNT = 256, 225 + BTF_KFUNC_FILTER_MAX_CNT = 16, 226 + }; 227 + 228 + struct btf_kfunc_hook_filter { 229 + btf_kfunc_filter_t filters[BTF_KFUNC_FILTER_MAX_CNT]; 230 + u32 nr_filters; 225 231 }; 226 232 227 233 struct btf_kfunc_set_tab { 228 234 struct btf_id_set8 *sets[BTF_KFUNC_HOOK_MAX]; 235 + struct btf_kfunc_hook_filter hook_filters[BTF_KFUNC_HOOK_MAX]; 229 236 }; 230 237 231 238 struct btf_id_dtor_kfunc_tab { ··· 7676 7669 /* Kernel Function (kfunc) BTF ID set registration API */ 7677 7670 7678 7671 static int btf_populate_kfunc_set(struct btf *btf, enum btf_kfunc_hook hook, 7679 - struct btf_id_set8 *add_set) 7672 + const struct btf_kfunc_id_set *kset) 7680 7673 { 7674 + struct btf_kfunc_hook_filter *hook_filter; 7675 + struct btf_id_set8 *add_set = kset->set; 7681 7676 bool vmlinux_set = !btf_is_module(btf); 7677 + bool add_filter = !!kset->filter; 7682 7678 struct btf_kfunc_set_tab *tab; 7683 7679 struct btf_id_set8 *set; 7684 7680 u32 set_cnt; ··· 7696 7686 return 0; 7697 7687 7698 7688 tab = btf->kfunc_set_tab; 7689 + 7690 + if (tab && add_filter) { 7691 + u32 i; 7692 + 7693 + hook_filter = &tab->hook_filters[hook]; 7694 + for (i = 0; i < hook_filter->nr_filters; i++) { 7695 + if (hook_filter->filters[i] == kset->filter) { 7696 + add_filter = false; 7697 + break; 7698 + } 7699 + } 7700 + 7701 + if (add_filter && hook_filter->nr_filters == BTF_KFUNC_FILTER_MAX_CNT) { 7702 + ret = -E2BIG; 7703 + goto end; 7704 + } 7705 + } 7706 + 7699 7707 if (!tab) { 7700 7708 tab = kzalloc(sizeof(*tab), GFP_KERNEL | __GFP_NOWARN); 7701 7709 if (!tab) ··· 7736 7708 */ 7737 7709 if (!vmlinux_set) { 7738 7710 tab->sets[hook] = add_set; 7739 - return 0; 7711 + goto do_add_filter; 7740 7712 } 7741 7713 7742 7714 /* In case of vmlinux sets, there may be more than one set being ··· 7778 7750 7779 7751 sort(set->pairs, set->cnt, sizeof(set->pairs[0]), btf_id_cmp_func, NULL); 7780 7752 7753 + do_add_filter: 7754 + if (add_filter) { 7755 + hook_filter = &tab->hook_filters[hook]; 7756 + hook_filter->filters[hook_filter->nr_filters++] = kset->filter; 7757 + } 7781 7758 return 0; 7782 7759 end: 7783 7760 btf_free_kfunc_set_tab(btf); ··· 7791 7758 7792 7759 static u32 *__btf_kfunc_id_set_contains(const struct btf *btf, 7793 7760 enum btf_kfunc_hook hook, 7794 - u32 kfunc_btf_id) 7761 + u32 kfunc_btf_id, 7762 + const struct bpf_prog *prog) 7795 7763 { 7764 + struct btf_kfunc_hook_filter *hook_filter; 7796 7765 struct btf_id_set8 *set; 7797 - u32 *id; 7766 + u32 *id, i; 7798 7767 7799 7768 if (hook >= BTF_KFUNC_HOOK_MAX) 7800 7769 return NULL; 7801 7770 if (!btf->kfunc_set_tab) 7802 7771 return NULL; 7772 + hook_filter = &btf->kfunc_set_tab->hook_filters[hook]; 7773 + for (i = 0; i < hook_filter->nr_filters; i++) { 7774 + if (hook_filter->filters[i](prog, kfunc_btf_id)) 7775 + return NULL; 7776 + } 7803 7777 set = btf->kfunc_set_tab->sets[hook]; 7804 7778 if (!set) 7805 7779 return NULL; ··· 7861 7821 * protection for looking up a well-formed btf->kfunc_set_tab. 7862 7822 */ 7863 7823 u32 *btf_kfunc_id_set_contains(const struct btf *btf, 7864 - enum bpf_prog_type prog_type, 7865 - u32 kfunc_btf_id) 7824 + u32 kfunc_btf_id, 7825 + const struct bpf_prog *prog) 7866 7826 { 7827 + enum bpf_prog_type prog_type = resolve_prog_type(prog); 7867 7828 enum btf_kfunc_hook hook; 7868 7829 u32 *kfunc_flags; 7869 7830 7870 - kfunc_flags = __btf_kfunc_id_set_contains(btf, BTF_KFUNC_HOOK_COMMON, kfunc_btf_id); 7831 + kfunc_flags = __btf_kfunc_id_set_contains(btf, BTF_KFUNC_HOOK_COMMON, kfunc_btf_id, prog); 7871 7832 if (kfunc_flags) 7872 7833 return kfunc_flags; 7873 7834 7874 7835 hook = bpf_prog_type_to_kfunc_hook(prog_type); 7875 - return __btf_kfunc_id_set_contains(btf, hook, kfunc_btf_id); 7836 + return __btf_kfunc_id_set_contains(btf, hook, kfunc_btf_id, prog); 7876 7837 } 7877 7838 7878 - u32 *btf_kfunc_is_modify_return(const struct btf *btf, u32 kfunc_btf_id) 7839 + u32 *btf_kfunc_is_modify_return(const struct btf *btf, u32 kfunc_btf_id, 7840 + const struct bpf_prog *prog) 7879 7841 { 7880 - return __btf_kfunc_id_set_contains(btf, BTF_KFUNC_HOOK_FMODRET, kfunc_btf_id); 7842 + return __btf_kfunc_id_set_contains(btf, BTF_KFUNC_HOOK_FMODRET, kfunc_btf_id, prog); 7881 7843 } 7882 7844 7883 7845 static int __register_btf_kfunc_id_set(enum btf_kfunc_hook hook, ··· 7910 7868 goto err_out; 7911 7869 } 7912 7870 7913 - ret = btf_populate_kfunc_set(btf, hook, kset->set); 7871 + ret = btf_populate_kfunc_set(btf, hook, kset); 7872 + 7914 7873 err_out: 7915 7874 btf_put(btf); 7916 7875 return ret;
+4 -3
kernel/bpf/verifier.c
··· 10939 10939 *kfunc_name = func_name; 10940 10940 func_proto = btf_type_by_id(desc_btf, func->type); 10941 10941 10942 - kfunc_flags = btf_kfunc_id_set_contains(desc_btf, resolve_prog_type(env->prog), func_id); 10942 + kfunc_flags = btf_kfunc_id_set_contains(desc_btf, func_id, env->prog); 10943 10943 if (!kfunc_flags) { 10944 10944 return -EACCES; 10945 10945 } ··· 19010 19010 * in the fmodret id set with the KF_SLEEPABLE flag. 19011 19011 */ 19012 19012 else { 19013 - u32 *flags = btf_kfunc_is_modify_return(btf, btf_id); 19013 + u32 *flags = btf_kfunc_is_modify_return(btf, btf_id, 19014 + prog); 19014 19015 19015 19016 if (flags && (*flags & KF_SLEEPABLE)) 19016 19017 ret = 0; ··· 19039 19038 return -EINVAL; 19040 19039 } 19041 19040 ret = -EINVAL; 19042 - if (btf_kfunc_is_modify_return(btf, btf_id) || 19041 + if (btf_kfunc_is_modify_return(btf, btf_id, prog) || 19043 19042 !check_attach_modify_return(addr, tname)) 19044 19043 ret = 0; 19045 19044 if (ret) {