mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 11:19:37 +00:00
![Andrii Nakryiko](/assets/img/avatar_default.png)
Teach libbpf to post-process BPF verifier log on BPF program load failure and detect known error patterns to provide user with more context. Currently there is one such common situation: an "unguarded" failed BPF CO-RE relocation. While failing CO-RE relocation is expected, it is expected to be property guarded in BPF code such that BPF verifier always eliminates BPF instructions corresponding to such failed CO-RE relos as dead code. In cases when user failed to take such precautions, BPF verifier provides the best log it can: 123: (85) call unknown#195896080 invalid func unknown#195896080 Such incomprehensible log error is due to libbpf "poisoning" BPF instruction that corresponds to failed CO-RE relocation by replacing it with invalid `call 0xbad2310` instruction (195896080 == 0xbad2310 reads "bad relo" if you squint hard enough). Luckily, libbpf has all the necessary information to look up CO-RE relocation that failed and provide more human-readable description of what's going on: 5: <invalid CO-RE relocation> failed to resolve CO-RE relocation <byte_off> [6] struct task_struct___bad.fake_field_subprog (0:2 @ offset 8) This hopefully makes it much easier to understand what's wrong with user's BPF program without googling magic constants. This BPF verifier log fixup is setup to be extensible and is going to be used for at least one other upcoming feature of libbpf in follow up patches. Libbpf is parsing lines of BPF verifier log starting from the very end. Currently it processes up to 10 lines of code looking for familiar patterns. This avoids wasting lots of CPU processing huge verifier logs (especially for log_level=2 verbosity level). Actual verification error should normally be found in last few lines, so this should work reliably. If libbpf needs to expand log beyond available log_buf_size, it truncates the end of the verifier log. Given verifier log normally ends with something like: processed 2 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0 ... truncating this on program load error isn't too bad (end user can always increase log size, if it needs to get complete log). Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://lore.kernel.org/bpf/20220426004511.2691730-10-andrii@kernel.org
93 lines
2.9 KiB
C
93 lines
2.9 KiB
C
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
|
|
/* Copyright (c) 2019 Facebook */
|
|
|
|
#ifndef __RELO_CORE_H
|
|
#define __RELO_CORE_H
|
|
|
|
#include <linux/bpf.h>
|
|
|
|
struct bpf_core_cand {
|
|
const struct btf *btf;
|
|
__u32 id;
|
|
};
|
|
|
|
/* dynamically sized list of type IDs and its associated struct btf */
|
|
struct bpf_core_cand_list {
|
|
struct bpf_core_cand *cands;
|
|
int len;
|
|
};
|
|
|
|
#define BPF_CORE_SPEC_MAX_LEN 64
|
|
|
|
/* represents BPF CO-RE field or array element accessor */
|
|
struct bpf_core_accessor {
|
|
__u32 type_id; /* struct/union type or array element type */
|
|
__u32 idx; /* field index or array index */
|
|
const char *name; /* field name or NULL for array accessor */
|
|
};
|
|
|
|
struct bpf_core_spec {
|
|
const struct btf *btf;
|
|
/* high-level spec: named fields and array indices only */
|
|
struct bpf_core_accessor spec[BPF_CORE_SPEC_MAX_LEN];
|
|
/* original unresolved (no skip_mods_or_typedefs) root type ID */
|
|
__u32 root_type_id;
|
|
/* CO-RE relocation kind */
|
|
enum bpf_core_relo_kind relo_kind;
|
|
/* high-level spec length */
|
|
int len;
|
|
/* raw, low-level spec: 1-to-1 with accessor spec string */
|
|
int raw_spec[BPF_CORE_SPEC_MAX_LEN];
|
|
/* raw spec length */
|
|
int raw_len;
|
|
/* field bit offset represented by spec */
|
|
__u32 bit_offset;
|
|
};
|
|
|
|
struct bpf_core_relo_res {
|
|
/* expected value in the instruction, unless validate == false */
|
|
__u32 orig_val;
|
|
/* new value that needs to be patched up to */
|
|
__u32 new_val;
|
|
/* relocation unsuccessful, poison instruction, but don't fail load */
|
|
bool poison;
|
|
/* some relocations can't be validated against orig_val */
|
|
bool validate;
|
|
/* for field byte offset relocations or the forms:
|
|
* *(T *)(rX + <off>) = rY
|
|
* rX = *(T *)(rY + <off>),
|
|
* we remember original and resolved field size to adjust direct
|
|
* memory loads of pointers and integers; this is necessary for 32-bit
|
|
* host kernel architectures, but also allows to automatically
|
|
* relocate fields that were resized from, e.g., u32 to u64, etc.
|
|
*/
|
|
bool fail_memsz_adjust;
|
|
__u32 orig_sz;
|
|
__u32 orig_type_id;
|
|
__u32 new_sz;
|
|
__u32 new_type_id;
|
|
};
|
|
|
|
int bpf_core_types_are_compat(const struct btf *local_btf, __u32 local_id,
|
|
const struct btf *targ_btf, __u32 targ_id);
|
|
|
|
size_t bpf_core_essential_name_len(const char *name);
|
|
|
|
int bpf_core_calc_relo_insn(const char *prog_name,
|
|
const struct bpf_core_relo *relo, int relo_idx,
|
|
const struct btf *local_btf,
|
|
struct bpf_core_cand_list *cands,
|
|
struct bpf_core_spec *specs_scratch,
|
|
struct bpf_core_relo_res *targ_res);
|
|
|
|
int bpf_core_patch_insn(const char *prog_name, struct bpf_insn *insn,
|
|
int insn_idx, const struct bpf_core_relo *relo,
|
|
int relo_idx, const struct bpf_core_relo_res *res);
|
|
|
|
int bpf_core_parse_spec(const char *prog_name, const struct btf *btf,
|
|
const struct bpf_core_relo *relo,
|
|
struct bpf_core_spec *spec);
|
|
|
|
int bpf_core_format_spec(char *buf, size_t buf_sz, const struct bpf_core_spec *spec);
|
|
|
|
#endif
|