15ad74616SKumar Kartikeya Dwivedi // SPDX-License-Identifier: GPL-2.0-only 25ad74616SKumar Kartikeya Dwivedi // Copyright (c) 2026 Meta Platforms, Inc. and affiliates. 35ad74616SKumar Kartikeya Dwivedi 4b9c5d822SKumar Kartikeya Dwivedi #include <linux/bpf.h> 55ad74616SKumar Kartikeya Dwivedi #include <linux/bpf_verifier.h> 6b9c5d822SKumar Kartikeya Dwivedi #include <linux/btf.h> 75ad74616SKumar Kartikeya Dwivedi #include <linux/ctype.h> 8b9c5d822SKumar Kartikeya Dwivedi #include <linux/kernel.h> 9b9c5d822SKumar Kartikeya Dwivedi #include <linux/list.h> 10b9c5d822SKumar Kartikeya Dwivedi #include <linux/seq_buf.h> 112bdc90f5SKumar Kartikeya Dwivedi #include <linux/overflow.h> 12b9c5d822SKumar Kartikeya Dwivedi #include <linux/slab.h> 135ad74616SKumar Kartikeya Dwivedi #include <linux/stdarg.h> 14b9c5d822SKumar Kartikeya Dwivedi #include <linux/string.h> 155ad74616SKumar Kartikeya Dwivedi 16b9c5d822SKumar Kartikeya Dwivedi #include "disasm.h" 175ad74616SKumar Kartikeya Dwivedi #include "diagnostics.h" 185ad74616SKumar Kartikeya Dwivedi 19d63284e6SKumar Kartikeya Dwivedi #define REGISTER_TYPE_SAFETY "Register Type Safety" 202bdc90f5SKumar Kartikeya Dwivedi #define MEMORY_SAFETY "Memory Safety" 215d576462SKumar Kartikeya Dwivedi #define RESOURCE_LIFETIME_SAFETY "Resource Lifetime Safety" 2266e27273SKumar Kartikeya Dwivedi #define CALL_TYPE_SAFETY "Call Type Safety" 2399a6a288SKumar Kartikeya Dwivedi #define EXECUTION_CONTEXT_SAFETY "Execution Context Safety" 24*a8f42783SKumar Kartikeya Dwivedi #define PROGRAM_STRUCTURE "Program Structure" 25d63284e6SKumar Kartikeya Dwivedi 26b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_TEXT_WIDTH 100 27d63284e6SKumar Kartikeya Dwivedi #define BPF_DIAG_TEXT_INDENT " " 28b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_CONTEXT 2 29b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_CONTEXT_CNT (1 + BPF_DIAG_CONTEXT * 2) 30d63284e6SKumar Kartikeya Dwivedi #define BPF_DIAG_HISTORY_RENDER_MAX 64 31b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_SOURCE_LANE_WIDTH 88 32b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_TAB_WIDTH 8 33b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_FMT_CHUNK_SIZE (PAGE_SIZE - sizeof(struct diag_fmt_chunk)) 34b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_FMT_BUF_SIZE 256 35daf82487SKumar Kartikeya Dwivedi #define BPF_DIAG_EVENT_LOG_MAX_SIZE (64U << 20) 36b9c5d822SKumar Kartikeya Dwivedi #define DISASM_LINE_LEN 160 37b9c5d822SKumar Kartikeya Dwivedi 38af4ea6e2SKumar Kartikeya Dwivedi enum bpf_diag_mod_target_kind { 39af4ea6e2SKumar Kartikeya Dwivedi BPF_DIAG_MOD_TARGET_NONE, 40af4ea6e2SKumar Kartikeya Dwivedi BPF_DIAG_MOD_TARGET_REG, 41af4ea6e2SKumar Kartikeya Dwivedi BPF_DIAG_MOD_TARGET_STACK_ARG, 42af4ea6e2SKumar Kartikeya Dwivedi BPF_DIAG_MOD_TARGET_STACK_SLOT, 43af4ea6e2SKumar Kartikeya Dwivedi BPF_DIAG_MOD_TARGET_STACK_RANGE, 44af4ea6e2SKumar Kartikeya Dwivedi }; 45af4ea6e2SKumar Kartikeya Dwivedi 46af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_target { 47af4ea6e2SKumar Kartikeya Dwivedi u32 frame_id; 48af4ea6e2SKumar Kartikeya Dwivedi union { 49af4ea6e2SKumar Kartikeya Dwivedi struct { 50af4ea6e2SKumar Kartikeya Dwivedi s16 min_off; 51af4ea6e2SKumar Kartikeya Dwivedi s16 max_off; 52af4ea6e2SKumar Kartikeya Dwivedi } range; 53af4ea6e2SKumar Kartikeya Dwivedi u16 spi; 54af4ea6e2SKumar Kartikeya Dwivedi u8 regno; 55af4ea6e2SKumar Kartikeya Dwivedi u8 stack_arg; 56af4ea6e2SKumar Kartikeya Dwivedi }; 57af4ea6e2SKumar Kartikeya Dwivedi u8 frameno; 58af4ea6e2SKumar Kartikeya Dwivedi u8 kind; 59af4ea6e2SKumar Kartikeya Dwivedi }; 60af4ea6e2SKumar Kartikeya Dwivedi 61af4ea6e2SKumar Kartikeya Dwivedi static struct bpf_diag_mod_target diag_reg_target(u32 frame_id, u8 frameno, u8 regno) 62af4ea6e2SKumar Kartikeya Dwivedi { 63af4ea6e2SKumar Kartikeya Dwivedi return (struct bpf_diag_mod_target){ 64af4ea6e2SKumar Kartikeya Dwivedi .frame_id = frame_id, 65af4ea6e2SKumar Kartikeya Dwivedi .frameno = frameno, 66af4ea6e2SKumar Kartikeya Dwivedi .kind = BPF_DIAG_MOD_TARGET_REG, 67af4ea6e2SKumar Kartikeya Dwivedi .regno = regno, 68af4ea6e2SKumar Kartikeya Dwivedi }; 69af4ea6e2SKumar Kartikeya Dwivedi } 70af4ea6e2SKumar Kartikeya Dwivedi 71af4ea6e2SKumar Kartikeya Dwivedi static struct bpf_diag_mod_target diag_stack_arg_target(u32 frame_id, u8 frameno, u8 slot) 72af4ea6e2SKumar Kartikeya Dwivedi { 73af4ea6e2SKumar Kartikeya Dwivedi return (struct bpf_diag_mod_target){ 74af4ea6e2SKumar Kartikeya Dwivedi .frame_id = frame_id, 75af4ea6e2SKumar Kartikeya Dwivedi .frameno = frameno, 76af4ea6e2SKumar Kartikeya Dwivedi .kind = BPF_DIAG_MOD_TARGET_STACK_ARG, 77af4ea6e2SKumar Kartikeya Dwivedi .stack_arg = slot, 78af4ea6e2SKumar Kartikeya Dwivedi }; 79af4ea6e2SKumar Kartikeya Dwivedi } 80af4ea6e2SKumar Kartikeya Dwivedi 81af4ea6e2SKumar Kartikeya Dwivedi static struct bpf_diag_mod_target diag_stack_slot_target(u32 frame_id, u8 frameno, u16 spi) 82af4ea6e2SKumar Kartikeya Dwivedi { 83af4ea6e2SKumar Kartikeya Dwivedi return (struct bpf_diag_mod_target){ 84af4ea6e2SKumar Kartikeya Dwivedi .frame_id = frame_id, 85af4ea6e2SKumar Kartikeya Dwivedi .frameno = frameno, 86af4ea6e2SKumar Kartikeya Dwivedi .kind = BPF_DIAG_MOD_TARGET_STACK_SLOT, 87af4ea6e2SKumar Kartikeya Dwivedi .spi = spi, 88af4ea6e2SKumar Kartikeya Dwivedi }; 89af4ea6e2SKumar Kartikeya Dwivedi } 90af4ea6e2SKumar Kartikeya Dwivedi 91af4ea6e2SKumar Kartikeya Dwivedi static struct bpf_diag_mod_target diag_stack_range_target(u32 frame_id, u8 frameno, 92af4ea6e2SKumar Kartikeya Dwivedi s16 min_off, s16 max_off) 93af4ea6e2SKumar Kartikeya Dwivedi { 94af4ea6e2SKumar Kartikeya Dwivedi return (struct bpf_diag_mod_target){ 95af4ea6e2SKumar Kartikeya Dwivedi .frame_id = frame_id, 96af4ea6e2SKumar Kartikeya Dwivedi .frameno = frameno, 97af4ea6e2SKumar Kartikeya Dwivedi .kind = BPF_DIAG_MOD_TARGET_STACK_RANGE, 98af4ea6e2SKumar Kartikeya Dwivedi .range.min_off = min_off, 99af4ea6e2SKumar Kartikeya Dwivedi .range.max_off = max_off, 100af4ea6e2SKumar Kartikeya Dwivedi }; 101af4ea6e2SKumar Kartikeya Dwivedi } 102af4ea6e2SKumar Kartikeya Dwivedi 103af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_reg_snapshot { 104af4ea6e2SKumar Kartikeya Dwivedi u32 type; 105af4ea6e2SKumar Kartikeya Dwivedi u32 btf_id; 106af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_map *map_ptr; 107af4ea6e2SKumar Kartikeya Dwivedi const struct btf *btf; 108af4ea6e2SKumar Kartikeya Dwivedi struct tnum var_off; 109af4ea6e2SKumar Kartikeya Dwivedi struct cnum64 r64; 110af4ea6e2SKumar Kartikeya Dwivedi }; 111af4ea6e2SKumar Kartikeya Dwivedi 112daf82487SKumar Kartikeya Dwivedi enum bpf_diag_history_kind { 113daf82487SKumar Kartikeya Dwivedi BPF_DIAG_HISTORY_BRANCH, 114af4ea6e2SKumar Kartikeya Dwivedi BPF_DIAG_HISTORY_MOD, 1159ecd7030SKumar Kartikeya Dwivedi BPF_DIAG_HISTORY_REF_ACQUIRE, 1169ecd7030SKumar Kartikeya Dwivedi BPF_DIAG_HISTORY_REF_RELEASE, 117956a66e5SKumar Kartikeya Dwivedi BPF_DIAG_HISTORY_CONTEXT, 118daf82487SKumar Kartikeya Dwivedi }; 119daf82487SKumar Kartikeya Dwivedi 120daf82487SKumar Kartikeya Dwivedi struct bpf_diag_history_event { 121daf82487SKumar Kartikeya Dwivedi u32 insn_idx : 24; 122daf82487SKumar Kartikeya Dwivedi u32 kind : 8; 123daf82487SKumar Kartikeya Dwivedi u8 in_lineage : 1; 124daf82487SKumar Kartikeya Dwivedi union { 125daf82487SKumar Kartikeya Dwivedi struct { 126daf82487SKumar Kartikeya Dwivedi bool cond_true; 127daf82487SKumar Kartikeya Dwivedi } branch; 128af4ea6e2SKumar Kartikeya Dwivedi struct { 129af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_target target; 130af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_target origin; 131af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_reg_snapshot old, new; 132af4ea6e2SKumar Kartikeya Dwivedi u8 reason; 133af4ea6e2SKumar Kartikeya Dwivedi bool origin_valid; 134af4ea6e2SKumar Kartikeya Dwivedi } mod; 1359ecd7030SKumar Kartikeya Dwivedi struct { 1369ecd7030SKumar Kartikeya Dwivedi u32 ref_id; 1379ecd7030SKumar Kartikeya Dwivedi } ref; 138956a66e5SKumar Kartikeya Dwivedi struct { 139956a66e5SKumar Kartikeya Dwivedi u32 depth; 140956a66e5SKumar Kartikeya Dwivedi u8 kind; 141956a66e5SKumar Kartikeya Dwivedi bool enter; 142956a66e5SKumar Kartikeya Dwivedi } ctx; 143daf82487SKumar Kartikeya Dwivedi }; 144daf82487SKumar Kartikeya Dwivedi }; 145daf82487SKumar Kartikeya Dwivedi 146d63284e6SKumar Kartikeya Dwivedi enum bpf_diag_history_scope { 147d63284e6SKumar Kartikeya Dwivedi BPF_DIAG_HISTORY_SCOPE_REG, 148d63284e6SKumar Kartikeya Dwivedi BPF_DIAG_HISTORY_SCOPE_STACK_ARG, 149d63284e6SKumar Kartikeya Dwivedi BPF_DIAG_HISTORY_SCOPE_REF, 150d63284e6SKumar Kartikeya Dwivedi BPF_DIAG_HISTORY_SCOPE_CONTEXT, 151d63284e6SKumar Kartikeya Dwivedi }; 152d63284e6SKumar Kartikeya Dwivedi 153d63284e6SKumar Kartikeya Dwivedi struct bpf_diag_history_opts { 154d63284e6SKumar Kartikeya Dwivedi enum bpf_diag_history_scope scope; 155d63284e6SKumar Kartikeya Dwivedi u32 frame_id; 156d63284e6SKumar Kartikeya Dwivedi u32 frameno; 157d63284e6SKumar Kartikeya Dwivedi int regno; 158d63284e6SKumar Kartikeya Dwivedi int stack_arg_slot; 159d63284e6SKumar Kartikeya Dwivedi u32 ref_id; 160d63284e6SKumar Kartikeya Dwivedi enum bpf_diag_context_kind ctx_kind; 161d63284e6SKumar Kartikeya Dwivedi u32 ctx_depth; 162d63284e6SKumar Kartikeya Dwivedi }; 163d63284e6SKumar Kartikeya Dwivedi 164d63284e6SKumar Kartikeya Dwivedi static void diag_print_history(struct bpf_verifier_env *env, 165d63284e6SKumar Kartikeya Dwivedi const struct bpf_diag_history_opts *opts); 166d63284e6SKumar Kartikeya Dwivedi static bool diag_target_matches(const struct bpf_diag_mod_target *event_target, 167d63284e6SKumar Kartikeya Dwivedi const struct bpf_diag_mod_target *target); 16899a6a288SKumar Kartikeya Dwivedi static const char *diag_context_name(enum bpf_diag_context_kind kind); 169b9c5d822SKumar Kartikeya Dwivedi struct disasm_line { 170b9c5d822SKumar Kartikeya Dwivedi char text[DISASM_LINE_LEN]; 171b9c5d822SKumar Kartikeya Dwivedi int idx; 172b9c5d822SKumar Kartikeya Dwivedi bool valid; 173b9c5d822SKumar Kartikeya Dwivedi }; 174b9c5d822SKumar Kartikeya Dwivedi 175b9c5d822SKumar Kartikeya Dwivedi struct disasm_ctx { 176b9c5d822SKumar Kartikeya Dwivedi struct bpf_verifier_env *env; 177b9c5d822SKumar Kartikeya Dwivedi struct seq_buf seq; 178b9c5d822SKumar Kartikeya Dwivedi }; 179b9c5d822SKumar Kartikeya Dwivedi 180b9c5d822SKumar Kartikeya Dwivedi struct diag_fmt_chunk { 181b9c5d822SKumar Kartikeya Dwivedi struct list_head node; 182b9c5d822SKumar Kartikeya Dwivedi struct seq_buf seq; 183b9c5d822SKumar Kartikeya Dwivedi char data[]; 184b9c5d822SKumar Kartikeya Dwivedi }; 185b9c5d822SKumar Kartikeya Dwivedi 186b9c5d822SKumar Kartikeya Dwivedi struct diag_fmt_mark { 187b9c5d822SKumar Kartikeya Dwivedi struct diag_fmt_chunk *chunk; 188b9c5d822SKumar Kartikeya Dwivedi size_t len; 189b9c5d822SKumar Kartikeya Dwivedi }; 190b9c5d822SKumar Kartikeya Dwivedi 191daf82487SKumar Kartikeya Dwivedi struct bpf_diag_log { 192daf82487SKumar Kartikeya Dwivedi struct bpf_diag_history_event *events; 193daf82487SKumar Kartikeya Dwivedi /* Sequence number of the oldest retained event on the active path. */ 194daf82487SKumar Kartikeya Dwivedi u64 first_seq; 195daf82487SKumar Kartikeya Dwivedi u32 cnt; 196daf82487SKumar Kartikeya Dwivedi u32 cap; 197daf82487SKumar Kartikeya Dwivedi u32 head; 198daf82487SKumar Kartikeya Dwivedi bool growth_failed; 199daf82487SKumar Kartikeya Dwivedi }; 200daf82487SKumar Kartikeya Dwivedi 201b9c5d822SKumar Kartikeya Dwivedi struct bpf_diag_scratch { 202b9c5d822SKumar Kartikeya Dwivedi struct bpf_linfo_source source_lines[BPF_DIAG_CONTEXT_CNT]; 203b9c5d822SKumar Kartikeya Dwivedi struct disasm_line disasm_lines[BPF_DIAG_CONTEXT_CNT]; 204b9c5d822SKumar Kartikeya Dwivedi }; 205b9c5d822SKumar Kartikeya Dwivedi 206af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_scope { 207af4ea6e2SKumar Kartikeya Dwivedi struct bpf_reg_state target_reg_snapshot; 208af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_target target; 209af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_target origin; 210af4ea6e2SKumar Kartikeya Dwivedi enum bpf_diag_mod_reason reason; 211af4ea6e2SKumar Kartikeya Dwivedi u32 insn_idx; 212af4ea6e2SKumar Kartikeya Dwivedi bool active; 213af4ea6e2SKumar Kartikeya Dwivedi bool origin_valid; 214af4ea6e2SKumar Kartikeya Dwivedi }; 215af4ea6e2SKumar Kartikeya Dwivedi 216b9c5d822SKumar Kartikeya Dwivedi struct bpf_diag { 217daf82487SKumar Kartikeya Dwivedi struct bpf_diag_log log; 218b9c5d822SKumar Kartikeya Dwivedi struct bpf_diag_scratch scratch; 219b9c5d822SKumar Kartikeya Dwivedi struct list_head fmt_chunks; 220af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_scope mod; 221af4ea6e2SKumar Kartikeya Dwivedi u32 frame_id_gen; 222b9c5d822SKumar Kartikeya Dwivedi }; 223b9c5d822SKumar Kartikeya Dwivedi 2245ad74616SKumar Kartikeya Dwivedi bool bpf_diag_enabled(const struct bpf_verifier_env *env) 2255ad74616SKumar Kartikeya Dwivedi { 2265ad74616SKumar Kartikeya Dwivedi return env->log.level & BPF_LOG_LEVEL; 2275ad74616SKumar Kartikeya Dwivedi } 2285ad74616SKumar Kartikeya Dwivedi 2295ad74616SKumar Kartikeya Dwivedi static void diag_write(struct bpf_verifier_env *env, const char *fmt, ...) __printf(2, 3); 2305ad74616SKumar Kartikeya Dwivedi 231b9c5d822SKumar Kartikeya Dwivedi int bpf_diag_init(struct bpf_verifier_env *env) 232b9c5d822SKumar Kartikeya Dwivedi { 233b9c5d822SKumar Kartikeya Dwivedi if (!bpf_diag_enabled(env)) 234b9c5d822SKumar Kartikeya Dwivedi return 0; 235b9c5d822SKumar Kartikeya Dwivedi 236b9c5d822SKumar Kartikeya Dwivedi env->diag = kzalloc_obj(struct bpf_diag, GFP_KERNEL_ACCOUNT); 237b9c5d822SKumar Kartikeya Dwivedi if (!env->diag) 238b9c5d822SKumar Kartikeya Dwivedi return -ENOMEM; 239b9c5d822SKumar Kartikeya Dwivedi 240b9c5d822SKumar Kartikeya Dwivedi INIT_LIST_HEAD(&env->diag->fmt_chunks); 241b9c5d822SKumar Kartikeya Dwivedi return 0; 242b9c5d822SKumar Kartikeya Dwivedi } 243b9c5d822SKumar Kartikeya Dwivedi 244af4ea6e2SKumar Kartikeya Dwivedi void bpf_diag_init_frame(struct bpf_verifier_env *env, struct bpf_func_state *state) 245af4ea6e2SKumar Kartikeya Dwivedi { 246af4ea6e2SKumar Kartikeya Dwivedi if (env->diag) 247af4ea6e2SKumar Kartikeya Dwivedi state->diag_frame_id = ++env->diag->frame_id_gen; 248af4ea6e2SKumar Kartikeya Dwivedi } 249af4ea6e2SKumar Kartikeya Dwivedi 250b9c5d822SKumar Kartikeya Dwivedi static char *diag_fmt_alloc(struct bpf_verifier_env *env, size_t size) 251b9c5d822SKumar Kartikeya Dwivedi { 252b9c5d822SKumar Kartikeya Dwivedi struct bpf_diag *diag = env->diag; 253b9c5d822SKumar Kartikeya Dwivedi struct diag_fmt_chunk *chunk; 254b9c5d822SKumar Kartikeya Dwivedi size_t capacity, available; 255b9c5d822SKumar Kartikeya Dwivedi char *buf; 256b9c5d822SKumar Kartikeya Dwivedi 257b9c5d822SKumar Kartikeya Dwivedi if (!diag || !size || size > INT_MAX) 258b9c5d822SKumar Kartikeya Dwivedi return NULL; 259b9c5d822SKumar Kartikeya Dwivedi 260b9c5d822SKumar Kartikeya Dwivedi if (!list_empty(&diag->fmt_chunks)) { 261b9c5d822SKumar Kartikeya Dwivedi chunk = list_last_entry(&diag->fmt_chunks, struct diag_fmt_chunk, node); 262b9c5d822SKumar Kartikeya Dwivedi available = seq_buf_get_buf(&chunk->seq, &buf); 263b9c5d822SKumar Kartikeya Dwivedi if (available >= size) 264b9c5d822SKumar Kartikeya Dwivedi goto commit; 265b9c5d822SKumar Kartikeya Dwivedi } 266b9c5d822SKumar Kartikeya Dwivedi 267b9c5d822SKumar Kartikeya Dwivedi capacity = max_t(size_t, BPF_DIAG_FMT_CHUNK_SIZE, size); 268b9c5d822SKumar Kartikeya Dwivedi chunk = kmalloc(struct_size(chunk, data, capacity), GFP_KERNEL_ACCOUNT); 269b9c5d822SKumar Kartikeya Dwivedi if (!chunk) 270b9c5d822SKumar Kartikeya Dwivedi return NULL; 271b9c5d822SKumar Kartikeya Dwivedi 272b9c5d822SKumar Kartikeya Dwivedi seq_buf_init(&chunk->seq, chunk->data, capacity); 273b9c5d822SKumar Kartikeya Dwivedi list_add_tail(&chunk->node, &diag->fmt_chunks); 274b9c5d822SKumar Kartikeya Dwivedi available = seq_buf_get_buf(&chunk->seq, &buf); 275b9c5d822SKumar Kartikeya Dwivedi if (WARN_ON_ONCE(available < size)) 276b9c5d822SKumar Kartikeya Dwivedi return NULL; 277b9c5d822SKumar Kartikeya Dwivedi 278b9c5d822SKumar Kartikeya Dwivedi commit: 279b9c5d822SKumar Kartikeya Dwivedi seq_buf_commit(&chunk->seq, size); 280b9c5d822SKumar Kartikeya Dwivedi return buf; 281b9c5d822SKumar Kartikeya Dwivedi } 282b9c5d822SKumar Kartikeya Dwivedi 283b9c5d822SKumar Kartikeya Dwivedi char *bpf_diag_fmt_buf(struct bpf_verifier_env *env, size_t size) 284b9c5d822SKumar Kartikeya Dwivedi { 285b9c5d822SKumar Kartikeya Dwivedi char *buf; 286b9c5d822SKumar Kartikeya Dwivedi 287b9c5d822SKumar Kartikeya Dwivedi buf = diag_fmt_alloc(env, size); 288b9c5d822SKumar Kartikeya Dwivedi if (buf) 289b9c5d822SKumar Kartikeya Dwivedi buf[0] = '\0'; 290b9c5d822SKumar Kartikeya Dwivedi return buf; 291b9c5d822SKumar Kartikeya Dwivedi } 292b9c5d822SKumar Kartikeya Dwivedi 293b9c5d822SKumar Kartikeya Dwivedi const char *bpf_diag_vfmt(struct bpf_verifier_env *env, const char *fmt, va_list args) 294b9c5d822SKumar Kartikeya Dwivedi { 295b9c5d822SKumar Kartikeya Dwivedi va_list copy; 296b9c5d822SKumar Kartikeya Dwivedi char *buf; 297b9c5d822SKumar Kartikeya Dwivedi int len; 298b9c5d822SKumar Kartikeya Dwivedi 299b9c5d822SKumar Kartikeya Dwivedi va_copy(copy, args); 300b9c5d822SKumar Kartikeya Dwivedi len = vsnprintf(NULL, 0, fmt, copy); 301b9c5d822SKumar Kartikeya Dwivedi va_end(copy); 302b9c5d822SKumar Kartikeya Dwivedi if (len < 0 || len == INT_MAX) 303b9c5d822SKumar Kartikeya Dwivedi return ""; 304b9c5d822SKumar Kartikeya Dwivedi 305b9c5d822SKumar Kartikeya Dwivedi buf = diag_fmt_alloc(env, len + 1); 306b9c5d822SKumar Kartikeya Dwivedi if (buf) 307b9c5d822SKumar Kartikeya Dwivedi vsnprintf(buf, len + 1, fmt, args); 308b9c5d822SKumar Kartikeya Dwivedi return buf ?: ""; 309b9c5d822SKumar Kartikeya Dwivedi } 310b9c5d822SKumar Kartikeya Dwivedi 311b9c5d822SKumar Kartikeya Dwivedi const char *bpf_diag_fmt(struct bpf_verifier_env *env, const char *fmt, ...) 312b9c5d822SKumar Kartikeya Dwivedi { 313b9c5d822SKumar Kartikeya Dwivedi const char *buf; 314b9c5d822SKumar Kartikeya Dwivedi va_list args; 315b9c5d822SKumar Kartikeya Dwivedi 316b9c5d822SKumar Kartikeya Dwivedi va_start(args, fmt); 317b9c5d822SKumar Kartikeya Dwivedi buf = bpf_diag_vfmt(env, fmt, args); 318b9c5d822SKumar Kartikeya Dwivedi va_end(args); 319b9c5d822SKumar Kartikeya Dwivedi return buf; 320b9c5d822SKumar Kartikeya Dwivedi } 321b9c5d822SKumar Kartikeya Dwivedi 322b9c5d822SKumar Kartikeya Dwivedi static struct diag_fmt_mark diag_fmt_save(struct bpf_verifier_env *env) 323b9c5d822SKumar Kartikeya Dwivedi { 324b9c5d822SKumar Kartikeya Dwivedi struct bpf_diag *diag = env->diag; 325b9c5d822SKumar Kartikeya Dwivedi struct diag_fmt_mark mark = {}; 326b9c5d822SKumar Kartikeya Dwivedi 327b9c5d822SKumar Kartikeya Dwivedi if (!diag || list_empty(&diag->fmt_chunks)) 328b9c5d822SKumar Kartikeya Dwivedi return mark; 329b9c5d822SKumar Kartikeya Dwivedi 330b9c5d822SKumar Kartikeya Dwivedi mark.chunk = list_last_entry(&diag->fmt_chunks, struct diag_fmt_chunk, node); 331b9c5d822SKumar Kartikeya Dwivedi mark.len = mark.chunk->seq.len; 332b9c5d822SKumar Kartikeya Dwivedi return mark; 333b9c5d822SKumar Kartikeya Dwivedi } 334b9c5d822SKumar Kartikeya Dwivedi 335b9c5d822SKumar Kartikeya Dwivedi static void diag_fmt_restore(struct bpf_verifier_env *env, struct diag_fmt_mark mark) 336b9c5d822SKumar Kartikeya Dwivedi { 337b9c5d822SKumar Kartikeya Dwivedi struct bpf_diag *diag = env->diag; 338b9c5d822SKumar Kartikeya Dwivedi struct diag_fmt_chunk *chunk; 339b9c5d822SKumar Kartikeya Dwivedi 340b9c5d822SKumar Kartikeya Dwivedi if (!diag) 341b9c5d822SKumar Kartikeya Dwivedi return; 342b9c5d822SKumar Kartikeya Dwivedi 343b9c5d822SKumar Kartikeya Dwivedi while (!list_empty(&diag->fmt_chunks)) { 344b9c5d822SKumar Kartikeya Dwivedi chunk = list_last_entry(&diag->fmt_chunks, struct diag_fmt_chunk, node); 345b9c5d822SKumar Kartikeya Dwivedi if (chunk == mark.chunk) 346b9c5d822SKumar Kartikeya Dwivedi break; 347b9c5d822SKumar Kartikeya Dwivedi list_del(&chunk->node); 348b9c5d822SKumar Kartikeya Dwivedi kfree(chunk); 349b9c5d822SKumar Kartikeya Dwivedi } 350b9c5d822SKumar Kartikeya Dwivedi 351b9c5d822SKumar Kartikeya Dwivedi if (mark.chunk) { 352b9c5d822SKumar Kartikeya Dwivedi mark.chunk->seq.len = mark.len; 353b9c5d822SKumar Kartikeya Dwivedi seq_buf_str(&mark.chunk->seq); 354b9c5d822SKumar Kartikeya Dwivedi } 355b9c5d822SKumar Kartikeya Dwivedi } 356b9c5d822SKumar Kartikeya Dwivedi 357b9c5d822SKumar Kartikeya Dwivedi void bpf_diag_free(struct bpf_verifier_env *env) 358b9c5d822SKumar Kartikeya Dwivedi { 359b9c5d822SKumar Kartikeya Dwivedi struct bpf_diag *diag = env->diag; 360b9c5d822SKumar Kartikeya Dwivedi 361b9c5d822SKumar Kartikeya Dwivedi if (!diag) 362b9c5d822SKumar Kartikeya Dwivedi return; 363b9c5d822SKumar Kartikeya Dwivedi 364b9c5d822SKumar Kartikeya Dwivedi diag_fmt_restore(env, (struct diag_fmt_mark){}); 365daf82487SKumar Kartikeya Dwivedi kvfree(diag->log.events); 366b9c5d822SKumar Kartikeya Dwivedi kfree(diag); 367b9c5d822SKumar Kartikeya Dwivedi env->diag = NULL; 368b9c5d822SKumar Kartikeya Dwivedi } 369b9c5d822SKumar Kartikeya Dwivedi 3705ad74616SKumar Kartikeya Dwivedi static void diag_write(struct bpf_verifier_env *env, const char *fmt, ...) 3715ad74616SKumar Kartikeya Dwivedi { 3725ad74616SKumar Kartikeya Dwivedi va_list args; 3735ad74616SKumar Kartikeya Dwivedi 3745ad74616SKumar Kartikeya Dwivedi if (!bpf_diag_enabled(env)) 3755ad74616SKumar Kartikeya Dwivedi return; 3765ad74616SKumar Kartikeya Dwivedi 3775ad74616SKumar Kartikeya Dwivedi va_start(args, fmt); 3785ad74616SKumar Kartikeya Dwivedi bpf_verifier_vlog(&env->log, fmt, args); 3795ad74616SKumar Kartikeya Dwivedi va_end(args); 3805ad74616SKumar Kartikeya Dwivedi } 3815ad74616SKumar Kartikeya Dwivedi 382daf82487SKumar Kartikeya Dwivedi static u64 log_end(const struct bpf_diag_log *log) 383daf82487SKumar Kartikeya Dwivedi { 384daf82487SKumar Kartikeya Dwivedi return log->first_seq + log->cnt; 385daf82487SKumar Kartikeya Dwivedi } 386daf82487SKumar Kartikeya Dwivedi 387daf82487SKumar Kartikeya Dwivedi static u32 log_pos(const struct bpf_diag_log *log, u32 idx) 388daf82487SKumar Kartikeya Dwivedi { 389daf82487SKumar Kartikeya Dwivedi u32 pos = log->head + idx; 390daf82487SKumar Kartikeya Dwivedi 391daf82487SKumar Kartikeya Dwivedi return pos < log->cap ? pos : pos - log->cap; 392daf82487SKumar Kartikeya Dwivedi } 393daf82487SKumar Kartikeya Dwivedi 394daf82487SKumar Kartikeya Dwivedi u64 bpf_diag_event_log_save(struct bpf_verifier_env *env) 395daf82487SKumar Kartikeya Dwivedi { 396daf82487SKumar Kartikeya Dwivedi struct bpf_diag *diag = env->diag; 397daf82487SKumar Kartikeya Dwivedi 398daf82487SKumar Kartikeya Dwivedi return diag ? log_end(&diag->log) : 0; 399daf82487SKumar Kartikeya Dwivedi } 400daf82487SKumar Kartikeya Dwivedi 401daf82487SKumar Kartikeya Dwivedi void bpf_diag_event_log_restore(struct bpf_verifier_env *env, u64 log_pos) 402daf82487SKumar Kartikeya Dwivedi { 403daf82487SKumar Kartikeya Dwivedi struct bpf_diag *diag = env->diag; 404daf82487SKumar Kartikeya Dwivedi struct bpf_diag_log *log; 405daf82487SKumar Kartikeya Dwivedi u64 end_seq; 406daf82487SKumar Kartikeya Dwivedi 407daf82487SKumar Kartikeya Dwivedi if (!diag) 408daf82487SKumar Kartikeya Dwivedi return; 409daf82487SKumar Kartikeya Dwivedi 410daf82487SKumar Kartikeya Dwivedi log = &diag->log; 411daf82487SKumar Kartikeya Dwivedi end_seq = log_end(log); 412daf82487SKumar Kartikeya Dwivedi if (WARN_ON_ONCE(log_pos > end_seq)) 413daf82487SKumar Kartikeya Dwivedi log_pos = end_seq; 414daf82487SKumar Kartikeya Dwivedi 415daf82487SKumar Kartikeya Dwivedi /* 416daf82487SKumar Kartikeya Dwivedi * A deep abandoned path may have rotated away the shared prefix. In 417daf82487SKumar Kartikeya Dwivedi * that case, restart with an empty retained suffix and remember that 418daf82487SKumar Kartikeya Dwivedi * every event before the restored mark is unavailable. 419daf82487SKumar Kartikeya Dwivedi */ 420daf82487SKumar Kartikeya Dwivedi if (log_pos <= log->first_seq) { 421daf82487SKumar Kartikeya Dwivedi log->first_seq = log_pos; 422daf82487SKumar Kartikeya Dwivedi log->head = 0; 423daf82487SKumar Kartikeya Dwivedi log->cnt = 0; 424daf82487SKumar Kartikeya Dwivedi return; 425daf82487SKumar Kartikeya Dwivedi } 426daf82487SKumar Kartikeya Dwivedi 427daf82487SKumar Kartikeya Dwivedi log->cnt = log_pos - log->first_seq; 428daf82487SKumar Kartikeya Dwivedi } 429daf82487SKumar Kartikeya Dwivedi 430956a66e5SKumar Kartikeya Dwivedi u32 bpf_diag_irq_depth(const struct bpf_verifier_state *state) 431956a66e5SKumar Kartikeya Dwivedi { 432956a66e5SKumar Kartikeya Dwivedi u32 depth = 0; 433956a66e5SKumar Kartikeya Dwivedi int i; 434956a66e5SKumar Kartikeya Dwivedi 435956a66e5SKumar Kartikeya Dwivedi for (i = 0; i < state->acquired_refs; i++) { 436956a66e5SKumar Kartikeya Dwivedi if (state->refs[i].type == REF_TYPE_IRQ) 437956a66e5SKumar Kartikeya Dwivedi depth++; 438956a66e5SKumar Kartikeya Dwivedi } 439956a66e5SKumar Kartikeya Dwivedi 440956a66e5SKumar Kartikeya Dwivedi return depth; 441956a66e5SKumar Kartikeya Dwivedi } 442956a66e5SKumar Kartikeya Dwivedi 443daf82487SKumar Kartikeya Dwivedi static void diag_append_history(struct bpf_verifier_env *env, 444daf82487SKumar Kartikeya Dwivedi const struct bpf_diag_history_event *event) 445daf82487SKumar Kartikeya Dwivedi { 446daf82487SKumar Kartikeya Dwivedi struct bpf_diag_history_event *events; 447daf82487SKumar Kartikeya Dwivedi struct bpf_diag *diag = env->diag; 448daf82487SKumar Kartikeya Dwivedi struct bpf_diag_log *log; 449daf82487SKumar Kartikeya Dwivedi u32 cap, max_events; 450daf82487SKumar Kartikeya Dwivedi 451daf82487SKumar Kartikeya Dwivedi if (!diag) 452daf82487SKumar Kartikeya Dwivedi return; 453daf82487SKumar Kartikeya Dwivedi log = &diag->log; 454daf82487SKumar Kartikeya Dwivedi 455daf82487SKumar Kartikeya Dwivedi if (log->cnt < log->cap) { 456daf82487SKumar Kartikeya Dwivedi log->events[log_pos(log, log->cnt++)] = *event; 457daf82487SKumar Kartikeya Dwivedi return; 458daf82487SKumar Kartikeya Dwivedi } 459daf82487SKumar Kartikeya Dwivedi 460daf82487SKumar Kartikeya Dwivedi max_events = BPF_DIAG_EVENT_LOG_MAX_SIZE / sizeof(*events); 461daf82487SKumar Kartikeya Dwivedi if (log->growth_failed || log->cap == max_events) 462daf82487SKumar Kartikeya Dwivedi goto rotate; 463daf82487SKumar Kartikeya Dwivedi 464daf82487SKumar Kartikeya Dwivedi cap = min(log->cap ? log->cap * 2 : 64, max_events); 465daf82487SKumar Kartikeya Dwivedi events = kvrealloc(log->events, array_size(cap, sizeof(*events)), GFP_KERNEL_ACCOUNT); 466daf82487SKumar Kartikeya Dwivedi if (!events) { 467daf82487SKumar Kartikeya Dwivedi log->growth_failed = true; 468daf82487SKumar Kartikeya Dwivedi goto rotate; 469daf82487SKumar Kartikeya Dwivedi } 470daf82487SKumar Kartikeya Dwivedi log->events = events; 471daf82487SKumar Kartikeya Dwivedi log->cap = cap; 472daf82487SKumar Kartikeya Dwivedi log->events[log->cnt++] = *event; 473daf82487SKumar Kartikeya Dwivedi return; 474daf82487SKumar Kartikeya Dwivedi 475daf82487SKumar Kartikeya Dwivedi rotate: 476daf82487SKumar Kartikeya Dwivedi if (log->cap) { 477daf82487SKumar Kartikeya Dwivedi log->events[log->head++] = *event; 478daf82487SKumar Kartikeya Dwivedi if (log->head == log->cap) 479daf82487SKumar Kartikeya Dwivedi log->head = 0; 480daf82487SKumar Kartikeya Dwivedi } 481daf82487SKumar Kartikeya Dwivedi log->first_seq++; 482daf82487SKumar Kartikeya Dwivedi } 483daf82487SKumar Kartikeya Dwivedi 484b9c5d822SKumar Kartikeya Dwivedi static void diag_print_wrapped_prefixed(struct bpf_verifier_env *env, const char *first_prefix, 485b9c5d822SKumar Kartikeya Dwivedi const char *next_prefix, const char *text) 486b9c5d822SKumar Kartikeya Dwivedi { 487b9c5d822SKumar Kartikeya Dwivedi const char *prefix = first_prefix; 488b9c5d822SKumar Kartikeya Dwivedi 489b9c5d822SKumar Kartikeya Dwivedi while (*text) { 490b9c5d822SKumar Kartikeya Dwivedi const char *line = text; 491b9c5d822SKumar Kartikeya Dwivedi int prefix_len = strlen(prefix); 492b9c5d822SKumar Kartikeya Dwivedi int text_width = BPF_DIAG_TEXT_WIDTH - prefix_len; 493b9c5d822SKumar Kartikeya Dwivedi int len = 0, last_space = -1; 494b9c5d822SKumar Kartikeya Dwivedi 495b9c5d822SKumar Kartikeya Dwivedi if (text_width < 1) 496b9c5d822SKumar Kartikeya Dwivedi text_width = 1; 497b9c5d822SKumar Kartikeya Dwivedi 498b9c5d822SKumar Kartikeya Dwivedi while (line[len] && line[len] != '\n' && len < text_width) { 499b9c5d822SKumar Kartikeya Dwivedi if (line[len] == ' ') 500b9c5d822SKumar Kartikeya Dwivedi last_space = len; 501b9c5d822SKumar Kartikeya Dwivedi len++; 502b9c5d822SKumar Kartikeya Dwivedi } 503b9c5d822SKumar Kartikeya Dwivedi 504b9c5d822SKumar Kartikeya Dwivedi if (line[len] && line[len] != '\n' && line[len] != ' ' && last_space > 0) 505b9c5d822SKumar Kartikeya Dwivedi len = last_space; 506b9c5d822SKumar Kartikeya Dwivedi 507b9c5d822SKumar Kartikeya Dwivedi diag_write(env, "%s%.*s\n", prefix, len, line); 508b9c5d822SKumar Kartikeya Dwivedi 509b9c5d822SKumar Kartikeya Dwivedi text = line + len; 510b9c5d822SKumar Kartikeya Dwivedi while (*text == ' ') 511b9c5d822SKumar Kartikeya Dwivedi text++; 512b9c5d822SKumar Kartikeya Dwivedi if (*text == '\n') 513b9c5d822SKumar Kartikeya Dwivedi text++; 514b9c5d822SKumar Kartikeya Dwivedi 515b9c5d822SKumar Kartikeya Dwivedi prefix = next_prefix; 516b9c5d822SKumar Kartikeya Dwivedi } 517b9c5d822SKumar Kartikeya Dwivedi } 518b9c5d822SKumar Kartikeya Dwivedi 519af4ea6e2SKumar Kartikeya Dwivedi const char *bpf_diag_fmt_btf_type(struct bpf_verifier_env *env, const struct btf *btf, u32 type_id) 520af4ea6e2SKumar Kartikeya Dwivedi { 521af4ea6e2SKumar Kartikeya Dwivedi char *buf = bpf_diag_fmt_buf(env, BPF_DIAG_FMT_BUF_SIZE); 522af4ea6e2SKumar Kartikeya Dwivedi size_t len; 523af4ea6e2SKumar Kartikeya Dwivedi int ret; 524af4ea6e2SKumar Kartikeya Dwivedi 525af4ea6e2SKumar Kartikeya Dwivedi if (!buf) 526af4ea6e2SKumar Kartikeya Dwivedi return ""; 527af4ea6e2SKumar Kartikeya Dwivedi 528af4ea6e2SKumar Kartikeya Dwivedi buf[0] = '\0'; 529af4ea6e2SKumar Kartikeya Dwivedi ret = btf_type_name_to_buf(btf, type_id, buf, BPF_DIAG_FMT_BUF_SIZE); 530af4ea6e2SKumar Kartikeya Dwivedi if (ret < 0 || !buf[0]) { 531af4ea6e2SKumar Kartikeya Dwivedi scnprintf(buf, BPF_DIAG_FMT_BUF_SIZE, "BTF type ID %u", type_id); 532af4ea6e2SKumar Kartikeya Dwivedi return buf; 533af4ea6e2SKumar Kartikeya Dwivedi } 534af4ea6e2SKumar Kartikeya Dwivedi 535af4ea6e2SKumar Kartikeya Dwivedi len = strlen(buf); 536af4ea6e2SKumar Kartikeya Dwivedi if (len && buf[len - 1] == '{') 537af4ea6e2SKumar Kartikeya Dwivedi buf[len - 1] = '\0'; 538af4ea6e2SKumar Kartikeya Dwivedi return buf; 539af4ea6e2SKumar Kartikeya Dwivedi } 540af4ea6e2SKumar Kartikeya Dwivedi 541d63284e6SKumar Kartikeya Dwivedi static void diag_vprint_indented(struct bpf_verifier_env *env, const char *fmt, va_list args) 542d63284e6SKumar Kartikeya Dwivedi __printf(2, 0); 543d63284e6SKumar Kartikeya Dwivedi 544d63284e6SKumar Kartikeya Dwivedi static void diag_vprint_indented(struct bpf_verifier_env *env, const char *fmt, va_list args) 545d63284e6SKumar Kartikeya Dwivedi { 546d63284e6SKumar Kartikeya Dwivedi char *buf; 547d63284e6SKumar Kartikeya Dwivedi 548d63284e6SKumar Kartikeya Dwivedi if (!bpf_diag_enabled(env)) 549d63284e6SKumar Kartikeya Dwivedi return; 550d63284e6SKumar Kartikeya Dwivedi 551d63284e6SKumar Kartikeya Dwivedi buf = kvasprintf(GFP_KERNEL_ACCOUNT, fmt, args); 552d63284e6SKumar Kartikeya Dwivedi if (!buf) { 553d63284e6SKumar Kartikeya Dwivedi diag_write(env, "%s<failed to allocate diagnostic text>\n", BPF_DIAG_TEXT_INDENT); 554d63284e6SKumar Kartikeya Dwivedi return; 555d63284e6SKumar Kartikeya Dwivedi } 556d63284e6SKumar Kartikeya Dwivedi 557d63284e6SKumar Kartikeya Dwivedi diag_print_wrapped_prefixed(env, BPF_DIAG_TEXT_INDENT, BPF_DIAG_TEXT_INDENT, buf); 558d63284e6SKumar Kartikeya Dwivedi kfree(buf); 559d63284e6SKumar Kartikeya Dwivedi } 560d63284e6SKumar Kartikeya Dwivedi 561b9c5d822SKumar Kartikeya Dwivedi static int diag_line_width(unsigned int line) 562b9c5d822SKumar Kartikeya Dwivedi { 563b9c5d822SKumar Kartikeya Dwivedi int width = 1; 564b9c5d822SKumar Kartikeya Dwivedi 565b9c5d822SKumar Kartikeya Dwivedi while (line >= 10) { 566b9c5d822SKumar Kartikeya Dwivedi line /= 10; 567b9c5d822SKumar Kartikeya Dwivedi width++; 568b9c5d822SKumar Kartikeya Dwivedi } 569b9c5d822SKumar Kartikeya Dwivedi 570b9c5d822SKumar Kartikeya Dwivedi return width; 571b9c5d822SKumar Kartikeya Dwivedi } 572b9c5d822SKumar Kartikeya Dwivedi 573b9c5d822SKumar Kartikeya Dwivedi static int diag_line_indent(const char *line) 574b9c5d822SKumar Kartikeya Dwivedi { 575b9c5d822SKumar Kartikeya Dwivedi int indent = 0; 576b9c5d822SKumar Kartikeya Dwivedi 577b9c5d822SKumar Kartikeya Dwivedi while (*line == ' ' || *line == '\t') { 578b9c5d822SKumar Kartikeya Dwivedi if (*line == '\t') 579b9c5d822SKumar Kartikeya Dwivedi indent = round_up(indent + 1, BPF_DIAG_TAB_WIDTH); 580b9c5d822SKumar Kartikeya Dwivedi else 581b9c5d822SKumar Kartikeya Dwivedi indent++; 582b9c5d822SKumar Kartikeya Dwivedi line++; 583b9c5d822SKumar Kartikeya Dwivedi } 584b9c5d822SKumar Kartikeya Dwivedi 585b9c5d822SKumar Kartikeya Dwivedi return indent; 586b9c5d822SKumar Kartikeya Dwivedi } 587b9c5d822SKumar Kartikeya Dwivedi 588b9c5d822SKumar Kartikeya Dwivedi static void disasm_print(void *private_data, const char *fmt, ...) __printf(2, 3); 589b9c5d822SKumar Kartikeya Dwivedi 590b9c5d822SKumar Kartikeya Dwivedi static void disasm_print(void *private_data, const char *fmt, ...) 591b9c5d822SKumar Kartikeya Dwivedi { 592b9c5d822SKumar Kartikeya Dwivedi struct disasm_ctx *ctx = private_data; 593b9c5d822SKumar Kartikeya Dwivedi va_list args; 594b9c5d822SKumar Kartikeya Dwivedi 595b9c5d822SKumar Kartikeya Dwivedi va_start(args, fmt); 596b9c5d822SKumar Kartikeya Dwivedi seq_buf_vprintf(&ctx->seq, fmt, args); 597b9c5d822SKumar Kartikeya Dwivedi va_end(args); 598b9c5d822SKumar Kartikeya Dwivedi } 599b9c5d822SKumar Kartikeya Dwivedi 600b9c5d822SKumar Kartikeya Dwivedi static const char *disasm_kfunc_name(void *private_data, const struct bpf_insn *insn) 601b9c5d822SKumar Kartikeya Dwivedi { 602b9c5d822SKumar Kartikeya Dwivedi struct disasm_ctx *ctx = private_data; 603b9c5d822SKumar Kartikeya Dwivedi 604b9c5d822SKumar Kartikeya Dwivedi return bpf_disasm_kfunc_name(ctx->env, insn); 605b9c5d822SKumar Kartikeya Dwivedi } 606b9c5d822SKumar Kartikeya Dwivedi 607b9c5d822SKumar Kartikeya Dwivedi static void format_disasm_line(struct bpf_verifier_env *env, int insn_idx, 608b9c5d822SKumar Kartikeya Dwivedi struct disasm_line *line) 609b9c5d822SKumar Kartikeya Dwivedi { 610b9c5d822SKumar Kartikeya Dwivedi struct disasm_ctx ctx = { .env = env }; 611b9c5d822SKumar Kartikeya Dwivedi struct bpf_insn *insn; 612b9c5d822SKumar Kartikeya Dwivedi const struct bpf_insn_cbs cbs = { 613b9c5d822SKumar Kartikeya Dwivedi .cb_call = disasm_kfunc_name, 614b9c5d822SKumar Kartikeya Dwivedi .cb_print = disasm_print, 615b9c5d822SKumar Kartikeya Dwivedi .private_data = &ctx, 616b9c5d822SKumar Kartikeya Dwivedi }; 617b9c5d822SKumar Kartikeya Dwivedi 618b9c5d822SKumar Kartikeya Dwivedi line->idx = insn_idx; 619b9c5d822SKumar Kartikeya Dwivedi line->valid = false; 620b9c5d822SKumar Kartikeya Dwivedi seq_buf_init(&ctx.seq, line->text, sizeof(line->text)); 621b9c5d822SKumar Kartikeya Dwivedi 622b9c5d822SKumar Kartikeya Dwivedi if (insn_idx < 0 || insn_idx >= env->prog->len) 623b9c5d822SKumar Kartikeya Dwivedi return; 624b9c5d822SKumar Kartikeya Dwivedi 625b9c5d822SKumar Kartikeya Dwivedi if (insn_idx > 0 && bpf_is_ldimm64(&env->prog->insnsi[insn_idx - 1])) 626b9c5d822SKumar Kartikeya Dwivedi return; 627b9c5d822SKumar Kartikeya Dwivedi 628b9c5d822SKumar Kartikeya Dwivedi insn = &env->prog->insnsi[insn_idx]; 629b9c5d822SKumar Kartikeya Dwivedi if (bpf_is_ldimm64(insn) && insn_idx + 1 >= env->prog->len) 630b9c5d822SKumar Kartikeya Dwivedi return; 631b9c5d822SKumar Kartikeya Dwivedi 632b9c5d822SKumar Kartikeya Dwivedi print_bpf_insn(&cbs, insn, env->allow_ptr_leaks); 633b9c5d822SKumar Kartikeya Dwivedi seq_buf_str(&ctx.seq); 634b9c5d822SKumar Kartikeya Dwivedi ctx.seq.len = strnlen(line->text, sizeof(line->text)); 635b9c5d822SKumar Kartikeya Dwivedi while (ctx.seq.len && line->text[ctx.seq.len - 1] == '\n') 636b9c5d822SKumar Kartikeya Dwivedi seq_buf_pop(&ctx.seq); 637b9c5d822SKumar Kartikeya Dwivedi seq_buf_str(&ctx.seq); 638b9c5d822SKumar Kartikeya Dwivedi 639b9c5d822SKumar Kartikeya Dwivedi line->valid = true; 640b9c5d822SKumar Kartikeya Dwivedi } 641b9c5d822SKumar Kartikeya Dwivedi 642b9c5d822SKumar Kartikeya Dwivedi static void diag_format_source_text(char *buf, size_t size, const char *line, int width) 643b9c5d822SKumar Kartikeya Dwivedi { 644b9c5d822SKumar Kartikeya Dwivedi int col = 0, len = 0; 645b9c5d822SKumar Kartikeya Dwivedi 646b9c5d822SKumar Kartikeya Dwivedi if (!size) 647b9c5d822SKumar Kartikeya Dwivedi return; 648b9c5d822SKumar Kartikeya Dwivedi if (width <= 0) { 649b9c5d822SKumar Kartikeya Dwivedi buf[0] = '\0'; 650b9c5d822SKumar Kartikeya Dwivedi return; 651b9c5d822SKumar Kartikeya Dwivedi } 652b9c5d822SKumar Kartikeya Dwivedi 653b9c5d822SKumar Kartikeya Dwivedi line = line ?: "..."; 654b9c5d822SKumar Kartikeya Dwivedi while (*line && col < width && len + 1 < size) { 655b9c5d822SKumar Kartikeya Dwivedi if (*line == '\t') { 656b9c5d822SKumar Kartikeya Dwivedi int next = round_up(col + 1, BPF_DIAG_TAB_WIDTH); 657b9c5d822SKumar Kartikeya Dwivedi 658b9c5d822SKumar Kartikeya Dwivedi while (col < next && col < width && len + 1 < size) { 659b9c5d822SKumar Kartikeya Dwivedi buf[len++] = ' '; 660b9c5d822SKumar Kartikeya Dwivedi col++; 661b9c5d822SKumar Kartikeya Dwivedi } 662b9c5d822SKumar Kartikeya Dwivedi line++; 663b9c5d822SKumar Kartikeya Dwivedi continue; 664b9c5d822SKumar Kartikeya Dwivedi } 665b9c5d822SKumar Kartikeya Dwivedi 666b9c5d822SKumar Kartikeya Dwivedi buf[len++] = *line++; 667b9c5d822SKumar Kartikeya Dwivedi col++; 668b9c5d822SKumar Kartikeya Dwivedi } 669b9c5d822SKumar Kartikeya Dwivedi 670b9c5d822SKumar Kartikeya Dwivedi if (*line) { 671b9c5d822SKumar Kartikeya Dwivedi int ellipsis_len = min(3, width); 672b9c5d822SKumar Kartikeya Dwivedi 673b9c5d822SKumar Kartikeya Dwivedi while (len > 0 && col > width - ellipsis_len) { 674b9c5d822SKumar Kartikeya Dwivedi len--; 675b9c5d822SKumar Kartikeya Dwivedi col--; 676b9c5d822SKumar Kartikeya Dwivedi } 677b9c5d822SKumar Kartikeya Dwivedi while (ellipsis_len-- && len + 1 < size) 678b9c5d822SKumar Kartikeya Dwivedi buf[len++] = '.'; 679b9c5d822SKumar Kartikeya Dwivedi } 680b9c5d822SKumar Kartikeya Dwivedi 681b9c5d822SKumar Kartikeya Dwivedi buf[len] = '\0'; 682b9c5d822SKumar Kartikeya Dwivedi } 683b9c5d822SKumar Kartikeya Dwivedi 684b9c5d822SKumar Kartikeya Dwivedi static void diag_format_source_lane(char *buf, size_t size, const char *source_prefix, 685b9c5d822SKumar Kartikeya Dwivedi int source_line_width, int line_num, const char *line) 686b9c5d822SKumar Kartikeya Dwivedi { 687b9c5d822SKumar Kartikeya Dwivedi int len, text_width; 688b9c5d822SKumar Kartikeya Dwivedi 689b9c5d822SKumar Kartikeya Dwivedi if (line_num <= 0) { 690b9c5d822SKumar Kartikeya Dwivedi buf[0] = '\0'; 691b9c5d822SKumar Kartikeya Dwivedi return; 692b9c5d822SKumar Kartikeya Dwivedi } 693b9c5d822SKumar Kartikeya Dwivedi 694b9c5d822SKumar Kartikeya Dwivedi len = scnprintf(buf, size, "%s%*d | ", source_prefix, source_line_width, line_num); 695b9c5d822SKumar Kartikeya Dwivedi text_width = BPF_DIAG_SOURCE_LANE_WIDTH - len; 696b9c5d822SKumar Kartikeya Dwivedi diag_format_source_text(buf + len, size - len, line, text_width); 697b9c5d822SKumar Kartikeya Dwivedi } 698b9c5d822SKumar Kartikeya Dwivedi 6995ad74616SKumar Kartikeya Dwivedi static void bpf_diag_header(struct bpf_verifier_env *env, const char *category, 7005ad74616SKumar Kartikeya Dwivedi const char *problem) 7015ad74616SKumar Kartikeya Dwivedi { 7025ad74616SKumar Kartikeya Dwivedi char first; 7035ad74616SKumar Kartikeya Dwivedi 7045ad74616SKumar Kartikeya Dwivedi if (!bpf_diag_enabled(env)) 7055ad74616SKumar Kartikeya Dwivedi return; 7065ad74616SKumar Kartikeya Dwivedi 7075ad74616SKumar Kartikeya Dwivedi category = category ?: "Verifier Error"; 7085ad74616SKumar Kartikeya Dwivedi problem = problem ?: ""; 7095ad74616SKumar Kartikeya Dwivedi 7105ad74616SKumar Kartikeya Dwivedi if (!problem[0]) { 7115ad74616SKumar Kartikeya Dwivedi diag_write(env, "\nVerification failed: %s\n", category); 7125ad74616SKumar Kartikeya Dwivedi return; 7135ad74616SKumar Kartikeya Dwivedi } 7145ad74616SKumar Kartikeya Dwivedi 7155ad74616SKumar Kartikeya Dwivedi first = toupper(problem[0]); 7165ad74616SKumar Kartikeya Dwivedi diag_write(env, "\nVerification failed: %s: %c%s\n", category, first, problem + 1); 7175ad74616SKumar Kartikeya Dwivedi } 718b9c5d822SKumar Kartikeya Dwivedi 719d63284e6SKumar Kartikeya Dwivedi static void diag_reason(struct bpf_verifier_env *env, const char *fmt, ...) __printf(2, 3); 720d63284e6SKumar Kartikeya Dwivedi static void diag_suggestion(struct bpf_verifier_env *env, const char *fmt, ...) 721d63284e6SKumar Kartikeya Dwivedi __printf(2, 3); 722d63284e6SKumar Kartikeya Dwivedi 723d63284e6SKumar Kartikeya Dwivedi static void diag_section(struct bpf_verifier_env *env, const char *title) 724d63284e6SKumar Kartikeya Dwivedi { 725d63284e6SKumar Kartikeya Dwivedi if (!bpf_diag_enabled(env)) 726d63284e6SKumar Kartikeya Dwivedi return; 727d63284e6SKumar Kartikeya Dwivedi 728d63284e6SKumar Kartikeya Dwivedi diag_write(env, "\n%s:\n", title); 729d63284e6SKumar Kartikeya Dwivedi } 730d63284e6SKumar Kartikeya Dwivedi 731d63284e6SKumar Kartikeya Dwivedi static void diag_reason(struct bpf_verifier_env *env, const char *fmt, ...) 732d63284e6SKumar Kartikeya Dwivedi { 733d63284e6SKumar Kartikeya Dwivedi va_list args; 734d63284e6SKumar Kartikeya Dwivedi 735d63284e6SKumar Kartikeya Dwivedi if (!bpf_diag_enabled(env)) 736d63284e6SKumar Kartikeya Dwivedi return; 737d63284e6SKumar Kartikeya Dwivedi 738d63284e6SKumar Kartikeya Dwivedi diag_section(env, "Reason"); 739d63284e6SKumar Kartikeya Dwivedi 740d63284e6SKumar Kartikeya Dwivedi va_start(args, fmt); 741d63284e6SKumar Kartikeya Dwivedi diag_vprint_indented(env, fmt, args); 742d63284e6SKumar Kartikeya Dwivedi va_end(args); 743d63284e6SKumar Kartikeya Dwivedi } 744d63284e6SKumar Kartikeya Dwivedi 745d63284e6SKumar Kartikeya Dwivedi static void diag_suggestion(struct bpf_verifier_env *env, const char *fmt, ...) 746d63284e6SKumar Kartikeya Dwivedi { 747d63284e6SKumar Kartikeya Dwivedi va_list args; 748d63284e6SKumar Kartikeya Dwivedi 749d63284e6SKumar Kartikeya Dwivedi if (!bpf_diag_enabled(env)) 750d63284e6SKumar Kartikeya Dwivedi return; 751d63284e6SKumar Kartikeya Dwivedi 752d63284e6SKumar Kartikeya Dwivedi diag_section(env, "Suggestion"); 753d63284e6SKumar Kartikeya Dwivedi 754d63284e6SKumar Kartikeya Dwivedi va_start(args, fmt); 755d63284e6SKumar Kartikeya Dwivedi diag_vprint_indented(env, fmt, args); 756d63284e6SKumar Kartikeya Dwivedi va_end(args); 757d63284e6SKumar Kartikeya Dwivedi diag_write(env, "\n"); 758d63284e6SKumar Kartikeya Dwivedi } 759d63284e6SKumar Kartikeya Dwivedi 760b9c5d822SKumar Kartikeya Dwivedi static void diag_print_source_annotation(struct bpf_verifier_env *env, int line_width, int indent, 761b9c5d822SKumar Kartikeya Dwivedi const char *label, const char *msg) 762b9c5d822SKumar Kartikeya Dwivedi { 763b9c5d822SKumar Kartikeya Dwivedi const char *first_prefix, *next_prefix, *text; 764b9c5d822SKumar Kartikeya Dwivedi 765b9c5d822SKumar Kartikeya Dwivedi indent = min_t(int, indent, max_t(int, 0, BPF_DIAG_SOURCE_LANE_WIDTH - line_width - 8)); 766b9c5d822SKumar Kartikeya Dwivedi text = bpf_diag_fmt(env, "%s: %s", label, msg); 767b9c5d822SKumar Kartikeya Dwivedi first_prefix = bpf_diag_fmt(env, " %*s | %*s^-- ", line_width + 4, "", indent, ""); 768b9c5d822SKumar Kartikeya Dwivedi next_prefix = bpf_diag_fmt(env, " %*s | %*s ", line_width + 4, "", indent, ""); 769b9c5d822SKumar Kartikeya Dwivedi 770b9c5d822SKumar Kartikeya Dwivedi diag_print_wrapped_prefixed(env, first_prefix, next_prefix, text); 771b9c5d822SKumar Kartikeya Dwivedi } 772b9c5d822SKumar Kartikeya Dwivedi 773b9c5d822SKumar Kartikeya Dwivedi static void diag_print_insn_context(struct bpf_verifier_env *env, u32 insn_idx, 774b9c5d822SKumar Kartikeya Dwivedi struct disasm_line *disasm_lines) 775b9c5d822SKumar Kartikeya Dwivedi { 776b9c5d822SKumar Kartikeya Dwivedi int insn_width = diag_line_width(env->prog->len ? env->prog->len - 1 : 0); 777b9c5d822SKumar Kartikeya Dwivedi int i; 778b9c5d822SKumar Kartikeya Dwivedi 779b9c5d822SKumar Kartikeya Dwivedi for (i = 0; i < BPF_DIAG_CONTEXT_CNT; i++) { 780b9c5d822SKumar Kartikeya Dwivedi int row = i - BPF_DIAG_CONTEXT; 781b9c5d822SKumar Kartikeya Dwivedi 782b9c5d822SKumar Kartikeya Dwivedi format_disasm_line(env, insn_idx + row, &disasm_lines[i]); 783b9c5d822SKumar Kartikeya Dwivedi } 784b9c5d822SKumar Kartikeya Dwivedi 785b9c5d822SKumar Kartikeya Dwivedi diag_write(env, " Instruction context:\n"); 786b9c5d822SKumar Kartikeya Dwivedi for (i = 0; i < BPF_DIAG_CONTEXT_CNT; i++) { 787b9c5d822SKumar Kartikeya Dwivedi struct disasm_line *line = &disasm_lines[i]; 788b9c5d822SKumar Kartikeya Dwivedi 789b9c5d822SKumar Kartikeya Dwivedi if (line->valid) 790b9c5d822SKumar Kartikeya Dwivedi diag_write(env, " %s%*d | %s\n", 791b9c5d822SKumar Kartikeya Dwivedi line->idx == insn_idx ? ">>> " : " ", 792b9c5d822SKumar Kartikeya Dwivedi insn_width, line->idx, line->text); 793b9c5d822SKumar Kartikeya Dwivedi } 794b9c5d822SKumar Kartikeya Dwivedi } 795b9c5d822SKumar Kartikeya Dwivedi 796b9c5d822SKumar Kartikeya Dwivedi static void bpf_diag_source(struct bpf_verifier_env *env, u32 insn_idx, const char *label, 797b9c5d822SKumar Kartikeya Dwivedi const char *fmt, ...) 798b9c5d822SKumar Kartikeya Dwivedi { 799b9c5d822SKumar Kartikeya Dwivedi struct bpf_diag_scratch *scratch; 800b9c5d822SKumar Kartikeya Dwivedi struct bpf_linfo_source *source_lines; 801b9c5d822SKumar Kartikeya Dwivedi struct disasm_line *disasm_lines; 802b9c5d822SKumar Kartikeya Dwivedi struct bpf_linfo_source src = {}; 803b9c5d822SKumar Kartikeya Dwivedi struct diag_fmt_mark mark; 804b9c5d822SKumar Kartikeya Dwivedi const struct bpf_line_info *linfo; 805b9c5d822SKumar Kartikeya Dwivedi const struct bpf_subprog_info *subprog; 806b9c5d822SKumar Kartikeya Dwivedi struct btf *btf = env->prog->aux->btf; 807b9c5d822SKumar Kartikeya Dwivedi char *source_lane; 808b9c5d822SKumar Kartikeya Dwivedi const char *msg; 809b9c5d822SKumar Kartikeya Dwivedi const char *func; 810b9c5d822SKumar Kartikeya Dwivedi int start_line, end_line, width, indent, subprogno, linfo_start, linfo_end, i; 811b9c5d822SKumar Kartikeya Dwivedi va_list args; 812b9c5d822SKumar Kartikeya Dwivedi 813b9c5d822SKumar Kartikeya Dwivedi if (!bpf_diag_enabled(env)) 814b9c5d822SKumar Kartikeya Dwivedi return; 815b9c5d822SKumar Kartikeya Dwivedi if (!env->diag) 816b9c5d822SKumar Kartikeya Dwivedi return; 817b9c5d822SKumar Kartikeya Dwivedi 818b9c5d822SKumar Kartikeya Dwivedi mark = diag_fmt_save(env); 819b9c5d822SKumar Kartikeya Dwivedi label = label ?: "note"; 820b9c5d822SKumar Kartikeya Dwivedi scratch = &env->diag->scratch; 821b9c5d822SKumar Kartikeya Dwivedi source_lines = scratch->source_lines; 822b9c5d822SKumar Kartikeya Dwivedi disasm_lines = scratch->disasm_lines; 823b9c5d822SKumar Kartikeya Dwivedi memset(source_lines, 0, sizeof(scratch->source_lines)); 824b9c5d822SKumar Kartikeya Dwivedi memset(disasm_lines, 0, sizeof(scratch->disasm_lines)); 825b9c5d822SKumar Kartikeya Dwivedi 826b9c5d822SKumar Kartikeya Dwivedi va_start(args, fmt); 827b9c5d822SKumar Kartikeya Dwivedi msg = bpf_diag_vfmt(env, fmt, args); 828b9c5d822SKumar Kartikeya Dwivedi va_end(args); 829b9c5d822SKumar Kartikeya Dwivedi if (!*msg) 830b9c5d822SKumar Kartikeya Dwivedi msg = "<failed to allocate diagnostic text>"; 831b9c5d822SKumar Kartikeya Dwivedi 832b9c5d822SKumar Kartikeya Dwivedi linfo = bpf_find_linfo(env->prog, insn_idx); 833b9c5d822SKumar Kartikeya Dwivedi if (btf && linfo) 834b9c5d822SKumar Kartikeya Dwivedi bpf_get_linfo_source(btf, linfo, &src); 835b9c5d822SKumar Kartikeya Dwivedi if (!src.file || !*src.file || !src.line || !*src.line) { 836b9c5d822SKumar Kartikeya Dwivedi diag_write(env, " insn %u\n", insn_idx); 837b9c5d822SKumar Kartikeya Dwivedi diag_print_source_annotation(env, 0, 0, label, msg); 838b9c5d822SKumar Kartikeya Dwivedi diag_print_insn_context(env, insn_idx, disasm_lines); 839b9c5d822SKumar Kartikeya Dwivedi goto out_restore; 840b9c5d822SKumar Kartikeya Dwivedi } 841b9c5d822SKumar Kartikeya Dwivedi 842b9c5d822SKumar Kartikeya Dwivedi subprog = bpf_find_containing_subprog(env, insn_idx); 843b9c5d822SKumar Kartikeya Dwivedi subprogno = subprog ? subprog - env->subprog_info : -ENOENT; 844b9c5d822SKumar Kartikeya Dwivedi func = subprogno >= 0 ? bpf_subprog_name(env, subprogno) : NULL; 845b9c5d822SKumar Kartikeya Dwivedi if (func && *func) 846b9c5d822SKumar Kartikeya Dwivedi diag_write(env, " %s @ %s:%d:%d\n", func, src.file, src.line_num, src.line_col); 847b9c5d822SKumar Kartikeya Dwivedi else 848b9c5d822SKumar Kartikeya Dwivedi diag_write(env, " %s:%d:%d\n", src.file, src.line_num, src.line_col); 849b9c5d822SKumar Kartikeya Dwivedi 850b9c5d822SKumar Kartikeya Dwivedi start_line = src.line_num - BPF_DIAG_CONTEXT; 851b9c5d822SKumar Kartikeya Dwivedi end_line = src.line_num + BPF_DIAG_CONTEXT; 852b9c5d822SKumar Kartikeya Dwivedi width = diag_line_width(end_line); 853b9c5d822SKumar Kartikeya Dwivedi indent = diag_line_indent(src.line); 854b9c5d822SKumar Kartikeya Dwivedi for (i = 0; i < BPF_DIAG_CONTEXT_CNT; i++) 855b9c5d822SKumar Kartikeya Dwivedi source_lines[i].line_num = start_line + i; 856b9c5d822SKumar Kartikeya Dwivedi 857b9c5d822SKumar Kartikeya Dwivedi linfo = env->prog->aux->linfo; 858b9c5d822SKumar Kartikeya Dwivedi linfo_start = subprog ? subprog->linfo_idx : 0; 859b9c5d822SKumar Kartikeya Dwivedi linfo_end = subprogno >= 0 && subprogno + 1 < env->subprog_cnt ? 860b9c5d822SKumar Kartikeya Dwivedi env->subprog_info[subprogno + 1].linfo_idx : env->prog->aux->nr_linfo; 861b9c5d822SKumar Kartikeya Dwivedi for (i = linfo_start; i < linfo_end; i++) { 862b9c5d822SKumar Kartikeya Dwivedi struct bpf_linfo_source line_src; 863b9c5d822SKumar Kartikeya Dwivedi int idx; 864b9c5d822SKumar Kartikeya Dwivedi 865b9c5d822SKumar Kartikeya Dwivedi bpf_get_linfo_source(btf, &linfo[i], &line_src); 866b9c5d822SKumar Kartikeya Dwivedi if (line_src.file_name_off != src.file_name_off || 867b9c5d822SKumar Kartikeya Dwivedi line_src.line_num < start_line || line_src.line_num > end_line || 868b9c5d822SKumar Kartikeya Dwivedi !line_src.line || !*line_src.line) 869b9c5d822SKumar Kartikeya Dwivedi continue; 870b9c5d822SKumar Kartikeya Dwivedi 871b9c5d822SKumar Kartikeya Dwivedi idx = line_src.line_num - start_line; 872b9c5d822SKumar Kartikeya Dwivedi if (!source_lines[idx].line) 873b9c5d822SKumar Kartikeya Dwivedi source_lines[idx] = line_src; 874b9c5d822SKumar Kartikeya Dwivedi } 875b9c5d822SKumar Kartikeya Dwivedi 876b9c5d822SKumar Kartikeya Dwivedi diag_write(env, " Source context:\n"); 877b9c5d822SKumar Kartikeya Dwivedi source_lane = bpf_diag_fmt_buf(env, BPF_DIAG_FMT_BUF_SIZE); 878b9c5d822SKumar Kartikeya Dwivedi if (!source_lane) 879b9c5d822SKumar Kartikeya Dwivedi goto out_restore; 880b9c5d822SKumar Kartikeya Dwivedi for (i = 0; i < BPF_DIAG_CONTEXT_CNT; i++) { 881b9c5d822SKumar Kartikeya Dwivedi const char *source_prefix; 882b9c5d822SKumar Kartikeya Dwivedi 883b9c5d822SKumar Kartikeya Dwivedi source_prefix = source_lines[i].line_num == src.line_num ? ">>> " : " "; 884b9c5d822SKumar Kartikeya Dwivedi diag_format_source_lane(source_lane, BPF_DIAG_FMT_BUF_SIZE, source_prefix, width, 885b9c5d822SKumar Kartikeya Dwivedi source_lines[i].line_num, source_lines[i].line); 886b9c5d822SKumar Kartikeya Dwivedi diag_write(env, " %s\n", source_lane); 887b9c5d822SKumar Kartikeya Dwivedi if (source_lines[i].line_num == src.line_num) 888b9c5d822SKumar Kartikeya Dwivedi diag_print_source_annotation(env, width, indent, label, msg); 889b9c5d822SKumar Kartikeya Dwivedi } 890b9c5d822SKumar Kartikeya Dwivedi diag_print_insn_context(env, insn_idx, disasm_lines); 891b9c5d822SKumar Kartikeya Dwivedi 892b9c5d822SKumar Kartikeya Dwivedi out_restore: 893b9c5d822SKumar Kartikeya Dwivedi diag_fmt_restore(env, mark); 894b9c5d822SKumar Kartikeya Dwivedi } 895daf82487SKumar Kartikeya Dwivedi 896d63284e6SKumar Kartikeya Dwivedi static const struct bpf_func_state *diag_current_frame(const struct bpf_verifier_env *env) 897d63284e6SKumar Kartikeya Dwivedi { 898d63284e6SKumar Kartikeya Dwivedi return env->cur_state->frame[env->cur_state->curframe]; 899d63284e6SKumar Kartikeya Dwivedi } 900d63284e6SKumar Kartikeya Dwivedi 901d63284e6SKumar Kartikeya Dwivedi void bpf_diag_register_type(struct bpf_verifier_env *env, u32 insn_idx, int regno, 902d63284e6SKumar Kartikeya Dwivedi const char *problem, const char *reason, const char *suggestion) 903d63284e6SKumar Kartikeya Dwivedi { 904d63284e6SKumar Kartikeya Dwivedi const struct bpf_func_state *frame = diag_current_frame(env); 905d63284e6SKumar Kartikeya Dwivedi struct bpf_diag_history_opts opts = { 906d63284e6SKumar Kartikeya Dwivedi .scope = BPF_DIAG_HISTORY_SCOPE_REG, 907d63284e6SKumar Kartikeya Dwivedi .frame_id = frame->diag_frame_id, 908d63284e6SKumar Kartikeya Dwivedi .frameno = frame->frameno, 909d63284e6SKumar Kartikeya Dwivedi .regno = regno, 910d63284e6SKumar Kartikeya Dwivedi }; 911d63284e6SKumar Kartikeya Dwivedi 912d63284e6SKumar Kartikeya Dwivedi bpf_diag_header(env, REGISTER_TYPE_SAFETY, problem); 913d63284e6SKumar Kartikeya Dwivedi diag_reason(env, "%s", reason); 914d63284e6SKumar Kartikeya Dwivedi 915d63284e6SKumar Kartikeya Dwivedi diag_section(env, "At"); 916d63284e6SKumar Kartikeya Dwivedi bpf_diag_source(env, insn_idx, "error", "%s", problem); 917d63284e6SKumar Kartikeya Dwivedi 918d63284e6SKumar Kartikeya Dwivedi if (regno >= 0) 919d63284e6SKumar Kartikeya Dwivedi diag_print_history(env, &opts); 920d63284e6SKumar Kartikeya Dwivedi 921d63284e6SKumar Kartikeya Dwivedi diag_suggestion(env, "%s", suggestion); 922d63284e6SKumar Kartikeya Dwivedi } 923d63284e6SKumar Kartikeya Dwivedi 924d63284e6SKumar Kartikeya Dwivedi const char *bpf_diag_reg_type_plain(struct bpf_verifier_env *env, enum bpf_reg_type type) 925d63284e6SKumar Kartikeya Dwivedi { 926d63284e6SKumar Kartikeya Dwivedi switch (base_type(type)) { 927d63284e6SKumar Kartikeya Dwivedi case NOT_INIT: 928d63284e6SKumar Kartikeya Dwivedi return "an uninitialized value"; 929d63284e6SKumar Kartikeya Dwivedi case SCALAR_VALUE: 930d63284e6SKumar Kartikeya Dwivedi return "an integer scalar"; 931d63284e6SKumar Kartikeya Dwivedi case PTR_TO_CTX: 932d63284e6SKumar Kartikeya Dwivedi return "a context pointer"; 933d63284e6SKumar Kartikeya Dwivedi case PTR_TO_STACK: 934d63284e6SKumar Kartikeya Dwivedi return "a stack pointer"; 935d63284e6SKumar Kartikeya Dwivedi case PTR_TO_MAP_VALUE: 936d63284e6SKumar Kartikeya Dwivedi if (type_may_be_null(type)) 937d63284e6SKumar Kartikeya Dwivedi return "a nullable map value pointer"; 938d63284e6SKumar Kartikeya Dwivedi return "a map value pointer"; 939d63284e6SKumar Kartikeya Dwivedi case PTR_TO_MEM: 940d63284e6SKumar Kartikeya Dwivedi if (type_may_be_null(type)) 941d63284e6SKumar Kartikeya Dwivedi return "a nullable memory pointer"; 942d63284e6SKumar Kartikeya Dwivedi return "a memory pointer"; 943d63284e6SKumar Kartikeya Dwivedi case PTR_TO_BTF_ID: 944d63284e6SKumar Kartikeya Dwivedi if (type_may_be_null(type)) 945d63284e6SKumar Kartikeya Dwivedi return "a nullable kernel object pointer"; 946d63284e6SKumar Kartikeya Dwivedi if (type_is_non_owning_ref(type)) 947d63284e6SKumar Kartikeya Dwivedi return "a borrowed allocated object pointer"; 948d63284e6SKumar Kartikeya Dwivedi if (type_is_ptr_alloc_obj(type)) 949d63284e6SKumar Kartikeya Dwivedi return "an owned allocated object pointer"; 950d63284e6SKumar Kartikeya Dwivedi if (type_flag(type) & PTR_UNTRUSTED) 951d63284e6SKumar Kartikeya Dwivedi return "an untrusted kernel object pointer"; 952d63284e6SKumar Kartikeya Dwivedi return "a kernel object pointer"; 953d63284e6SKumar Kartikeya Dwivedi default: 954d63284e6SKumar Kartikeya Dwivedi return reg_type_str(env, type); 955d63284e6SKumar Kartikeya Dwivedi } 956d63284e6SKumar Kartikeya Dwivedi } 957d63284e6SKumar Kartikeya Dwivedi 958d63284e6SKumar Kartikeya Dwivedi static const char *diag_arg_ordinal(int argno) 959d63284e6SKumar Kartikeya Dwivedi { 960d63284e6SKumar Kartikeya Dwivedi switch (argno) { 961d63284e6SKumar Kartikeya Dwivedi case 1: 962d63284e6SKumar Kartikeya Dwivedi return "first"; 963d63284e6SKumar Kartikeya Dwivedi case 2: 964d63284e6SKumar Kartikeya Dwivedi return "second"; 965d63284e6SKumar Kartikeya Dwivedi case 3: 966d63284e6SKumar Kartikeya Dwivedi return "third"; 967d63284e6SKumar Kartikeya Dwivedi case 4: 968d63284e6SKumar Kartikeya Dwivedi return "fourth"; 969d63284e6SKumar Kartikeya Dwivedi case 5: 970d63284e6SKumar Kartikeya Dwivedi return "fifth"; 971d63284e6SKumar Kartikeya Dwivedi case 6: 972d63284e6SKumar Kartikeya Dwivedi return "sixth"; 973d63284e6SKumar Kartikeya Dwivedi case 7: 974d63284e6SKumar Kartikeya Dwivedi return "seventh"; 975d63284e6SKumar Kartikeya Dwivedi case 8: 976d63284e6SKumar Kartikeya Dwivedi return "eighth"; 977d63284e6SKumar Kartikeya Dwivedi case 9: 978d63284e6SKumar Kartikeya Dwivedi return "ninth"; 979d63284e6SKumar Kartikeya Dwivedi case 10: 980d63284e6SKumar Kartikeya Dwivedi return "tenth"; 981d63284e6SKumar Kartikeya Dwivedi case 11: 982d63284e6SKumar Kartikeya Dwivedi return "eleventh"; 983d63284e6SKumar Kartikeya Dwivedi case 12: 984d63284e6SKumar Kartikeya Dwivedi return "twelfth"; 985d63284e6SKumar Kartikeya Dwivedi default: 986d63284e6SKumar Kartikeya Dwivedi return NULL; 987d63284e6SKumar Kartikeya Dwivedi } 988d63284e6SKumar Kartikeya Dwivedi } 989d63284e6SKumar Kartikeya Dwivedi 99066e27273SKumar Kartikeya Dwivedi void bpf_diag_call_type(struct bpf_verifier_env *env, u32 insn_idx, int argno, int regno, 99166e27273SKumar Kartikeya Dwivedi int stack_arg_slot, const char *call_name, const char *arg_name, 99266e27273SKumar Kartikeya Dwivedi const char *reason, const char *suggestion) 99366e27273SKumar Kartikeya Dwivedi { 99466e27273SKumar Kartikeya Dwivedi const struct bpf_func_state *frame = diag_current_frame(env); 99566e27273SKumar Kartikeya Dwivedi struct bpf_diag_history_opts opts = { 99666e27273SKumar Kartikeya Dwivedi .frame_id = frame->diag_frame_id, 99766e27273SKumar Kartikeya Dwivedi .frameno = frame->frameno, 99866e27273SKumar Kartikeya Dwivedi }; 99966e27273SKumar Kartikeya Dwivedi const char *ordinal = diag_arg_ordinal(argno); 100066e27273SKumar Kartikeya Dwivedi const char *arg_desc; 100166e27273SKumar Kartikeya Dwivedi bool print_history = true; 100266e27273SKumar Kartikeya Dwivedi 100366e27273SKumar Kartikeya Dwivedi if (regno >= 0) { 100466e27273SKumar Kartikeya Dwivedi opts.scope = BPF_DIAG_HISTORY_SCOPE_REG; 100566e27273SKumar Kartikeya Dwivedi opts.regno = regno; 100666e27273SKumar Kartikeya Dwivedi } else if (stack_arg_slot >= 0) { 100766e27273SKumar Kartikeya Dwivedi opts.scope = BPF_DIAG_HISTORY_SCOPE_STACK_ARG; 100866e27273SKumar Kartikeya Dwivedi opts.stack_arg_slot = stack_arg_slot; 100966e27273SKumar Kartikeya Dwivedi } else { 101066e27273SKumar Kartikeya Dwivedi print_history = false; 101166e27273SKumar Kartikeya Dwivedi } 101266e27273SKumar Kartikeya Dwivedi 101366e27273SKumar Kartikeya Dwivedi if (ordinal && arg_name) 101466e27273SKumar Kartikeya Dwivedi arg_desc = bpf_diag_fmt(env, "%s argument (%s)", ordinal, arg_name); 101566e27273SKumar Kartikeya Dwivedi else if (ordinal) 101666e27273SKumar Kartikeya Dwivedi arg_desc = bpf_diag_fmt(env, "%s argument", ordinal); 101766e27273SKumar Kartikeya Dwivedi else if (arg_name) 101866e27273SKumar Kartikeya Dwivedi arg_desc = bpf_diag_fmt(env, "argument %s", arg_name); 101966e27273SKumar Kartikeya Dwivedi else 102066e27273SKumar Kartikeya Dwivedi arg_desc = "argument"; 102166e27273SKumar Kartikeya Dwivedi 102266e27273SKumar Kartikeya Dwivedi bpf_diag_header(env, CALL_TYPE_SAFETY, "invalid call argument"); 102366e27273SKumar Kartikeya Dwivedi diag_reason(env, "The %s to %s does not satisfy the verifier contract: %s.", 102466e27273SKumar Kartikeya Dwivedi arg_desc, call_name, reason); 102566e27273SKumar Kartikeya Dwivedi 102666e27273SKumar Kartikeya Dwivedi diag_section(env, "At"); 102766e27273SKumar Kartikeya Dwivedi bpf_diag_source(env, insn_idx, "error", "invalid %s for %s", arg_desc, call_name); 102866e27273SKumar Kartikeya Dwivedi 102966e27273SKumar Kartikeya Dwivedi if (print_history) 103066e27273SKumar Kartikeya Dwivedi diag_print_history(env, &opts); 103166e27273SKumar Kartikeya Dwivedi 103266e27273SKumar Kartikeya Dwivedi diag_suggestion(env, "%s", suggestion); 103366e27273SKumar Kartikeya Dwivedi } 103466e27273SKumar Kartikeya Dwivedi 103599a6a288SKumar Kartikeya Dwivedi static const char *diag_context_constraint(enum bpf_diag_context_kind kind) 103699a6a288SKumar Kartikeya Dwivedi { 103799a6a288SKumar Kartikeya Dwivedi switch (kind) { 103899a6a288SKumar Kartikeya Dwivedi case BPF_DIAG_CONTEXT_RCU: 103999a6a288SKumar Kartikeya Dwivedi return "RCU read-side critical sections cannot call operations that may sleep"; 104099a6a288SKumar Kartikeya Dwivedi case BPF_DIAG_CONTEXT_PREEMPT: 104199a6a288SKumar Kartikeya Dwivedi return "preemption-disabled code cannot call operations that may sleep"; 104299a6a288SKumar Kartikeya Dwivedi case BPF_DIAG_CONTEXT_IRQ: 104399a6a288SKumar Kartikeya Dwivedi return "IRQ-disabled code cannot call operations that may sleep"; 104499a6a288SKumar Kartikeya Dwivedi case BPF_DIAG_CONTEXT_LOCK: 104599a6a288SKumar Kartikeya Dwivedi return "code holding a BPF spin lock cannot call operations that may sleep"; 104699a6a288SKumar Kartikeya Dwivedi case BPF_DIAG_CONTEXT_NONE: 104799a6a288SKumar Kartikeya Dwivedi default: 104899a6a288SKumar Kartikeya Dwivedi return NULL; 104999a6a288SKumar Kartikeya Dwivedi } 105099a6a288SKumar Kartikeya Dwivedi } 105199a6a288SKumar Kartikeya Dwivedi 105299a6a288SKumar Kartikeya Dwivedi static const char *diag_active_context(struct bpf_verifier_env *env, u32 depth, 105399a6a288SKumar Kartikeya Dwivedi const char *context) 105499a6a288SKumar Kartikeya Dwivedi { 105599a6a288SKumar Kartikeya Dwivedi if (depth == 1) 105699a6a288SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "an active %s (depth 1)", context); 105799a6a288SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "%u active %ss (depth %u)", depth, context, depth); 105899a6a288SKumar Kartikeya Dwivedi } 105999a6a288SKumar Kartikeya Dwivedi 106099a6a288SKumar Kartikeya Dwivedi static u32 diag_context_depth(struct bpf_verifier_env *env, enum bpf_diag_context_kind kind) 106199a6a288SKumar Kartikeya Dwivedi { 106299a6a288SKumar Kartikeya Dwivedi switch (kind) { 106399a6a288SKumar Kartikeya Dwivedi case BPF_DIAG_CONTEXT_RCU: 106499a6a288SKumar Kartikeya Dwivedi return env->cur_state->active_rcu_locks; 106599a6a288SKumar Kartikeya Dwivedi case BPF_DIAG_CONTEXT_PREEMPT: 106699a6a288SKumar Kartikeya Dwivedi return env->cur_state->active_preempt_locks; 106799a6a288SKumar Kartikeya Dwivedi case BPF_DIAG_CONTEXT_IRQ: 106899a6a288SKumar Kartikeya Dwivedi return bpf_diag_irq_depth(env->cur_state); 106999a6a288SKumar Kartikeya Dwivedi case BPF_DIAG_CONTEXT_LOCK: 107099a6a288SKumar Kartikeya Dwivedi return env->cur_state->active_locks; 107199a6a288SKumar Kartikeya Dwivedi case BPF_DIAG_CONTEXT_NONE: 107299a6a288SKumar Kartikeya Dwivedi default: 107399a6a288SKumar Kartikeya Dwivedi return 0; 107499a6a288SKumar Kartikeya Dwivedi } 107599a6a288SKumar Kartikeya Dwivedi } 107699a6a288SKumar Kartikeya Dwivedi 107799a6a288SKumar Kartikeya Dwivedi void bpf_diag_ctx_forbidden(struct bpf_verifier_env *env, u32 insn_idx, 107899a6a288SKumar Kartikeya Dwivedi const char *operation, const char *suggestion) 107999a6a288SKumar Kartikeya Dwivedi { 108099a6a288SKumar Kartikeya Dwivedi struct bpf_diag_history_opts opts; 108199a6a288SKumar Kartikeya Dwivedi enum bpf_diag_context_kind ctx_kind; 108299a6a288SKumar Kartikeya Dwivedi const char *constraint, *context; 108399a6a288SKumar Kartikeya Dwivedi u32 depth; 108499a6a288SKumar Kartikeya Dwivedi 108599a6a288SKumar Kartikeya Dwivedi if (env->cur_state->active_rcu_locks) 108699a6a288SKumar Kartikeya Dwivedi ctx_kind = BPF_DIAG_CONTEXT_RCU; 108799a6a288SKumar Kartikeya Dwivedi else if (env->cur_state->active_preempt_locks) 108899a6a288SKumar Kartikeya Dwivedi ctx_kind = BPF_DIAG_CONTEXT_PREEMPT; 108999a6a288SKumar Kartikeya Dwivedi else if (env->cur_state->active_irq_id) 109099a6a288SKumar Kartikeya Dwivedi ctx_kind = BPF_DIAG_CONTEXT_IRQ; 109199a6a288SKumar Kartikeya Dwivedi else if (env->cur_state->active_locks) 109299a6a288SKumar Kartikeya Dwivedi ctx_kind = BPF_DIAG_CONTEXT_LOCK; 109399a6a288SKumar Kartikeya Dwivedi else 109499a6a288SKumar Kartikeya Dwivedi ctx_kind = BPF_DIAG_CONTEXT_NONE; 109599a6a288SKumar Kartikeya Dwivedi 109699a6a288SKumar Kartikeya Dwivedi depth = diag_context_depth(env, ctx_kind); 109799a6a288SKumar Kartikeya Dwivedi opts = (struct bpf_diag_history_opts) { 109899a6a288SKumar Kartikeya Dwivedi .scope = BPF_DIAG_HISTORY_SCOPE_CONTEXT, 109999a6a288SKumar Kartikeya Dwivedi .ctx_kind = ctx_kind, 110099a6a288SKumar Kartikeya Dwivedi .ctx_depth = depth, 110199a6a288SKumar Kartikeya Dwivedi }; 110299a6a288SKumar Kartikeya Dwivedi constraint = diag_context_constraint(ctx_kind); 110399a6a288SKumar Kartikeya Dwivedi context = diag_context_name(ctx_kind); 110499a6a288SKumar Kartikeya Dwivedi 110599a6a288SKumar Kartikeya Dwivedi bpf_diag_header(env, EXECUTION_CONTEXT_SAFETY, 110699a6a288SKumar Kartikeya Dwivedi "operation is not allowed in this context"); 110799a6a288SKumar Kartikeya Dwivedi if (constraint) { 110899a6a288SKumar Kartikeya Dwivedi if (depth) { 110999a6a288SKumar Kartikeya Dwivedi diag_reason( 111099a6a288SKumar Kartikeya Dwivedi env, "The operation %s cannot be used in %s because %s. This path is still inside %s.", 111199a6a288SKumar Kartikeya Dwivedi operation, context, constraint, diag_active_context(env, depth, context)); 111299a6a288SKumar Kartikeya Dwivedi } else { 111399a6a288SKumar Kartikeya Dwivedi diag_reason(env, "The operation %s cannot be used in %s because %s.", 111499a6a288SKumar Kartikeya Dwivedi operation, context, constraint); 111599a6a288SKumar Kartikeya Dwivedi } 111699a6a288SKumar Kartikeya Dwivedi } else { 111799a6a288SKumar Kartikeya Dwivedi diag_reason(env, "The operation %s cannot be used in %s.", operation, 111899a6a288SKumar Kartikeya Dwivedi context); 111999a6a288SKumar Kartikeya Dwivedi } 112099a6a288SKumar Kartikeya Dwivedi 112199a6a288SKumar Kartikeya Dwivedi diag_section(env, "At"); 112299a6a288SKumar Kartikeya Dwivedi bpf_diag_source(env, insn_idx, "error", "%s is not allowed in %s", operation, 112399a6a288SKumar Kartikeya Dwivedi context); 112499a6a288SKumar Kartikeya Dwivedi 112599a6a288SKumar Kartikeya Dwivedi if (ctx_kind != BPF_DIAG_CONTEXT_NONE) 112699a6a288SKumar Kartikeya Dwivedi diag_print_history(env, &opts); 112799a6a288SKumar Kartikeya Dwivedi 112899a6a288SKumar Kartikeya Dwivedi diag_suggestion(env, "%s", suggestion); 112999a6a288SKumar Kartikeya Dwivedi } 113099a6a288SKumar Kartikeya Dwivedi 113199a6a288SKumar Kartikeya Dwivedi void bpf_diag_ctx_active(struct bpf_verifier_env *env, u32 insn_idx, const char *operation, 113299a6a288SKumar Kartikeya Dwivedi enum bpf_diag_context_kind ctx_kind, const char *suggestion) 113399a6a288SKumar Kartikeya Dwivedi { 113499a6a288SKumar Kartikeya Dwivedi u32 depth = diag_context_depth(env, ctx_kind); 113599a6a288SKumar Kartikeya Dwivedi struct bpf_diag_history_opts opts = { 113699a6a288SKumar Kartikeya Dwivedi .scope = BPF_DIAG_HISTORY_SCOPE_CONTEXT, 113799a6a288SKumar Kartikeya Dwivedi .ctx_kind = ctx_kind, 113899a6a288SKumar Kartikeya Dwivedi .ctx_depth = depth, 113999a6a288SKumar Kartikeya Dwivedi }; 114099a6a288SKumar Kartikeya Dwivedi const char *context = diag_context_name(ctx_kind); 114199a6a288SKumar Kartikeya Dwivedi 114299a6a288SKumar Kartikeya Dwivedi bpf_diag_header(env, EXECUTION_CONTEXT_SAFETY, 114399a6a288SKumar Kartikeya Dwivedi "operation is not allowed in this context"); 114499a6a288SKumar Kartikeya Dwivedi diag_reason( 114599a6a288SKumar Kartikeya Dwivedi env, "The operation %s cannot be used while this path is still inside %s. Leave the region before this operation.", 114699a6a288SKumar Kartikeya Dwivedi operation, diag_active_context(env, depth, context)); 114799a6a288SKumar Kartikeya Dwivedi 114899a6a288SKumar Kartikeya Dwivedi diag_section(env, "At"); 114999a6a288SKumar Kartikeya Dwivedi bpf_diag_source(env, insn_idx, "error", "%s is not allowed before leaving %s", 115099a6a288SKumar Kartikeya Dwivedi operation, context); 115199a6a288SKumar Kartikeya Dwivedi 115299a6a288SKumar Kartikeya Dwivedi diag_print_history(env, &opts); 115399a6a288SKumar Kartikeya Dwivedi 115499a6a288SKumar Kartikeya Dwivedi diag_suggestion(env, "%s", suggestion); 115599a6a288SKumar Kartikeya Dwivedi } 115699a6a288SKumar Kartikeya Dwivedi 115799a6a288SKumar Kartikeya Dwivedi void bpf_diag_ctx_required(struct bpf_verifier_env *env, u32 insn_idx, const char *operation, 115899a6a288SKumar Kartikeya Dwivedi enum bpf_diag_context_kind ctx_kind, const char *suggestion) 115999a6a288SKumar Kartikeya Dwivedi { 116099a6a288SKumar Kartikeya Dwivedi const char *context = diag_context_name(ctx_kind); 116199a6a288SKumar Kartikeya Dwivedi 116299a6a288SKumar Kartikeya Dwivedi bpf_diag_header(env, EXECUTION_CONTEXT_SAFETY, "required context is not active"); 116399a6a288SKumar Kartikeya Dwivedi diag_reason(env, "The operation %s requires an active %s, but this path is outside one.", 116499a6a288SKumar Kartikeya Dwivedi operation, context); 116599a6a288SKumar Kartikeya Dwivedi 116699a6a288SKumar Kartikeya Dwivedi diag_section(env, "At"); 116799a6a288SKumar Kartikeya Dwivedi bpf_diag_source(env, insn_idx, "error", "%s requires %s", operation, context); 116899a6a288SKumar Kartikeya Dwivedi 116999a6a288SKumar Kartikeya Dwivedi diag_suggestion(env, "%s", suggestion); 117099a6a288SKumar Kartikeya Dwivedi } 117199a6a288SKumar Kartikeya Dwivedi 117299a6a288SKumar Kartikeya Dwivedi void bpf_diag_ctx_underflow(struct bpf_verifier_env *env, u32 insn_idx, 117399a6a288SKumar Kartikeya Dwivedi const char *operation, enum bpf_diag_context_kind ctx_kind, 117499a6a288SKumar Kartikeya Dwivedi const char *suggestion) 117599a6a288SKumar Kartikeya Dwivedi { 117699a6a288SKumar Kartikeya Dwivedi struct bpf_diag_history_opts opts = { 117799a6a288SKumar Kartikeya Dwivedi .scope = BPF_DIAG_HISTORY_SCOPE_CONTEXT, 117899a6a288SKumar Kartikeya Dwivedi .ctx_kind = ctx_kind, 117999a6a288SKumar Kartikeya Dwivedi }; 118099a6a288SKumar Kartikeya Dwivedi const char *context = diag_context_name(ctx_kind); 118199a6a288SKumar Kartikeya Dwivedi 118299a6a288SKumar Kartikeya Dwivedi bpf_diag_header(env, EXECUTION_CONTEXT_SAFETY, "unmatched context exit"); 118399a6a288SKumar Kartikeya Dwivedi diag_reason( 118499a6a288SKumar Kartikeya Dwivedi env, "The operation %s tries to leave %s, but this path has no active %s to leave. The current depth is 0.", 118599a6a288SKumar Kartikeya Dwivedi operation, context, context); 118699a6a288SKumar Kartikeya Dwivedi 118799a6a288SKumar Kartikeya Dwivedi diag_section(env, "At"); 118899a6a288SKumar Kartikeya Dwivedi bpf_diag_source(env, insn_idx, "error", "%s has no matching enter on this path", 118999a6a288SKumar Kartikeya Dwivedi operation); 119099a6a288SKumar Kartikeya Dwivedi 119199a6a288SKumar Kartikeya Dwivedi diag_print_history(env, &opts); 119299a6a288SKumar Kartikeya Dwivedi 119399a6a288SKumar Kartikeya Dwivedi diag_suggestion(env, "%s", suggestion); 119499a6a288SKumar Kartikeya Dwivedi } 119599a6a288SKumar Kartikeya Dwivedi 1196*a8f42783SKumar Kartikeya Dwivedi void bpf_diag_program_structure(struct bpf_verifier_env *env, u32 insn_idx, 1197*a8f42783SKumar Kartikeya Dwivedi const char *problem, const char *suggestion, 1198*a8f42783SKumar Kartikeya Dwivedi const char *reason_fmt, ...) 1199*a8f42783SKumar Kartikeya Dwivedi { 1200*a8f42783SKumar Kartikeya Dwivedi va_list args; 1201*a8f42783SKumar Kartikeya Dwivedi 1202*a8f42783SKumar Kartikeya Dwivedi bpf_diag_header(env, PROGRAM_STRUCTURE, problem); 1203*a8f42783SKumar Kartikeya Dwivedi diag_section(env, "Reason"); 1204*a8f42783SKumar Kartikeya Dwivedi 1205*a8f42783SKumar Kartikeya Dwivedi va_start(args, reason_fmt); 1206*a8f42783SKumar Kartikeya Dwivedi diag_vprint_indented(env, reason_fmt, args); 1207*a8f42783SKumar Kartikeya Dwivedi va_end(args); 1208*a8f42783SKumar Kartikeya Dwivedi 1209*a8f42783SKumar Kartikeya Dwivedi diag_section(env, "At"); 1210*a8f42783SKumar Kartikeya Dwivedi bpf_diag_source(env, insn_idx, "error", "%s", problem); 1211*a8f42783SKumar Kartikeya Dwivedi 1212*a8f42783SKumar Kartikeya Dwivedi diag_suggestion(env, "%s", suggestion); 1213*a8f42783SKumar Kartikeya Dwivedi } 1214d63284e6SKumar Kartikeya Dwivedi void bpf_diag_invalid_deref(struct bpf_verifier_env *env, u32 insn_idx, int regno, 1215d63284e6SKumar Kartikeya Dwivedi const char *reg_name, const struct bpf_reg_state *reg, 1216d63284e6SKumar Kartikeya Dwivedi enum bpf_diag_invalid_deref_kind kind, s64 offset) 1217d63284e6SKumar Kartikeya Dwivedi { 1218d63284e6SKumar Kartikeya Dwivedi const struct bpf_func_state *frame = diag_current_frame(env); 1219d63284e6SKumar Kartikeya Dwivedi struct bpf_diag_history_opts opts = { 1220d63284e6SKumar Kartikeya Dwivedi .scope = BPF_DIAG_HISTORY_SCOPE_REG, 1221d63284e6SKumar Kartikeya Dwivedi .frame_id = frame->diag_frame_id, 1222d63284e6SKumar Kartikeya Dwivedi .frameno = frame->frameno, 1223d63284e6SKumar Kartikeya Dwivedi .regno = regno, 1224d63284e6SKumar Kartikeya Dwivedi }; 1225d63284e6SKumar Kartikeya Dwivedi const char *type_name = bpf_diag_reg_type_plain(env, reg->type); 1226d63284e6SKumar Kartikeya Dwivedi 1227d63284e6SKumar Kartikeya Dwivedi bpf_diag_header(env, REGISTER_TYPE_SAFETY, "invalid dereference"); 1228d63284e6SKumar Kartikeya Dwivedi 1229d63284e6SKumar Kartikeya Dwivedi switch (kind) { 1230d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_DEREF_SCALAR: 1231d63284e6SKumar Kartikeya Dwivedi diag_reason(env, "%s is an integer scalar here, not a pointer to memory.", 1232d63284e6SKumar Kartikeya Dwivedi reg_name); 1233d63284e6SKumar Kartikeya Dwivedi break; 1234d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_DEREF_NULLABLE_PTR: 1235d63284e6SKumar Kartikeya Dwivedi diag_reason( 1236d63284e6SKumar Kartikeya Dwivedi env, "%s may be NULL here (%s). The program could dereference NULL on this path, so the verifier cannot prove this access is safe.", 1237d63284e6SKumar Kartikeya Dwivedi reg_name, type_name); 1238d63284e6SKumar Kartikeya Dwivedi break; 1239d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_DEREF_MODIFIED_PTR: 1240d63284e6SKumar Kartikeya Dwivedi diag_reason( 1241d63284e6SKumar Kartikeya Dwivedi env, "%s has offset %lld here, but this pointer type must be dereferenced in its original form.", 1242d63284e6SKumar Kartikeya Dwivedi reg_name, offset); 1243d63284e6SKumar Kartikeya Dwivedi break; 1244d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_DEREF_INVALID_PTR: 1245d63284e6SKumar Kartikeya Dwivedi default: 1246d63284e6SKumar Kartikeya Dwivedi diag_reason( 1247d63284e6SKumar Kartikeya Dwivedi env, "%s has type %s here, which is not valid for this memory access.", 1248d63284e6SKumar Kartikeya Dwivedi reg_name, type_name); 1249d63284e6SKumar Kartikeya Dwivedi break; 1250d63284e6SKumar Kartikeya Dwivedi } 1251d63284e6SKumar Kartikeya Dwivedi 1252d63284e6SKumar Kartikeya Dwivedi diag_section(env, "At"); 1253d63284e6SKumar Kartikeya Dwivedi if (kind == BPF_DIAG_DEREF_MODIFIED_PTR) 1254d63284e6SKumar Kartikeya Dwivedi bpf_diag_source(env, insn_idx, "error", 1255d63284e6SKumar Kartikeya Dwivedi "dereference requires the original %s pointer", type_name); 1256d63284e6SKumar Kartikeya Dwivedi else 1257d63284e6SKumar Kartikeya Dwivedi bpf_diag_source(env, insn_idx, "error", "invalid dereference of %s (%s)", 1258d63284e6SKumar Kartikeya Dwivedi reg_name, type_name); 1259d63284e6SKumar Kartikeya Dwivedi 1260d63284e6SKumar Kartikeya Dwivedi if (regno >= 0) 1261d63284e6SKumar Kartikeya Dwivedi diag_print_history(env, &opts); 1262d63284e6SKumar Kartikeya Dwivedi 1263d63284e6SKumar Kartikeya Dwivedi switch (kind) { 1264d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_DEREF_NULLABLE_PTR: 1265d63284e6SKumar Kartikeya Dwivedi diag_suggestion( 1266d63284e6SKumar Kartikeya Dwivedi env, "Add a NULL check before the access and dereference the pointer only on the non-NULL path."); 1267d63284e6SKumar Kartikeya Dwivedi break; 1268d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_DEREF_MODIFIED_PTR: 1269d63284e6SKumar Kartikeya Dwivedi diag_suggestion( 1270d63284e6SKumar Kartikeya Dwivedi env, "Preserve the original pointer in another register, or use only offsets this pointer type permits before dereferencing it."); 1271d63284e6SKumar Kartikeya Dwivedi break; 1272d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_DEREF_SCALAR: 1273d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_DEREF_INVALID_PTR: 1274d63284e6SKumar Kartikeya Dwivedi default: 1275d63284e6SKumar Kartikeya Dwivedi diag_suggestion( 1276d63284e6SKumar Kartikeya Dwivedi env, "Preserve a pointer-valued register where needed, or reload and revalidate the pointer after scalar arithmetic, helper calls, or other operations that can invalidate it."); 1277d63284e6SKumar Kartikeya Dwivedi break; 1278d63284e6SKumar Kartikeya Dwivedi } 1279d63284e6SKumar Kartikeya Dwivedi } 1280d63284e6SKumar Kartikeya Dwivedi 1281d63284e6SKumar Kartikeya Dwivedi void bpf_diag_unreadable_reg(struct bpf_verifier_env *env, u32 insn_idx, int regno) 1282d63284e6SKumar Kartikeya Dwivedi { 1283d63284e6SKumar Kartikeya Dwivedi const struct bpf_func_state *frame = diag_current_frame(env); 1284d63284e6SKumar Kartikeya Dwivedi struct bpf_diag_history_opts opts = { 1285d63284e6SKumar Kartikeya Dwivedi .scope = BPF_DIAG_HISTORY_SCOPE_REG, 1286d63284e6SKumar Kartikeya Dwivedi .frame_id = frame->diag_frame_id, 1287d63284e6SKumar Kartikeya Dwivedi .frameno = frame->frameno, 1288d63284e6SKumar Kartikeya Dwivedi .regno = regno, 1289d63284e6SKumar Kartikeya Dwivedi }; 1290d63284e6SKumar Kartikeya Dwivedi const struct bpf_diag_log *log = env->diag ? &env->diag->log : NULL; 1291d63284e6SKumar Kartikeya Dwivedi struct bpf_diag_mod_target target; 1292d63284e6SKumar Kartikeya Dwivedi bool invalidated = false; 1293d63284e6SKumar Kartikeya Dwivedi int i; 1294d63284e6SKumar Kartikeya Dwivedi 1295d63284e6SKumar Kartikeya Dwivedi target = diag_reg_target(opts.frame_id, opts.frameno, regno); 1296d63284e6SKumar Kartikeya Dwivedi for (i = log ? log->cnt : 0; i > 0; i--) { 1297d63284e6SKumar Kartikeya Dwivedi const struct bpf_diag_history_event *event; 1298d63284e6SKumar Kartikeya Dwivedi 1299d63284e6SKumar Kartikeya Dwivedi event = &log->events[log_pos(log, i - 1)]; 1300d63284e6SKumar Kartikeya Dwivedi 1301d63284e6SKumar Kartikeya Dwivedi if (event->kind != BPF_DIAG_HISTORY_MOD || 1302d63284e6SKumar Kartikeya Dwivedi !diag_target_matches(&event->mod.target, &target)) 1303d63284e6SKumar Kartikeya Dwivedi continue; 1304d63284e6SKumar Kartikeya Dwivedi invalidated = event->mod.new.type == NOT_INIT; 1305d63284e6SKumar Kartikeya Dwivedi break; 1306d63284e6SKumar Kartikeya Dwivedi } 1307d63284e6SKumar Kartikeya Dwivedi 1308d63284e6SKumar Kartikeya Dwivedi bpf_diag_header(env, REGISTER_TYPE_SAFETY, "unreadable register"); 1309d63284e6SKumar Kartikeya Dwivedi if (invalidated) 1310d63284e6SKumar Kartikeya Dwivedi diag_reason( 1311d63284e6SKumar Kartikeya Dwivedi env, "R%d is not readable here. A previous operation invalidated this register, so the verifier cannot use it as an input.", 1312d63284e6SKumar Kartikeya Dwivedi regno); 1313d63284e6SKumar Kartikeya Dwivedi else if (log && !log->first_seq) 1314d63284e6SKumar Kartikeya Dwivedi diag_reason(env, 1315d63284e6SKumar Kartikeya Dwivedi "R%d has never been initialized on this path, so the verifier cannot use it as an input.", 1316d63284e6SKumar Kartikeya Dwivedi regno); 1317d63284e6SKumar Kartikeya Dwivedi else 1318d63284e6SKumar Kartikeya Dwivedi diag_reason( 1319d63284e6SKumar Kartikeya Dwivedi env, "R%d is not readable here. It may never have been initialized, or an earlier operation may have invalidated it.", 1320d63284e6SKumar Kartikeya Dwivedi regno); 1321d63284e6SKumar Kartikeya Dwivedi 1322d63284e6SKumar Kartikeya Dwivedi diag_section(env, "At"); 1323d63284e6SKumar Kartikeya Dwivedi bpf_diag_source(env, insn_idx, "error", "R%d is not readable", regno); 1324d63284e6SKumar Kartikeya Dwivedi 1325d63284e6SKumar Kartikeya Dwivedi if (regno >= 0) 1326d63284e6SKumar Kartikeya Dwivedi diag_print_history(env, &opts); 1327d63284e6SKumar Kartikeya Dwivedi 1328d63284e6SKumar Kartikeya Dwivedi if (invalidated) 1329d63284e6SKumar Kartikeya Dwivedi diag_suggestion( 1330d63284e6SKumar Kartikeya Dwivedi env, "Avoid using the register after it is invalidated, or initialize it again before this instruction."); 1331d63284e6SKumar Kartikeya Dwivedi else if (log && !log->first_seq) 1332d63284e6SKumar Kartikeya Dwivedi diag_suggestion(env, "Initialize R%d on every path before this instruction.", regno); 1333d63284e6SKumar Kartikeya Dwivedi else 1334d63284e6SKumar Kartikeya Dwivedi diag_suggestion( 1335d63284e6SKumar Kartikeya Dwivedi env, "Initialize the register on every path, or initialize it again after any operation that invalidates it."); 1336d63284e6SKumar Kartikeya Dwivedi } 1337d63284e6SKumar Kartikeya Dwivedi 1338d63284e6SKumar Kartikeya Dwivedi static int diag_stack_argno(u8 slot) 1339d63284e6SKumar Kartikeya Dwivedi { 1340d63284e6SKumar Kartikeya Dwivedi return MAX_BPF_FUNC_REG_ARGS + slot + 1; 1341d63284e6SKumar Kartikeya Dwivedi } 1342d63284e6SKumar Kartikeya Dwivedi 1343d63284e6SKumar Kartikeya Dwivedi static void diag_format_stack_arg(char *buf, size_t size, u8 slot, const char *arg_name) 1344d63284e6SKumar Kartikeya Dwivedi { 1345d63284e6SKumar Kartikeya Dwivedi int argno = diag_stack_argno(slot); 1346d63284e6SKumar Kartikeya Dwivedi const char *ordinal = diag_arg_ordinal(argno); 1347d63284e6SKumar Kartikeya Dwivedi 1348d63284e6SKumar Kartikeya Dwivedi if (ordinal && arg_name) 1349d63284e6SKumar Kartikeya Dwivedi scnprintf(buf, size, "outgoing stack argument %u (%s argument, %s)", slot + 1, 1350d63284e6SKumar Kartikeya Dwivedi ordinal, arg_name); 1351d63284e6SKumar Kartikeya Dwivedi else if (ordinal) 1352d63284e6SKumar Kartikeya Dwivedi scnprintf(buf, size, "outgoing stack argument %u (%s argument)", slot + 1, ordinal); 1353d63284e6SKumar Kartikeya Dwivedi else if (arg_name) 1354d63284e6SKumar Kartikeya Dwivedi scnprintf(buf, size, "outgoing stack argument %u (%s)", slot + 1, arg_name); 1355d63284e6SKumar Kartikeya Dwivedi else 1356d63284e6SKumar Kartikeya Dwivedi scnprintf(buf, size, "outgoing stack argument %u", slot + 1); 1357d63284e6SKumar Kartikeya Dwivedi } 1358d63284e6SKumar Kartikeya Dwivedi 1359d63284e6SKumar Kartikeya Dwivedi void bpf_diag_stack_arg_uninit(struct bpf_verifier_env *env, u32 insn_idx, int nargs, 1360d63284e6SKumar Kartikeya Dwivedi int stack_arg_slot, const char *callee_name, 1361d63284e6SKumar Kartikeya Dwivedi const char *arg_name) 1362d63284e6SKumar Kartikeya Dwivedi { 1363d63284e6SKumar Kartikeya Dwivedi const struct bpf_func_state *frame = diag_current_frame(env); 1364d63284e6SKumar Kartikeya Dwivedi struct bpf_diag_history_opts opts = { 1365d63284e6SKumar Kartikeya Dwivedi .scope = BPF_DIAG_HISTORY_SCOPE_STACK_ARG, 1366d63284e6SKumar Kartikeya Dwivedi .frame_id = frame->diag_frame_id, 1367d63284e6SKumar Kartikeya Dwivedi .frameno = frame->frameno, 1368d63284e6SKumar Kartikeya Dwivedi .stack_arg_slot = stack_arg_slot, 1369d63284e6SKumar Kartikeya Dwivedi }; 1370d63284e6SKumar Kartikeya Dwivedi const char *arg_buf; 1371d63284e6SKumar Kartikeya Dwivedi 1372d63284e6SKumar Kartikeya Dwivedi arg_buf = bpf_diag_fmt_buf(env, BPF_DIAG_FMT_BUF_SIZE); 1373d63284e6SKumar Kartikeya Dwivedi if (arg_buf) 1374d63284e6SKumar Kartikeya Dwivedi diag_format_stack_arg((char *)arg_buf, BPF_DIAG_FMT_BUF_SIZE, stack_arg_slot, 1375d63284e6SKumar Kartikeya Dwivedi arg_name); 1376d63284e6SKumar Kartikeya Dwivedi else 1377d63284e6SKumar Kartikeya Dwivedi arg_buf = ""; 1378d63284e6SKumar Kartikeya Dwivedi bpf_diag_header(env, REGISTER_TYPE_SAFETY, "missing stack argument"); 1379d63284e6SKumar Kartikeya Dwivedi if (callee_name && *callee_name) 1380d63284e6SKumar Kartikeya Dwivedi diag_reason( 1381d63284e6SKumar Kartikeya Dwivedi env, "Function %s expects %d arguments, but %s is not initialized at this call.", 1382d63284e6SKumar Kartikeya Dwivedi callee_name, nargs, arg_buf); 1383d63284e6SKumar Kartikeya Dwivedi else 1384d63284e6SKumar Kartikeya Dwivedi diag_reason( 1385d63284e6SKumar Kartikeya Dwivedi env, "The callee expects %d arguments, but %s is not initialized at this call.", 1386d63284e6SKumar Kartikeya Dwivedi nargs, arg_buf); 1387d63284e6SKumar Kartikeya Dwivedi 1388d63284e6SKumar Kartikeya Dwivedi diag_section(env, "At"); 1389d63284e6SKumar Kartikeya Dwivedi bpf_diag_source(env, insn_idx, "error", "%s is not initialized", arg_buf); 1390d63284e6SKumar Kartikeya Dwivedi 1391d63284e6SKumar Kartikeya Dwivedi if (stack_arg_slot >= 0) 1392d63284e6SKumar Kartikeya Dwivedi diag_print_history(env, &opts); 1393d63284e6SKumar Kartikeya Dwivedi 1394d63284e6SKumar Kartikeya Dwivedi diag_suggestion( 1395d63284e6SKumar Kartikeya Dwivedi env, "Write the outgoing stack argument after any operation that may invalidate stored pointer values, and before making this call."); 1396d63284e6SKumar Kartikeya Dwivedi } 1397d63284e6SKumar Kartikeya Dwivedi 13982bdc90f5SKumar Kartikeya Dwivedi void bpf_diag_memory(struct bpf_verifier_env *env, u32 insn_idx, const char *problem, 13992bdc90f5SKumar Kartikeya Dwivedi const char *reason, const char *suggestion) 14002bdc90f5SKumar Kartikeya Dwivedi { 14012bdc90f5SKumar Kartikeya Dwivedi bpf_diag_header(env, MEMORY_SAFETY, problem); 14022bdc90f5SKumar Kartikeya Dwivedi diag_reason(env, "%s", reason); 14032bdc90f5SKumar Kartikeya Dwivedi 14042bdc90f5SKumar Kartikeya Dwivedi diag_section(env, "At"); 14052bdc90f5SKumar Kartikeya Dwivedi bpf_diag_source(env, insn_idx, "error", "%s", problem); 14062bdc90f5SKumar Kartikeya Dwivedi 14072bdc90f5SKumar Kartikeya Dwivedi diag_suggestion(env, "%s", suggestion); 14082bdc90f5SKumar Kartikeya Dwivedi } 14092bdc90f5SKumar Kartikeya Dwivedi 1410daf82487SKumar Kartikeya Dwivedi void bpf_diag_record_branch(struct bpf_verifier_env *env, u32 insn_idx, bool cond_true) 1411daf82487SKumar Kartikeya Dwivedi { 1412daf82487SKumar Kartikeya Dwivedi struct bpf_diag_history_event event = { 1413daf82487SKumar Kartikeya Dwivedi .insn_idx = insn_idx, 1414daf82487SKumar Kartikeya Dwivedi .kind = BPF_DIAG_HISTORY_BRANCH, 1415daf82487SKumar Kartikeya Dwivedi .branch = { 1416daf82487SKumar Kartikeya Dwivedi .cond_true = cond_true, 1417daf82487SKumar Kartikeya Dwivedi }, 1418daf82487SKumar Kartikeya Dwivedi }; 1419daf82487SKumar Kartikeya Dwivedi 1420daf82487SKumar Kartikeya Dwivedi diag_append_history(env, &event); 1421daf82487SKumar Kartikeya Dwivedi } 1422af4ea6e2SKumar Kartikeya Dwivedi 1423af4ea6e2SKumar Kartikeya Dwivedi static void diag_snapshot_reg(struct bpf_diag_reg_snapshot *snapshot, 1424af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_reg_state *reg) 1425af4ea6e2SKumar Kartikeya Dwivedi { 1426af4ea6e2SKumar Kartikeya Dwivedi snapshot->type = reg->type; 1427af4ea6e2SKumar Kartikeya Dwivedi if (type_is_map_ptr(reg->type)) 1428af4ea6e2SKumar Kartikeya Dwivedi snapshot->map_ptr = reg->map_ptr; 1429af4ea6e2SKumar Kartikeya Dwivedi if (base_type(reg->type) == PTR_TO_BTF_ID && reg->btf && reg->btf_id) { 1430af4ea6e2SKumar Kartikeya Dwivedi snapshot->btf_id = reg->btf_id; 1431af4ea6e2SKumar Kartikeya Dwivedi snapshot->btf = reg->btf; 1432af4ea6e2SKumar Kartikeya Dwivedi } 1433af4ea6e2SKumar Kartikeya Dwivedi snapshot->var_off = reg->var_off; 1434af4ea6e2SKumar Kartikeya Dwivedi snapshot->r64 = reg->r64; 1435af4ea6e2SKumar Kartikeya Dwivedi } 1436af4ea6e2SKumar Kartikeya Dwivedi 1437af4ea6e2SKumar Kartikeya Dwivedi static bool diag_mod_insn_origin(struct bpf_verifier_env *env, u32 insn_idx, 1438af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_diag_mod_target *target, 1439af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_target *origin) 1440af4ea6e2SKumar Kartikeya Dwivedi { 1441af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_insn *insn = &env->prog->insnsi[insn_idx]; 1442af4ea6e2SKumar Kartikeya Dwivedi u8 class = BPF_CLASS(insn->code); 1443af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_func_state *state; 1444af4ea6e2SKumar Kartikeya Dwivedi 1445af4ea6e2SKumar Kartikeya Dwivedi if (target->kind == BPF_DIAG_MOD_TARGET_REG && (class == BPF_ALU || class == BPF_ALU64) && 1446af4ea6e2SKumar Kartikeya Dwivedi BPF_OP(insn->code) == BPF_MOV && BPF_SRC(insn->code) == BPF_X) { 1447af4ea6e2SKumar Kartikeya Dwivedi *origin = diag_reg_target(target->frame_id, target->frameno, insn->src_reg); 1448af4ea6e2SKumar Kartikeya Dwivedi return true; 1449af4ea6e2SKumar Kartikeya Dwivedi } 1450af4ea6e2SKumar Kartikeya Dwivedi 1451af4ea6e2SKumar Kartikeya Dwivedi if ((target->kind != BPF_DIAG_MOD_TARGET_STACK_ARG && 1452af4ea6e2SKumar Kartikeya Dwivedi target->kind != BPF_DIAG_MOD_TARGET_STACK_SLOT) || 1453af4ea6e2SKumar Kartikeya Dwivedi class != BPF_STX) 1454af4ea6e2SKumar Kartikeya Dwivedi return false; 1455af4ea6e2SKumar Kartikeya Dwivedi 1456af4ea6e2SKumar Kartikeya Dwivedi state = env->cur_state->frame[env->cur_state->curframe]; 1457af4ea6e2SKumar Kartikeya Dwivedi *origin = diag_reg_target(state->diag_frame_id, state->frameno, insn->src_reg); 1458af4ea6e2SKumar Kartikeya Dwivedi return true; 1459af4ea6e2SKumar Kartikeya Dwivedi } 1460af4ea6e2SKumar Kartikeya Dwivedi 1461af4ea6e2SKumar Kartikeya Dwivedi static bool diag_mod_keeps_lineage(struct bpf_verifier_env *env, 1462af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_diag_history_event *event) 1463af4ea6e2SKumar Kartikeya Dwivedi { 1464af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_insn *insn; 1465af4ea6e2SKumar Kartikeya Dwivedi u8 class; 1466af4ea6e2SKumar Kartikeya Dwivedi 1467af4ea6e2SKumar Kartikeya Dwivedi if (event->mod.reason != BPF_DIAG_MOD_WRITE || 1468af4ea6e2SKumar Kartikeya Dwivedi event->mod.target.kind != BPF_DIAG_MOD_TARGET_REG) 1469af4ea6e2SKumar Kartikeya Dwivedi return false; 1470af4ea6e2SKumar Kartikeya Dwivedi 1471af4ea6e2SKumar Kartikeya Dwivedi insn = &env->prog->insnsi[event->insn_idx]; 1472af4ea6e2SKumar Kartikeya Dwivedi class = BPF_CLASS(insn->code); 1473af4ea6e2SKumar Kartikeya Dwivedi if (class != BPF_ALU && class != BPF_ALU64) 1474af4ea6e2SKumar Kartikeya Dwivedi return false; 1475af4ea6e2SKumar Kartikeya Dwivedi 1476af4ea6e2SKumar Kartikeya Dwivedi switch (BPF_OP(insn->code)) { 1477af4ea6e2SKumar Kartikeya Dwivedi case BPF_ADD: 1478af4ea6e2SKumar Kartikeya Dwivedi case BPF_SUB: 1479af4ea6e2SKumar Kartikeya Dwivedi case BPF_MUL: 1480af4ea6e2SKumar Kartikeya Dwivedi case BPF_OR: 1481af4ea6e2SKumar Kartikeya Dwivedi case BPF_AND: 1482af4ea6e2SKumar Kartikeya Dwivedi case BPF_LSH: 1483af4ea6e2SKumar Kartikeya Dwivedi case BPF_RSH: 1484af4ea6e2SKumar Kartikeya Dwivedi case BPF_ARSH: 1485af4ea6e2SKumar Kartikeya Dwivedi case BPF_XOR: 1486af4ea6e2SKumar Kartikeya Dwivedi case BPF_NEG: 1487af4ea6e2SKumar Kartikeya Dwivedi case BPF_END: 1488af4ea6e2SKumar Kartikeya Dwivedi return true; 1489af4ea6e2SKumar Kartikeya Dwivedi default: 1490af4ea6e2SKumar Kartikeya Dwivedi return false; 1491af4ea6e2SKumar Kartikeya Dwivedi } 1492af4ea6e2SKumar Kartikeya Dwivedi } 1493af4ea6e2SKumar Kartikeya Dwivedi 1494af4ea6e2SKumar Kartikeya Dwivedi static void diag_record_mod(struct bpf_verifier_env *env, u32 insn_idx, 1495af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_target target, 1496af4ea6e2SKumar Kartikeya Dwivedi enum bpf_diag_mod_reason reason, 1497af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_reg_state *old_reg, 1498af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_reg_state *new_reg, 1499af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_diag_mod_target *origin) 1500af4ea6e2SKumar Kartikeya Dwivedi { 1501af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_history_event event = { 1502af4ea6e2SKumar Kartikeya Dwivedi .insn_idx = insn_idx, 1503af4ea6e2SKumar Kartikeya Dwivedi .kind = BPF_DIAG_HISTORY_MOD, 1504af4ea6e2SKumar Kartikeya Dwivedi .mod = { 1505af4ea6e2SKumar Kartikeya Dwivedi .target = target, 1506af4ea6e2SKumar Kartikeya Dwivedi .reason = reason, 1507af4ea6e2SKumar Kartikeya Dwivedi }, 1508af4ea6e2SKumar Kartikeya Dwivedi }; 1509af4ea6e2SKumar Kartikeya Dwivedi 1510af4ea6e2SKumar Kartikeya Dwivedi if (old_reg) 1511af4ea6e2SKumar Kartikeya Dwivedi diag_snapshot_reg(&event.mod.old, old_reg); 1512af4ea6e2SKumar Kartikeya Dwivedi if (new_reg) 1513af4ea6e2SKumar Kartikeya Dwivedi diag_snapshot_reg(&event.mod.new, new_reg); 1514af4ea6e2SKumar Kartikeya Dwivedi if (origin) { 1515af4ea6e2SKumar Kartikeya Dwivedi event.mod.origin = *origin; 1516af4ea6e2SKumar Kartikeya Dwivedi event.mod.origin_valid = true; 1517af4ea6e2SKumar Kartikeya Dwivedi } else if (diag_mod_insn_origin(env, insn_idx, &target, &event.mod.origin)) { 1518af4ea6e2SKumar Kartikeya Dwivedi event.mod.origin_valid = true; 1519af4ea6e2SKumar Kartikeya Dwivedi } 1520af4ea6e2SKumar Kartikeya Dwivedi if (old_reg && new_reg && 1521af4ea6e2SKumar Kartikeya Dwivedi (reason == BPF_DIAG_MOD_WRITE || reason == BPF_DIAG_MOD_SPILL) && 1522af4ea6e2SKumar Kartikeya Dwivedi !memcmp(&event.mod.old, &event.mod.new, sizeof(event.mod.old)) && 1523af4ea6e2SKumar Kartikeya Dwivedi !event.mod.origin_valid && 1524af4ea6e2SKumar Kartikeya Dwivedi diag_mod_keeps_lineage(env, &event)) 1525af4ea6e2SKumar Kartikeya Dwivedi return; 1526af4ea6e2SKumar Kartikeya Dwivedi 1527af4ea6e2SKumar Kartikeya Dwivedi diag_append_history(env, &event); 1528af4ea6e2SKumar Kartikeya Dwivedi } 1529af4ea6e2SKumar Kartikeya Dwivedi 1530af4ea6e2SKumar Kartikeya Dwivedi static struct bpf_reg_state *target_to_reg(struct bpf_verifier_env *env, 1531af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_diag_mod_target *target) 1532af4ea6e2SKumar Kartikeya Dwivedi { 1533af4ea6e2SKumar Kartikeya Dwivedi struct bpf_verifier_state *vstate = env->cur_state; 1534af4ea6e2SKumar Kartikeya Dwivedi struct bpf_func_state *state; 1535af4ea6e2SKumar Kartikeya Dwivedi 1536af4ea6e2SKumar Kartikeya Dwivedi state = target->frameno <= vstate->curframe ? vstate->frame[target->frameno] : NULL; 1537af4ea6e2SKumar Kartikeya Dwivedi 1538af4ea6e2SKumar Kartikeya Dwivedi if (!state) 1539af4ea6e2SKumar Kartikeya Dwivedi return NULL; 1540af4ea6e2SKumar Kartikeya Dwivedi if (state->diag_frame_id != target->frame_id) 1541af4ea6e2SKumar Kartikeya Dwivedi return NULL; 1542af4ea6e2SKumar Kartikeya Dwivedi 1543af4ea6e2SKumar Kartikeya Dwivedi switch (target->kind) { 1544af4ea6e2SKumar Kartikeya Dwivedi case BPF_DIAG_MOD_TARGET_REG: 1545af4ea6e2SKumar Kartikeya Dwivedi if (target->regno >= MAX_BPF_REG) 1546af4ea6e2SKumar Kartikeya Dwivedi return NULL; 1547af4ea6e2SKumar Kartikeya Dwivedi return &state->regs[target->regno]; 1548af4ea6e2SKumar Kartikeya Dwivedi case BPF_DIAG_MOD_TARGET_STACK_ARG: 1549af4ea6e2SKumar Kartikeya Dwivedi if (target->stack_arg >= state->out_stack_arg_cnt) 1550af4ea6e2SKumar Kartikeya Dwivedi return NULL; 1551af4ea6e2SKumar Kartikeya Dwivedi return &state->stack_arg_regs[target->stack_arg]; 1552af4ea6e2SKumar Kartikeya Dwivedi case BPF_DIAG_MOD_TARGET_STACK_SLOT: 1553af4ea6e2SKumar Kartikeya Dwivedi if (target->spi >= state->allocated_stack / BPF_REG_SIZE) 1554af4ea6e2SKumar Kartikeya Dwivedi return NULL; 1555af4ea6e2SKumar Kartikeya Dwivedi return &state->stack[target->spi].spilled_ptr; 1556af4ea6e2SKumar Kartikeya Dwivedi default: 1557af4ea6e2SKumar Kartikeya Dwivedi return NULL; 1558af4ea6e2SKumar Kartikeya Dwivedi } 1559af4ea6e2SKumar Kartikeya Dwivedi } 1560af4ea6e2SKumar Kartikeya Dwivedi 1561af4ea6e2SKumar Kartikeya Dwivedi static bool reg_to_target(struct bpf_verifier_env *env, const struct bpf_reg_state *reg, 1562af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_target *target) 1563af4ea6e2SKumar Kartikeya Dwivedi { 1564af4ea6e2SKumar Kartikeya Dwivedi struct bpf_verifier_state *vstate = env->cur_state; 1565af4ea6e2SKumar Kartikeya Dwivedi unsigned long addr = (unsigned long)reg; 1566af4ea6e2SKumar Kartikeya Dwivedi int frame; 1567af4ea6e2SKumar Kartikeya Dwivedi 1568af4ea6e2SKumar Kartikeya Dwivedi for (frame = 0; frame <= vstate->curframe; frame++) { 1569af4ea6e2SKumar Kartikeya Dwivedi struct bpf_func_state *state = vstate->frame[frame]; 1570af4ea6e2SKumar Kartikeya Dwivedi unsigned long start, end; 1571af4ea6e2SKumar Kartikeya Dwivedi u32 nslots = state->allocated_stack / BPF_REG_SIZE; 1572af4ea6e2SKumar Kartikeya Dwivedi int spi; 1573af4ea6e2SKumar Kartikeya Dwivedi 1574af4ea6e2SKumar Kartikeya Dwivedi start = (unsigned long)state->regs; 1575af4ea6e2SKumar Kartikeya Dwivedi end = (unsigned long)(state->regs + MAX_BPF_REG); 1576af4ea6e2SKumar Kartikeya Dwivedi if (addr >= start && addr < end) { 1577af4ea6e2SKumar Kartikeya Dwivedi *target = diag_reg_target(state->diag_frame_id, state->frameno, 1578af4ea6e2SKumar Kartikeya Dwivedi reg - state->regs); 1579af4ea6e2SKumar Kartikeya Dwivedi return true; 1580af4ea6e2SKumar Kartikeya Dwivedi } 1581af4ea6e2SKumar Kartikeya Dwivedi 1582af4ea6e2SKumar Kartikeya Dwivedi start = (unsigned long)state->stack_arg_regs; 1583af4ea6e2SKumar Kartikeya Dwivedi end = (unsigned long)(state->stack_arg_regs + state->out_stack_arg_cnt); 1584af4ea6e2SKumar Kartikeya Dwivedi if (state->out_stack_arg_cnt && addr >= start && addr < end) { 1585af4ea6e2SKumar Kartikeya Dwivedi *target = diag_stack_arg_target(state->diag_frame_id, state->frameno, 1586af4ea6e2SKumar Kartikeya Dwivedi reg - state->stack_arg_regs); 1587af4ea6e2SKumar Kartikeya Dwivedi return true; 1588af4ea6e2SKumar Kartikeya Dwivedi } 1589af4ea6e2SKumar Kartikeya Dwivedi 1590af4ea6e2SKumar Kartikeya Dwivedi start = (unsigned long)state->stack; 1591af4ea6e2SKumar Kartikeya Dwivedi end = (unsigned long)(state->stack + nslots); 1592af4ea6e2SKumar Kartikeya Dwivedi if (nslots && addr >= start && addr < end) { 1593af4ea6e2SKumar Kartikeya Dwivedi spi = ((const char *)reg - (const char *)state->stack) / 1594af4ea6e2SKumar Kartikeya Dwivedi sizeof(*state->stack); 1595af4ea6e2SKumar Kartikeya Dwivedi *target = diag_stack_slot_target(state->diag_frame_id, state->frameno, spi); 1596af4ea6e2SKumar Kartikeya Dwivedi return true; 1597af4ea6e2SKumar Kartikeya Dwivedi } 1598af4ea6e2SKumar Kartikeya Dwivedi } 1599af4ea6e2SKumar Kartikeya Dwivedi return false; 1600af4ea6e2SKumar Kartikeya Dwivedi } 1601af4ea6e2SKumar Kartikeya Dwivedi 1602af4ea6e2SKumar Kartikeya Dwivedi void bpf_diag_mod_begin(struct bpf_verifier_env *env, const struct bpf_reg_state *reg, 1603af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_reg_state *origin, enum bpf_diag_mod_reason reason) 1604af4ea6e2SKumar Kartikeya Dwivedi { 1605af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag *diag = env->diag; 1606af4ea6e2SKumar Kartikeya Dwivedi 1607af4ea6e2SKumar Kartikeya Dwivedi if (!diag) 1608af4ea6e2SKumar Kartikeya Dwivedi return; 1609af4ea6e2SKumar Kartikeya Dwivedi diag->mod.active = reg_to_target(env, reg, &diag->mod.target); 1610af4ea6e2SKumar Kartikeya Dwivedi if (!diag->mod.active) 1611af4ea6e2SKumar Kartikeya Dwivedi return; 1612af4ea6e2SKumar Kartikeya Dwivedi diag->mod.target_reg_snapshot = *reg; 1613af4ea6e2SKumar Kartikeya Dwivedi diag->mod.insn_idx = env->insn_idx; 1614af4ea6e2SKumar Kartikeya Dwivedi diag->mod.reason = reason; 1615af4ea6e2SKumar Kartikeya Dwivedi diag->mod.origin_valid = origin && reg_to_target(env, origin, &diag->mod.origin); 1616af4ea6e2SKumar Kartikeya Dwivedi } 1617af4ea6e2SKumar Kartikeya Dwivedi 1618af4ea6e2SKumar Kartikeya Dwivedi void bpf_diag_mod_end(struct bpf_verifier_env *env) 1619af4ea6e2SKumar Kartikeya Dwivedi { 1620af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag *diag = env->diag; 1621af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_reg_state *new_reg; 1622af4ea6e2SKumar Kartikeya Dwivedi 1623af4ea6e2SKumar Kartikeya Dwivedi if (!diag || !diag->mod.active) 1624af4ea6e2SKumar Kartikeya Dwivedi return; 1625af4ea6e2SKumar Kartikeya Dwivedi diag->mod.active = false; 1626af4ea6e2SKumar Kartikeya Dwivedi /* 1627af4ea6e2SKumar Kartikeya Dwivedi * Resolve the target again because the enclosing function state's stack 1628af4ea6e2SKumar Kartikeya Dwivedi * may have been reallocated while the modification was in progress. 1629af4ea6e2SKumar Kartikeya Dwivedi */ 1630af4ea6e2SKumar Kartikeya Dwivedi new_reg = target_to_reg(env, &diag->mod.target); 1631af4ea6e2SKumar Kartikeya Dwivedi if (!new_reg) 1632af4ea6e2SKumar Kartikeya Dwivedi return; 1633af4ea6e2SKumar Kartikeya Dwivedi diag_record_mod(env, diag->mod.insn_idx, diag->mod.target, diag->mod.reason, 1634af4ea6e2SKumar Kartikeya Dwivedi &diag->mod.target_reg_snapshot, new_reg, 1635af4ea6e2SKumar Kartikeya Dwivedi diag->mod.origin_valid ? &diag->mod.origin : NULL); 1636af4ea6e2SKumar Kartikeya Dwivedi } 1637af4ea6e2SKumar Kartikeya Dwivedi 1638af4ea6e2SKumar Kartikeya Dwivedi void bpf_diag_record_scrub(struct bpf_verifier_env *env, const struct bpf_reg_state *reg, 1639af4ea6e2SKumar Kartikeya Dwivedi enum bpf_diag_mod_reason reason) 1640af4ea6e2SKumar Kartikeya Dwivedi { 1641af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_target target; 1642af4ea6e2SKumar Kartikeya Dwivedi 1643af4ea6e2SKumar Kartikeya Dwivedi if (!env->diag || reg->type == NOT_INIT || !reg_to_target(env, reg, &target)) 1644af4ea6e2SKumar Kartikeya Dwivedi return; 1645af4ea6e2SKumar Kartikeya Dwivedi diag_record_mod(env, env->insn_idx, target, reason, reg, NULL, NULL); 1646af4ea6e2SKumar Kartikeya Dwivedi } 1647af4ea6e2SKumar Kartikeya Dwivedi 1648af4ea6e2SKumar Kartikeya Dwivedi void bpf_diag_record_scrub_stack(struct bpf_verifier_env *env, 1649af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_func_state *state, s16 min_off, s16 max_off, 1650af4ea6e2SKumar Kartikeya Dwivedi enum bpf_diag_mod_reason reason) 1651af4ea6e2SKumar Kartikeya Dwivedi { 1652af4ea6e2SKumar Kartikeya Dwivedi diag_record_mod(env, env->insn_idx, 1653af4ea6e2SKumar Kartikeya Dwivedi diag_stack_range_target(state->diag_frame_id, state->frameno, min_off, max_off), 1654af4ea6e2SKumar Kartikeya Dwivedi reason, NULL, NULL, NULL); 1655af4ea6e2SKumar Kartikeya Dwivedi } 16569ecd7030SKumar Kartikeya Dwivedi 16579ecd7030SKumar Kartikeya Dwivedi static void diag_record_ref(struct bpf_verifier_env *env, u32 insn_idx, u8 kind, u32 ref_id) 16589ecd7030SKumar Kartikeya Dwivedi { 16599ecd7030SKumar Kartikeya Dwivedi struct bpf_diag_history_event event = { 16609ecd7030SKumar Kartikeya Dwivedi .insn_idx = insn_idx, 16619ecd7030SKumar Kartikeya Dwivedi .kind = kind, 16629ecd7030SKumar Kartikeya Dwivedi .ref = { 16639ecd7030SKumar Kartikeya Dwivedi .ref_id = ref_id, 16649ecd7030SKumar Kartikeya Dwivedi }, 16659ecd7030SKumar Kartikeya Dwivedi }; 16669ecd7030SKumar Kartikeya Dwivedi 16679ecd7030SKumar Kartikeya Dwivedi diag_append_history(env, &event); 16689ecd7030SKumar Kartikeya Dwivedi } 16699ecd7030SKumar Kartikeya Dwivedi 16709ecd7030SKumar Kartikeya Dwivedi void bpf_diag_record_ref_acquire(struct bpf_verifier_env *env, u32 insn_idx, u32 ref_id) 16719ecd7030SKumar Kartikeya Dwivedi { 16729ecd7030SKumar Kartikeya Dwivedi diag_record_ref(env, insn_idx, BPF_DIAG_HISTORY_REF_ACQUIRE, ref_id); 16739ecd7030SKumar Kartikeya Dwivedi } 16749ecd7030SKumar Kartikeya Dwivedi 16759ecd7030SKumar Kartikeya Dwivedi void bpf_diag_record_ref_release(struct bpf_verifier_env *env, u32 insn_idx, u32 ref_id) 16769ecd7030SKumar Kartikeya Dwivedi { 16779ecd7030SKumar Kartikeya Dwivedi diag_record_ref(env, insn_idx, BPF_DIAG_HISTORY_REF_RELEASE, ref_id); 16789ecd7030SKumar Kartikeya Dwivedi } 1679956a66e5SKumar Kartikeya Dwivedi 1680956a66e5SKumar Kartikeya Dwivedi void bpf_diag_record_context(struct bpf_verifier_env *env, u32 insn_idx, 1681956a66e5SKumar Kartikeya Dwivedi enum bpf_diag_context_kind ctx_kind, bool enter, u32 depth) 1682956a66e5SKumar Kartikeya Dwivedi { 1683956a66e5SKumar Kartikeya Dwivedi /* 1684956a66e5SKumar Kartikeya Dwivedi * Keep leave events so context rendering can stop at a depth-zero exit 1685956a66e5SKumar Kartikeya Dwivedi * and show nested-region depth accurately for the active path. 1686956a66e5SKumar Kartikeya Dwivedi */ 1687956a66e5SKumar Kartikeya Dwivedi struct bpf_diag_history_event event = { 1688956a66e5SKumar Kartikeya Dwivedi .insn_idx = insn_idx, 1689956a66e5SKumar Kartikeya Dwivedi .kind = BPF_DIAG_HISTORY_CONTEXT, 1690956a66e5SKumar Kartikeya Dwivedi .ctx = { 1691956a66e5SKumar Kartikeya Dwivedi .kind = ctx_kind, 1692956a66e5SKumar Kartikeya Dwivedi .enter = enter, 1693956a66e5SKumar Kartikeya Dwivedi .depth = depth, 1694956a66e5SKumar Kartikeya Dwivedi }, 1695956a66e5SKumar Kartikeya Dwivedi }; 1696956a66e5SKumar Kartikeya Dwivedi 1697956a66e5SKumar Kartikeya Dwivedi diag_append_history(env, &event); 1698956a66e5SKumar Kartikeya Dwivedi } 1699d63284e6SKumar Kartikeya Dwivedi 1700d63284e6SKumar Kartikeya Dwivedi static int diag_history_context_start_idx(const struct bpf_diag_log *log, 1701d63284e6SKumar Kartikeya Dwivedi const struct bpf_diag_history_opts *opts) 1702d63284e6SKumar Kartikeya Dwivedi { 1703d63284e6SKumar Kartikeya Dwivedi int i; 1704d63284e6SKumar Kartikeya Dwivedi 1705d63284e6SKumar Kartikeya Dwivedi if (!opts->ctx_depth) 1706d63284e6SKumar Kartikeya Dwivedi return 0; 1707d63284e6SKumar Kartikeya Dwivedi 1708d63284e6SKumar Kartikeya Dwivedi /* Find the most recent outermost entry, or a depth-zero exit. */ 1709d63284e6SKumar Kartikeya Dwivedi for (i = log->cnt; i > 0; i--) { 1710d63284e6SKumar Kartikeya Dwivedi const struct bpf_diag_history_event *event; 1711d63284e6SKumar Kartikeya Dwivedi 1712d63284e6SKumar Kartikeya Dwivedi event = &log->events[log_pos(log, i - 1)]; 1713d63284e6SKumar Kartikeya Dwivedi 1714d63284e6SKumar Kartikeya Dwivedi if (event->kind != BPF_DIAG_HISTORY_CONTEXT || event->ctx.kind != opts->ctx_kind) 1715d63284e6SKumar Kartikeya Dwivedi continue; 1716d63284e6SKumar Kartikeya Dwivedi 1717d63284e6SKumar Kartikeya Dwivedi if (event->ctx.enter && event->ctx.depth == 1) 1718d63284e6SKumar Kartikeya Dwivedi return i - 1; 1719d63284e6SKumar Kartikeya Dwivedi if (!event->ctx.enter && event->ctx.depth == 0) 1720d63284e6SKumar Kartikeya Dwivedi return 0; 1721d63284e6SKumar Kartikeya Dwivedi } 1722d63284e6SKumar Kartikeya Dwivedi 1723d63284e6SKumar Kartikeya Dwivedi return 0; 1724d63284e6SKumar Kartikeya Dwivedi } 1725d63284e6SKumar Kartikeya Dwivedi 1726d63284e6SKumar Kartikeya Dwivedi struct bpf_diag_history_filter { 1727d63284e6SKumar Kartikeya Dwivedi const struct bpf_diag_history_opts *opts; 1728d63284e6SKumar Kartikeya Dwivedi u32 lineage_start; 1729d63284e6SKumar Kartikeya Dwivedi bool lineage_valid; 1730d63284e6SKumar Kartikeya Dwivedi }; 1731d63284e6SKumar Kartikeya Dwivedi 1732d63284e6SKumar Kartikeya Dwivedi static bool diag_target_matches(const struct bpf_diag_mod_target *event_target, 1733d63284e6SKumar Kartikeya Dwivedi const struct bpf_diag_mod_target *target) 1734d63284e6SKumar Kartikeya Dwivedi { 1735d63284e6SKumar Kartikeya Dwivedi int slot_off; 1736d63284e6SKumar Kartikeya Dwivedi 1737d63284e6SKumar Kartikeya Dwivedi if (event_target->frame_id != target->frame_id || event_target->frameno != target->frameno) 1738d63284e6SKumar Kartikeya Dwivedi return false; 1739d63284e6SKumar Kartikeya Dwivedi 1740d63284e6SKumar Kartikeya Dwivedi if (event_target->kind == BPF_DIAG_MOD_TARGET_STACK_RANGE && 1741d63284e6SKumar Kartikeya Dwivedi target->kind == BPF_DIAG_MOD_TARGET_STACK_SLOT) { 1742d63284e6SKumar Kartikeya Dwivedi slot_off = -(target->spi + 1) * BPF_REG_SIZE; 1743d63284e6SKumar Kartikeya Dwivedi return event_target->range.min_off < slot_off + BPF_REG_SIZE && 1744d63284e6SKumar Kartikeya Dwivedi event_target->range.max_off > slot_off; 1745d63284e6SKumar Kartikeya Dwivedi } 1746d63284e6SKumar Kartikeya Dwivedi 1747d63284e6SKumar Kartikeya Dwivedi if (event_target->kind != target->kind) 1748d63284e6SKumar Kartikeya Dwivedi return false; 1749d63284e6SKumar Kartikeya Dwivedi 1750d63284e6SKumar Kartikeya Dwivedi switch (target->kind) { 1751d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_MOD_TARGET_REG: 1752d63284e6SKumar Kartikeya Dwivedi return event_target->regno == target->regno; 1753d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_MOD_TARGET_STACK_ARG: 1754d63284e6SKumar Kartikeya Dwivedi return event_target->stack_arg == target->stack_arg; 1755d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_MOD_TARGET_STACK_SLOT: 1756d63284e6SKumar Kartikeya Dwivedi return event_target->spi == target->spi; 1757d63284e6SKumar Kartikeya Dwivedi default: 1758d63284e6SKumar Kartikeya Dwivedi return false; 1759d63284e6SKumar Kartikeya Dwivedi } 1760d63284e6SKumar Kartikeya Dwivedi } 1761d63284e6SKumar Kartikeya Dwivedi 1762d63284e6SKumar Kartikeya Dwivedi static void diag_build_lineage(struct bpf_verifier_env *env, struct bpf_diag_log *log, 1763d63284e6SKumar Kartikeya Dwivedi struct bpf_diag_history_filter *filter) 1764d63284e6SKumar Kartikeya Dwivedi { 1765d63284e6SKumar Kartikeya Dwivedi const struct bpf_diag_history_opts *opts = filter->opts; 1766d63284e6SKumar Kartikeya Dwivedi struct bpf_diag_mod_target target; 1767d63284e6SKumar Kartikeya Dwivedi int i; 1768d63284e6SKumar Kartikeya Dwivedi 1769d63284e6SKumar Kartikeya Dwivedi for (i = 0; i < log->cnt; i++) 1770d63284e6SKumar Kartikeya Dwivedi log->events[log_pos(log, i)].in_lineage = false; 1771d63284e6SKumar Kartikeya Dwivedi 1772d63284e6SKumar Kartikeya Dwivedi if (opts->scope == BPF_DIAG_HISTORY_SCOPE_REG) 1773d63284e6SKumar Kartikeya Dwivedi target = diag_reg_target(opts->frame_id, opts->frameno, opts->regno); 1774d63284e6SKumar Kartikeya Dwivedi else if (opts->scope == BPF_DIAG_HISTORY_SCOPE_STACK_ARG) 1775d63284e6SKumar Kartikeya Dwivedi target = diag_stack_arg_target(opts->frame_id, opts->frameno, 1776d63284e6SKumar Kartikeya Dwivedi opts->stack_arg_slot); 1777d63284e6SKumar Kartikeya Dwivedi else 1778d63284e6SKumar Kartikeya Dwivedi return; 1779d63284e6SKumar Kartikeya Dwivedi 1780d63284e6SKumar Kartikeya Dwivedi /* 1781d63284e6SKumar Kartikeya Dwivedi * Find the nearest mutation of the active target. A fill or spill changes 1782d63284e6SKumar Kartikeya Dwivedi * the target to its origin, so the same walk follows register/stack 1783d63284e6SKumar Kartikeya Dwivedi * lineage recursively until it reaches the write that created the value. 1784d63284e6SKumar Kartikeya Dwivedi */ 1785d63284e6SKumar Kartikeya Dwivedi for (i = log->cnt; i > 0; i--) { 1786d63284e6SKumar Kartikeya Dwivedi struct bpf_diag_history_event *event; 1787d63284e6SKumar Kartikeya Dwivedi 1788d63284e6SKumar Kartikeya Dwivedi event = &log->events[log_pos(log, i - 1)]; 1789d63284e6SKumar Kartikeya Dwivedi if (event->kind != BPF_DIAG_HISTORY_MOD || 1790d63284e6SKumar Kartikeya Dwivedi !diag_target_matches(&event->mod.target, &target)) 1791d63284e6SKumar Kartikeya Dwivedi continue; 1792d63284e6SKumar Kartikeya Dwivedi 1793d63284e6SKumar Kartikeya Dwivedi event->in_lineage = true; 1794d63284e6SKumar Kartikeya Dwivedi filter->lineage_start = i - 1; 1795d63284e6SKumar Kartikeya Dwivedi filter->lineage_valid = true; 1796d63284e6SKumar Kartikeya Dwivedi 1797d63284e6SKumar Kartikeya Dwivedi if (event->mod.origin_valid) { 1798d63284e6SKumar Kartikeya Dwivedi target = event->mod.origin; 1799d63284e6SKumar Kartikeya Dwivedi continue; 1800d63284e6SKumar Kartikeya Dwivedi } 1801d63284e6SKumar Kartikeya Dwivedi if (event->mod.reason != BPF_DIAG_MOD_WRITE && 1802d63284e6SKumar Kartikeya Dwivedi event->mod.reason != BPF_DIAG_MOD_SPILL) 1803d63284e6SKumar Kartikeya Dwivedi continue; 1804d63284e6SKumar Kartikeya Dwivedi if (diag_mod_keeps_lineage(env, event)) 1805d63284e6SKumar Kartikeya Dwivedi continue; 1806d63284e6SKumar Kartikeya Dwivedi break; 1807d63284e6SKumar Kartikeya Dwivedi } 1808d63284e6SKumar Kartikeya Dwivedi } 1809d63284e6SKumar Kartikeya Dwivedi 1810d63284e6SKumar Kartikeya Dwivedi static int diag_history_start_idx(const struct bpf_diag_log *log, 1811d63284e6SKumar Kartikeya Dwivedi const struct bpf_diag_history_filter *filter) 1812d63284e6SKumar Kartikeya Dwivedi { 1813d63284e6SKumar Kartikeya Dwivedi const struct bpf_diag_history_opts *opts = filter->opts; 1814d63284e6SKumar Kartikeya Dwivedi int i; 1815d63284e6SKumar Kartikeya Dwivedi 1816d63284e6SKumar Kartikeya Dwivedi if (opts->scope == BPF_DIAG_HISTORY_SCOPE_CONTEXT) 1817d63284e6SKumar Kartikeya Dwivedi return diag_history_context_start_idx(log, opts); 1818d63284e6SKumar Kartikeya Dwivedi if (filter->lineage_valid) 1819d63284e6SKumar Kartikeya Dwivedi return filter->lineage_start; 1820d63284e6SKumar Kartikeya Dwivedi if (opts->scope != BPF_DIAG_HISTORY_SCOPE_REF) 1821d63284e6SKumar Kartikeya Dwivedi return 0; 1822d63284e6SKumar Kartikeya Dwivedi 1823d63284e6SKumar Kartikeya Dwivedi for (i = log->cnt; i > 0; i--) { 1824d63284e6SKumar Kartikeya Dwivedi const struct bpf_diag_history_event *event; 1825d63284e6SKumar Kartikeya Dwivedi 1826d63284e6SKumar Kartikeya Dwivedi event = &log->events[log_pos(log, i - 1)]; 1827d63284e6SKumar Kartikeya Dwivedi if (event->kind == BPF_DIAG_HISTORY_REF_ACQUIRE && 1828d63284e6SKumar Kartikeya Dwivedi event->ref.ref_id == opts->ref_id) 1829d63284e6SKumar Kartikeya Dwivedi return i - 1; 1830d63284e6SKumar Kartikeya Dwivedi } 1831d63284e6SKumar Kartikeya Dwivedi 1832d63284e6SKumar Kartikeya Dwivedi return 0; 1833d63284e6SKumar Kartikeya Dwivedi } 1834d63284e6SKumar Kartikeya Dwivedi 1835d63284e6SKumar Kartikeya Dwivedi static bool diag_history_event_visible(const struct bpf_diag_history_event *event, 1836d63284e6SKumar Kartikeya Dwivedi const struct bpf_diag_history_filter *filter) 1837d63284e6SKumar Kartikeya Dwivedi { 1838d63284e6SKumar Kartikeya Dwivedi const struct bpf_diag_history_opts *opts = filter->opts; 1839d63284e6SKumar Kartikeya Dwivedi 1840d63284e6SKumar Kartikeya Dwivedi switch (event->kind) { 1841d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_HISTORY_BRANCH: 1842d63284e6SKumar Kartikeya Dwivedi return true; 1843d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_HISTORY_MOD: 1844d63284e6SKumar Kartikeya Dwivedi return filter->lineage_valid && event->in_lineage; 1845d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_HISTORY_REF_ACQUIRE: 1846d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_HISTORY_REF_RELEASE: 1847d63284e6SKumar Kartikeya Dwivedi return opts->scope == BPF_DIAG_HISTORY_SCOPE_REF && 1848d63284e6SKumar Kartikeya Dwivedi event->ref.ref_id == opts->ref_id; 1849d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_HISTORY_CONTEXT: 1850d63284e6SKumar Kartikeya Dwivedi return opts->scope == BPF_DIAG_HISTORY_SCOPE_CONTEXT && 1851d63284e6SKumar Kartikeya Dwivedi event->ctx.kind == opts->ctx_kind; 1852d63284e6SKumar Kartikeya Dwivedi default: 1853d63284e6SKumar Kartikeya Dwivedi return false; 1854d63284e6SKumar Kartikeya Dwivedi } 1855d63284e6SKumar Kartikeya Dwivedi } 1856d63284e6SKumar Kartikeya Dwivedi 1857d63284e6SKumar Kartikeya Dwivedi static const char *diag_s64_bound_name(s64 value) 1858d63284e6SKumar Kartikeya Dwivedi { 1859d63284e6SKumar Kartikeya Dwivedi if (value == S64_MIN) 1860d63284e6SKumar Kartikeya Dwivedi return "S64_MIN"; 1861d63284e6SKumar Kartikeya Dwivedi if (value == S64_MAX) 1862d63284e6SKumar Kartikeya Dwivedi return "S64_MAX"; 1863d63284e6SKumar Kartikeya Dwivedi return NULL; 1864d63284e6SKumar Kartikeya Dwivedi } 1865d63284e6SKumar Kartikeya Dwivedi 1866d63284e6SKumar Kartikeya Dwivedi static const char *diag_u64_bound_name(u64 value) 1867d63284e6SKumar Kartikeya Dwivedi { 1868d63284e6SKumar Kartikeya Dwivedi if (value == U64_MAX) 1869d63284e6SKumar Kartikeya Dwivedi return "U64_MAX"; 1870d63284e6SKumar Kartikeya Dwivedi return NULL; 1871d63284e6SKumar Kartikeya Dwivedi } 1872d63284e6SKumar Kartikeya Dwivedi 1873d63284e6SKumar Kartikeya Dwivedi static const char *diag_s64_str(struct bpf_verifier_env *env, s64 value) 1874d63284e6SKumar Kartikeya Dwivedi { 1875d63284e6SKumar Kartikeya Dwivedi return diag_s64_bound_name(value) ?: bpf_diag_fmt(env, "%lld", value); 1876d63284e6SKumar Kartikeya Dwivedi } 1877d63284e6SKumar Kartikeya Dwivedi 1878d63284e6SKumar Kartikeya Dwivedi static const char *diag_u64_str(struct bpf_verifier_env *env, u64 value) 1879d63284e6SKumar Kartikeya Dwivedi { 1880d63284e6SKumar Kartikeya Dwivedi return diag_u64_bound_name(value) ?: bpf_diag_fmt(env, "%llu", value); 1881d63284e6SKumar Kartikeya Dwivedi } 1882d63284e6SKumar Kartikeya Dwivedi 1883d63284e6SKumar Kartikeya Dwivedi static bool diag_cnum64_unknown(struct cnum64 range) 1884d63284e6SKumar Kartikeya Dwivedi { 1885d63284e6SKumar Kartikeya Dwivedi return cnum64_smin(range) == S64_MIN && cnum64_smax(range) == S64_MAX && 1886d63284e6SKumar Kartikeya Dwivedi cnum64_umin(range) == 0 && cnum64_umax(range) == U64_MAX; 1887d63284e6SKumar Kartikeya Dwivedi } 1888d63284e6SKumar Kartikeya Dwivedi 1889d63284e6SKumar Kartikeya Dwivedi static bool diag_snapshot_unknown(const struct bpf_diag_reg_snapshot *snapshot) 1890d63284e6SKumar Kartikeya Dwivedi { 1891d63284e6SKumar Kartikeya Dwivedi return tnum_is_unknown(snapshot->var_off) && diag_cnum64_unknown(snapshot->r64); 1892d63284e6SKumar Kartikeya Dwivedi } 1893d63284e6SKumar Kartikeya Dwivedi 1894d63284e6SKumar Kartikeya Dwivedi static const char *diag_scalar_range(struct bpf_verifier_env *env, struct cnum64 range) 1895d63284e6SKumar Kartikeya Dwivedi { 1896d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "signed range [%s, %s], unsigned range [%s, %s]", 1897d63284e6SKumar Kartikeya Dwivedi diag_s64_str(env, cnum64_smin(range)), 1898d63284e6SKumar Kartikeya Dwivedi diag_s64_str(env, cnum64_smax(range)), 1899d63284e6SKumar Kartikeya Dwivedi diag_u64_str(env, cnum64_umin(range)), 1900d63284e6SKumar Kartikeya Dwivedi diag_u64_str(env, cnum64_umax(range))); 1901d63284e6SKumar Kartikeya Dwivedi } 1902d63284e6SKumar Kartikeya Dwivedi 19032bdc90f5SKumar Kartikeya Dwivedi const char *bpf_diag_fmt_s64_sum(struct bpf_verifier_env *env, s64 value, int addend) 19042bdc90f5SKumar Kartikeya Dwivedi { 19052bdc90f5SKumar Kartikeya Dwivedi s64 sum; 19062bdc90f5SKumar Kartikeya Dwivedi 19072bdc90f5SKumar Kartikeya Dwivedi if (check_add_overflow(value, (s64)addend, &sum)) 19082bdc90f5SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "%lld plus %d (%s)", value, addend, 19092bdc90f5SKumar Kartikeya Dwivedi addend < 0 ? "below S64_MIN" : "above S64_MAX"); 19102bdc90f5SKumar Kartikeya Dwivedi 19112bdc90f5SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "%lld", sum); 19122bdc90f5SKumar Kartikeya Dwivedi } 19132bdc90f5SKumar Kartikeya Dwivedi 19142bdc90f5SKumar Kartikeya Dwivedi static const char *diag_access_offset(struct bpf_verifier_env *env, int off, 19152bdc90f5SKumar Kartikeya Dwivedi const struct bpf_reg_state *reg) 19162bdc90f5SKumar Kartikeya Dwivedi { 19172bdc90f5SKumar Kartikeya Dwivedi if (tnum_is_const(reg->var_off)) 19182bdc90f5SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "constant %s", 19192bdc90f5SKumar Kartikeya Dwivedi bpf_diag_fmt_s64_sum(env, (s64)reg->var_off.value, off)); 19202bdc90f5SKumar Kartikeya Dwivedi 19212bdc90f5SKumar Kartikeya Dwivedi if (tnum_is_unknown(reg->var_off) && diag_cnum64_unknown(reg->r64)) 19222bdc90f5SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "unbounded"); 19232bdc90f5SKumar Kartikeya Dwivedi 19242bdc90f5SKumar Kartikeya Dwivedi if (off) 19252bdc90f5SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, 19262bdc90f5SKumar Kartikeya Dwivedi "variable: known bits %#llx, unknown mask %#llx, plus fixed offset %d; %s", 19272bdc90f5SKumar Kartikeya Dwivedi (u64)reg->var_off.value, reg->var_off.mask, off, 19282bdc90f5SKumar Kartikeya Dwivedi diag_scalar_range(env, reg->r64)); 19292bdc90f5SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "variable: known bits %#llx, unknown mask %#llx; %s", 19302bdc90f5SKumar Kartikeya Dwivedi (u64)reg->var_off.value, reg->var_off.mask, 19312bdc90f5SKumar Kartikeya Dwivedi diag_scalar_range(env, reg->r64)); 19322bdc90f5SKumar Kartikeya Dwivedi } 19332bdc90f5SKumar Kartikeya Dwivedi 19342bdc90f5SKumar Kartikeya Dwivedi void bpf_diag_mem_bounds(struct bpf_verifier_env *env, u32 insn_idx, int regno, 19352bdc90f5SKumar Kartikeya Dwivedi const char *reg_name, const char *type_name, const char *proof, 19362bdc90f5SKumar Kartikeya Dwivedi int off, int size, u32 mem_size, const struct bpf_reg_state *reg) 19372bdc90f5SKumar Kartikeya Dwivedi { 19382bdc90f5SKumar Kartikeya Dwivedi const struct bpf_func_state *frame = diag_current_frame(env); 19392bdc90f5SKumar Kartikeya Dwivedi struct bpf_diag_history_opts opts = { 19402bdc90f5SKumar Kartikeya Dwivedi .scope = BPF_DIAG_HISTORY_SCOPE_REG, 19412bdc90f5SKumar Kartikeya Dwivedi .frame_id = frame->diag_frame_id, 19422bdc90f5SKumar Kartikeya Dwivedi .frameno = frame->frameno, 19432bdc90f5SKumar Kartikeya Dwivedi .regno = regno, 19442bdc90f5SKumar Kartikeya Dwivedi }; 19452bdc90f5SKumar Kartikeya Dwivedi const char *offset_desc; 19462bdc90f5SKumar Kartikeya Dwivedi 19472bdc90f5SKumar Kartikeya Dwivedi if (!bpf_diag_enabled(env)) 19482bdc90f5SKumar Kartikeya Dwivedi return; 19492bdc90f5SKumar Kartikeya Dwivedi 19502bdc90f5SKumar Kartikeya Dwivedi offset_desc = diag_access_offset(env, off, reg); 19512bdc90f5SKumar Kartikeya Dwivedi 19522bdc90f5SKumar Kartikeya Dwivedi bpf_diag_header(env, MEMORY_SAFETY, "access outside bounds"); 19532bdc90f5SKumar Kartikeya Dwivedi diag_reason( 19542bdc90f5SKumar Kartikeya Dwivedi env, "The verifier cannot prove offset + access_size <= object_size. Here, %s. %s is %s; offset is %s; access_size is %d; object_size is %u.", 19552bdc90f5SKumar Kartikeya Dwivedi proof, reg_name, type_name, offset_desc, size, mem_size); 19562bdc90f5SKumar Kartikeya Dwivedi 19572bdc90f5SKumar Kartikeya Dwivedi diag_section(env, "At"); 19582bdc90f5SKumar Kartikeya Dwivedi bpf_diag_source(env, insn_idx, "error", "access may be outside object bounds"); 19592bdc90f5SKumar Kartikeya Dwivedi 19602bdc90f5SKumar Kartikeya Dwivedi if (regno >= 0) 19612bdc90f5SKumar Kartikeya Dwivedi diag_print_history(env, &opts); 19622bdc90f5SKumar Kartikeya Dwivedi 19632bdc90f5SKumar Kartikeya Dwivedi diag_suggestion( 19642bdc90f5SKumar Kartikeya Dwivedi env, "Add or adjust a bounds check that proves offset + access_size stays within the object."); 19652bdc90f5SKumar Kartikeya Dwivedi } 19662bdc90f5SKumar Kartikeya Dwivedi 19675d576462SKumar Kartikeya Dwivedi static const char *diag_lock_name(const struct bpf_reference_state *lock) 19685d576462SKumar Kartikeya Dwivedi { 19695d576462SKumar Kartikeya Dwivedi switch (lock->type) { 19705d576462SKumar Kartikeya Dwivedi case REF_TYPE_LOCK: 19715d576462SKumar Kartikeya Dwivedi return "bpf_spin_lock"; 19725d576462SKumar Kartikeya Dwivedi case REF_TYPE_RES_LOCK: 19735d576462SKumar Kartikeya Dwivedi return "resource spin lock"; 19745d576462SKumar Kartikeya Dwivedi case REF_TYPE_RES_LOCK_IRQ: 19755d576462SKumar Kartikeya Dwivedi return "IRQ-saving resource spin lock"; 19765d576462SKumar Kartikeya Dwivedi default: 19775d576462SKumar Kartikeya Dwivedi return "lock"; 19785d576462SKumar Kartikeya Dwivedi } 19795d576462SKumar Kartikeya Dwivedi } 19805d576462SKumar Kartikeya Dwivedi 19815d576462SKumar Kartikeya Dwivedi static void diag_res_report(struct bpf_verifier_env *env, u32 insn_idx, const char *problem, 19825d576462SKumar Kartikeya Dwivedi const char *reason) 19835d576462SKumar Kartikeya Dwivedi { 19845d576462SKumar Kartikeya Dwivedi bpf_diag_header(env, RESOURCE_LIFETIME_SAFETY, problem); 19855d576462SKumar Kartikeya Dwivedi diag_reason(env, "%s", reason); 19865d576462SKumar Kartikeya Dwivedi 19875d576462SKumar Kartikeya Dwivedi diag_section(env, "At"); 19885d576462SKumar Kartikeya Dwivedi bpf_diag_source(env, insn_idx, "error", "%s", problem); 19895d576462SKumar Kartikeya Dwivedi } 19905d576462SKumar Kartikeya Dwivedi 19915d576462SKumar Kartikeya Dwivedi void bpf_diag_res(struct bpf_verifier_env *env, u32 insn_idx, const char *problem, 19925d576462SKumar Kartikeya Dwivedi const char *reason, const char *suggestion) 19935d576462SKumar Kartikeya Dwivedi { 19945d576462SKumar Kartikeya Dwivedi diag_res_report(env, insn_idx, problem, reason); 19955d576462SKumar Kartikeya Dwivedi diag_suggestion(env, "%s", suggestion); 19965d576462SKumar Kartikeya Dwivedi } 19975d576462SKumar Kartikeya Dwivedi 19985d576462SKumar Kartikeya Dwivedi void bpf_diag_lock(struct bpf_verifier_env *env, u32 insn_idx, const char *problem, 19995d576462SKumar Kartikeya Dwivedi const char *reason, const char *suggestion, 20005d576462SKumar Kartikeya Dwivedi const struct bpf_reference_state *active_lock) 20015d576462SKumar Kartikeya Dwivedi { 20025d576462SKumar Kartikeya Dwivedi diag_res_report(env, insn_idx, problem, reason); 20035d576462SKumar Kartikeya Dwivedi 20045d576462SKumar Kartikeya Dwivedi if (active_lock) { 20055d576462SKumar Kartikeya Dwivedi diag_section(env, "Active lock"); 20065d576462SKumar Kartikeya Dwivedi bpf_diag_source(env, active_lock->insn_idx, "acquired", 20075d576462SKumar Kartikeya Dwivedi "active %s has verifier identity %d", 20085d576462SKumar Kartikeya Dwivedi diag_lock_name(active_lock), active_lock->id); 20095d576462SKumar Kartikeya Dwivedi } 20105d576462SKumar Kartikeya Dwivedi 20115d576462SKumar Kartikeya Dwivedi diag_suggestion(env, "%s", suggestion); 20125d576462SKumar Kartikeya Dwivedi } 20135d576462SKumar Kartikeya Dwivedi 20145d576462SKumar Kartikeya Dwivedi void bpf_diag_irq(struct bpf_verifier_env *env, u32 insn_idx, const char *problem, 20155d576462SKumar Kartikeya Dwivedi const char *reason, const char *suggestion, u32 depth) 20165d576462SKumar Kartikeya Dwivedi { 20175d576462SKumar Kartikeya Dwivedi struct bpf_diag_history_opts opts = { 20185d576462SKumar Kartikeya Dwivedi .scope = BPF_DIAG_HISTORY_SCOPE_CONTEXT, 20195d576462SKumar Kartikeya Dwivedi .ctx_kind = BPF_DIAG_CONTEXT_IRQ, 20205d576462SKumar Kartikeya Dwivedi .ctx_depth = depth, 20215d576462SKumar Kartikeya Dwivedi }; 20225d576462SKumar Kartikeya Dwivedi 20235d576462SKumar Kartikeya Dwivedi bpf_diag_header(env, RESOURCE_LIFETIME_SAFETY, problem); 20245d576462SKumar Kartikeya Dwivedi diag_reason(env, "%s", reason); 20255d576462SKumar Kartikeya Dwivedi 20265d576462SKumar Kartikeya Dwivedi diag_section(env, "At"); 20275d576462SKumar Kartikeya Dwivedi bpf_diag_source(env, insn_idx, "error", "%s", problem); 20285d576462SKumar Kartikeya Dwivedi 20295d576462SKumar Kartikeya Dwivedi if (depth) 20305d576462SKumar Kartikeya Dwivedi diag_print_history(env, &opts); 20315d576462SKumar Kartikeya Dwivedi 20325d576462SKumar Kartikeya Dwivedi diag_suggestion(env, "%s", suggestion); 20335d576462SKumar Kartikeya Dwivedi } 20345d576462SKumar Kartikeya Dwivedi 20355d576462SKumar Kartikeya Dwivedi void bpf_diag_leak(struct bpf_verifier_env *env, u32 ref_id, u32 alloc_insn, u32 fail_insn) 20365d576462SKumar Kartikeya Dwivedi { 20375d576462SKumar Kartikeya Dwivedi struct bpf_diag_history_opts opts = { 20385d576462SKumar Kartikeya Dwivedi .scope = BPF_DIAG_HISTORY_SCOPE_REF, 20395d576462SKumar Kartikeya Dwivedi .ref_id = ref_id, 20405d576462SKumar Kartikeya Dwivedi }; 20415d576462SKumar Kartikeya Dwivedi 20425d576462SKumar Kartikeya Dwivedi bpf_diag_header(env, RESOURCE_LIFETIME_SAFETY, "unreleased resource"); 20435d576462SKumar Kartikeya Dwivedi diag_reason( 20445d576462SKumar Kartikeya Dwivedi env, "Owned resource (id=%u) was acquired at instruction %u and still needs to be released before this exit path.", 20455d576462SKumar Kartikeya Dwivedi ref_id, alloc_insn); 20465d576462SKumar Kartikeya Dwivedi 20475d576462SKumar Kartikeya Dwivedi diag_section(env, "At"); 20485d576462SKumar Kartikeya Dwivedi bpf_diag_source(env, fail_insn, "error", 20495d576462SKumar Kartikeya Dwivedi "owned resource (id=%u) still needs release", ref_id); 20505d576462SKumar Kartikeya Dwivedi 20515d576462SKumar Kartikeya Dwivedi diag_print_history(env, &opts); 20525d576462SKumar Kartikeya Dwivedi 20535d576462SKumar Kartikeya Dwivedi diag_suggestion( 20545d576462SKumar Kartikeya Dwivedi env, "Release or transfer ownership of the acquired resource on every path before the program exits."); 20555d576462SKumar Kartikeya Dwivedi } 20565d576462SKumar Kartikeya Dwivedi 2057d63284e6SKumar Kartikeya Dwivedi static const char *diag_var_offset(struct bpf_verifier_env *env, 2058d63284e6SKumar Kartikeya Dwivedi const struct bpf_diag_reg_snapshot *snapshot) 2059d63284e6SKumar Kartikeya Dwivedi { 2060d63284e6SKumar Kartikeya Dwivedi if (tnum_is_const(snapshot->var_off)) 2061d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "at offset %lld", (s64)snapshot->var_off.value); 2062d63284e6SKumar Kartikeya Dwivedi 2063d63284e6SKumar Kartikeya Dwivedi if (diag_snapshot_unknown(snapshot)) 2064d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "with unknown offset"); 2065d63284e6SKumar Kartikeya Dwivedi 2066d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, 2067d63284e6SKumar Kartikeya Dwivedi "with variable offset: known bits %#llx, unknown mask %#llx, %s", 2068d63284e6SKumar Kartikeya Dwivedi snapshot->var_off.value, snapshot->var_off.mask, 2069d63284e6SKumar Kartikeya Dwivedi diag_scalar_range(env, snapshot->r64)); 2070d63284e6SKumar Kartikeya Dwivedi } 2071d63284e6SKumar Kartikeya Dwivedi 2072d63284e6SKumar Kartikeya Dwivedi static const char *diag_reg_map_name(const struct bpf_map *map) 2073d63284e6SKumar Kartikeya Dwivedi { 2074d63284e6SKumar Kartikeya Dwivedi if (!map || !map->name[0]) 2075d63284e6SKumar Kartikeya Dwivedi return NULL; 2076d63284e6SKumar Kartikeya Dwivedi 2077d63284e6SKumar Kartikeya Dwivedi return map->name; 2078d63284e6SKumar Kartikeya Dwivedi } 2079d63284e6SKumar Kartikeya Dwivedi 2080d63284e6SKumar Kartikeya Dwivedi static const char *diag_reg_snapshot(struct bpf_verifier_env *env, 2081d63284e6SKumar Kartikeya Dwivedi const struct bpf_diag_reg_snapshot *snapshot) 2082d63284e6SKumar Kartikeya Dwivedi { 2083d63284e6SKumar Kartikeya Dwivedi const char *type_name = reg_type_str(env, snapshot->type); 2084d63284e6SKumar Kartikeya Dwivedi const char *offset = diag_var_offset(env, snapshot); 2085d63284e6SKumar Kartikeya Dwivedi const char *btf = snapshot->btf && snapshot->btf_id ? 2086d63284e6SKumar Kartikeya Dwivedi bpf_diag_fmt_btf_type(env, snapshot->btf, snapshot->btf_id) : NULL; 2087d63284e6SKumar Kartikeya Dwivedi const char *map_name; 2088d63284e6SKumar Kartikeya Dwivedi 2089d63284e6SKumar Kartikeya Dwivedi if (snapshot->type == SCALAR_VALUE) { 2090d63284e6SKumar Kartikeya Dwivedi if (tnum_is_const(snapshot->var_off)) 2091d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "integer scalar value %lld", 2092d63284e6SKumar Kartikeya Dwivedi (s64)snapshot->var_off.value); 2093d63284e6SKumar Kartikeya Dwivedi if (diag_snapshot_unknown(snapshot)) 2094d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "integer scalar with unknown value"); 2095d63284e6SKumar Kartikeya Dwivedi if (cnum64_is_const(snapshot->r64)) 2096d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "integer scalar value %lld", 2097d63284e6SKumar Kartikeya Dwivedi cnum64_smin(snapshot->r64)); 2098d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "integer scalar with %s", 2099d63284e6SKumar Kartikeya Dwivedi diag_scalar_range(env, snapshot->r64)); 2100d63284e6SKumar Kartikeya Dwivedi } 2101d63284e6SKumar Kartikeya Dwivedi 2102d63284e6SKumar Kartikeya Dwivedi if (snapshot->type == NOT_INIT) 2103d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "uninitialized value"); 2104d63284e6SKumar Kartikeya Dwivedi 2105d63284e6SKumar Kartikeya Dwivedi if (base_type(snapshot->type) == PTR_TO_CTX) 2106d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "context pointer %s", offset); 2107d63284e6SKumar Kartikeya Dwivedi 2108d63284e6SKumar Kartikeya Dwivedi if (base_type(snapshot->type) == PTR_TO_STACK) 2109d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "stack pointer %s", offset); 2110d63284e6SKumar Kartikeya Dwivedi 2111d63284e6SKumar Kartikeya Dwivedi if (base_type(snapshot->type) == PTR_TO_MAP_VALUE) { 2112d63284e6SKumar Kartikeya Dwivedi const char *kind = type_may_be_null(snapshot->type) ? "nullable map value" : 2113d63284e6SKumar Kartikeya Dwivedi "map value"; 2114d63284e6SKumar Kartikeya Dwivedi 2115d63284e6SKumar Kartikeya Dwivedi map_name = diag_reg_map_name(snapshot->map_ptr); 2116d63284e6SKumar Kartikeya Dwivedi if (map_name) 2117d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "%s from %s %s", kind, map_name, offset); 2118d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "%s %s", kind, offset); 2119d63284e6SKumar Kartikeya Dwivedi } 2120d63284e6SKumar Kartikeya Dwivedi 2121d63284e6SKumar Kartikeya Dwivedi if (base_type(snapshot->type) == CONST_PTR_TO_MAP) { 2122d63284e6SKumar Kartikeya Dwivedi map_name = diag_reg_map_name(snapshot->map_ptr); 2123d63284e6SKumar Kartikeya Dwivedi if (map_name) 2124d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "map pointer for map %s", map_name); 2125d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "map pointer"); 2126d63284e6SKumar Kartikeya Dwivedi } 2127d63284e6SKumar Kartikeya Dwivedi 2128d63284e6SKumar Kartikeya Dwivedi if (type_is_non_owning_ref(snapshot->type)) { 2129d63284e6SKumar Kartikeya Dwivedi if (btf) 2130d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "borrowed allocated object pointer type=%s", btf); 2131d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "borrowed allocated object pointer"); 2132d63284e6SKumar Kartikeya Dwivedi } 2133d63284e6SKumar Kartikeya Dwivedi 2134d63284e6SKumar Kartikeya Dwivedi if (type_is_ptr_alloc_obj(snapshot->type)) { 2135d63284e6SKumar Kartikeya Dwivedi if (btf) 2136d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "owned allocated object pointer type=%s", btf); 2137d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "owned allocated object pointer"); 2138d63284e6SKumar Kartikeya Dwivedi } 2139d63284e6SKumar Kartikeya Dwivedi 2140d63284e6SKumar Kartikeya Dwivedi if (base_type(snapshot->type) == PTR_TO_BTF_ID && btf) 2141d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "%s type=%s %s", type_name, btf, offset); 2142d63284e6SKumar Kartikeya Dwivedi 2143d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "%s %s", type_name, offset); 2144d63284e6SKumar Kartikeya Dwivedi } 2145d63284e6SKumar Kartikeya Dwivedi 2146d63284e6SKumar Kartikeya Dwivedi static const char *diag_mod_target_desc(struct bpf_verifier_env *env, 2147d63284e6SKumar Kartikeya Dwivedi const struct bpf_diag_mod_target *target) 2148d63284e6SKumar Kartikeya Dwivedi { 2149d63284e6SKumar Kartikeya Dwivedi switch (target->kind) { 2150d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_MOD_TARGET_REG: 2151d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "R%u", target->regno); 2152d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_MOD_TARGET_STACK_ARG: 2153d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "stack arg%d", diag_stack_argno(target->stack_arg)); 2154d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_MOD_TARGET_STACK_SLOT: 2155d63284e6SKumar Kartikeya Dwivedi return bpf_diag_fmt(env, "stack slot fp%d", -(target->spi + 1) * BPF_REG_SIZE); 2156d63284e6SKumar Kartikeya Dwivedi default: 2157d63284e6SKumar Kartikeya Dwivedi return "value"; 2158d63284e6SKumar Kartikeya Dwivedi } 2159d63284e6SKumar Kartikeya Dwivedi } 2160d63284e6SKumar Kartikeya Dwivedi 2161d63284e6SKumar Kartikeya Dwivedi static void diag_print_mod(struct bpf_verifier_env *env, const struct bpf_diag_history_event *event) 2162d63284e6SKumar Kartikeya Dwivedi { 2163d63284e6SKumar Kartikeya Dwivedi const struct bpf_diag_mod_target *target = &event->mod.target; 2164d63284e6SKumar Kartikeya Dwivedi const char *target_desc, *reason = NULL, *old, *new; 2165d63284e6SKumar Kartikeya Dwivedi const char *label = "update"; 2166d63284e6SKumar Kartikeya Dwivedi 2167d63284e6SKumar Kartikeya Dwivedi if (target->kind == BPF_DIAG_MOD_TARGET_STACK_RANGE) { 2168d63284e6SKumar Kartikeya Dwivedi bpf_diag_source( 2169d63284e6SKumar Kartikeya Dwivedi env, event->insn_idx, "invalidated", 2170d63284e6SKumar Kartikeya Dwivedi "variable-offset stack write may affect bytes fp%d through fp%d", 2171d63284e6SKumar Kartikeya Dwivedi target->range.min_off, target->range.max_off - 1); 2172d63284e6SKumar Kartikeya Dwivedi return; 2173d63284e6SKumar Kartikeya Dwivedi } 2174d63284e6SKumar Kartikeya Dwivedi 2175d63284e6SKumar Kartikeya Dwivedi old = diag_reg_snapshot(env, &event->mod.old); 2176d63284e6SKumar Kartikeya Dwivedi new = diag_reg_snapshot(env, &event->mod.new); 2177d63284e6SKumar Kartikeya Dwivedi target_desc = diag_mod_target_desc(env, target); 2178d63284e6SKumar Kartikeya Dwivedi 2179d63284e6SKumar Kartikeya Dwivedi switch (event->mod.reason) { 2180d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_MOD_REF_RELEASE: 2181d63284e6SKumar Kartikeya Dwivedi reason = target->kind == BPF_DIAG_MOD_TARGET_REG ? "resource release invalidated " 2182d63284e6SKumar Kartikeya Dwivedi "this pointer" : 2183d63284e6SKumar Kartikeya Dwivedi "resource release invalidated " 2184d63284e6SKumar Kartikeya Dwivedi "this value"; 2185d63284e6SKumar Kartikeya Dwivedi break; 2186d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_MOD_PKT_DATA_CHANGE: 2187d63284e6SKumar Kartikeya Dwivedi reason = "packet data may have moved"; 2188d63284e6SKumar Kartikeya Dwivedi break; 2189d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_MOD_NON_OWN_REF: 2190d63284e6SKumar Kartikeya Dwivedi reason = "leaving the protected region invalidated this borrowed pointer"; 2191d63284e6SKumar Kartikeya Dwivedi break; 2192d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_MOD_CALLER_SAVED: 2193d63284e6SKumar Kartikeya Dwivedi reason = target->kind == BPF_DIAG_MOD_TARGET_STACK_ARG ? 2194d63284e6SKumar Kartikeya Dwivedi "call invalidated this outgoing stack argument" : 2195d63284e6SKumar Kartikeya Dwivedi "call invalidated this caller-saved register"; 2196d63284e6SKumar Kartikeya Dwivedi break; 2197d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_MOD_WRITE: 2198d63284e6SKumar Kartikeya Dwivedi if (target->kind == BPF_DIAG_MOD_TARGET_STACK_SLOT) 2199d63284e6SKumar Kartikeya Dwivedi reason = "a later stack write overwrote this spilled value"; 2200d63284e6SKumar Kartikeya Dwivedi break; 2201d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_MOD_SPILL: 2202d63284e6SKumar Kartikeya Dwivedi label = "spilled"; 2203d63284e6SKumar Kartikeya Dwivedi break; 2204d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_MOD_VAR_WRITE: 2205d63284e6SKumar Kartikeya Dwivedi default: 2206d63284e6SKumar Kartikeya Dwivedi break; 2207d63284e6SKumar Kartikeya Dwivedi } 2208d63284e6SKumar Kartikeya Dwivedi 2209d63284e6SKumar Kartikeya Dwivedi if (reason) { 2210d63284e6SKumar Kartikeya Dwivedi bpf_diag_source(env, event->insn_idx, "invalidated", 2211d63284e6SKumar Kartikeya Dwivedi "%s: %s; previous value was %s", target_desc, reason, old); 2212d63284e6SKumar Kartikeya Dwivedi return; 2213d63284e6SKumar Kartikeya Dwivedi } 2214d63284e6SKumar Kartikeya Dwivedi 2215d63284e6SKumar Kartikeya Dwivedi bpf_diag_source(env, event->insn_idx, label, "%s changed from %s to %s", target_desc, 2216d63284e6SKumar Kartikeya Dwivedi old, new); 2217d63284e6SKumar Kartikeya Dwivedi } 2218d63284e6SKumar Kartikeya Dwivedi 2219d63284e6SKumar Kartikeya Dwivedi static void diag_print_ref_event(struct bpf_verifier_env *env, 2220d63284e6SKumar Kartikeya Dwivedi const struct bpf_diag_history_event *event) 2221d63284e6SKumar Kartikeya Dwivedi { 2222d63284e6SKumar Kartikeya Dwivedi const char *label; 2223d63284e6SKumar Kartikeya Dwivedi 2224d63284e6SKumar Kartikeya Dwivedi label = event->kind == BPF_DIAG_HISTORY_REF_ACQUIRE ? "acquired" : "released"; 2225d63284e6SKumar Kartikeya Dwivedi bpf_diag_source(env, event->insn_idx, label, "owned resource (id=%u)", 2226d63284e6SKumar Kartikeya Dwivedi event->ref.ref_id); 2227d63284e6SKumar Kartikeya Dwivedi } 2228d63284e6SKumar Kartikeya Dwivedi 2229d63284e6SKumar Kartikeya Dwivedi static const char *diag_context_name(enum bpf_diag_context_kind kind) 2230d63284e6SKumar Kartikeya Dwivedi { 2231d63284e6SKumar Kartikeya Dwivedi switch (kind) { 2232d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_CONTEXT_RCU: 2233d63284e6SKumar Kartikeya Dwivedi return "RCU read lock region"; 2234d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_CONTEXT_PREEMPT: 2235d63284e6SKumar Kartikeya Dwivedi return "non-preemptible region"; 2236d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_CONTEXT_IRQ: 2237d63284e6SKumar Kartikeya Dwivedi return "IRQ-disabled region"; 2238d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_CONTEXT_LOCK: 2239d63284e6SKumar Kartikeya Dwivedi return "lock region"; 2240d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_CONTEXT_NONE: 2241d63284e6SKumar Kartikeya Dwivedi default: 224299a6a288SKumar Kartikeya Dwivedi return "non-sleepable program"; 2243d63284e6SKumar Kartikeya Dwivedi } 2244d63284e6SKumar Kartikeya Dwivedi } 2245d63284e6SKumar Kartikeya Dwivedi 2246d63284e6SKumar Kartikeya Dwivedi static void diag_print_context_event(struct bpf_verifier_env *env, 2247d63284e6SKumar Kartikeya Dwivedi const struct bpf_diag_history_event *event) 2248d63284e6SKumar Kartikeya Dwivedi { 2249d63284e6SKumar Kartikeya Dwivedi bpf_diag_source(env, event->insn_idx, "context", "%s %s; depth is now %u", 2250d63284e6SKumar Kartikeya Dwivedi event->ctx.enter ? "entered" : "left", 2251d63284e6SKumar Kartikeya Dwivedi diag_context_name(event->ctx.kind), event->ctx.depth); 2252d63284e6SKumar Kartikeya Dwivedi } 2253d63284e6SKumar Kartikeya Dwivedi 2254d63284e6SKumar Kartikeya Dwivedi static void diag_print_history(struct bpf_verifier_env *env, 2255d63284e6SKumar Kartikeya Dwivedi const struct bpf_diag_history_opts *opts) 2256d63284e6SKumar Kartikeya Dwivedi { 2257d63284e6SKumar Kartikeya Dwivedi const struct bpf_diag_history_event *event; 2258d63284e6SKumar Kartikeya Dwivedi struct bpf_diag_history_filter filter = { 2259d63284e6SKumar Kartikeya Dwivedi .opts = opts, 2260d63284e6SKumar Kartikeya Dwivedi }; 2261d63284e6SKumar Kartikeya Dwivedi struct bpf_diag_log *log; 2262d63284e6SKumar Kartikeya Dwivedi struct diag_fmt_mark mark; 2263d63284e6SKumar Kartikeya Dwivedi bool first = true; 2264d63284e6SKumar Kartikeya Dwivedi int start_idx; 2265d63284e6SKumar Kartikeya Dwivedi u32 i, visible_cnt = 0, visible_idx = 0; 2266d63284e6SKumar Kartikeya Dwivedi 2267d63284e6SKumar Kartikeya Dwivedi if (!bpf_diag_enabled(env)) 2268d63284e6SKumar Kartikeya Dwivedi return; 2269d63284e6SKumar Kartikeya Dwivedi 2270d63284e6SKumar Kartikeya Dwivedi if (!env->diag) 2271d63284e6SKumar Kartikeya Dwivedi return; 2272d63284e6SKumar Kartikeya Dwivedi log = &env->diag->log; 2273d63284e6SKumar Kartikeya Dwivedi 2274d63284e6SKumar Kartikeya Dwivedi diag_build_lineage(env, log, &filter); 2275d63284e6SKumar Kartikeya Dwivedi 2276d63284e6SKumar Kartikeya Dwivedi start_idx = diag_history_start_idx(log, &filter); 2277d63284e6SKumar Kartikeya Dwivedi for (i = start_idx; i < log->cnt; i++) { 2278d63284e6SKumar Kartikeya Dwivedi event = &log->events[log_pos(log, i)]; 2279d63284e6SKumar Kartikeya Dwivedi if (diag_history_event_visible(event, &filter)) 2280d63284e6SKumar Kartikeya Dwivedi visible_cnt++; 2281d63284e6SKumar Kartikeya Dwivedi } 2282d63284e6SKumar Kartikeya Dwivedi 2283d63284e6SKumar Kartikeya Dwivedi if (!visible_cnt && !log->first_seq && opts->scope == BPF_DIAG_HISTORY_SCOPE_STACK_ARG) 2284d63284e6SKumar Kartikeya Dwivedi return; 2285d63284e6SKumar Kartikeya Dwivedi 2286d63284e6SKumar Kartikeya Dwivedi diag_section(env, "Causal path"); 2287d63284e6SKumar Kartikeya Dwivedi mark = diag_fmt_save(env); 2288d63284e6SKumar Kartikeya Dwivedi for (i = start_idx; i < log->cnt; i++) { 2289d63284e6SKumar Kartikeya Dwivedi event = &log->events[log_pos(log, i)]; 2290d63284e6SKumar Kartikeya Dwivedi if (!diag_history_event_visible(event, &filter)) 2291d63284e6SKumar Kartikeya Dwivedi continue; 2292d63284e6SKumar Kartikeya Dwivedi 2293d63284e6SKumar Kartikeya Dwivedi diag_fmt_restore(env, mark); 2294d63284e6SKumar Kartikeya Dwivedi if (visible_cnt > BPF_DIAG_HISTORY_RENDER_MAX && 2295d63284e6SKumar Kartikeya Dwivedi visible_idx >= BPF_DIAG_HISTORY_RENDER_MAX / 2 && 2296d63284e6SKumar Kartikeya Dwivedi visible_idx < visible_cnt - BPF_DIAG_HISTORY_RENDER_MAX / 2) { 2297d63284e6SKumar Kartikeya Dwivedi if (visible_idx++ != BPF_DIAG_HISTORY_RENDER_MAX / 2) 2298d63284e6SKumar Kartikeya Dwivedi continue; 2299d63284e6SKumar Kartikeya Dwivedi if (!first) 2300d63284e6SKumar Kartikeya Dwivedi diag_write(env, "\n"); 2301d63284e6SKumar Kartikeya Dwivedi first = false; 2302d63284e6SKumar Kartikeya Dwivedi diag_write(env, " %u intermediate causal-history events omitted\n", 2303d63284e6SKumar Kartikeya Dwivedi visible_cnt - BPF_DIAG_HISTORY_RENDER_MAX); 2304d63284e6SKumar Kartikeya Dwivedi continue; 2305d63284e6SKumar Kartikeya Dwivedi } 2306d63284e6SKumar Kartikeya Dwivedi visible_idx++; 2307d63284e6SKumar Kartikeya Dwivedi 2308d63284e6SKumar Kartikeya Dwivedi if (!first) 2309d63284e6SKumar Kartikeya Dwivedi diag_write(env, "\n"); 2310d63284e6SKumar Kartikeya Dwivedi first = false; 2311d63284e6SKumar Kartikeya Dwivedi 2312d63284e6SKumar Kartikeya Dwivedi switch (event->kind) { 2313d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_HISTORY_BRANCH: 2314d63284e6SKumar Kartikeya Dwivedi bpf_diag_source(env, event->insn_idx, "branch", 2315d63284e6SKumar Kartikeya Dwivedi "took the %s branch of this conditional, goto %s", 2316d63284e6SKumar Kartikeya Dwivedi event->branch.cond_true ? "true" : "false", 2317d63284e6SKumar Kartikeya Dwivedi event->branch.cond_true ? "followed" : "not followed"); 2318d63284e6SKumar Kartikeya Dwivedi break; 2319d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_HISTORY_MOD: 2320d63284e6SKumar Kartikeya Dwivedi diag_print_mod(env, event); 2321d63284e6SKumar Kartikeya Dwivedi break; 2322d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_HISTORY_REF_ACQUIRE: 2323d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_HISTORY_REF_RELEASE: 2324d63284e6SKumar Kartikeya Dwivedi diag_print_ref_event(env, event); 2325d63284e6SKumar Kartikeya Dwivedi break; 2326d63284e6SKumar Kartikeya Dwivedi case BPF_DIAG_HISTORY_CONTEXT: 2327d63284e6SKumar Kartikeya Dwivedi diag_print_context_event(env, event); 2328d63284e6SKumar Kartikeya Dwivedi break; 2329d63284e6SKumar Kartikeya Dwivedi default: 2330d63284e6SKumar Kartikeya Dwivedi break; 2331d63284e6SKumar Kartikeya Dwivedi } 2332d63284e6SKumar Kartikeya Dwivedi } 2333d63284e6SKumar Kartikeya Dwivedi 2334d63284e6SKumar Kartikeya Dwivedi if (!visible_cnt) 2335d63284e6SKumar Kartikeya Dwivedi diag_write(env, " no retained diagnostic events on this path\n"); 2336d63284e6SKumar Kartikeya Dwivedi if (log->first_seq) 2337d63284e6SKumar Kartikeya Dwivedi diag_write(env, " %llu older causal-history event%s not retained because diagnostic " 2338d63284e6SKumar Kartikeya Dwivedi "event storage reached capacity\n", 2339d63284e6SKumar Kartikeya Dwivedi log->first_seq, log->first_seq == 1 ? "" : "s"); 2340d63284e6SKumar Kartikeya Dwivedi diag_fmt_restore(env, mark); 2341d63284e6SKumar Kartikeya Dwivedi } 2342