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