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

Configure Feed

Select the types of activity you want to include in your feed.

resolve_btfids: Support for KF_IMPLICIT_ARGS

Implement BTF modifications in resolve_btfids to support BPF kernel
functions with implicit arguments.

For a kfunc marked with KF_IMPLICIT_ARGS flag, a new function
prototype is added to BTF that does not have implicit arguments. The
kfunc's prototype is then updated to a new one in BTF. This prototype
is the intended interface for the BPF programs.

A <func_name>_impl function is added to BTF to make the original kfunc
prototype searchable for the BPF verifier. If a <func_name>_impl
function already exists in BTF, its interpreted as a legacy case, and
this step is skipped.

Whether an argument is implicit is determined by its type:
currently only `struct bpf_prog_aux *` is supported.

As a result, the BTF associated with kfunc is changed from

__bpf_kfunc bpf_foo(int arg1, struct bpf_prog_aux *aux);

into

bpf_foo_impl(int arg1, struct bpf_prog_aux *aux);
__bpf_kfunc bpf_foo(int arg1);

For more context see previous discussions and patches [1][2].

[1] https://lore.kernel.org/dwarves/ba1650aa-fafd-49a8-bea4-bdddee7c38c9@linux.dev/
[2] https://lore.kernel.org/bpf/20251029190113.3323406-1-ihor.solodrai@linux.dev/

Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
Link: https://lore.kernel.org/r/20260120222638.3976562-6-ihor.solodrai@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Ihor Solodrai and committed by
Alexei Starovoitov
9d199965 2583e81f

+382
+382
tools/bpf/resolve_btfids/main.c
··· 152 152 int nr_typedefs; 153 153 }; 154 154 155 + #define KF_IMPLICIT_ARGS (1 << 16) 156 + #define KF_IMPL_SUFFIX "_impl" 157 + 158 + struct kfunc { 159 + const char *name; 160 + u32 btf_id; 161 + u32 flags; 162 + }; 163 + 164 + struct btf2btf_context { 165 + struct btf *btf; 166 + u32 *decl_tags; 167 + u32 nr_decl_tags; 168 + u32 max_decl_tags; 169 + struct kfunc *kfuncs; 170 + u32 nr_kfuncs; 171 + u32 max_kfuncs; 172 + }; 173 + 155 174 static int verbose; 156 175 static int warnings; 157 176 ··· 856 837 return 0; 857 838 } 858 839 840 + static const struct btf_type *btf_type_skip_qualifiers(const struct btf *btf, s32 type_id) 841 + { 842 + const struct btf_type *t = btf__type_by_id(btf, type_id); 843 + 844 + while (btf_is_mod(t)) 845 + t = btf__type_by_id(btf, t->type); 846 + 847 + return t; 848 + } 849 + 850 + static int push_decl_tag_id(struct btf2btf_context *ctx, u32 decl_tag_id) 851 + { 852 + u32 *arr = ctx->decl_tags; 853 + u32 cap = ctx->max_decl_tags; 854 + 855 + if (ctx->nr_decl_tags + 1 > cap) { 856 + cap = max(cap + 256, cap * 2); 857 + arr = realloc(arr, sizeof(u32) * cap); 858 + if (!arr) 859 + return -ENOMEM; 860 + ctx->max_decl_tags = cap; 861 + ctx->decl_tags = arr; 862 + } 863 + 864 + ctx->decl_tags[ctx->nr_decl_tags++] = decl_tag_id; 865 + 866 + return 0; 867 + } 868 + 869 + static int push_kfunc(struct btf2btf_context *ctx, struct kfunc *kfunc) 870 + { 871 + struct kfunc *arr = ctx->kfuncs; 872 + u32 cap = ctx->max_kfuncs; 873 + 874 + if (ctx->nr_kfuncs + 1 > cap) { 875 + cap = max(cap + 256, cap * 2); 876 + arr = realloc(arr, sizeof(struct kfunc) * cap); 877 + if (!arr) 878 + return -ENOMEM; 879 + ctx->max_kfuncs = cap; 880 + ctx->kfuncs = arr; 881 + } 882 + 883 + ctx->kfuncs[ctx->nr_kfuncs++] = *kfunc; 884 + 885 + return 0; 886 + } 887 + 888 + static int collect_decl_tags(struct btf2btf_context *ctx) 889 + { 890 + const u32 type_cnt = btf__type_cnt(ctx->btf); 891 + struct btf *btf = ctx->btf; 892 + const struct btf_type *t; 893 + int err; 894 + 895 + for (u32 id = 1; id < type_cnt; id++) { 896 + t = btf__type_by_id(btf, id); 897 + if (!btf_is_decl_tag(t)) 898 + continue; 899 + err = push_decl_tag_id(ctx, id); 900 + if (err) 901 + return err; 902 + } 903 + 904 + return 0; 905 + } 906 + 907 + /* 908 + * To find the kfunc flags having its struct btf_id (with ELF addresses) 909 + * we need to find the address that is in range of a set8. 910 + * If a set8 is found, then the flags are located at addr + 4 bytes. 911 + * Return 0 (no flags!) if not found. 912 + */ 913 + static u32 find_kfunc_flags(struct object *obj, struct btf_id *kfunc_id) 914 + { 915 + const u32 *elf_data_ptr = obj->efile.idlist->d_buf; 916 + u64 set_lower_addr, set_upper_addr, addr; 917 + struct btf_id *set_id; 918 + struct rb_node *next; 919 + u32 flags; 920 + u64 idx; 921 + 922 + for (next = rb_first(&obj->sets); next; next = rb_next(next)) { 923 + set_id = rb_entry(next, struct btf_id, rb_node); 924 + if (set_id->kind != BTF_ID_KIND_SET8 || set_id->addr_cnt != 1) 925 + continue; 926 + 927 + set_lower_addr = set_id->addr[0]; 928 + set_upper_addr = set_lower_addr + set_id->cnt * sizeof(u64); 929 + 930 + for (u32 i = 0; i < kfunc_id->addr_cnt; i++) { 931 + addr = kfunc_id->addr[i]; 932 + /* 933 + * Lower bound is exclusive to skip the 8-byte header of the set. 934 + * Upper bound is inclusive to capture the last entry at offset 8*cnt. 935 + */ 936 + if (set_lower_addr < addr && addr <= set_upper_addr) { 937 + pr_debug("found kfunc %s in BTF_ID_FLAGS %s\n", 938 + kfunc_id->name, set_id->name); 939 + idx = addr - obj->efile.idlist_addr; 940 + idx = idx / sizeof(u32) + 1; 941 + flags = elf_data_ptr[idx]; 942 + 943 + return flags; 944 + } 945 + } 946 + } 947 + 948 + return 0; 949 + } 950 + 951 + static int collect_kfuncs(struct object *obj, struct btf2btf_context *ctx) 952 + { 953 + const char *tag_name, *func_name; 954 + struct btf *btf = ctx->btf; 955 + const struct btf_type *t; 956 + u32 flags, func_id; 957 + struct kfunc kfunc; 958 + struct btf_id *id; 959 + int err; 960 + 961 + if (ctx->nr_decl_tags == 0) 962 + return 0; 963 + 964 + for (u32 i = 0; i < ctx->nr_decl_tags; i++) { 965 + t = btf__type_by_id(btf, ctx->decl_tags[i]); 966 + if (btf_kflag(t) || btf_decl_tag(t)->component_idx != -1) 967 + continue; 968 + 969 + tag_name = btf__name_by_offset(btf, t->name_off); 970 + if (strcmp(tag_name, "bpf_kfunc") != 0) 971 + continue; 972 + 973 + func_id = t->type; 974 + t = btf__type_by_id(btf, func_id); 975 + if (!btf_is_func(t)) 976 + continue; 977 + 978 + func_name = btf__name_by_offset(btf, t->name_off); 979 + if (!func_name) 980 + continue; 981 + 982 + id = btf_id__find(&obj->funcs, func_name); 983 + if (!id || id->kind != BTF_ID_KIND_SYM) 984 + continue; 985 + 986 + flags = find_kfunc_flags(obj, id); 987 + 988 + kfunc.name = id->name; 989 + kfunc.btf_id = func_id; 990 + kfunc.flags = flags; 991 + 992 + err = push_kfunc(ctx, &kfunc); 993 + if (err) 994 + return err; 995 + } 996 + 997 + return 0; 998 + } 999 + 1000 + static int build_btf2btf_context(struct object *obj, struct btf2btf_context *ctx) 1001 + { 1002 + int err; 1003 + 1004 + ctx->btf = obj->btf; 1005 + 1006 + err = collect_decl_tags(ctx); 1007 + if (err) { 1008 + pr_err("ERROR: resolve_btfids: failed to collect decl tags from BTF\n"); 1009 + return err; 1010 + } 1011 + 1012 + err = collect_kfuncs(obj, ctx); 1013 + if (err) { 1014 + pr_err("ERROR: resolve_btfids: failed to collect kfuncs from BTF\n"); 1015 + return err; 1016 + } 1017 + 1018 + return 0; 1019 + } 1020 + 1021 + 1022 + /* Implicit BPF kfunc arguments can only be of particular types */ 1023 + static bool is_kf_implicit_arg(const struct btf *btf, const struct btf_param *p) 1024 + { 1025 + static const char *const kf_implicit_arg_types[] = { 1026 + "bpf_prog_aux", 1027 + }; 1028 + const struct btf_type *t; 1029 + const char *name; 1030 + 1031 + t = btf_type_skip_qualifiers(btf, p->type); 1032 + if (!btf_is_ptr(t)) 1033 + return false; 1034 + 1035 + t = btf_type_skip_qualifiers(btf, t->type); 1036 + if (!btf_is_struct(t)) 1037 + return false; 1038 + 1039 + name = btf__name_by_offset(btf, t->name_off); 1040 + if (!name) 1041 + return false; 1042 + 1043 + for (int i = 0; i < ARRAY_SIZE(kf_implicit_arg_types); i++) 1044 + if (strcmp(name, kf_implicit_arg_types[i]) == 0) 1045 + return true; 1046 + 1047 + return false; 1048 + } 1049 + 1050 + /* 1051 + * For a kfunc with KF_IMPLICIT_ARGS we do the following: 1052 + * 1. Add a new function with _impl suffix in the name, with the prototype 1053 + * of the original kfunc. 1054 + * 2. Add all decl tags except "bpf_kfunc" for the _impl func. 1055 + * 3. Add a new function prototype with modified list of arguments: 1056 + * omitting implicit args. 1057 + * 4. Change the prototype of the original kfunc to the new one. 1058 + * 1059 + * This way we transform the BTF associated with the kfunc from 1060 + * __bpf_kfunc bpf_foo(int arg1, void *implicit_arg); 1061 + * into 1062 + * bpf_foo_impl(int arg1, void *implicit_arg); 1063 + * __bpf_kfunc bpf_foo(int arg1); 1064 + * 1065 + * If a kfunc with KF_IMPLICIT_ARGS already has an _impl counterpart 1066 + * in BTF, then it's a legacy case: an _impl function is declared in the 1067 + * source code. In this case, we can skip adding an _impl function, but we 1068 + * still have to add a func prototype that omits implicit args. 1069 + */ 1070 + static int process_kfunc_with_implicit_args(struct btf2btf_context *ctx, struct kfunc *kfunc) 1071 + { 1072 + s32 idx, new_proto_id, new_func_id, proto_id; 1073 + const char *param_name, *tag_name; 1074 + const struct btf_param *params; 1075 + enum btf_func_linkage linkage; 1076 + char tmp_name[KSYM_NAME_LEN]; 1077 + struct btf *btf = ctx->btf; 1078 + int err, len, nr_params; 1079 + struct btf_type *t; 1080 + 1081 + t = (struct btf_type *)btf__type_by_id(btf, kfunc->btf_id); 1082 + if (!t || !btf_is_func(t)) { 1083 + pr_err("ERROR: resolve_btfids: btf id %d is not a function\n", kfunc->btf_id); 1084 + return -EINVAL; 1085 + } 1086 + 1087 + linkage = btf_vlen(t); 1088 + 1089 + proto_id = t->type; 1090 + t = (struct btf_type *)btf__type_by_id(btf, proto_id); 1091 + if (!t || !btf_is_func_proto(t)) { 1092 + pr_err("ERROR: resolve_btfids: btf id %d is not a function prototype\n", proto_id); 1093 + return -EINVAL; 1094 + } 1095 + 1096 + len = snprintf(tmp_name, sizeof(tmp_name), "%s%s", kfunc->name, KF_IMPL_SUFFIX); 1097 + if (len < 0 || len >= sizeof(tmp_name)) { 1098 + pr_err("ERROR: function name is too long: %s%s\n", kfunc->name, KF_IMPL_SUFFIX); 1099 + return -E2BIG; 1100 + } 1101 + 1102 + if (btf__find_by_name_kind(btf, tmp_name, BTF_KIND_FUNC) > 0) { 1103 + pr_debug("resolve_btfids: function %s already exists in BTF\n", tmp_name); 1104 + goto add_new_proto; 1105 + } 1106 + 1107 + /* Add a new function with _impl suffix and original prototype */ 1108 + new_func_id = btf__add_func(btf, tmp_name, linkage, proto_id); 1109 + if (new_func_id < 0) { 1110 + pr_err("ERROR: resolve_btfids: failed to add func %s to BTF\n", tmp_name); 1111 + return new_func_id; 1112 + } 1113 + 1114 + /* Copy all decl tags except "bpf_kfunc" from the original kfunc to the new one */ 1115 + for (int i = 0; i < ctx->nr_decl_tags; i++) { 1116 + t = (struct btf_type *)btf__type_by_id(btf, ctx->decl_tags[i]); 1117 + if (t->type != kfunc->btf_id) 1118 + continue; 1119 + 1120 + tag_name = btf__name_by_offset(btf, t->name_off); 1121 + if (strcmp(tag_name, "bpf_kfunc") == 0) 1122 + continue; 1123 + 1124 + idx = btf_decl_tag(t)->component_idx; 1125 + 1126 + if (btf_kflag(t)) 1127 + err = btf__add_decl_attr(btf, tag_name, new_func_id, idx); 1128 + else 1129 + err = btf__add_decl_tag(btf, tag_name, new_func_id, idx); 1130 + 1131 + if (err < 0) { 1132 + pr_err("ERROR: resolve_btfids: failed to add decl tag %s for %s\n", 1133 + tag_name, tmp_name); 1134 + return -EINVAL; 1135 + } 1136 + } 1137 + 1138 + add_new_proto: 1139 + t = (struct btf_type *)btf__type_by_id(btf, proto_id); 1140 + new_proto_id = btf__add_func_proto(btf, t->type); 1141 + if (new_proto_id < 0) { 1142 + pr_err("ERROR: resolve_btfids: failed to add func proto for %s\n", kfunc->name); 1143 + return new_proto_id; 1144 + } 1145 + 1146 + /* Add non-implicit args to the new prototype */ 1147 + t = (struct btf_type *)btf__type_by_id(btf, proto_id); 1148 + nr_params = btf_vlen(t); 1149 + for (int i = 0; i < nr_params; i++) { 1150 + params = btf_params(t); 1151 + if (is_kf_implicit_arg(btf, &params[i])) 1152 + break; 1153 + param_name = btf__name_by_offset(btf, params[i].name_off); 1154 + err = btf__add_func_param(btf, param_name, params[i].type); 1155 + if (err < 0) { 1156 + pr_err("ERROR: resolve_btfids: failed to add param %s for %s\n", 1157 + param_name, kfunc->name); 1158 + return err; 1159 + } 1160 + t = (struct btf_type *)btf__type_by_id(btf, proto_id); 1161 + } 1162 + 1163 + /* Finally change the prototype of the original kfunc to the new one */ 1164 + t = (struct btf_type *)btf__type_by_id(btf, kfunc->btf_id); 1165 + t->type = new_proto_id; 1166 + 1167 + pr_debug("resolve_btfids: updated BTF for kfunc with implicit args %s\n", kfunc->name); 1168 + 1169 + return 0; 1170 + } 1171 + 1172 + static int btf2btf(struct object *obj) 1173 + { 1174 + struct btf2btf_context ctx = {}; 1175 + int err; 1176 + 1177 + err = build_btf2btf_context(obj, &ctx); 1178 + if (err) 1179 + goto out; 1180 + 1181 + for (u32 i = 0; i < ctx.nr_kfuncs; i++) { 1182 + struct kfunc *kfunc = &ctx.kfuncs[i]; 1183 + 1184 + if (!(kfunc->flags & KF_IMPLICIT_ARGS)) 1185 + continue; 1186 + 1187 + err = process_kfunc_with_implicit_args(&ctx, kfunc); 1188 + if (err) 1189 + goto out; 1190 + } 1191 + 1192 + err = 0; 1193 + out: 1194 + free(ctx.decl_tags); 1195 + free(ctx.kfuncs); 1196 + 1197 + return err; 1198 + } 1199 + 859 1200 /* 860 1201 * Sort types by name in ascending order resulting in all 861 1202 * anonymous types being placed before named types. ··· 1503 1124 goto out; 1504 1125 1505 1126 if (load_btf(&obj)) 1127 + goto out; 1128 + 1129 + if (btf2btf(&obj)) 1506 1130 goto out; 1507 1131 1508 1132 if (finalize_btf(&obj))