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.

bpf: Process in-kernel BTF

If in-kernel BTF exists parse it and prepare 'struct btf *btf_vmlinux'
for further use by the verifier.
In-kernel BTF is trusted just like kallsyms and other build artifacts
embedded into vmlinux.
Yet run this BTF image through BTF verifier to make sure
that it is valid and it wasn't mangled during the build.
If in-kernel BTF is incorrect it means either gcc or pahole or kernel
are buggy. In such case disallow loading BPF programs.

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Andrii Nakryiko <andriin@fb.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Link: https://lore.kernel.org/bpf/20191016032505.2089704-4-ast@kernel.org

authored by

Alexei Starovoitov and committed by
Daniel Borkmann
8580ac94 7c6a469e

+94 -2
+3 -1
include/linux/bpf_verifier.h
··· 330 330 #define BPF_LOG_STATS 4 331 331 #define BPF_LOG_LEVEL (BPF_LOG_LEVEL1 | BPF_LOG_LEVEL2) 332 332 #define BPF_LOG_MASK (BPF_LOG_LEVEL | BPF_LOG_STATS) 333 + #define BPF_LOG_KERNEL (BPF_LOG_MASK + 1) /* kernel internal flag */ 333 334 334 335 static inline bool bpf_verifier_log_needed(const struct bpf_verifier_log *log) 335 336 { 336 - return log->level && log->ubuf && !bpf_verifier_log_full(log); 337 + return (log->level && log->ubuf && !bpf_verifier_log_full(log)) || 338 + log->level == BPF_LOG_KERNEL; 337 339 } 338 340 339 341 #define BPF_MAX_SUBPROGS 256
+1
include/linux/btf.h
··· 56 56 #ifdef CONFIG_BPF_SYSCALL 57 57 const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id); 58 58 const char *btf_name_by_offset(const struct btf *btf, u32 offset); 59 + struct btf *btf_parse_vmlinux(void); 59 60 #else 60 61 static inline const struct btf_type *btf_type_by_id(const struct btf *btf, 61 62 u32 type_id)
+70 -1
kernel/bpf/btf.c
··· 698 698 if (!bpf_verifier_log_needed(log)) 699 699 return; 700 700 701 + /* btf verifier prints all types it is processing via 702 + * btf_verifier_log_type(..., fmt = NULL). 703 + * Skip those prints for in-kernel BTF verification. 704 + */ 705 + if (log->level == BPF_LOG_KERNEL && !fmt) 706 + return; 707 + 701 708 __btf_verifier_log(log, "[%u] %s %s%s", 702 709 env->log_type_id, 703 710 btf_kind_str[kind], ··· 742 735 if (!bpf_verifier_log_needed(log)) 743 736 return; 744 737 738 + if (log->level == BPF_LOG_KERNEL && !fmt) 739 + return; 745 740 /* The CHECK_META phase already did a btf dump. 746 741 * 747 742 * If member is logged again, it must hit an error in ··· 786 777 787 778 if (!bpf_verifier_log_needed(log)) 788 779 return; 780 + if (log->level == BPF_LOG_KERNEL && !fmt) 781 + return; 789 782 if (env->phase != CHECK_META) 790 783 btf_verifier_log_type(env, datasec_type, NULL); 791 784 ··· 813 802 if (!bpf_verifier_log_needed(log)) 814 803 return; 815 804 805 + if (log->level == BPF_LOG_KERNEL) 806 + return; 816 807 hdr = &btf->hdr; 817 808 __btf_verifier_log(log, "magic: 0x%x\n", hdr->magic); 818 809 __btf_verifier_log(log, "version: %u\n", hdr->version); ··· 2418 2405 return -EINVAL; 2419 2406 } 2420 2407 2421 - 2408 + if (env->log.level == BPF_LOG_KERNEL) 2409 + continue; 2422 2410 btf_verifier_log(env, "\t%s val=%d\n", 2423 2411 __btf_name_by_offset(btf, enums[i].name_off), 2424 2412 enums[i].val); ··· 3378 3364 btf_verifier_env_free(env); 3379 3365 if (btf) 3380 3366 btf_free(btf); 3367 + return ERR_PTR(err); 3368 + } 3369 + 3370 + extern char __weak _binary__btf_vmlinux_bin_start[]; 3371 + extern char __weak _binary__btf_vmlinux_bin_end[]; 3372 + 3373 + struct btf *btf_parse_vmlinux(void) 3374 + { 3375 + struct btf_verifier_env *env = NULL; 3376 + struct bpf_verifier_log *log; 3377 + struct btf *btf = NULL; 3378 + int err; 3379 + 3380 + env = kzalloc(sizeof(*env), GFP_KERNEL | __GFP_NOWARN); 3381 + if (!env) 3382 + return ERR_PTR(-ENOMEM); 3383 + 3384 + log = &env->log; 3385 + log->level = BPF_LOG_KERNEL; 3386 + 3387 + btf = kzalloc(sizeof(*btf), GFP_KERNEL | __GFP_NOWARN); 3388 + if (!btf) { 3389 + err = -ENOMEM; 3390 + goto errout; 3391 + } 3392 + env->btf = btf; 3393 + 3394 + btf->data = _binary__btf_vmlinux_bin_start; 3395 + btf->data_size = _binary__btf_vmlinux_bin_end - 3396 + _binary__btf_vmlinux_bin_start; 3397 + 3398 + err = btf_parse_hdr(env); 3399 + if (err) 3400 + goto errout; 3401 + 3402 + btf->nohdr_data = btf->data + btf->hdr.hdr_len; 3403 + 3404 + err = btf_parse_str_sec(env); 3405 + if (err) 3406 + goto errout; 3407 + 3408 + err = btf_check_all_metas(env); 3409 + if (err) 3410 + goto errout; 3411 + 3412 + btf_verifier_env_free(env); 3413 + refcount_set(&btf->refcnt, 1); 3414 + return btf; 3415 + 3416 + errout: 3417 + btf_verifier_env_free(env); 3418 + if (btf) { 3419 + kvfree(btf->types); 3420 + kfree(btf); 3421 + } 3381 3422 return ERR_PTR(err); 3382 3423 } 3383 3424
+20
kernel/bpf/verifier.c
··· 207 207 int func_id; 208 208 }; 209 209 210 + struct btf *btf_vmlinux; 211 + 210 212 static DEFINE_MUTEX(bpf_verifier_lock); 211 213 212 214 static const struct bpf_line_info * ··· 245 243 n = min(log->len_total - log->len_used - 1, n); 246 244 log->kbuf[n] = '\0'; 247 245 246 + if (log->level == BPF_LOG_KERNEL) { 247 + pr_err("BPF:%s\n", log->kbuf); 248 + return; 249 + } 248 250 if (!copy_to_user(log->ubuf + log->len_used, log->kbuf, n + 1)) 249 251 log->len_used += n; 250 252 else ··· 9300 9294 env->ops = bpf_verifier_ops[env->prog->type]; 9301 9295 is_priv = capable(CAP_SYS_ADMIN); 9302 9296 9297 + if (!btf_vmlinux && IS_ENABLED(CONFIG_DEBUG_INFO_BTF)) { 9298 + mutex_lock(&bpf_verifier_lock); 9299 + if (!btf_vmlinux) 9300 + btf_vmlinux = btf_parse_vmlinux(); 9301 + mutex_unlock(&bpf_verifier_lock); 9302 + } 9303 + 9303 9304 /* grab the mutex to protect few globals used by verifier */ 9304 9305 if (!is_priv) 9305 9306 mutex_lock(&bpf_verifier_lock); ··· 9324 9311 if (log->len_total < 128 || log->len_total > UINT_MAX >> 2 || 9325 9312 !log->level || !log->ubuf || log->level & ~BPF_LOG_MASK) 9326 9313 goto err_unlock; 9314 + } 9315 + 9316 + if (IS_ERR(btf_vmlinux)) { 9317 + /* Either gcc or pahole or kernel are broken. */ 9318 + verbose(env, "in-kernel BTF is malformed\n"); 9319 + ret = PTR_ERR(btf_vmlinux); 9320 + goto err_unlock; 9327 9321 } 9328 9322 9329 9323 env->strict_alignment = !!(attr->prog_flags & BPF_F_STRICT_ALIGNMENT);