Augment selected existing internal-error paths with Verifier Internal Error reports. These reports avoid suggesting source-level fixes and instead identify the verifier invariant that failed. Cover non-overwritten BPF_PTR_POISON helper argument types and inconsistent kfunc graph-node argument classification. Signed-off-by: Kumar Kartikeya Dwivedi --- include/linux/bpf_verifier.h | 10 +++++--- kernel/bpf/diagnostics.c | 50 ++++++++++++++++++++++++++++++++++++ kernel/bpf/verifier.c | 13 +++++----- 3 files changed, 62 insertions(+), 11 deletions(-) diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h index 625ea3e394a2..a120110aaf3e 100644 --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -1090,6 +1090,8 @@ __printf(3, 4) void verbose_linfo(struct bpf_verifier_env *env, u32 insn_off, const char *prefix_fmt, ...); +__printf(2, 3) void bpf_verifier_log_bug(struct bpf_verifier_env *env, const char *fmt, ...); + #define verifier_bug_if(cond, env, fmt, args...) \ ({ \ bool __cond = (cond); \ @@ -1097,10 +1099,10 @@ __printf(3, 4) void verbose_linfo(struct bpf_verifier_env *env, verifier_bug(env, fmt " (" #cond ")", ##args); \ (__cond); \ }) -#define verifier_bug(env, fmt, args...) \ - ({ \ - BPF_WARN_ONCE(1, "verifier bug: " fmt "\n", ##args); \ - bpf_log(&env->log, "verifier bug: " fmt "\n", ##args); \ +#define verifier_bug(env, fmt, args...) \ + ({ \ + BPF_WARN_ONCE(1, "verifier bug: " fmt "\n", ##args); \ + bpf_verifier_log_bug(env, fmt, ##args); \ }) static inline void mark_prune_point(struct bpf_verifier_env *env, int idx) diff --git a/kernel/bpf/diagnostics.c b/kernel/bpf/diagnostics.c index e2772c1deaff..eb4c2817e0f1 100644 --- a/kernel/bpf/diagnostics.c +++ b/kernel/bpf/diagnostics.c @@ -1346,6 +1346,56 @@ void bpf_diag_report_limit(struct bpf_verifier_env *env, u32 insn_idx, const cha diag_report_suggestion(env, "%s", suggestion); } +static void diag_internal_error(struct bpf_verifier_env *env, u32 insn_idx, const char *problem, + const char *reason) +{ + bpf_diag_report_header(env, CATEGORY_VERIFIER_INTERNAL_ERROR, problem); + diag_report_reason(env, "The verifier hit an internal error: %s", reason); + + diag_report_section(env, "At"); + bpf_diag_report_source(env, insn_idx, "error", "%s", problem); + + diag_report_suggestion(env, "Report this problem to bpf@vger.kernel.org with the full " + "verifier log and program."); +} + +void bpf_verifier_log_bug(struct bpf_verifier_env *env, const char *fmt, ...) +{ + const char *fallback = "the verifier could not format details for this invariant violation"; + va_list args, copy; + char *reason; + size_t len; + + va_start(args, fmt); + if (bpf_verifier_log_needed(&env->log)) { + bpf_verifier_log_write(env, "verifier bug: "); + va_copy(copy, args); + bpf_verifier_vlog(&env->log, fmt, copy); + va_end(copy); + bpf_verifier_log_write(env, "\n"); + } + + if (!bpf_diag_enabled(env)) + goto out; + + va_copy(copy, args); + reason = kvasprintf(GFP_KERNEL_ACCOUNT, fmt, copy); + va_end(copy); + if (!reason) { + diag_internal_error(env, env->insn_idx, "verifier invariant violation", fallback); + goto out; + } + + len = strlen(reason); + while (len && reason[len - 1] == '\n') + reason[--len] = '\0'; + diag_internal_error(env, env->insn_idx, "verifier invariant violation", + *reason ? reason : fallback); + kfree(reason); +out: + va_end(args); +} + void bpf_diag_report_invalid_deref(struct bpf_verifier_env *env, u32 insn_idx, int regno, const char *reg_name, const struct bpf_reg_state *reg, enum bpf_diag_invalid_deref_kind kind, s64 offset) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 552b3d4dd5ae..f7c5beb88217 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -8650,9 +8650,8 @@ static int check_reg_type(struct bpf_verifier_env *env, struct bpf_reg_state *re return -EACCES; } else { if (arg_btf_id == BPF_PTR_POISON) { - verbose(env, "verifier internal error:"); - verbose(env, "%s has non-overwritten BPF_PTR_POISON type\n", - reg_arg_name(env, argno)); + verifier_bug(env, "%s has non-overwritten BPF_PTR_POISON type", + reg_arg_name(env, argno)); return -EACCES; } @@ -12748,14 +12747,14 @@ static bool check_kfunc_is_graph_node_api(struct bpf_verifier_env *env, kfunc_btf_id == special_kfunc_list[KF_bpf_rbtree_right]); break; default: - verbose(env, "verifier internal error: unexpected graph node argument type %s\n", - btf_field_type_name(node_field_type)); + verifier_bug(env, "unexpected graph node argument type %s", + btf_field_type_name(node_field_type)); return false; } if (!ret) - verbose(env, "verifier internal error: %s node arg for unknown kfunc\n", - btf_field_type_name(node_field_type)); + verifier_bug(env, "%s node arg for unknown kfunc", + btf_field_type_name(node_field_type)); return ret; } -- 2.53.0