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.

libbpf: Support sanitization of BTF layout for older kernels

Add a FEAT_BTF_LAYOUT feature check which checks if the
kernel supports BTF layout information. Also sanitize
BTF if it contains layout data but the kernel does not
support it. The sanitization requires rewriting raw
BTF data to update the header and eliminate the layout
section (since it lies between the types and strings),
so refactor sanitization to do the raw BTF retrieval
and creation of updated BTF, returning that new BTF
on success.

Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20260326145444.2076244-7-alan.maguire@oracle.com

authored by

Alan Maguire and committed by
Andrii Nakryiko
081677d0 6ad89285

+131 -40
+29
tools/lib/bpf/features.c
··· 589 589 } 590 590 #endif 591 591 592 + static int probe_kern_btf_layout(int token_fd) 593 + { 594 + static const char strs[] = "\0int"; 595 + __u32 types[] = { 596 + /* int */ 597 + BTF_TYPE_INT_ENC(1, BTF_INT_SIGNED, 0, 32, 4), 598 + }; 599 + struct btf_layout layout[] = { 600 + { 0, 0, 0 }, 601 + { sizeof(__u32), 0, 0 }, 602 + }; 603 + struct btf_header hdr = { 604 + .magic = BTF_MAGIC, 605 + .version = BTF_VERSION, 606 + .hdr_len = sizeof(struct btf_header), 607 + .type_len = sizeof(types), 608 + .str_off = sizeof(types) + sizeof(layout), 609 + .str_len = sizeof(strs), 610 + .layout_off = sizeof(types), 611 + .layout_len = sizeof(layout), 612 + }; 613 + 614 + return probe_fd(libbpf__load_raw_btf_hdr(&hdr, (char *)types, strs, 615 + (char *)layout, token_fd)); 616 + } 617 + 592 618 typedef int (*feature_probe_fn)(int /* token_fd */); 593 619 594 620 static struct kern_feature_cache feature_cache; ··· 695 669 }, 696 670 [FEAT_UPROBE_SYSCALL] = { 697 671 "kernel supports uprobe syscall", probe_uprobe_syscall, 672 + }, 673 + [FEAT_BTF_LAYOUT] = { 674 + "kernel supports BTF layout", probe_kern_btf_layout, 698 675 }, 699 676 }; 700 677
+67 -21
tools/lib/bpf/libbpf.c
··· 3138 3138 bool has_type_tag = kernel_supports(obj, FEAT_BTF_TYPE_TAG); 3139 3139 bool has_enum64 = kernel_supports(obj, FEAT_BTF_ENUM64); 3140 3140 bool has_qmark_datasec = kernel_supports(obj, FEAT_BTF_QMARK_DATASEC); 3141 + bool has_layout = kernel_supports(obj, FEAT_BTF_LAYOUT); 3141 3142 3142 3143 return !has_func || !has_datasec || !has_func_global || !has_float || 3143 - !has_decl_tag || !has_type_tag || !has_enum64 || !has_qmark_datasec; 3144 + !has_decl_tag || !has_type_tag || !has_enum64 || !has_qmark_datasec || 3145 + !has_layout; 3144 3146 } 3145 3147 3146 - static int bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *btf) 3148 + static struct btf *bpf_object__sanitize_btf(struct bpf_object *obj, struct btf *orig_btf) 3147 3149 { 3148 3150 bool has_func_global = kernel_supports(obj, FEAT_BTF_GLOBAL_FUNC); 3149 3151 bool has_datasec = kernel_supports(obj, FEAT_BTF_DATASEC); ··· 3155 3153 bool has_type_tag = kernel_supports(obj, FEAT_BTF_TYPE_TAG); 3156 3154 bool has_enum64 = kernel_supports(obj, FEAT_BTF_ENUM64); 3157 3155 bool has_qmark_datasec = kernel_supports(obj, FEAT_BTF_QMARK_DATASEC); 3156 + bool has_layout = kernel_supports(obj, FEAT_BTF_LAYOUT); 3158 3157 int enum64_placeholder_id = 0; 3158 + const struct btf_header *hdr; 3159 + struct btf *btf = NULL; 3160 + const void *raw_data; 3159 3161 struct btf_type *t; 3160 3162 int i, j, vlen; 3163 + __u32 sz; 3164 + int err; 3165 + 3166 + /* clone BTF to sanitize a copy and leave the original intact */ 3167 + raw_data = btf__raw_data(orig_btf, &sz); 3168 + if (!raw_data) 3169 + return ERR_PTR(-ENOMEM); 3170 + /* btf_header() gives us endian-safe header info */ 3171 + hdr = btf_header(orig_btf); 3172 + 3173 + if (!has_layout && hdr->hdr_len >= sizeof(struct btf_header) && 3174 + (hdr->layout_len != 0 || hdr->layout_off != 0)) { 3175 + const struct btf_header *old_hdr = raw_data; 3176 + struct btf_header *new_hdr; 3177 + void *new_raw_data; 3178 + __u32 new_str_off; 3179 + 3180 + /* 3181 + * Need to rewrite BTF to exclude layout information and 3182 + * move string section to immediately after types. 3183 + */ 3184 + new_raw_data = malloc(sz); 3185 + if (!new_raw_data) 3186 + return ERR_PTR(-ENOMEM); 3187 + 3188 + memcpy(new_raw_data, raw_data, sz); 3189 + new_hdr = new_raw_data; 3190 + new_hdr->layout_off = 0; 3191 + new_hdr->layout_len = 0; 3192 + new_str_off = hdr->type_off + hdr->type_len; 3193 + /* Handle swapped endian case */ 3194 + if (old_hdr->magic != hdr->magic) 3195 + new_hdr->str_off = bswap_32(new_str_off); 3196 + else 3197 + new_hdr->str_off = new_str_off; 3198 + 3199 + memmove(new_raw_data + hdr->hdr_len + new_str_off, 3200 + new_raw_data + hdr->hdr_len + hdr->str_off, 3201 + hdr->str_len); 3202 + sz = hdr->hdr_len + hdr->type_off + hdr->type_len + hdr->str_len; 3203 + btf = btf__new(new_raw_data, sz); 3204 + free(new_raw_data); 3205 + } else { 3206 + btf = btf__new(raw_data, sz); 3207 + } 3208 + err = libbpf_get_error(btf); 3209 + if (err) 3210 + return ERR_PTR(err); 3211 + 3212 + /* enforce 8-byte pointers for BPF-targeted BTFs */ 3213 + btf__set_pointer_size(btf, 8); 3161 3214 3162 3215 for (i = 1; i < btf__type_cnt(btf); i++) { 3163 3216 t = (struct btf_type *)btf__type_by_id(btf, i); ··· 3290 3233 3291 3234 if (enum64_placeholder_id == 0) { 3292 3235 enum64_placeholder_id = btf__add_int(btf, "enum64_placeholder", 1, 0); 3293 - if (enum64_placeholder_id < 0) 3294 - return enum64_placeholder_id; 3295 - 3236 + if (enum64_placeholder_id < 0) { 3237 + btf__free(btf); 3238 + return ERR_PTR(enum64_placeholder_id); 3239 + } 3296 3240 t = (struct btf_type *)btf__type_by_id(btf, i); 3297 3241 } 3298 3242 ··· 3307 3249 } 3308 3250 } 3309 3251 3310 - return 0; 3252 + return btf; 3311 3253 } 3312 3254 3313 3255 static bool libbpf_needs_btf(const struct bpf_object *obj) ··· 3658 3600 3659 3601 sanitize = btf_needs_sanitization(obj); 3660 3602 if (sanitize) { 3661 - const void *raw_data; 3662 - __u32 sz; 3663 - 3664 - /* clone BTF to sanitize a copy and leave the original intact */ 3665 - raw_data = btf__raw_data(obj->btf, &sz); 3666 - kern_btf = btf__new(raw_data, sz); 3667 - err = libbpf_get_error(kern_btf); 3668 - if (err) 3669 - return err; 3670 - 3671 - /* enforce 8-byte pointers for BPF-targeted BTFs */ 3672 - btf__set_pointer_size(obj->btf, 8); 3673 - err = bpf_object__sanitize_btf(obj, kern_btf); 3674 - if (err) 3675 - return err; 3603 + kern_btf = bpf_object__sanitize_btf(obj, obj->btf); 3604 + if (IS_ERR(kern_btf)) 3605 + return PTR_ERR(kern_btf); 3676 3606 } 3677 3607 3678 3608 if (obj->gen_loader) {
+6
tools/lib/bpf/libbpf_internal.h
··· 396 396 FEAT_LDIMM64_FULL_RANGE_OFF, 397 397 /* Kernel supports uprobe syscall */ 398 398 FEAT_UPROBE_SYSCALL, 399 + /* Kernel supports BTF layout information */ 400 + FEAT_BTF_LAYOUT, 399 401 __FEAT_CNT, 400 402 }; 401 403 ··· 424 422 int libbpf__load_raw_btf(const char *raw_types, size_t types_len, 425 423 const char *str_sec, size_t str_len, 426 424 int token_fd); 425 + int libbpf__load_raw_btf_hdr(const struct btf_header *hdr, 426 + const char *raw_types, const char *str_sec, 427 + const char *layout_sec, int token_fd); 428 + 427 429 int btf_load_into_kernel(struct btf *btf, 428 430 char *log_buf, size_t log_sz, __u32 log_level, 429 431 int token_fd);
+29 -19
tools/lib/bpf/libbpf_probes.c
··· 218 218 return libbpf_err(ret); 219 219 } 220 220 221 + int libbpf__load_raw_btf_hdr(const struct btf_header *hdr, const char *raw_types, 222 + const char *str_sec, const char *layout_sec, 223 + int token_fd) 224 + { 225 + LIBBPF_OPTS(bpf_btf_load_opts, opts, 226 + .token_fd = token_fd, 227 + .btf_flags = token_fd ? BPF_F_TOKEN_FD : 0, 228 + ); 229 + int btf_fd, btf_len; 230 + __u8 *raw_btf; 231 + 232 + btf_len = hdr->hdr_len + hdr->type_off + hdr->type_len + hdr->str_len + hdr->layout_len; 233 + raw_btf = malloc(btf_len); 234 + if (!raw_btf) 235 + return -ENOMEM; 236 + 237 + memcpy(raw_btf, hdr, sizeof(*hdr)); 238 + memcpy(raw_btf + hdr->hdr_len + hdr->type_off, raw_types, hdr->type_len); 239 + memcpy(raw_btf + hdr->hdr_len + hdr->str_off, str_sec, hdr->str_len); 240 + if (layout_sec) 241 + memcpy(raw_btf + hdr->hdr_len + hdr->layout_off, layout_sec, hdr->layout_len); 242 + 243 + btf_fd = bpf_btf_load(raw_btf, btf_len, &opts); 244 + 245 + free(raw_btf); 246 + return btf_fd; 247 + } 248 + 221 249 int libbpf__load_raw_btf(const char *raw_types, size_t types_len, 222 250 const char *str_sec, size_t str_len, 223 251 int token_fd) ··· 258 230 .str_off = types_len, 259 231 .str_len = str_len, 260 232 }; 261 - LIBBPF_OPTS(bpf_btf_load_opts, opts, 262 - .token_fd = token_fd, 263 - .btf_flags = token_fd ? BPF_F_TOKEN_FD : 0, 264 - ); 265 - int btf_fd, btf_len; 266 - __u8 *raw_btf; 267 233 268 - btf_len = hdr.hdr_len + hdr.type_len + hdr.str_len; 269 - raw_btf = malloc(btf_len); 270 - if (!raw_btf) 271 - return -ENOMEM; 272 - 273 - memcpy(raw_btf, &hdr, sizeof(hdr)); 274 - memcpy(raw_btf + hdr.hdr_len, raw_types, hdr.type_len); 275 - memcpy(raw_btf + hdr.hdr_len + hdr.type_len, str_sec, hdr.str_len); 276 - 277 - btf_fd = bpf_btf_load(raw_btf, btf_len, &opts); 278 - 279 - free(raw_btf); 280 - return btf_fd; 234 + return libbpf__load_raw_btf_hdr(&hdr, raw_types, str_sec, NULL, token_fd); 281 235 } 282 236 283 237 static int load_local_storage_btf(void)