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> 11b9c5d822SKumar Kartikeya Dwivedi #include <linux/slab.h> 125ad74616SKumar Kartikeya Dwivedi #include <linux/stdarg.h> 13b9c5d822SKumar Kartikeya Dwivedi #include <linux/string.h> 145ad74616SKumar Kartikeya Dwivedi 15b9c5d822SKumar Kartikeya Dwivedi #include "disasm.h" 165ad74616SKumar Kartikeya Dwivedi #include "diagnostics.h" 175ad74616SKumar Kartikeya Dwivedi 18b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_TEXT_WIDTH 100 19b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_CONTEXT 2 20b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_CONTEXT_CNT (1 + BPF_DIAG_CONTEXT * 2) 21b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_SOURCE_LANE_WIDTH 88 22b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_TAB_WIDTH 8 23b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_FMT_CHUNK_SIZE (PAGE_SIZE - sizeof(struct diag_fmt_chunk)) 24b9c5d822SKumar Kartikeya Dwivedi #define BPF_DIAG_FMT_BUF_SIZE 256 25daf82487SKumar Kartikeya Dwivedi #define BPF_DIAG_EVENT_LOG_MAX_SIZE (64U << 20) 26b9c5d822SKumar Kartikeya Dwivedi #define DISASM_LINE_LEN 160 27b9c5d822SKumar Kartikeya Dwivedi 28af4ea6e2SKumar Kartikeya Dwivedi enum bpf_diag_mod_target_kind { 29af4ea6e2SKumar Kartikeya Dwivedi BPF_DIAG_MOD_TARGET_NONE, 30af4ea6e2SKumar Kartikeya Dwivedi BPF_DIAG_MOD_TARGET_REG, 31af4ea6e2SKumar Kartikeya Dwivedi BPF_DIAG_MOD_TARGET_STACK_ARG, 32af4ea6e2SKumar Kartikeya Dwivedi BPF_DIAG_MOD_TARGET_STACK_SLOT, 33af4ea6e2SKumar Kartikeya Dwivedi BPF_DIAG_MOD_TARGET_STACK_RANGE, 34af4ea6e2SKumar Kartikeya Dwivedi }; 35af4ea6e2SKumar Kartikeya Dwivedi 36af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_target { 37af4ea6e2SKumar Kartikeya Dwivedi u32 frame_id; 38af4ea6e2SKumar Kartikeya Dwivedi union { 39af4ea6e2SKumar Kartikeya Dwivedi struct { 40af4ea6e2SKumar Kartikeya Dwivedi s16 min_off; 41af4ea6e2SKumar Kartikeya Dwivedi s16 max_off; 42af4ea6e2SKumar Kartikeya Dwivedi } range; 43af4ea6e2SKumar Kartikeya Dwivedi u16 spi; 44af4ea6e2SKumar Kartikeya Dwivedi u8 regno; 45af4ea6e2SKumar Kartikeya Dwivedi u8 stack_arg; 46af4ea6e2SKumar Kartikeya Dwivedi }; 47af4ea6e2SKumar Kartikeya Dwivedi u8 frameno; 48af4ea6e2SKumar Kartikeya Dwivedi u8 kind; 49af4ea6e2SKumar Kartikeya Dwivedi }; 50af4ea6e2SKumar Kartikeya Dwivedi 51af4ea6e2SKumar Kartikeya Dwivedi static struct bpf_diag_mod_target diag_reg_target(u32 frame_id, u8 frameno, u8 regno) 52af4ea6e2SKumar Kartikeya Dwivedi { 53af4ea6e2SKumar Kartikeya Dwivedi return (struct bpf_diag_mod_target){ 54af4ea6e2SKumar Kartikeya Dwivedi .frame_id = frame_id, 55af4ea6e2SKumar Kartikeya Dwivedi .frameno = frameno, 56af4ea6e2SKumar Kartikeya Dwivedi .kind = BPF_DIAG_MOD_TARGET_REG, 57af4ea6e2SKumar Kartikeya Dwivedi .regno = regno, 58af4ea6e2SKumar Kartikeya Dwivedi }; 59af4ea6e2SKumar Kartikeya Dwivedi } 60af4ea6e2SKumar Kartikeya Dwivedi 61af4ea6e2SKumar Kartikeya Dwivedi static struct bpf_diag_mod_target diag_stack_arg_target(u32 frame_id, u8 frameno, u8 slot) 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_STACK_ARG, 67af4ea6e2SKumar Kartikeya Dwivedi .stack_arg = slot, 68af4ea6e2SKumar Kartikeya Dwivedi }; 69af4ea6e2SKumar Kartikeya Dwivedi } 70af4ea6e2SKumar Kartikeya Dwivedi 71af4ea6e2SKumar Kartikeya Dwivedi static struct bpf_diag_mod_target diag_stack_slot_target(u32 frame_id, u8 frameno, u16 spi) 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_SLOT, 77af4ea6e2SKumar Kartikeya Dwivedi .spi = spi, 78af4ea6e2SKumar Kartikeya Dwivedi }; 79af4ea6e2SKumar Kartikeya Dwivedi } 80af4ea6e2SKumar Kartikeya Dwivedi 81af4ea6e2SKumar Kartikeya Dwivedi static struct bpf_diag_mod_target diag_stack_range_target(u32 frame_id, u8 frameno, 82af4ea6e2SKumar Kartikeya Dwivedi s16 min_off, s16 max_off) 83af4ea6e2SKumar Kartikeya Dwivedi { 84af4ea6e2SKumar Kartikeya Dwivedi return (struct bpf_diag_mod_target){ 85af4ea6e2SKumar Kartikeya Dwivedi .frame_id = frame_id, 86af4ea6e2SKumar Kartikeya Dwivedi .frameno = frameno, 87af4ea6e2SKumar Kartikeya Dwivedi .kind = BPF_DIAG_MOD_TARGET_STACK_RANGE, 88af4ea6e2SKumar Kartikeya Dwivedi .range.min_off = min_off, 89af4ea6e2SKumar Kartikeya Dwivedi .range.max_off = max_off, 90af4ea6e2SKumar Kartikeya Dwivedi }; 91af4ea6e2SKumar Kartikeya Dwivedi } 92af4ea6e2SKumar Kartikeya Dwivedi 93af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_reg_snapshot { 94af4ea6e2SKumar Kartikeya Dwivedi u32 type; 95af4ea6e2SKumar Kartikeya Dwivedi u32 btf_id; 96af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_map *map_ptr; 97af4ea6e2SKumar Kartikeya Dwivedi const struct btf *btf; 98af4ea6e2SKumar Kartikeya Dwivedi struct tnum var_off; 99af4ea6e2SKumar Kartikeya Dwivedi struct cnum64 r64; 100af4ea6e2SKumar Kartikeya Dwivedi }; 101af4ea6e2SKumar Kartikeya Dwivedi 102daf82487SKumar Kartikeya Dwivedi enum bpf_diag_history_kind { 103daf82487SKumar Kartikeya Dwivedi BPF_DIAG_HISTORY_BRANCH, 104af4ea6e2SKumar Kartikeya Dwivedi BPF_DIAG_HISTORY_MOD, 1059ecd7030SKumar Kartikeya Dwivedi BPF_DIAG_HISTORY_REF_ACQUIRE, 1069ecd7030SKumar Kartikeya Dwivedi BPF_DIAG_HISTORY_REF_RELEASE, 107*956a66e5SKumar Kartikeya Dwivedi BPF_DIAG_HISTORY_CONTEXT, 108daf82487SKumar Kartikeya Dwivedi }; 109daf82487SKumar Kartikeya Dwivedi 110daf82487SKumar Kartikeya Dwivedi struct bpf_diag_history_event { 111daf82487SKumar Kartikeya Dwivedi u32 insn_idx : 24; 112daf82487SKumar Kartikeya Dwivedi u32 kind : 8; 113daf82487SKumar Kartikeya Dwivedi u8 in_lineage : 1; 114daf82487SKumar Kartikeya Dwivedi union { 115daf82487SKumar Kartikeya Dwivedi struct { 116daf82487SKumar Kartikeya Dwivedi bool cond_true; 117daf82487SKumar Kartikeya Dwivedi } branch; 118af4ea6e2SKumar Kartikeya Dwivedi struct { 119af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_target target; 120af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_target origin; 121af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_reg_snapshot old, new; 122af4ea6e2SKumar Kartikeya Dwivedi u8 reason; 123af4ea6e2SKumar Kartikeya Dwivedi bool origin_valid; 124af4ea6e2SKumar Kartikeya Dwivedi } mod; 1259ecd7030SKumar Kartikeya Dwivedi struct { 1269ecd7030SKumar Kartikeya Dwivedi u32 ref_id; 1279ecd7030SKumar Kartikeya Dwivedi } ref; 128*956a66e5SKumar Kartikeya Dwivedi struct { 129*956a66e5SKumar Kartikeya Dwivedi u32 depth; 130*956a66e5SKumar Kartikeya Dwivedi u8 kind; 131*956a66e5SKumar Kartikeya Dwivedi bool enter; 132*956a66e5SKumar Kartikeya Dwivedi } ctx; 133daf82487SKumar Kartikeya Dwivedi }; 134daf82487SKumar Kartikeya Dwivedi }; 135daf82487SKumar Kartikeya Dwivedi 136b9c5d822SKumar Kartikeya Dwivedi struct disasm_line { 137b9c5d822SKumar Kartikeya Dwivedi char text[DISASM_LINE_LEN]; 138b9c5d822SKumar Kartikeya Dwivedi int idx; 139b9c5d822SKumar Kartikeya Dwivedi bool valid; 140b9c5d822SKumar Kartikeya Dwivedi }; 141b9c5d822SKumar Kartikeya Dwivedi 142b9c5d822SKumar Kartikeya Dwivedi struct disasm_ctx { 143b9c5d822SKumar Kartikeya Dwivedi struct bpf_verifier_env *env; 144b9c5d822SKumar Kartikeya Dwivedi struct seq_buf seq; 145b9c5d822SKumar Kartikeya Dwivedi }; 146b9c5d822SKumar Kartikeya Dwivedi 147b9c5d822SKumar Kartikeya Dwivedi struct diag_fmt_chunk { 148b9c5d822SKumar Kartikeya Dwivedi struct list_head node; 149b9c5d822SKumar Kartikeya Dwivedi struct seq_buf seq; 150b9c5d822SKumar Kartikeya Dwivedi char data[]; 151b9c5d822SKumar Kartikeya Dwivedi }; 152b9c5d822SKumar Kartikeya Dwivedi 153b9c5d822SKumar Kartikeya Dwivedi struct diag_fmt_mark { 154b9c5d822SKumar Kartikeya Dwivedi struct diag_fmt_chunk *chunk; 155b9c5d822SKumar Kartikeya Dwivedi size_t len; 156b9c5d822SKumar Kartikeya Dwivedi }; 157b9c5d822SKumar Kartikeya Dwivedi 158daf82487SKumar Kartikeya Dwivedi struct bpf_diag_log { 159daf82487SKumar Kartikeya Dwivedi struct bpf_diag_history_event *events; 160daf82487SKumar Kartikeya Dwivedi /* Sequence number of the oldest retained event on the active path. */ 161daf82487SKumar Kartikeya Dwivedi u64 first_seq; 162daf82487SKumar Kartikeya Dwivedi u32 cnt; 163daf82487SKumar Kartikeya Dwivedi u32 cap; 164daf82487SKumar Kartikeya Dwivedi u32 head; 165daf82487SKumar Kartikeya Dwivedi bool growth_failed; 166daf82487SKumar Kartikeya Dwivedi }; 167daf82487SKumar Kartikeya Dwivedi 168b9c5d822SKumar Kartikeya Dwivedi struct bpf_diag_scratch { 169b9c5d822SKumar Kartikeya Dwivedi struct bpf_linfo_source source_lines[BPF_DIAG_CONTEXT_CNT]; 170b9c5d822SKumar Kartikeya Dwivedi struct disasm_line disasm_lines[BPF_DIAG_CONTEXT_CNT]; 171b9c5d822SKumar Kartikeya Dwivedi }; 172b9c5d822SKumar Kartikeya Dwivedi 173af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_scope { 174af4ea6e2SKumar Kartikeya Dwivedi struct bpf_reg_state target_reg_snapshot; 175af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_target target; 176af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_target origin; 177af4ea6e2SKumar Kartikeya Dwivedi enum bpf_diag_mod_reason reason; 178af4ea6e2SKumar Kartikeya Dwivedi u32 insn_idx; 179af4ea6e2SKumar Kartikeya Dwivedi bool active; 180af4ea6e2SKumar Kartikeya Dwivedi bool origin_valid; 181af4ea6e2SKumar Kartikeya Dwivedi }; 182af4ea6e2SKumar Kartikeya Dwivedi 183b9c5d822SKumar Kartikeya Dwivedi struct bpf_diag { 184daf82487SKumar Kartikeya Dwivedi struct bpf_diag_log log; 185b9c5d822SKumar Kartikeya Dwivedi struct bpf_diag_scratch scratch; 186b9c5d822SKumar Kartikeya Dwivedi struct list_head fmt_chunks; 187af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_scope mod; 188af4ea6e2SKumar Kartikeya Dwivedi u32 frame_id_gen; 189b9c5d822SKumar Kartikeya Dwivedi }; 190b9c5d822SKumar Kartikeya Dwivedi 1915ad74616SKumar Kartikeya Dwivedi bool bpf_diag_enabled(const struct bpf_verifier_env *env) 1925ad74616SKumar Kartikeya Dwivedi { 1935ad74616SKumar Kartikeya Dwivedi return env->log.level & BPF_LOG_LEVEL; 1945ad74616SKumar Kartikeya Dwivedi } 1955ad74616SKumar Kartikeya Dwivedi 1965ad74616SKumar Kartikeya Dwivedi static void diag_write(struct bpf_verifier_env *env, const char *fmt, ...) __printf(2, 3); 1975ad74616SKumar Kartikeya Dwivedi 198b9c5d822SKumar Kartikeya Dwivedi int bpf_diag_init(struct bpf_verifier_env *env) 199b9c5d822SKumar Kartikeya Dwivedi { 200b9c5d822SKumar Kartikeya Dwivedi if (!bpf_diag_enabled(env)) 201b9c5d822SKumar Kartikeya Dwivedi return 0; 202b9c5d822SKumar Kartikeya Dwivedi 203b9c5d822SKumar Kartikeya Dwivedi env->diag = kzalloc_obj(struct bpf_diag, GFP_KERNEL_ACCOUNT); 204b9c5d822SKumar Kartikeya Dwivedi if (!env->diag) 205b9c5d822SKumar Kartikeya Dwivedi return -ENOMEM; 206b9c5d822SKumar Kartikeya Dwivedi 207b9c5d822SKumar Kartikeya Dwivedi INIT_LIST_HEAD(&env->diag->fmt_chunks); 208b9c5d822SKumar Kartikeya Dwivedi return 0; 209b9c5d822SKumar Kartikeya Dwivedi } 210b9c5d822SKumar Kartikeya Dwivedi 211af4ea6e2SKumar Kartikeya Dwivedi void bpf_diag_init_frame(struct bpf_verifier_env *env, struct bpf_func_state *state) 212af4ea6e2SKumar Kartikeya Dwivedi { 213af4ea6e2SKumar Kartikeya Dwivedi if (env->diag) 214af4ea6e2SKumar Kartikeya Dwivedi state->diag_frame_id = ++env->diag->frame_id_gen; 215af4ea6e2SKumar Kartikeya Dwivedi } 216af4ea6e2SKumar Kartikeya Dwivedi 217b9c5d822SKumar Kartikeya Dwivedi static char *diag_fmt_alloc(struct bpf_verifier_env *env, size_t size) 218b9c5d822SKumar Kartikeya Dwivedi { 219b9c5d822SKumar Kartikeya Dwivedi struct bpf_diag *diag = env->diag; 220b9c5d822SKumar Kartikeya Dwivedi struct diag_fmt_chunk *chunk; 221b9c5d822SKumar Kartikeya Dwivedi size_t capacity, available; 222b9c5d822SKumar Kartikeya Dwivedi char *buf; 223b9c5d822SKumar Kartikeya Dwivedi 224b9c5d822SKumar Kartikeya Dwivedi if (!diag || !size || size > INT_MAX) 225b9c5d822SKumar Kartikeya Dwivedi return NULL; 226b9c5d822SKumar Kartikeya Dwivedi 227b9c5d822SKumar Kartikeya Dwivedi if (!list_empty(&diag->fmt_chunks)) { 228b9c5d822SKumar Kartikeya Dwivedi chunk = list_last_entry(&diag->fmt_chunks, struct diag_fmt_chunk, node); 229b9c5d822SKumar Kartikeya Dwivedi available = seq_buf_get_buf(&chunk->seq, &buf); 230b9c5d822SKumar Kartikeya Dwivedi if (available >= size) 231b9c5d822SKumar Kartikeya Dwivedi goto commit; 232b9c5d822SKumar Kartikeya Dwivedi } 233b9c5d822SKumar Kartikeya Dwivedi 234b9c5d822SKumar Kartikeya Dwivedi capacity = max_t(size_t, BPF_DIAG_FMT_CHUNK_SIZE, size); 235b9c5d822SKumar Kartikeya Dwivedi chunk = kmalloc(struct_size(chunk, data, capacity), GFP_KERNEL_ACCOUNT); 236b9c5d822SKumar Kartikeya Dwivedi if (!chunk) 237b9c5d822SKumar Kartikeya Dwivedi return NULL; 238b9c5d822SKumar Kartikeya Dwivedi 239b9c5d822SKumar Kartikeya Dwivedi seq_buf_init(&chunk->seq, chunk->data, capacity); 240b9c5d822SKumar Kartikeya Dwivedi list_add_tail(&chunk->node, &diag->fmt_chunks); 241b9c5d822SKumar Kartikeya Dwivedi available = seq_buf_get_buf(&chunk->seq, &buf); 242b9c5d822SKumar Kartikeya Dwivedi if (WARN_ON_ONCE(available < size)) 243b9c5d822SKumar Kartikeya Dwivedi return NULL; 244b9c5d822SKumar Kartikeya Dwivedi 245b9c5d822SKumar Kartikeya Dwivedi commit: 246b9c5d822SKumar Kartikeya Dwivedi seq_buf_commit(&chunk->seq, size); 247b9c5d822SKumar Kartikeya Dwivedi return buf; 248b9c5d822SKumar Kartikeya Dwivedi } 249b9c5d822SKumar Kartikeya Dwivedi 250b9c5d822SKumar Kartikeya Dwivedi char *bpf_diag_fmt_buf(struct bpf_verifier_env *env, size_t size) 251b9c5d822SKumar Kartikeya Dwivedi { 252b9c5d822SKumar Kartikeya Dwivedi char *buf; 253b9c5d822SKumar Kartikeya Dwivedi 254b9c5d822SKumar Kartikeya Dwivedi buf = diag_fmt_alloc(env, size); 255b9c5d822SKumar Kartikeya Dwivedi if (buf) 256b9c5d822SKumar Kartikeya Dwivedi buf[0] = '\0'; 257b9c5d822SKumar Kartikeya Dwivedi return buf; 258b9c5d822SKumar Kartikeya Dwivedi } 259b9c5d822SKumar Kartikeya Dwivedi 260b9c5d822SKumar Kartikeya Dwivedi const char *bpf_diag_vfmt(struct bpf_verifier_env *env, const char *fmt, va_list args) 261b9c5d822SKumar Kartikeya Dwivedi { 262b9c5d822SKumar Kartikeya Dwivedi va_list copy; 263b9c5d822SKumar Kartikeya Dwivedi char *buf; 264b9c5d822SKumar Kartikeya Dwivedi int len; 265b9c5d822SKumar Kartikeya Dwivedi 266b9c5d822SKumar Kartikeya Dwivedi va_copy(copy, args); 267b9c5d822SKumar Kartikeya Dwivedi len = vsnprintf(NULL, 0, fmt, copy); 268b9c5d822SKumar Kartikeya Dwivedi va_end(copy); 269b9c5d822SKumar Kartikeya Dwivedi if (len < 0 || len == INT_MAX) 270b9c5d822SKumar Kartikeya Dwivedi return ""; 271b9c5d822SKumar Kartikeya Dwivedi 272b9c5d822SKumar Kartikeya Dwivedi buf = diag_fmt_alloc(env, len + 1); 273b9c5d822SKumar Kartikeya Dwivedi if (buf) 274b9c5d822SKumar Kartikeya Dwivedi vsnprintf(buf, len + 1, fmt, args); 275b9c5d822SKumar Kartikeya Dwivedi return buf ?: ""; 276b9c5d822SKumar Kartikeya Dwivedi } 277b9c5d822SKumar Kartikeya Dwivedi 278b9c5d822SKumar Kartikeya Dwivedi const char *bpf_diag_fmt(struct bpf_verifier_env *env, const char *fmt, ...) 279b9c5d822SKumar Kartikeya Dwivedi { 280b9c5d822SKumar Kartikeya Dwivedi const char *buf; 281b9c5d822SKumar Kartikeya Dwivedi va_list args; 282b9c5d822SKumar Kartikeya Dwivedi 283b9c5d822SKumar Kartikeya Dwivedi va_start(args, fmt); 284b9c5d822SKumar Kartikeya Dwivedi buf = bpf_diag_vfmt(env, fmt, args); 285b9c5d822SKumar Kartikeya Dwivedi va_end(args); 286b9c5d822SKumar Kartikeya Dwivedi return buf; 287b9c5d822SKumar Kartikeya Dwivedi } 288b9c5d822SKumar Kartikeya Dwivedi 289b9c5d822SKumar Kartikeya Dwivedi static struct diag_fmt_mark diag_fmt_save(struct bpf_verifier_env *env) 290b9c5d822SKumar Kartikeya Dwivedi { 291b9c5d822SKumar Kartikeya Dwivedi struct bpf_diag *diag = env->diag; 292b9c5d822SKumar Kartikeya Dwivedi struct diag_fmt_mark mark = {}; 293b9c5d822SKumar Kartikeya Dwivedi 294b9c5d822SKumar Kartikeya Dwivedi if (!diag || list_empty(&diag->fmt_chunks)) 295b9c5d822SKumar Kartikeya Dwivedi return mark; 296b9c5d822SKumar Kartikeya Dwivedi 297b9c5d822SKumar Kartikeya Dwivedi mark.chunk = list_last_entry(&diag->fmt_chunks, struct diag_fmt_chunk, node); 298b9c5d822SKumar Kartikeya Dwivedi mark.len = mark.chunk->seq.len; 299b9c5d822SKumar Kartikeya Dwivedi return mark; 300b9c5d822SKumar Kartikeya Dwivedi } 301b9c5d822SKumar Kartikeya Dwivedi 302b9c5d822SKumar Kartikeya Dwivedi static void diag_fmt_restore(struct bpf_verifier_env *env, struct diag_fmt_mark mark) 303b9c5d822SKumar Kartikeya Dwivedi { 304b9c5d822SKumar Kartikeya Dwivedi struct bpf_diag *diag = env->diag; 305b9c5d822SKumar Kartikeya Dwivedi struct diag_fmt_chunk *chunk; 306b9c5d822SKumar Kartikeya Dwivedi 307b9c5d822SKumar Kartikeya Dwivedi if (!diag) 308b9c5d822SKumar Kartikeya Dwivedi return; 309b9c5d822SKumar Kartikeya Dwivedi 310b9c5d822SKumar Kartikeya Dwivedi while (!list_empty(&diag->fmt_chunks)) { 311b9c5d822SKumar Kartikeya Dwivedi chunk = list_last_entry(&diag->fmt_chunks, struct diag_fmt_chunk, node); 312b9c5d822SKumar Kartikeya Dwivedi if (chunk == mark.chunk) 313b9c5d822SKumar Kartikeya Dwivedi break; 314b9c5d822SKumar Kartikeya Dwivedi list_del(&chunk->node); 315b9c5d822SKumar Kartikeya Dwivedi kfree(chunk); 316b9c5d822SKumar Kartikeya Dwivedi } 317b9c5d822SKumar Kartikeya Dwivedi 318b9c5d822SKumar Kartikeya Dwivedi if (mark.chunk) { 319b9c5d822SKumar Kartikeya Dwivedi mark.chunk->seq.len = mark.len; 320b9c5d822SKumar Kartikeya Dwivedi seq_buf_str(&mark.chunk->seq); 321b9c5d822SKumar Kartikeya Dwivedi } 322b9c5d822SKumar Kartikeya Dwivedi } 323b9c5d822SKumar Kartikeya Dwivedi 324b9c5d822SKumar Kartikeya Dwivedi void bpf_diag_free(struct bpf_verifier_env *env) 325b9c5d822SKumar Kartikeya Dwivedi { 326b9c5d822SKumar Kartikeya Dwivedi struct bpf_diag *diag = env->diag; 327b9c5d822SKumar Kartikeya Dwivedi 328b9c5d822SKumar Kartikeya Dwivedi if (!diag) 329b9c5d822SKumar Kartikeya Dwivedi return; 330b9c5d822SKumar Kartikeya Dwivedi 331b9c5d822SKumar Kartikeya Dwivedi diag_fmt_restore(env, (struct diag_fmt_mark){}); 332daf82487SKumar Kartikeya Dwivedi kvfree(diag->log.events); 333b9c5d822SKumar Kartikeya Dwivedi kfree(diag); 334b9c5d822SKumar Kartikeya Dwivedi env->diag = NULL; 335b9c5d822SKumar Kartikeya Dwivedi } 336b9c5d822SKumar Kartikeya Dwivedi 3375ad74616SKumar Kartikeya Dwivedi static void diag_write(struct bpf_verifier_env *env, const char *fmt, ...) 3385ad74616SKumar Kartikeya Dwivedi { 3395ad74616SKumar Kartikeya Dwivedi va_list args; 3405ad74616SKumar Kartikeya Dwivedi 3415ad74616SKumar Kartikeya Dwivedi if (!bpf_diag_enabled(env)) 3425ad74616SKumar Kartikeya Dwivedi return; 3435ad74616SKumar Kartikeya Dwivedi 3445ad74616SKumar Kartikeya Dwivedi va_start(args, fmt); 3455ad74616SKumar Kartikeya Dwivedi bpf_verifier_vlog(&env->log, fmt, args); 3465ad74616SKumar Kartikeya Dwivedi va_end(args); 3475ad74616SKumar Kartikeya Dwivedi } 3485ad74616SKumar Kartikeya Dwivedi 349daf82487SKumar Kartikeya Dwivedi static u64 log_end(const struct bpf_diag_log *log) 350daf82487SKumar Kartikeya Dwivedi { 351daf82487SKumar Kartikeya Dwivedi return log->first_seq + log->cnt; 352daf82487SKumar Kartikeya Dwivedi } 353daf82487SKumar Kartikeya Dwivedi 354daf82487SKumar Kartikeya Dwivedi static u32 log_pos(const struct bpf_diag_log *log, u32 idx) 355daf82487SKumar Kartikeya Dwivedi { 356daf82487SKumar Kartikeya Dwivedi u32 pos = log->head + idx; 357daf82487SKumar Kartikeya Dwivedi 358daf82487SKumar Kartikeya Dwivedi return pos < log->cap ? pos : pos - log->cap; 359daf82487SKumar Kartikeya Dwivedi } 360daf82487SKumar Kartikeya Dwivedi 361daf82487SKumar Kartikeya Dwivedi u64 bpf_diag_event_log_save(struct bpf_verifier_env *env) 362daf82487SKumar Kartikeya Dwivedi { 363daf82487SKumar Kartikeya Dwivedi struct bpf_diag *diag = env->diag; 364daf82487SKumar Kartikeya Dwivedi 365daf82487SKumar Kartikeya Dwivedi return diag ? log_end(&diag->log) : 0; 366daf82487SKumar Kartikeya Dwivedi } 367daf82487SKumar Kartikeya Dwivedi 368daf82487SKumar Kartikeya Dwivedi void bpf_diag_event_log_restore(struct bpf_verifier_env *env, u64 log_pos) 369daf82487SKumar Kartikeya Dwivedi { 370daf82487SKumar Kartikeya Dwivedi struct bpf_diag *diag = env->diag; 371daf82487SKumar Kartikeya Dwivedi struct bpf_diag_log *log; 372daf82487SKumar Kartikeya Dwivedi u64 end_seq; 373daf82487SKumar Kartikeya Dwivedi 374daf82487SKumar Kartikeya Dwivedi if (!diag) 375daf82487SKumar Kartikeya Dwivedi return; 376daf82487SKumar Kartikeya Dwivedi 377daf82487SKumar Kartikeya Dwivedi log = &diag->log; 378daf82487SKumar Kartikeya Dwivedi end_seq = log_end(log); 379daf82487SKumar Kartikeya Dwivedi if (WARN_ON_ONCE(log_pos > end_seq)) 380daf82487SKumar Kartikeya Dwivedi log_pos = end_seq; 381daf82487SKumar Kartikeya Dwivedi 382daf82487SKumar Kartikeya Dwivedi /* 383daf82487SKumar Kartikeya Dwivedi * A deep abandoned path may have rotated away the shared prefix. In 384daf82487SKumar Kartikeya Dwivedi * that case, restart with an empty retained suffix and remember that 385daf82487SKumar Kartikeya Dwivedi * every event before the restored mark is unavailable. 386daf82487SKumar Kartikeya Dwivedi */ 387daf82487SKumar Kartikeya Dwivedi if (log_pos <= log->first_seq) { 388daf82487SKumar Kartikeya Dwivedi log->first_seq = log_pos; 389daf82487SKumar Kartikeya Dwivedi log->head = 0; 390daf82487SKumar Kartikeya Dwivedi log->cnt = 0; 391daf82487SKumar Kartikeya Dwivedi return; 392daf82487SKumar Kartikeya Dwivedi } 393daf82487SKumar Kartikeya Dwivedi 394daf82487SKumar Kartikeya Dwivedi log->cnt = log_pos - log->first_seq; 395daf82487SKumar Kartikeya Dwivedi } 396daf82487SKumar Kartikeya Dwivedi 397*956a66e5SKumar Kartikeya Dwivedi u32 bpf_diag_irq_depth(const struct bpf_verifier_state *state) 398*956a66e5SKumar Kartikeya Dwivedi { 399*956a66e5SKumar Kartikeya Dwivedi u32 depth = 0; 400*956a66e5SKumar Kartikeya Dwivedi int i; 401*956a66e5SKumar Kartikeya Dwivedi 402*956a66e5SKumar Kartikeya Dwivedi for (i = 0; i < state->acquired_refs; i++) { 403*956a66e5SKumar Kartikeya Dwivedi if (state->refs[i].type == REF_TYPE_IRQ) 404*956a66e5SKumar Kartikeya Dwivedi depth++; 405*956a66e5SKumar Kartikeya Dwivedi } 406*956a66e5SKumar Kartikeya Dwivedi 407*956a66e5SKumar Kartikeya Dwivedi return depth; 408*956a66e5SKumar Kartikeya Dwivedi } 409*956a66e5SKumar Kartikeya Dwivedi 410daf82487SKumar Kartikeya Dwivedi static void diag_append_history(struct bpf_verifier_env *env, 411daf82487SKumar Kartikeya Dwivedi const struct bpf_diag_history_event *event) 412daf82487SKumar Kartikeya Dwivedi { 413daf82487SKumar Kartikeya Dwivedi struct bpf_diag_history_event *events; 414daf82487SKumar Kartikeya Dwivedi struct bpf_diag *diag = env->diag; 415daf82487SKumar Kartikeya Dwivedi struct bpf_diag_log *log; 416daf82487SKumar Kartikeya Dwivedi u32 cap, max_events; 417daf82487SKumar Kartikeya Dwivedi 418daf82487SKumar Kartikeya Dwivedi if (!diag) 419daf82487SKumar Kartikeya Dwivedi return; 420daf82487SKumar Kartikeya Dwivedi log = &diag->log; 421daf82487SKumar Kartikeya Dwivedi 422daf82487SKumar Kartikeya Dwivedi if (log->cnt < log->cap) { 423daf82487SKumar Kartikeya Dwivedi log->events[log_pos(log, log->cnt++)] = *event; 424daf82487SKumar Kartikeya Dwivedi return; 425daf82487SKumar Kartikeya Dwivedi } 426daf82487SKumar Kartikeya Dwivedi 427daf82487SKumar Kartikeya Dwivedi max_events = BPF_DIAG_EVENT_LOG_MAX_SIZE / sizeof(*events); 428daf82487SKumar Kartikeya Dwivedi if (log->growth_failed || log->cap == max_events) 429daf82487SKumar Kartikeya Dwivedi goto rotate; 430daf82487SKumar Kartikeya Dwivedi 431daf82487SKumar Kartikeya Dwivedi cap = min(log->cap ? log->cap * 2 : 64, max_events); 432daf82487SKumar Kartikeya Dwivedi events = kvrealloc(log->events, array_size(cap, sizeof(*events)), GFP_KERNEL_ACCOUNT); 433daf82487SKumar Kartikeya Dwivedi if (!events) { 434daf82487SKumar Kartikeya Dwivedi log->growth_failed = true; 435daf82487SKumar Kartikeya Dwivedi goto rotate; 436daf82487SKumar Kartikeya Dwivedi } 437daf82487SKumar Kartikeya Dwivedi log->events = events; 438daf82487SKumar Kartikeya Dwivedi log->cap = cap; 439daf82487SKumar Kartikeya Dwivedi log->events[log->cnt++] = *event; 440daf82487SKumar Kartikeya Dwivedi return; 441daf82487SKumar Kartikeya Dwivedi 442daf82487SKumar Kartikeya Dwivedi rotate: 443daf82487SKumar Kartikeya Dwivedi if (log->cap) { 444daf82487SKumar Kartikeya Dwivedi log->events[log->head++] = *event; 445daf82487SKumar Kartikeya Dwivedi if (log->head == log->cap) 446daf82487SKumar Kartikeya Dwivedi log->head = 0; 447daf82487SKumar Kartikeya Dwivedi } 448daf82487SKumar Kartikeya Dwivedi log->first_seq++; 449daf82487SKumar Kartikeya Dwivedi } 450daf82487SKumar Kartikeya Dwivedi 451b9c5d822SKumar Kartikeya Dwivedi static void diag_print_wrapped_prefixed(struct bpf_verifier_env *env, const char *first_prefix, 452b9c5d822SKumar Kartikeya Dwivedi const char *next_prefix, const char *text) 453b9c5d822SKumar Kartikeya Dwivedi { 454b9c5d822SKumar Kartikeya Dwivedi const char *prefix = first_prefix; 455b9c5d822SKumar Kartikeya Dwivedi 456b9c5d822SKumar Kartikeya Dwivedi while (*text) { 457b9c5d822SKumar Kartikeya Dwivedi const char *line = text; 458b9c5d822SKumar Kartikeya Dwivedi int prefix_len = strlen(prefix); 459b9c5d822SKumar Kartikeya Dwivedi int text_width = BPF_DIAG_TEXT_WIDTH - prefix_len; 460b9c5d822SKumar Kartikeya Dwivedi int len = 0, last_space = -1; 461b9c5d822SKumar Kartikeya Dwivedi 462b9c5d822SKumar Kartikeya Dwivedi if (text_width < 1) 463b9c5d822SKumar Kartikeya Dwivedi text_width = 1; 464b9c5d822SKumar Kartikeya Dwivedi 465b9c5d822SKumar Kartikeya Dwivedi while (line[len] && line[len] != '\n' && len < text_width) { 466b9c5d822SKumar Kartikeya Dwivedi if (line[len] == ' ') 467b9c5d822SKumar Kartikeya Dwivedi last_space = len; 468b9c5d822SKumar Kartikeya Dwivedi len++; 469b9c5d822SKumar Kartikeya Dwivedi } 470b9c5d822SKumar Kartikeya Dwivedi 471b9c5d822SKumar Kartikeya Dwivedi if (line[len] && line[len] != '\n' && line[len] != ' ' && last_space > 0) 472b9c5d822SKumar Kartikeya Dwivedi len = last_space; 473b9c5d822SKumar Kartikeya Dwivedi 474b9c5d822SKumar Kartikeya Dwivedi diag_write(env, "%s%.*s\n", prefix, len, line); 475b9c5d822SKumar Kartikeya Dwivedi 476b9c5d822SKumar Kartikeya Dwivedi text = line + len; 477b9c5d822SKumar Kartikeya Dwivedi while (*text == ' ') 478b9c5d822SKumar Kartikeya Dwivedi text++; 479b9c5d822SKumar Kartikeya Dwivedi if (*text == '\n') 480b9c5d822SKumar Kartikeya Dwivedi text++; 481b9c5d822SKumar Kartikeya Dwivedi 482b9c5d822SKumar Kartikeya Dwivedi prefix = next_prefix; 483b9c5d822SKumar Kartikeya Dwivedi } 484b9c5d822SKumar Kartikeya Dwivedi } 485b9c5d822SKumar Kartikeya Dwivedi 486af4ea6e2SKumar Kartikeya Dwivedi const char *bpf_diag_fmt_btf_type(struct bpf_verifier_env *env, const struct btf *btf, u32 type_id) 487af4ea6e2SKumar Kartikeya Dwivedi { 488af4ea6e2SKumar Kartikeya Dwivedi char *buf = bpf_diag_fmt_buf(env, BPF_DIAG_FMT_BUF_SIZE); 489af4ea6e2SKumar Kartikeya Dwivedi size_t len; 490af4ea6e2SKumar Kartikeya Dwivedi int ret; 491af4ea6e2SKumar Kartikeya Dwivedi 492af4ea6e2SKumar Kartikeya Dwivedi if (!buf) 493af4ea6e2SKumar Kartikeya Dwivedi return ""; 494af4ea6e2SKumar Kartikeya Dwivedi 495af4ea6e2SKumar Kartikeya Dwivedi buf[0] = '\0'; 496af4ea6e2SKumar Kartikeya Dwivedi ret = btf_type_name_to_buf(btf, type_id, buf, BPF_DIAG_FMT_BUF_SIZE); 497af4ea6e2SKumar Kartikeya Dwivedi if (ret < 0 || !buf[0]) { 498af4ea6e2SKumar Kartikeya Dwivedi scnprintf(buf, BPF_DIAG_FMT_BUF_SIZE, "BTF type ID %u", type_id); 499af4ea6e2SKumar Kartikeya Dwivedi return buf; 500af4ea6e2SKumar Kartikeya Dwivedi } 501af4ea6e2SKumar Kartikeya Dwivedi 502af4ea6e2SKumar Kartikeya Dwivedi len = strlen(buf); 503af4ea6e2SKumar Kartikeya Dwivedi if (len && buf[len - 1] == '{') 504af4ea6e2SKumar Kartikeya Dwivedi buf[len - 1] = '\0'; 505af4ea6e2SKumar Kartikeya Dwivedi return buf; 506af4ea6e2SKumar Kartikeya Dwivedi } 507af4ea6e2SKumar Kartikeya Dwivedi 508b9c5d822SKumar Kartikeya Dwivedi static int diag_line_width(unsigned int line) 509b9c5d822SKumar Kartikeya Dwivedi { 510b9c5d822SKumar Kartikeya Dwivedi int width = 1; 511b9c5d822SKumar Kartikeya Dwivedi 512b9c5d822SKumar Kartikeya Dwivedi while (line >= 10) { 513b9c5d822SKumar Kartikeya Dwivedi line /= 10; 514b9c5d822SKumar Kartikeya Dwivedi width++; 515b9c5d822SKumar Kartikeya Dwivedi } 516b9c5d822SKumar Kartikeya Dwivedi 517b9c5d822SKumar Kartikeya Dwivedi return width; 518b9c5d822SKumar Kartikeya Dwivedi } 519b9c5d822SKumar Kartikeya Dwivedi 520b9c5d822SKumar Kartikeya Dwivedi static int diag_line_indent(const char *line) 521b9c5d822SKumar Kartikeya Dwivedi { 522b9c5d822SKumar Kartikeya Dwivedi int indent = 0; 523b9c5d822SKumar Kartikeya Dwivedi 524b9c5d822SKumar Kartikeya Dwivedi while (*line == ' ' || *line == '\t') { 525b9c5d822SKumar Kartikeya Dwivedi if (*line == '\t') 526b9c5d822SKumar Kartikeya Dwivedi indent = round_up(indent + 1, BPF_DIAG_TAB_WIDTH); 527b9c5d822SKumar Kartikeya Dwivedi else 528b9c5d822SKumar Kartikeya Dwivedi indent++; 529b9c5d822SKumar Kartikeya Dwivedi line++; 530b9c5d822SKumar Kartikeya Dwivedi } 531b9c5d822SKumar Kartikeya Dwivedi 532b9c5d822SKumar Kartikeya Dwivedi return indent; 533b9c5d822SKumar Kartikeya Dwivedi } 534b9c5d822SKumar Kartikeya Dwivedi 535b9c5d822SKumar Kartikeya Dwivedi static void disasm_print(void *private_data, const char *fmt, ...) __printf(2, 3); 536b9c5d822SKumar Kartikeya Dwivedi 537b9c5d822SKumar Kartikeya Dwivedi static void disasm_print(void *private_data, const char *fmt, ...) 538b9c5d822SKumar Kartikeya Dwivedi { 539b9c5d822SKumar Kartikeya Dwivedi struct disasm_ctx *ctx = private_data; 540b9c5d822SKumar Kartikeya Dwivedi va_list args; 541b9c5d822SKumar Kartikeya Dwivedi 542b9c5d822SKumar Kartikeya Dwivedi va_start(args, fmt); 543b9c5d822SKumar Kartikeya Dwivedi seq_buf_vprintf(&ctx->seq, fmt, args); 544b9c5d822SKumar Kartikeya Dwivedi va_end(args); 545b9c5d822SKumar Kartikeya Dwivedi } 546b9c5d822SKumar Kartikeya Dwivedi 547b9c5d822SKumar Kartikeya Dwivedi static const char *disasm_kfunc_name(void *private_data, const struct bpf_insn *insn) 548b9c5d822SKumar Kartikeya Dwivedi { 549b9c5d822SKumar Kartikeya Dwivedi struct disasm_ctx *ctx = private_data; 550b9c5d822SKumar Kartikeya Dwivedi 551b9c5d822SKumar Kartikeya Dwivedi return bpf_disasm_kfunc_name(ctx->env, insn); 552b9c5d822SKumar Kartikeya Dwivedi } 553b9c5d822SKumar Kartikeya Dwivedi 554b9c5d822SKumar Kartikeya Dwivedi static void format_disasm_line(struct bpf_verifier_env *env, int insn_idx, 555b9c5d822SKumar Kartikeya Dwivedi struct disasm_line *line) 556b9c5d822SKumar Kartikeya Dwivedi { 557b9c5d822SKumar Kartikeya Dwivedi struct disasm_ctx ctx = { .env = env }; 558b9c5d822SKumar Kartikeya Dwivedi struct bpf_insn *insn; 559b9c5d822SKumar Kartikeya Dwivedi const struct bpf_insn_cbs cbs = { 560b9c5d822SKumar Kartikeya Dwivedi .cb_call = disasm_kfunc_name, 561b9c5d822SKumar Kartikeya Dwivedi .cb_print = disasm_print, 562b9c5d822SKumar Kartikeya Dwivedi .private_data = &ctx, 563b9c5d822SKumar Kartikeya Dwivedi }; 564b9c5d822SKumar Kartikeya Dwivedi 565b9c5d822SKumar Kartikeya Dwivedi line->idx = insn_idx; 566b9c5d822SKumar Kartikeya Dwivedi line->valid = false; 567b9c5d822SKumar Kartikeya Dwivedi seq_buf_init(&ctx.seq, line->text, sizeof(line->text)); 568b9c5d822SKumar Kartikeya Dwivedi 569b9c5d822SKumar Kartikeya Dwivedi if (insn_idx < 0 || insn_idx >= env->prog->len) 570b9c5d822SKumar Kartikeya Dwivedi return; 571b9c5d822SKumar Kartikeya Dwivedi 572b9c5d822SKumar Kartikeya Dwivedi if (insn_idx > 0 && bpf_is_ldimm64(&env->prog->insnsi[insn_idx - 1])) 573b9c5d822SKumar Kartikeya Dwivedi return; 574b9c5d822SKumar Kartikeya Dwivedi 575b9c5d822SKumar Kartikeya Dwivedi insn = &env->prog->insnsi[insn_idx]; 576b9c5d822SKumar Kartikeya Dwivedi if (bpf_is_ldimm64(insn) && insn_idx + 1 >= env->prog->len) 577b9c5d822SKumar Kartikeya Dwivedi return; 578b9c5d822SKumar Kartikeya Dwivedi 579b9c5d822SKumar Kartikeya Dwivedi print_bpf_insn(&cbs, insn, env->allow_ptr_leaks); 580b9c5d822SKumar Kartikeya Dwivedi seq_buf_str(&ctx.seq); 581b9c5d822SKumar Kartikeya Dwivedi ctx.seq.len = strnlen(line->text, sizeof(line->text)); 582b9c5d822SKumar Kartikeya Dwivedi while (ctx.seq.len && line->text[ctx.seq.len - 1] == '\n') 583b9c5d822SKumar Kartikeya Dwivedi seq_buf_pop(&ctx.seq); 584b9c5d822SKumar Kartikeya Dwivedi seq_buf_str(&ctx.seq); 585b9c5d822SKumar Kartikeya Dwivedi 586b9c5d822SKumar Kartikeya Dwivedi line->valid = true; 587b9c5d822SKumar Kartikeya Dwivedi } 588b9c5d822SKumar Kartikeya Dwivedi 589b9c5d822SKumar Kartikeya Dwivedi static void diag_format_source_text(char *buf, size_t size, const char *line, int width) 590b9c5d822SKumar Kartikeya Dwivedi { 591b9c5d822SKumar Kartikeya Dwivedi int col = 0, len = 0; 592b9c5d822SKumar Kartikeya Dwivedi 593b9c5d822SKumar Kartikeya Dwivedi if (!size) 594b9c5d822SKumar Kartikeya Dwivedi return; 595b9c5d822SKumar Kartikeya Dwivedi if (width <= 0) { 596b9c5d822SKumar Kartikeya Dwivedi buf[0] = '\0'; 597b9c5d822SKumar Kartikeya Dwivedi return; 598b9c5d822SKumar Kartikeya Dwivedi } 599b9c5d822SKumar Kartikeya Dwivedi 600b9c5d822SKumar Kartikeya Dwivedi line = line ?: "..."; 601b9c5d822SKumar Kartikeya Dwivedi while (*line && col < width && len + 1 < size) { 602b9c5d822SKumar Kartikeya Dwivedi if (*line == '\t') { 603b9c5d822SKumar Kartikeya Dwivedi int next = round_up(col + 1, BPF_DIAG_TAB_WIDTH); 604b9c5d822SKumar Kartikeya Dwivedi 605b9c5d822SKumar Kartikeya Dwivedi while (col < next && col < width && len + 1 < size) { 606b9c5d822SKumar Kartikeya Dwivedi buf[len++] = ' '; 607b9c5d822SKumar Kartikeya Dwivedi col++; 608b9c5d822SKumar Kartikeya Dwivedi } 609b9c5d822SKumar Kartikeya Dwivedi line++; 610b9c5d822SKumar Kartikeya Dwivedi continue; 611b9c5d822SKumar Kartikeya Dwivedi } 612b9c5d822SKumar Kartikeya Dwivedi 613b9c5d822SKumar Kartikeya Dwivedi buf[len++] = *line++; 614b9c5d822SKumar Kartikeya Dwivedi col++; 615b9c5d822SKumar Kartikeya Dwivedi } 616b9c5d822SKumar Kartikeya Dwivedi 617b9c5d822SKumar Kartikeya Dwivedi if (*line) { 618b9c5d822SKumar Kartikeya Dwivedi int ellipsis_len = min(3, width); 619b9c5d822SKumar Kartikeya Dwivedi 620b9c5d822SKumar Kartikeya Dwivedi while (len > 0 && col > width - ellipsis_len) { 621b9c5d822SKumar Kartikeya Dwivedi len--; 622b9c5d822SKumar Kartikeya Dwivedi col--; 623b9c5d822SKumar Kartikeya Dwivedi } 624b9c5d822SKumar Kartikeya Dwivedi while (ellipsis_len-- && len + 1 < size) 625b9c5d822SKumar Kartikeya Dwivedi buf[len++] = '.'; 626b9c5d822SKumar Kartikeya Dwivedi } 627b9c5d822SKumar Kartikeya Dwivedi 628b9c5d822SKumar Kartikeya Dwivedi buf[len] = '\0'; 629b9c5d822SKumar Kartikeya Dwivedi } 630b9c5d822SKumar Kartikeya Dwivedi 631b9c5d822SKumar Kartikeya Dwivedi static void diag_format_source_lane(char *buf, size_t size, const char *source_prefix, 632b9c5d822SKumar Kartikeya Dwivedi int source_line_width, int line_num, const char *line) 633b9c5d822SKumar Kartikeya Dwivedi { 634b9c5d822SKumar Kartikeya Dwivedi int len, text_width; 635b9c5d822SKumar Kartikeya Dwivedi 636b9c5d822SKumar Kartikeya Dwivedi if (line_num <= 0) { 637b9c5d822SKumar Kartikeya Dwivedi buf[0] = '\0'; 638b9c5d822SKumar Kartikeya Dwivedi return; 639b9c5d822SKumar Kartikeya Dwivedi } 640b9c5d822SKumar Kartikeya Dwivedi 641b9c5d822SKumar Kartikeya Dwivedi len = scnprintf(buf, size, "%s%*d | ", source_prefix, source_line_width, line_num); 642b9c5d822SKumar Kartikeya Dwivedi text_width = BPF_DIAG_SOURCE_LANE_WIDTH - len; 643b9c5d822SKumar Kartikeya Dwivedi diag_format_source_text(buf + len, size - len, line, text_width); 644b9c5d822SKumar Kartikeya Dwivedi } 645b9c5d822SKumar Kartikeya Dwivedi 6465ad74616SKumar Kartikeya Dwivedi static void bpf_diag_header(struct bpf_verifier_env *env, const char *category, 6475ad74616SKumar Kartikeya Dwivedi const char *problem) 6485ad74616SKumar Kartikeya Dwivedi { 6495ad74616SKumar Kartikeya Dwivedi char first; 6505ad74616SKumar Kartikeya Dwivedi 6515ad74616SKumar Kartikeya Dwivedi if (!bpf_diag_enabled(env)) 6525ad74616SKumar Kartikeya Dwivedi return; 6535ad74616SKumar Kartikeya Dwivedi 6545ad74616SKumar Kartikeya Dwivedi category = category ?: "Verifier Error"; 6555ad74616SKumar Kartikeya Dwivedi problem = problem ?: ""; 6565ad74616SKumar Kartikeya Dwivedi 6575ad74616SKumar Kartikeya Dwivedi if (!problem[0]) { 6585ad74616SKumar Kartikeya Dwivedi diag_write(env, "\nVerification failed: %s\n", category); 6595ad74616SKumar Kartikeya Dwivedi return; 6605ad74616SKumar Kartikeya Dwivedi } 6615ad74616SKumar Kartikeya Dwivedi 6625ad74616SKumar Kartikeya Dwivedi first = toupper(problem[0]); 6635ad74616SKumar Kartikeya Dwivedi diag_write(env, "\nVerification failed: %s: %c%s\n", category, first, problem + 1); 6645ad74616SKumar Kartikeya Dwivedi } 665b9c5d822SKumar Kartikeya Dwivedi 666b9c5d822SKumar Kartikeya Dwivedi static void diag_print_source_annotation(struct bpf_verifier_env *env, int line_width, int indent, 667b9c5d822SKumar Kartikeya Dwivedi const char *label, const char *msg) 668b9c5d822SKumar Kartikeya Dwivedi { 669b9c5d822SKumar Kartikeya Dwivedi const char *first_prefix, *next_prefix, *text; 670b9c5d822SKumar Kartikeya Dwivedi 671b9c5d822SKumar Kartikeya Dwivedi indent = min_t(int, indent, max_t(int, 0, BPF_DIAG_SOURCE_LANE_WIDTH - line_width - 8)); 672b9c5d822SKumar Kartikeya Dwivedi text = bpf_diag_fmt(env, "%s: %s", label, msg); 673b9c5d822SKumar Kartikeya Dwivedi first_prefix = bpf_diag_fmt(env, " %*s | %*s^-- ", line_width + 4, "", indent, ""); 674b9c5d822SKumar Kartikeya Dwivedi next_prefix = bpf_diag_fmt(env, " %*s | %*s ", line_width + 4, "", indent, ""); 675b9c5d822SKumar Kartikeya Dwivedi 676b9c5d822SKumar Kartikeya Dwivedi diag_print_wrapped_prefixed(env, first_prefix, next_prefix, text); 677b9c5d822SKumar Kartikeya Dwivedi } 678b9c5d822SKumar Kartikeya Dwivedi 679b9c5d822SKumar Kartikeya Dwivedi static void diag_print_insn_context(struct bpf_verifier_env *env, u32 insn_idx, 680b9c5d822SKumar Kartikeya Dwivedi struct disasm_line *disasm_lines) 681b9c5d822SKumar Kartikeya Dwivedi { 682b9c5d822SKumar Kartikeya Dwivedi int insn_width = diag_line_width(env->prog->len ? env->prog->len - 1 : 0); 683b9c5d822SKumar Kartikeya Dwivedi int i; 684b9c5d822SKumar Kartikeya Dwivedi 685b9c5d822SKumar Kartikeya Dwivedi for (i = 0; i < BPF_DIAG_CONTEXT_CNT; i++) { 686b9c5d822SKumar Kartikeya Dwivedi int row = i - BPF_DIAG_CONTEXT; 687b9c5d822SKumar Kartikeya Dwivedi 688b9c5d822SKumar Kartikeya Dwivedi format_disasm_line(env, insn_idx + row, &disasm_lines[i]); 689b9c5d822SKumar Kartikeya Dwivedi } 690b9c5d822SKumar Kartikeya Dwivedi 691b9c5d822SKumar Kartikeya Dwivedi diag_write(env, " Instruction context:\n"); 692b9c5d822SKumar Kartikeya Dwivedi for (i = 0; i < BPF_DIAG_CONTEXT_CNT; i++) { 693b9c5d822SKumar Kartikeya Dwivedi struct disasm_line *line = &disasm_lines[i]; 694b9c5d822SKumar Kartikeya Dwivedi 695b9c5d822SKumar Kartikeya Dwivedi if (line->valid) 696b9c5d822SKumar Kartikeya Dwivedi diag_write(env, " %s%*d | %s\n", 697b9c5d822SKumar Kartikeya Dwivedi line->idx == insn_idx ? ">>> " : " ", 698b9c5d822SKumar Kartikeya Dwivedi insn_width, line->idx, line->text); 699b9c5d822SKumar Kartikeya Dwivedi } 700b9c5d822SKumar Kartikeya Dwivedi } 701b9c5d822SKumar Kartikeya Dwivedi 702b9c5d822SKumar Kartikeya Dwivedi static void bpf_diag_source(struct bpf_verifier_env *env, u32 insn_idx, const char *label, 703b9c5d822SKumar Kartikeya Dwivedi const char *fmt, ...) 704b9c5d822SKumar Kartikeya Dwivedi { 705b9c5d822SKumar Kartikeya Dwivedi struct bpf_diag_scratch *scratch; 706b9c5d822SKumar Kartikeya Dwivedi struct bpf_linfo_source *source_lines; 707b9c5d822SKumar Kartikeya Dwivedi struct disasm_line *disasm_lines; 708b9c5d822SKumar Kartikeya Dwivedi struct bpf_linfo_source src = {}; 709b9c5d822SKumar Kartikeya Dwivedi struct diag_fmt_mark mark; 710b9c5d822SKumar Kartikeya Dwivedi const struct bpf_line_info *linfo; 711b9c5d822SKumar Kartikeya Dwivedi const struct bpf_subprog_info *subprog; 712b9c5d822SKumar Kartikeya Dwivedi struct btf *btf = env->prog->aux->btf; 713b9c5d822SKumar Kartikeya Dwivedi char *source_lane; 714b9c5d822SKumar Kartikeya Dwivedi const char *msg; 715b9c5d822SKumar Kartikeya Dwivedi const char *func; 716b9c5d822SKumar Kartikeya Dwivedi int start_line, end_line, width, indent, subprogno, linfo_start, linfo_end, i; 717b9c5d822SKumar Kartikeya Dwivedi va_list args; 718b9c5d822SKumar Kartikeya Dwivedi 719b9c5d822SKumar Kartikeya Dwivedi if (!bpf_diag_enabled(env)) 720b9c5d822SKumar Kartikeya Dwivedi return; 721b9c5d822SKumar Kartikeya Dwivedi if (!env->diag) 722b9c5d822SKumar Kartikeya Dwivedi return; 723b9c5d822SKumar Kartikeya Dwivedi 724b9c5d822SKumar Kartikeya Dwivedi mark = diag_fmt_save(env); 725b9c5d822SKumar Kartikeya Dwivedi label = label ?: "note"; 726b9c5d822SKumar Kartikeya Dwivedi scratch = &env->diag->scratch; 727b9c5d822SKumar Kartikeya Dwivedi source_lines = scratch->source_lines; 728b9c5d822SKumar Kartikeya Dwivedi disasm_lines = scratch->disasm_lines; 729b9c5d822SKumar Kartikeya Dwivedi memset(source_lines, 0, sizeof(scratch->source_lines)); 730b9c5d822SKumar Kartikeya Dwivedi memset(disasm_lines, 0, sizeof(scratch->disasm_lines)); 731b9c5d822SKumar Kartikeya Dwivedi 732b9c5d822SKumar Kartikeya Dwivedi va_start(args, fmt); 733b9c5d822SKumar Kartikeya Dwivedi msg = bpf_diag_vfmt(env, fmt, args); 734b9c5d822SKumar Kartikeya Dwivedi va_end(args); 735b9c5d822SKumar Kartikeya Dwivedi if (!*msg) 736b9c5d822SKumar Kartikeya Dwivedi msg = "<failed to allocate diagnostic text>"; 737b9c5d822SKumar Kartikeya Dwivedi 738b9c5d822SKumar Kartikeya Dwivedi linfo = bpf_find_linfo(env->prog, insn_idx); 739b9c5d822SKumar Kartikeya Dwivedi if (btf && linfo) 740b9c5d822SKumar Kartikeya Dwivedi bpf_get_linfo_source(btf, linfo, &src); 741b9c5d822SKumar Kartikeya Dwivedi if (!src.file || !*src.file || !src.line || !*src.line) { 742b9c5d822SKumar Kartikeya Dwivedi diag_write(env, " insn %u\n", insn_idx); 743b9c5d822SKumar Kartikeya Dwivedi diag_print_source_annotation(env, 0, 0, label, msg); 744b9c5d822SKumar Kartikeya Dwivedi diag_print_insn_context(env, insn_idx, disasm_lines); 745b9c5d822SKumar Kartikeya Dwivedi goto out_restore; 746b9c5d822SKumar Kartikeya Dwivedi } 747b9c5d822SKumar Kartikeya Dwivedi 748b9c5d822SKumar Kartikeya Dwivedi subprog = bpf_find_containing_subprog(env, insn_idx); 749b9c5d822SKumar Kartikeya Dwivedi subprogno = subprog ? subprog - env->subprog_info : -ENOENT; 750b9c5d822SKumar Kartikeya Dwivedi func = subprogno >= 0 ? bpf_subprog_name(env, subprogno) : NULL; 751b9c5d822SKumar Kartikeya Dwivedi if (func && *func) 752b9c5d822SKumar Kartikeya Dwivedi diag_write(env, " %s @ %s:%d:%d\n", func, src.file, src.line_num, src.line_col); 753b9c5d822SKumar Kartikeya Dwivedi else 754b9c5d822SKumar Kartikeya Dwivedi diag_write(env, " %s:%d:%d\n", src.file, src.line_num, src.line_col); 755b9c5d822SKumar Kartikeya Dwivedi 756b9c5d822SKumar Kartikeya Dwivedi start_line = src.line_num - BPF_DIAG_CONTEXT; 757b9c5d822SKumar Kartikeya Dwivedi end_line = src.line_num + BPF_DIAG_CONTEXT; 758b9c5d822SKumar Kartikeya Dwivedi width = diag_line_width(end_line); 759b9c5d822SKumar Kartikeya Dwivedi indent = diag_line_indent(src.line); 760b9c5d822SKumar Kartikeya Dwivedi for (i = 0; i < BPF_DIAG_CONTEXT_CNT; i++) 761b9c5d822SKumar Kartikeya Dwivedi source_lines[i].line_num = start_line + i; 762b9c5d822SKumar Kartikeya Dwivedi 763b9c5d822SKumar Kartikeya Dwivedi linfo = env->prog->aux->linfo; 764b9c5d822SKumar Kartikeya Dwivedi linfo_start = subprog ? subprog->linfo_idx : 0; 765b9c5d822SKumar Kartikeya Dwivedi linfo_end = subprogno >= 0 && subprogno + 1 < env->subprog_cnt ? 766b9c5d822SKumar Kartikeya Dwivedi env->subprog_info[subprogno + 1].linfo_idx : env->prog->aux->nr_linfo; 767b9c5d822SKumar Kartikeya Dwivedi for (i = linfo_start; i < linfo_end; i++) { 768b9c5d822SKumar Kartikeya Dwivedi struct bpf_linfo_source line_src; 769b9c5d822SKumar Kartikeya Dwivedi int idx; 770b9c5d822SKumar Kartikeya Dwivedi 771b9c5d822SKumar Kartikeya Dwivedi bpf_get_linfo_source(btf, &linfo[i], &line_src); 772b9c5d822SKumar Kartikeya Dwivedi if (line_src.file_name_off != src.file_name_off || 773b9c5d822SKumar Kartikeya Dwivedi line_src.line_num < start_line || line_src.line_num > end_line || 774b9c5d822SKumar Kartikeya Dwivedi !line_src.line || !*line_src.line) 775b9c5d822SKumar Kartikeya Dwivedi continue; 776b9c5d822SKumar Kartikeya Dwivedi 777b9c5d822SKumar Kartikeya Dwivedi idx = line_src.line_num - start_line; 778b9c5d822SKumar Kartikeya Dwivedi if (!source_lines[idx].line) 779b9c5d822SKumar Kartikeya Dwivedi source_lines[idx] = line_src; 780b9c5d822SKumar Kartikeya Dwivedi } 781b9c5d822SKumar Kartikeya Dwivedi 782b9c5d822SKumar Kartikeya Dwivedi diag_write(env, " Source context:\n"); 783b9c5d822SKumar Kartikeya Dwivedi source_lane = bpf_diag_fmt_buf(env, BPF_DIAG_FMT_BUF_SIZE); 784b9c5d822SKumar Kartikeya Dwivedi if (!source_lane) 785b9c5d822SKumar Kartikeya Dwivedi goto out_restore; 786b9c5d822SKumar Kartikeya Dwivedi for (i = 0; i < BPF_DIAG_CONTEXT_CNT; i++) { 787b9c5d822SKumar Kartikeya Dwivedi const char *source_prefix; 788b9c5d822SKumar Kartikeya Dwivedi 789b9c5d822SKumar Kartikeya Dwivedi source_prefix = source_lines[i].line_num == src.line_num ? ">>> " : " "; 790b9c5d822SKumar Kartikeya Dwivedi diag_format_source_lane(source_lane, BPF_DIAG_FMT_BUF_SIZE, source_prefix, width, 791b9c5d822SKumar Kartikeya Dwivedi source_lines[i].line_num, source_lines[i].line); 792b9c5d822SKumar Kartikeya Dwivedi diag_write(env, " %s\n", source_lane); 793b9c5d822SKumar Kartikeya Dwivedi if (source_lines[i].line_num == src.line_num) 794b9c5d822SKumar Kartikeya Dwivedi diag_print_source_annotation(env, width, indent, label, msg); 795b9c5d822SKumar Kartikeya Dwivedi } 796b9c5d822SKumar Kartikeya Dwivedi diag_print_insn_context(env, insn_idx, disasm_lines); 797b9c5d822SKumar Kartikeya Dwivedi 798b9c5d822SKumar Kartikeya Dwivedi out_restore: 799b9c5d822SKumar Kartikeya Dwivedi diag_fmt_restore(env, mark); 800b9c5d822SKumar Kartikeya Dwivedi } 801daf82487SKumar Kartikeya Dwivedi 802daf82487SKumar Kartikeya Dwivedi void bpf_diag_record_branch(struct bpf_verifier_env *env, u32 insn_idx, bool cond_true) 803daf82487SKumar Kartikeya Dwivedi { 804daf82487SKumar Kartikeya Dwivedi struct bpf_diag_history_event event = { 805daf82487SKumar Kartikeya Dwivedi .insn_idx = insn_idx, 806daf82487SKumar Kartikeya Dwivedi .kind = BPF_DIAG_HISTORY_BRANCH, 807daf82487SKumar Kartikeya Dwivedi .branch = { 808daf82487SKumar Kartikeya Dwivedi .cond_true = cond_true, 809daf82487SKumar Kartikeya Dwivedi }, 810daf82487SKumar Kartikeya Dwivedi }; 811daf82487SKumar Kartikeya Dwivedi 812daf82487SKumar Kartikeya Dwivedi diag_append_history(env, &event); 813daf82487SKumar Kartikeya Dwivedi } 814af4ea6e2SKumar Kartikeya Dwivedi 815af4ea6e2SKumar Kartikeya Dwivedi static void diag_snapshot_reg(struct bpf_diag_reg_snapshot *snapshot, 816af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_reg_state *reg) 817af4ea6e2SKumar Kartikeya Dwivedi { 818af4ea6e2SKumar Kartikeya Dwivedi snapshot->type = reg->type; 819af4ea6e2SKumar Kartikeya Dwivedi if (type_is_map_ptr(reg->type)) 820af4ea6e2SKumar Kartikeya Dwivedi snapshot->map_ptr = reg->map_ptr; 821af4ea6e2SKumar Kartikeya Dwivedi if (base_type(reg->type) == PTR_TO_BTF_ID && reg->btf && reg->btf_id) { 822af4ea6e2SKumar Kartikeya Dwivedi snapshot->btf_id = reg->btf_id; 823af4ea6e2SKumar Kartikeya Dwivedi snapshot->btf = reg->btf; 824af4ea6e2SKumar Kartikeya Dwivedi } 825af4ea6e2SKumar Kartikeya Dwivedi snapshot->var_off = reg->var_off; 826af4ea6e2SKumar Kartikeya Dwivedi snapshot->r64 = reg->r64; 827af4ea6e2SKumar Kartikeya Dwivedi } 828af4ea6e2SKumar Kartikeya Dwivedi 829af4ea6e2SKumar Kartikeya Dwivedi static bool diag_mod_insn_origin(struct bpf_verifier_env *env, u32 insn_idx, 830af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_diag_mod_target *target, 831af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_target *origin) 832af4ea6e2SKumar Kartikeya Dwivedi { 833af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_insn *insn = &env->prog->insnsi[insn_idx]; 834af4ea6e2SKumar Kartikeya Dwivedi u8 class = BPF_CLASS(insn->code); 835af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_func_state *state; 836af4ea6e2SKumar Kartikeya Dwivedi 837af4ea6e2SKumar Kartikeya Dwivedi if (target->kind == BPF_DIAG_MOD_TARGET_REG && (class == BPF_ALU || class == BPF_ALU64) && 838af4ea6e2SKumar Kartikeya Dwivedi BPF_OP(insn->code) == BPF_MOV && BPF_SRC(insn->code) == BPF_X) { 839af4ea6e2SKumar Kartikeya Dwivedi *origin = diag_reg_target(target->frame_id, target->frameno, insn->src_reg); 840af4ea6e2SKumar Kartikeya Dwivedi return true; 841af4ea6e2SKumar Kartikeya Dwivedi } 842af4ea6e2SKumar Kartikeya Dwivedi 843af4ea6e2SKumar Kartikeya Dwivedi if ((target->kind != BPF_DIAG_MOD_TARGET_STACK_ARG && 844af4ea6e2SKumar Kartikeya Dwivedi target->kind != BPF_DIAG_MOD_TARGET_STACK_SLOT) || 845af4ea6e2SKumar Kartikeya Dwivedi class != BPF_STX) 846af4ea6e2SKumar Kartikeya Dwivedi return false; 847af4ea6e2SKumar Kartikeya Dwivedi 848af4ea6e2SKumar Kartikeya Dwivedi state = env->cur_state->frame[env->cur_state->curframe]; 849af4ea6e2SKumar Kartikeya Dwivedi *origin = diag_reg_target(state->diag_frame_id, state->frameno, insn->src_reg); 850af4ea6e2SKumar Kartikeya Dwivedi return true; 851af4ea6e2SKumar Kartikeya Dwivedi } 852af4ea6e2SKumar Kartikeya Dwivedi 853af4ea6e2SKumar Kartikeya Dwivedi static bool diag_mod_keeps_lineage(struct bpf_verifier_env *env, 854af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_diag_history_event *event) 855af4ea6e2SKumar Kartikeya Dwivedi { 856af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_insn *insn; 857af4ea6e2SKumar Kartikeya Dwivedi u8 class; 858af4ea6e2SKumar Kartikeya Dwivedi 859af4ea6e2SKumar Kartikeya Dwivedi if (event->mod.reason != BPF_DIAG_MOD_WRITE || 860af4ea6e2SKumar Kartikeya Dwivedi event->mod.target.kind != BPF_DIAG_MOD_TARGET_REG) 861af4ea6e2SKumar Kartikeya Dwivedi return false; 862af4ea6e2SKumar Kartikeya Dwivedi 863af4ea6e2SKumar Kartikeya Dwivedi insn = &env->prog->insnsi[event->insn_idx]; 864af4ea6e2SKumar Kartikeya Dwivedi class = BPF_CLASS(insn->code); 865af4ea6e2SKumar Kartikeya Dwivedi if (class != BPF_ALU && class != BPF_ALU64) 866af4ea6e2SKumar Kartikeya Dwivedi return false; 867af4ea6e2SKumar Kartikeya Dwivedi 868af4ea6e2SKumar Kartikeya Dwivedi switch (BPF_OP(insn->code)) { 869af4ea6e2SKumar Kartikeya Dwivedi case BPF_ADD: 870af4ea6e2SKumar Kartikeya Dwivedi case BPF_SUB: 871af4ea6e2SKumar Kartikeya Dwivedi case BPF_MUL: 872af4ea6e2SKumar Kartikeya Dwivedi case BPF_OR: 873af4ea6e2SKumar Kartikeya Dwivedi case BPF_AND: 874af4ea6e2SKumar Kartikeya Dwivedi case BPF_LSH: 875af4ea6e2SKumar Kartikeya Dwivedi case BPF_RSH: 876af4ea6e2SKumar Kartikeya Dwivedi case BPF_ARSH: 877af4ea6e2SKumar Kartikeya Dwivedi case BPF_XOR: 878af4ea6e2SKumar Kartikeya Dwivedi case BPF_NEG: 879af4ea6e2SKumar Kartikeya Dwivedi case BPF_END: 880af4ea6e2SKumar Kartikeya Dwivedi return true; 881af4ea6e2SKumar Kartikeya Dwivedi default: 882af4ea6e2SKumar Kartikeya Dwivedi return false; 883af4ea6e2SKumar Kartikeya Dwivedi } 884af4ea6e2SKumar Kartikeya Dwivedi } 885af4ea6e2SKumar Kartikeya Dwivedi 886af4ea6e2SKumar Kartikeya Dwivedi static void diag_record_mod(struct bpf_verifier_env *env, u32 insn_idx, 887af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_target target, 888af4ea6e2SKumar Kartikeya Dwivedi enum bpf_diag_mod_reason reason, 889af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_reg_state *old_reg, 890af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_reg_state *new_reg, 891af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_diag_mod_target *origin) 892af4ea6e2SKumar Kartikeya Dwivedi { 893af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_history_event event = { 894af4ea6e2SKumar Kartikeya Dwivedi .insn_idx = insn_idx, 895af4ea6e2SKumar Kartikeya Dwivedi .kind = BPF_DIAG_HISTORY_MOD, 896af4ea6e2SKumar Kartikeya Dwivedi .mod = { 897af4ea6e2SKumar Kartikeya Dwivedi .target = target, 898af4ea6e2SKumar Kartikeya Dwivedi .reason = reason, 899af4ea6e2SKumar Kartikeya Dwivedi }, 900af4ea6e2SKumar Kartikeya Dwivedi }; 901af4ea6e2SKumar Kartikeya Dwivedi 902af4ea6e2SKumar Kartikeya Dwivedi if (old_reg) 903af4ea6e2SKumar Kartikeya Dwivedi diag_snapshot_reg(&event.mod.old, old_reg); 904af4ea6e2SKumar Kartikeya Dwivedi if (new_reg) 905af4ea6e2SKumar Kartikeya Dwivedi diag_snapshot_reg(&event.mod.new, new_reg); 906af4ea6e2SKumar Kartikeya Dwivedi if (origin) { 907af4ea6e2SKumar Kartikeya Dwivedi event.mod.origin = *origin; 908af4ea6e2SKumar Kartikeya Dwivedi event.mod.origin_valid = true; 909af4ea6e2SKumar Kartikeya Dwivedi } else if (diag_mod_insn_origin(env, insn_idx, &target, &event.mod.origin)) { 910af4ea6e2SKumar Kartikeya Dwivedi event.mod.origin_valid = true; 911af4ea6e2SKumar Kartikeya Dwivedi } 912af4ea6e2SKumar Kartikeya Dwivedi if (old_reg && new_reg && 913af4ea6e2SKumar Kartikeya Dwivedi (reason == BPF_DIAG_MOD_WRITE || reason == BPF_DIAG_MOD_SPILL) && 914af4ea6e2SKumar Kartikeya Dwivedi !memcmp(&event.mod.old, &event.mod.new, sizeof(event.mod.old)) && 915af4ea6e2SKumar Kartikeya Dwivedi !event.mod.origin_valid && 916af4ea6e2SKumar Kartikeya Dwivedi diag_mod_keeps_lineage(env, &event)) 917af4ea6e2SKumar Kartikeya Dwivedi return; 918af4ea6e2SKumar Kartikeya Dwivedi 919af4ea6e2SKumar Kartikeya Dwivedi diag_append_history(env, &event); 920af4ea6e2SKumar Kartikeya Dwivedi } 921af4ea6e2SKumar Kartikeya Dwivedi 922af4ea6e2SKumar Kartikeya Dwivedi static struct bpf_reg_state *target_to_reg(struct bpf_verifier_env *env, 923af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_diag_mod_target *target) 924af4ea6e2SKumar Kartikeya Dwivedi { 925af4ea6e2SKumar Kartikeya Dwivedi struct bpf_verifier_state *vstate = env->cur_state; 926af4ea6e2SKumar Kartikeya Dwivedi struct bpf_func_state *state; 927af4ea6e2SKumar Kartikeya Dwivedi 928af4ea6e2SKumar Kartikeya Dwivedi state = target->frameno <= vstate->curframe ? vstate->frame[target->frameno] : NULL; 929af4ea6e2SKumar Kartikeya Dwivedi 930af4ea6e2SKumar Kartikeya Dwivedi if (!state) 931af4ea6e2SKumar Kartikeya Dwivedi return NULL; 932af4ea6e2SKumar Kartikeya Dwivedi if (state->diag_frame_id != target->frame_id) 933af4ea6e2SKumar Kartikeya Dwivedi return NULL; 934af4ea6e2SKumar Kartikeya Dwivedi 935af4ea6e2SKumar Kartikeya Dwivedi switch (target->kind) { 936af4ea6e2SKumar Kartikeya Dwivedi case BPF_DIAG_MOD_TARGET_REG: 937af4ea6e2SKumar Kartikeya Dwivedi if (target->regno >= MAX_BPF_REG) 938af4ea6e2SKumar Kartikeya Dwivedi return NULL; 939af4ea6e2SKumar Kartikeya Dwivedi return &state->regs[target->regno]; 940af4ea6e2SKumar Kartikeya Dwivedi case BPF_DIAG_MOD_TARGET_STACK_ARG: 941af4ea6e2SKumar Kartikeya Dwivedi if (target->stack_arg >= state->out_stack_arg_cnt) 942af4ea6e2SKumar Kartikeya Dwivedi return NULL; 943af4ea6e2SKumar Kartikeya Dwivedi return &state->stack_arg_regs[target->stack_arg]; 944af4ea6e2SKumar Kartikeya Dwivedi case BPF_DIAG_MOD_TARGET_STACK_SLOT: 945af4ea6e2SKumar Kartikeya Dwivedi if (target->spi >= state->allocated_stack / BPF_REG_SIZE) 946af4ea6e2SKumar Kartikeya Dwivedi return NULL; 947af4ea6e2SKumar Kartikeya Dwivedi return &state->stack[target->spi].spilled_ptr; 948af4ea6e2SKumar Kartikeya Dwivedi default: 949af4ea6e2SKumar Kartikeya Dwivedi return NULL; 950af4ea6e2SKumar Kartikeya Dwivedi } 951af4ea6e2SKumar Kartikeya Dwivedi } 952af4ea6e2SKumar Kartikeya Dwivedi 953af4ea6e2SKumar Kartikeya Dwivedi static bool reg_to_target(struct bpf_verifier_env *env, const struct bpf_reg_state *reg, 954af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_target *target) 955af4ea6e2SKumar Kartikeya Dwivedi { 956af4ea6e2SKumar Kartikeya Dwivedi struct bpf_verifier_state *vstate = env->cur_state; 957af4ea6e2SKumar Kartikeya Dwivedi unsigned long addr = (unsigned long)reg; 958af4ea6e2SKumar Kartikeya Dwivedi int frame; 959af4ea6e2SKumar Kartikeya Dwivedi 960af4ea6e2SKumar Kartikeya Dwivedi for (frame = 0; frame <= vstate->curframe; frame++) { 961af4ea6e2SKumar Kartikeya Dwivedi struct bpf_func_state *state = vstate->frame[frame]; 962af4ea6e2SKumar Kartikeya Dwivedi unsigned long start, end; 963af4ea6e2SKumar Kartikeya Dwivedi u32 nslots = state->allocated_stack / BPF_REG_SIZE; 964af4ea6e2SKumar Kartikeya Dwivedi int spi; 965af4ea6e2SKumar Kartikeya Dwivedi 966af4ea6e2SKumar Kartikeya Dwivedi start = (unsigned long)state->regs; 967af4ea6e2SKumar Kartikeya Dwivedi end = (unsigned long)(state->regs + MAX_BPF_REG); 968af4ea6e2SKumar Kartikeya Dwivedi if (addr >= start && addr < end) { 969af4ea6e2SKumar Kartikeya Dwivedi *target = diag_reg_target(state->diag_frame_id, state->frameno, 970af4ea6e2SKumar Kartikeya Dwivedi reg - state->regs); 971af4ea6e2SKumar Kartikeya Dwivedi return true; 972af4ea6e2SKumar Kartikeya Dwivedi } 973af4ea6e2SKumar Kartikeya Dwivedi 974af4ea6e2SKumar Kartikeya Dwivedi start = (unsigned long)state->stack_arg_regs; 975af4ea6e2SKumar Kartikeya Dwivedi end = (unsigned long)(state->stack_arg_regs + state->out_stack_arg_cnt); 976af4ea6e2SKumar Kartikeya Dwivedi if (state->out_stack_arg_cnt && addr >= start && addr < end) { 977af4ea6e2SKumar Kartikeya Dwivedi *target = diag_stack_arg_target(state->diag_frame_id, state->frameno, 978af4ea6e2SKumar Kartikeya Dwivedi reg - state->stack_arg_regs); 979af4ea6e2SKumar Kartikeya Dwivedi return true; 980af4ea6e2SKumar Kartikeya Dwivedi } 981af4ea6e2SKumar Kartikeya Dwivedi 982af4ea6e2SKumar Kartikeya Dwivedi start = (unsigned long)state->stack; 983af4ea6e2SKumar Kartikeya Dwivedi end = (unsigned long)(state->stack + nslots); 984af4ea6e2SKumar Kartikeya Dwivedi if (nslots && addr >= start && addr < end) { 985af4ea6e2SKumar Kartikeya Dwivedi spi = ((const char *)reg - (const char *)state->stack) / 986af4ea6e2SKumar Kartikeya Dwivedi sizeof(*state->stack); 987af4ea6e2SKumar Kartikeya Dwivedi *target = diag_stack_slot_target(state->diag_frame_id, state->frameno, spi); 988af4ea6e2SKumar Kartikeya Dwivedi return true; 989af4ea6e2SKumar Kartikeya Dwivedi } 990af4ea6e2SKumar Kartikeya Dwivedi } 991af4ea6e2SKumar Kartikeya Dwivedi return false; 992af4ea6e2SKumar Kartikeya Dwivedi } 993af4ea6e2SKumar Kartikeya Dwivedi 994af4ea6e2SKumar Kartikeya Dwivedi void bpf_diag_mod_begin(struct bpf_verifier_env *env, const struct bpf_reg_state *reg, 995af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_reg_state *origin, enum bpf_diag_mod_reason reason) 996af4ea6e2SKumar Kartikeya Dwivedi { 997af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag *diag = env->diag; 998af4ea6e2SKumar Kartikeya Dwivedi 999af4ea6e2SKumar Kartikeya Dwivedi if (!diag) 1000af4ea6e2SKumar Kartikeya Dwivedi return; 1001af4ea6e2SKumar Kartikeya Dwivedi diag->mod.active = reg_to_target(env, reg, &diag->mod.target); 1002af4ea6e2SKumar Kartikeya Dwivedi if (!diag->mod.active) 1003af4ea6e2SKumar Kartikeya Dwivedi return; 1004af4ea6e2SKumar Kartikeya Dwivedi diag->mod.target_reg_snapshot = *reg; 1005af4ea6e2SKumar Kartikeya Dwivedi diag->mod.insn_idx = env->insn_idx; 1006af4ea6e2SKumar Kartikeya Dwivedi diag->mod.reason = reason; 1007af4ea6e2SKumar Kartikeya Dwivedi diag->mod.origin_valid = origin && reg_to_target(env, origin, &diag->mod.origin); 1008af4ea6e2SKumar Kartikeya Dwivedi } 1009af4ea6e2SKumar Kartikeya Dwivedi 1010af4ea6e2SKumar Kartikeya Dwivedi void bpf_diag_mod_end(struct bpf_verifier_env *env) 1011af4ea6e2SKumar Kartikeya Dwivedi { 1012af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag *diag = env->diag; 1013af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_reg_state *new_reg; 1014af4ea6e2SKumar Kartikeya Dwivedi 1015af4ea6e2SKumar Kartikeya Dwivedi if (!diag || !diag->mod.active) 1016af4ea6e2SKumar Kartikeya Dwivedi return; 1017af4ea6e2SKumar Kartikeya Dwivedi diag->mod.active = false; 1018af4ea6e2SKumar Kartikeya Dwivedi /* 1019af4ea6e2SKumar Kartikeya Dwivedi * Resolve the target again because the enclosing function state's stack 1020af4ea6e2SKumar Kartikeya Dwivedi * may have been reallocated while the modification was in progress. 1021af4ea6e2SKumar Kartikeya Dwivedi */ 1022af4ea6e2SKumar Kartikeya Dwivedi new_reg = target_to_reg(env, &diag->mod.target); 1023af4ea6e2SKumar Kartikeya Dwivedi if (!new_reg) 1024af4ea6e2SKumar Kartikeya Dwivedi return; 1025af4ea6e2SKumar Kartikeya Dwivedi diag_record_mod(env, diag->mod.insn_idx, diag->mod.target, diag->mod.reason, 1026af4ea6e2SKumar Kartikeya Dwivedi &diag->mod.target_reg_snapshot, new_reg, 1027af4ea6e2SKumar Kartikeya Dwivedi diag->mod.origin_valid ? &diag->mod.origin : NULL); 1028af4ea6e2SKumar Kartikeya Dwivedi } 1029af4ea6e2SKumar Kartikeya Dwivedi 1030af4ea6e2SKumar Kartikeya Dwivedi void bpf_diag_record_scrub(struct bpf_verifier_env *env, const struct bpf_reg_state *reg, 1031af4ea6e2SKumar Kartikeya Dwivedi enum bpf_diag_mod_reason reason) 1032af4ea6e2SKumar Kartikeya Dwivedi { 1033af4ea6e2SKumar Kartikeya Dwivedi struct bpf_diag_mod_target target; 1034af4ea6e2SKumar Kartikeya Dwivedi 1035af4ea6e2SKumar Kartikeya Dwivedi if (!env->diag || reg->type == NOT_INIT || !reg_to_target(env, reg, &target)) 1036af4ea6e2SKumar Kartikeya Dwivedi return; 1037af4ea6e2SKumar Kartikeya Dwivedi diag_record_mod(env, env->insn_idx, target, reason, reg, NULL, NULL); 1038af4ea6e2SKumar Kartikeya Dwivedi } 1039af4ea6e2SKumar Kartikeya Dwivedi 1040af4ea6e2SKumar Kartikeya Dwivedi void bpf_diag_record_scrub_stack(struct bpf_verifier_env *env, 1041af4ea6e2SKumar Kartikeya Dwivedi const struct bpf_func_state *state, s16 min_off, s16 max_off, 1042af4ea6e2SKumar Kartikeya Dwivedi enum bpf_diag_mod_reason reason) 1043af4ea6e2SKumar Kartikeya Dwivedi { 1044af4ea6e2SKumar Kartikeya Dwivedi diag_record_mod(env, env->insn_idx, 1045af4ea6e2SKumar Kartikeya Dwivedi diag_stack_range_target(state->diag_frame_id, state->frameno, min_off, max_off), 1046af4ea6e2SKumar Kartikeya Dwivedi reason, NULL, NULL, NULL); 1047af4ea6e2SKumar Kartikeya Dwivedi } 10489ecd7030SKumar Kartikeya Dwivedi 10499ecd7030SKumar Kartikeya Dwivedi static void diag_record_ref(struct bpf_verifier_env *env, u32 insn_idx, u8 kind, u32 ref_id) 10509ecd7030SKumar Kartikeya Dwivedi { 10519ecd7030SKumar Kartikeya Dwivedi struct bpf_diag_history_event event = { 10529ecd7030SKumar Kartikeya Dwivedi .insn_idx = insn_idx, 10539ecd7030SKumar Kartikeya Dwivedi .kind = kind, 10549ecd7030SKumar Kartikeya Dwivedi .ref = { 10559ecd7030SKumar Kartikeya Dwivedi .ref_id = ref_id, 10569ecd7030SKumar Kartikeya Dwivedi }, 10579ecd7030SKumar Kartikeya Dwivedi }; 10589ecd7030SKumar Kartikeya Dwivedi 10599ecd7030SKumar Kartikeya Dwivedi diag_append_history(env, &event); 10609ecd7030SKumar Kartikeya Dwivedi } 10619ecd7030SKumar Kartikeya Dwivedi 10629ecd7030SKumar Kartikeya Dwivedi void bpf_diag_record_ref_acquire(struct bpf_verifier_env *env, u32 insn_idx, u32 ref_id) 10639ecd7030SKumar Kartikeya Dwivedi { 10649ecd7030SKumar Kartikeya Dwivedi diag_record_ref(env, insn_idx, BPF_DIAG_HISTORY_REF_ACQUIRE, ref_id); 10659ecd7030SKumar Kartikeya Dwivedi } 10669ecd7030SKumar Kartikeya Dwivedi 10679ecd7030SKumar Kartikeya Dwivedi void bpf_diag_record_ref_release(struct bpf_verifier_env *env, u32 insn_idx, u32 ref_id) 10689ecd7030SKumar Kartikeya Dwivedi { 10699ecd7030SKumar Kartikeya Dwivedi diag_record_ref(env, insn_idx, BPF_DIAG_HISTORY_REF_RELEASE, ref_id); 10709ecd7030SKumar Kartikeya Dwivedi } 1071*956a66e5SKumar Kartikeya Dwivedi 1072*956a66e5SKumar Kartikeya Dwivedi void bpf_diag_record_context(struct bpf_verifier_env *env, u32 insn_idx, 1073*956a66e5SKumar Kartikeya Dwivedi enum bpf_diag_context_kind ctx_kind, bool enter, u32 depth) 1074*956a66e5SKumar Kartikeya Dwivedi { 1075*956a66e5SKumar Kartikeya Dwivedi /* 1076*956a66e5SKumar Kartikeya Dwivedi * Keep leave events so context rendering can stop at a depth-zero exit 1077*956a66e5SKumar Kartikeya Dwivedi * and show nested-region depth accurately for the active path. 1078*956a66e5SKumar Kartikeya Dwivedi */ 1079*956a66e5SKumar Kartikeya Dwivedi struct bpf_diag_history_event event = { 1080*956a66e5SKumar Kartikeya Dwivedi .insn_idx = insn_idx, 1081*956a66e5SKumar Kartikeya Dwivedi .kind = BPF_DIAG_HISTORY_CONTEXT, 1082*956a66e5SKumar Kartikeya Dwivedi .ctx = { 1083*956a66e5SKumar Kartikeya Dwivedi .kind = ctx_kind, 1084*956a66e5SKumar Kartikeya Dwivedi .enter = enter, 1085*956a66e5SKumar Kartikeya Dwivedi .depth = depth, 1086*956a66e5SKumar Kartikeya Dwivedi }, 1087*956a66e5SKumar Kartikeya Dwivedi }; 1088*956a66e5SKumar Kartikeya Dwivedi 1089*956a66e5SKumar Kartikeya Dwivedi diag_append_history(env, &event); 1090*956a66e5SKumar Kartikeya Dwivedi } 1091